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 12, 2024
1 parent 4d06805 commit 3b4e98d
Show file tree
Hide file tree
Showing 7 changed files with 62 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
9 changes: 7 additions & 2 deletions lib/draper/decoratable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ module Decoratable
extend ActiveSupport::Concern
include Draper::Decoratable::Equality

included do
if defined? Turbo::Broadcastable
require_relative 'compatibility/broadcastable'
prepend Compatibility::Broadcastable
end
end

# Decorates the object using the inferred {#decorator_class}.
# @param [Hash] options
# see {Decorator#initialize}
Expand Down Expand Up @@ -87,8 +94,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 3b4e98d

Please sign in to comment.