Skip to content

Commit

Permalink
Integration with Turbo::Broadcastable
Browse files Browse the repository at this point in the history
Overriding defaults for Turbo broadcast jobs allows one to get decorated
objects in model partials by default.

Resolves drapergem#910.
Requires drapergem#928.
  • Loading branch information
Alexander-Senko committed Sep 3, 2024
1 parent 4d06805 commit a1439ff
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 2 deletions.
5 changes: 5 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ platforms :jruby do
gem "activerecord-jdbcsqlite3-adapter"
end

if RUBY_VERSION >= "2.6.0"
gem "turbo-rails"
gem "redis", "~> 4.0"
end

if RUBY_VERSION >= "2.5.0"
gem "rails", "~> 6.0"
gem 'webrick'
Expand Down
24 changes: 24 additions & 0 deletions lib/draper/compatibility/broadcastable.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# frozen_string_literal: true

module Draper
module Compatibility
# It would look consistent to use decorated objects inside templates broadcasted with
# Turbo::Broadcastable.
#
# This compatibility patch fixes the issue by overriding the original defaults to decorate the
# object, that's passed to the partial in a local variable.
module Broadcastable
private

def broadcast_rendering_with_defaults(options)
return super unless decorator_class?

# Add the decorated current instance into the locals (see original method for details).
options[:locals] =
(options[:locals] || {}).reverse_merge!(model_name.element.to_sym => decorate)

super
end
end
end
end
7 changes: 5 additions & 2 deletions lib/draper/decoratable.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'draper/decoratable/equality'
require 'draper/compatibility/broadcastable'

module Draper
# Provides shortcuts to decorate objects directly, so you can do
Expand All @@ -11,6 +12,10 @@ module Decoratable
extend ActiveSupport::Concern
include Draper::Decoratable::Equality

included do
prepend Draper::Compatibility::Broadcastable if defined? Turbo::Broadcastable
end

# Decorates the object using the inferred {#decorator_class}.
# @param [Hash] options
# see {Decorator#initialize}
Expand Down Expand Up @@ -87,8 +92,6 @@ def decorator_class(called_on = self)
def ===(other)
super || (other.is_a?(Draper::Decorator) && super(other.object))
end

end

end
end
4 changes: 4 additions & 0 deletions spec/dummy/app/models/post.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
require 'turbo/broadcastable' if defined? Turbo::Broadcastable # HACK: looks weird, but works

class Post < ApplicationRecord
# attr_accessible :title, :body

broadcasts if defined? Turbo::Broadcastable
end
1 change: 1 addition & 0 deletions spec/dummy/config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ def attempt_require(file)
require 'draper'
attempt_require 'mongoid'
attempt_require 'devise'
attempt_require 'turbo-rails'
require 'active_model_serializers'

module Dummy
Expand Down
8 changes: 8 additions & 0 deletions spec/dummy/config/cable.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# production:
# url: redis://redis.example.com:6379

local: &local
url: redis://localhost:6379

development: *local
test: *local
13 changes: 13 additions & 0 deletions spec/dummy/spec/models/post_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,17 @@
it_behaves_like 'a decoratable model'

it { should be_a ApplicationRecord }

describe 'broadcasts' do
let(:modification) { described_class.create! }

it 'passes a decorated object for rendering' do
expect do
modification
end.to have_enqueued_job(Turbo::Streams::ActionBroadcastJob).with { |stream, action:, target:, **rendering|
expect(rendering[:locals]).to include :post
expect(rendering[:locals][:post]).to be_decorated
}
end
end if defined? Turbo::Broadcastable
end

0 comments on commit a1439ff

Please sign in to comment.