diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b362dc4..a4228a92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Draper Changelog +## Unreleased + +### Fixes +* Fix decoration of AR relations [#944](https://github.com/drapergem/draper/pull/944) + ## 4.0.4 - 2025-01-28 ### Fixes diff --git a/lib/draper/decoratable.rb b/lib/draper/decoratable.rb index f8ecde81..e6e98028 100644 --- a/lib/draper/decoratable.rb +++ b/lib/draper/decoratable.rb @@ -12,7 +12,7 @@ module Decoratable extend ActiveSupport::Concern include Draper::Decoratable::Equality - autoload :CollectionProxy, 'draper/decoratable/collection_proxy' + autoload :Relation, 'draper/decoratable/relation' included do prepend Draper::Compatibility::Broadcastable if defined? Turbo::Broadcastable diff --git a/lib/draper/decoratable/collection_proxy.rb b/lib/draper/decoratable/collection_proxy.rb deleted file mode 100644 index 4a8873f5..00000000 --- a/lib/draper/decoratable/collection_proxy.rb +++ /dev/null @@ -1,15 +0,0 @@ -module Draper - module Decoratable - module CollectionProxy - # Decorates a collection of objects. Used at the end of a scope chain. - # - # @example - # company.products.popular.decorate - # @param [Hash] options - # see {Decorator.decorate_collection}. - def decorate(options = {}) - decorator_class.decorate_collection(load_target, options.reverse_merge(with: nil)) - end - end - end -end diff --git a/lib/draper/decoratable/relation.rb b/lib/draper/decoratable/relation.rb new file mode 100644 index 00000000..ee29e304 --- /dev/null +++ b/lib/draper/decoratable/relation.rb @@ -0,0 +1,15 @@ +module Draper + module Decoratable + module Relation + # Decorates a relation of objects. Used at the end of a scope chain. + # + # @example + # Product.popular.decorate + # @param [Hash] options + # see {Decorator.decorate_collection}. + def decorate(options = {}) + decorator_class.decorate_collection(self, options.reverse_merge(with: nil)) + end + end + end +end diff --git a/lib/draper/railtie.rb b/lib/draper/railtie.rb index f5d25e0e..3ff089d2 100644 --- a/lib/draper/railtie.rb +++ b/lib/draper/railtie.rb @@ -36,7 +36,7 @@ class Railtie < Rails::Railtie ActiveSupport.on_load :active_record do include Draper::Decoratable - ActiveRecord::Associations::CollectionProxy.include Draper::Decoratable::CollectionProxy + ActiveRecord::Relation.include Draper::Decoratable::Relation end ActiveSupport.on_load :mongoid do diff --git a/spec/dummy/spec/models/post_spec.rb b/spec/dummy/spec/models/post_spec.rb index 51ce22a0..4de3f6ba 100644 --- a/spec/dummy/spec/models/post_spec.rb +++ b/spec/dummy/spec/models/post_spec.rb @@ -21,6 +21,38 @@ end end if defined? Turbo::Broadcastable + describe 'relations' do + context 'when decorated' do + subject { relation.decorate } + + let(:relation) { described_class.where('1=1') } + let(:persisted) { relation.create! [{}] * rand(0..2) } + + before { persisted } # should exist + + it 'returns a decorated collection' do + is_expected.to match_array persisted + is_expected.to be_all &:decorated? + end + + it 'uses cached records' do + expect(relation).not_to be_loaded + + relation.load + + expect { subject.to_a }.to execute.exactly(0).queries + end + + it 'caches records' do + expect(relation).not_to be_loaded + + relation.decorate.to_a + + expect { subject.to_a; relation.load }.to execute.exactly(0).queries + end + end + end + describe 'associations' do context 'when decorated' do subject { associated.decorate } @@ -47,7 +79,7 @@ it 'caches records' do expect(associated).not_to be_loaded - associated.decorate + associated.decorate.to_a expect { subject.to_a; associated.load }.to execute.exactly(0).queries end