Repository: stimulusreflex/cable_ready (Ruby)

Issue:
Inlcude changed keys when broadcasting to model class? (updates_for :only)
My use case is that I would like to put this in a view:

```erb
<%= updates_for StaffMember, only: 'current_task' do %>
 <%# show what people are working on #%>
<% end %>
```

That is: trigger a refresh when the `current_task` of any StaffMember changes. However, it seems like broadcasts to the subscription ID of a model class are always an empty hash, so the `:only` option is effectively ignored.

I'm pretty sure that's happening here: https://github.com/stimulusreflex/cable_ready/blob/40bc658cc500b0715dfb9fb49cf539f23f24f98c/app/models/concerns/cable_ready/updatable/model_updatable_callbacks.rb#L22-L25

Could we include the changed attributes when broadcasting to the `model.class` as well? I feel like it would at least be harmless, but maybe I've missed the reasoning for doing it this way.


Discussion:
My understanding of line 23 is that broadcasts to the Class are specifically to respond to records being created or destroyed. The intended use case is that you have an index view, and you want to track items being added or removed from the list.

Your intention sounds perfectly reasonable to me, though.

What I suggest is that you clone the CR repo and try out what you're looking to do, and if it works, please make a PR. I'll even give you the code:
```ruby
def broadcast_update(model)
  changeset = model.respond_to?(:previous_changes) ? {changed: model.previous_changes.keys} : {}
  ActionCable.server.broadcast(model.class, changeset)
  ActionCable.server.broadcast(model.to_global_id, changeset)
end
```
> My understanding of line 23 is that broadcasts to the Class are specifically to respond to records being created or destroyed.

Those are handled by `broadcast_create` (which is also aliased as `broadcast_destroy`).

> What I suggest is that you clone the CR repo and try out what you're looking to do, and if it works, please make a PR.

I actually monkey-patched this locally in my app already to test it and it works. However, I am not using CableReady very extensively so I thought I'd ask here first. I've created PR #193 with those changes.
Sorry, wrt line 23 I wasn't speculating on how it works, I was speculating on the intended functionality of the feature. Apologies, that wasn't as clear as it could have been.

So really what this PR is about (since I think I already gave you the code, such as it is) is the bigger "why" question, a close cousin of "wait, does this make sense?"

I'm hoping that @julianrubisch can help me get my thoughts straight on this. Does it make sense to broadcast changed columns to the class form components? I think so, but need another pair of eyes.



Patch:
diff --git a/app/models/concerns/cable_ready/updatable/model_updatable_callbacks.rb b/app/models/concerns/cable_ready/updatable/model_updatable_callbacks.rb
index 6a7e3398..e2aeda93 100644
--- a/app/models/concerns/cable_ready/updatable/model_updatable_callbacks.rb
+++ b/app/models/concerns/cable_ready/updatable/model_updatable_callbacks.rb
@@ -20,8 +20,9 @@ def broadcast_create(model)
       alias_method :broadcast_destroy, :broadcast_create
 
       def broadcast_update(model)
-        model.class.send(:broadcast_updates, model.class, {})
-        model.class.send(:broadcast_updates, model.to_global_id, model.respond_to?(:previous_changes) ? {changed: model.previous_changes.keys} : {})
+        changeset = model.respond_to?(:previous_changes) ? {changed: model.previous_changes.keys} : {}
+        model.class.send(:broadcast_updates, model.class, changeset)
+        model.class.send(:broadcast_updates, model.to_global_id, changeset)
       end
     end
   end


Test patch:
diff --git a/test/lib/cable_ready/updatable_test.rb b/test/lib/cable_ready/updatable_test.rb
index 24dfa324..aaf87178 100644
--- a/test/lib/cable_ready/updatable_test.rb
+++ b/test/lib/cable_ready/updatable_test.rb
@@ -49,7 +49,7 @@ class CableReady::UpdatableTest < ActiveSupport::TestCase
     user = User.create(name: "John Doe")
 
     mock_server = mock("server")
-    mock_server.expects(:broadcast).with(User, {}).once
+    mock_server.expects(:broadcast).with(User, {changed: ["name", "updated_at"]}).once
     mock_server.expects(:broadcast).with(user.to_global_id, {changed: ["name", "updated_at"]}).once
 
     ActionCable.stubs(:server).returns(mock_server)
@@ -62,10 +62,10 @@ class CableReady::UpdatableTest < ActiveSupport::TestCase
     user = team.users.create(name: "Ada Lovelace")
 
     mock_server = mock("server")
-    mock_server.expects(:broadcast).with(User, {}).once
+    mock_server.expects(:broadcast).with(User, {changed: ["name", "updated_at"]}).once
     mock_server.expects(:broadcast).with(user.to_global_id, {changed: ["name", "updated_at"]}).once
     mock_server.expects(:broadcast).with("gid://dummy/Team/1:users", {changed: ["name", "updated_at"]}).once
-    mock_server.expects(:broadcast).with(Team, {}).once
+    mock_server.expects(:broadcast).with(Team, {changed: ["id", "created_at", "updated_at"]}).once
     mock_server.expects(:broadcast).with(team.to_global_id, {changed: ["id", "created_at", "updated_at"]}).once
 
     ActionCable.stubs(:server).returns(mock_server)
@@ -93,7 +93,7 @@ class CableReady::UpdatableTest < ActiveSupport::TestCase
     section = Section.create
     section.updates_enabled = true
 
-    mock_server.expects(:broadcast).with(Section, {}).once
+    mock_server.expects(:broadcast).with(Section, {changed: ["title", "updated_at", "updates_enabled"]}).once
     mock_server.expects(:broadcast).with(section.to_global_id, {changed: ["title", "updated_at", "updates_enabled"]}).once
     section.update(title: "First Section")
   end