module RenderSync::Model::ClassMethods
Attributes
Public Instance Methods
Set up automatic syncing of partials when a record of this class is created, updated or deleted. Be sure to wrap your model actions inside a sync_enable block for sync to do its magic.
# File lib/render_sync/model.rb, line 36 def sync(*actions) include ModelActions unless include?(ModelActions) include ModelChangeTracking unless include?(ModelChangeTracking) include ModelRenderSyncing if actions.last.is_a? Hash @sync_default_scope = actions.last.fetch :default_scope end actions = [:create, :update, :destroy] if actions.include? :all actions.flatten! if actions.include? :create after_create :prepare_sync_create, if: -> { RenderSync::Model.enabled? } end if actions.include? :update after_update :prepare_sync_update, if: -> { RenderSync::Model.enabled? } end if actions.include? :destroy after_destroy :prepare_sync_destroy, if: -> { RenderSync::Model.enabled? } end end
Set up a sync scope for the model defining a set of records to be updated via sync
name - The name of the scope lambda - A lambda defining the scope.
Has to return an ActiveRecord::Relation.
You can define the lambda with arguments (see examples). Note that the naming of the parameters is very important. Only use names of methods or ActiveRecord attributes defined on the model (e.g. user_id). This way sync will be able to pass changed records to the lambda and track changes to the scope.
Example:
class Todo < ActiveRecord::Base belongs_to :user belongs_to :project scope :incomplete, -> { where(complete: false) } sync :all sync_scope :complete, -> { where(complete: true) } sync_scope :by_project, ->(project_id) { where(project_id: project_id) } sync_scope :my_incomplete_todos, ->(user) { incomplete.where(user_id: user.id) } end
To subscribe to these scopes you would put these lines into your views:
<%= sync partial: "todo", collection: @todos, scope: Todo.complete %>
If the collection you want to render is exactly defined be the given scope the scope can be omitted:
<%= sync partial: "todo", collection: Todo.complete %>
For rendering my_incomplete_todos:
<%= sync partial: "todo", collection: Todo.my_incomplete_todos(current_user) %>
The render_new call has to look like this:
<%= sync_new partial: "todo", resource: Todo.new, scope: Todo.complete %>
Now when a record changes sync will use the names of the lambda parameters (project_id and user), get the corresponding attributes from the record (project_id column or user association) and pass it to the lambda. This way sync can identify if a record has been added or removed from a scope and will then publish the changes to subscribers on all scoped channels.
Beware that chaining of sync scopes in the view is currently not possible. So the following example would raise an exception:
<%= sync_new partial: "todo", Todo.new, scope: Todo.mine(current_user).incomplete %>
To work around this just create an explicit sync_scope
for your problem:
sync_scope :my_incomplete_todos, ->(user) { incomplete.mine(current_user) }
And in the view:
<%= sync_new partial: "todo", Todo.new, scope: Todo.my_incomplete_todos(current_user) %>
# File lib/render_sync/model.rb, line 126 def sync_scope(name, lambda) if self.respond_to?(name) raise ArgumentError, "invalid scope name '#{name}'. Already defined on #{self.name}" end @sync_scope_definitions[name] = RenderSync::ScopeDefinition.new(self, name, lambda) singleton_class.send(:define_method, name) do |*args| RenderSync::Scope.new_from_args(@sync_scope_definitions[name], args) end end
Register one or more associations to be sync’d when this record changes.
Example:
class Todo < ActiveRecord::Base belongs_to :project belongs_to :user sync :all sync_touch :project, :user end
# File lib/render_sync/model.rb, line 150 def sync_touch(*args) # Only load Modules and set up callbacks if sync_touch wasn't # called before if @sync_touches.blank? include ModelActions unless include?(ModelActions) include ModelChangeTracking unless include?(ModelChangeTracking) include ModelTouching @sync_touches ||= [] after_create :prepare_sync_touches, if: -> { RenderSync::Model.enabled? } after_update :prepare_sync_touches, if: -> { RenderSync::Model.enabled? } after_destroy :prepare_sync_touches, if: -> { RenderSync::Model.enabled? } end options = args.extract_options! args.each do |arg| @sync_touches.push(arg) end end