From 5e4f529bb874b2c96ac49a7fd271e4186bc45748 Mon Sep 17 00:00:00 2001 From: Bruno Castro Date: Sat, 16 Mar 2019 16:15:16 -0300 Subject: [PATCH] fix: Make CollectionDecorator respond_to? to ORM methods (#850) ## Testing 1. Create a decorator for the model and its association ```ruby class OrderHistoryDecorator < Draper::Decorator delegate_all end class OrderDecorator < Draper::Decorator delegate_all decorates_association :order_histories, with: OrderHistoryDecorator end ``` 2. Call `respond_to?` with some ORM method allowed by the strategy ```ruby [1] pry(main)> order.order_histories.decorate.respond_to?(:includes) => true ``` ## References * method_missing [usage](https://thoughtbot.com/blog/always-define-respond-to-missing-when-overriding) --- lib/draper/query_methods.rb | 4 ++++ spec/draper/query_methods_spec.rb | 30 +++++++++++++++++++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/lib/draper/query_methods.rb b/lib/draper/query_methods.rb index ec40d4b..267ee8a 100644 --- a/lib/draper/query_methods.rb +++ b/lib/draper/query_methods.rb @@ -9,6 +9,10 @@ module Draper object.send(method, *args, &block).decorate end + def respond_to_missing?(method, include_private = false) + strategy.allowed?(method) || super + end + private # Configures the strategy used to proxy the query methods, which defaults to `:active_record`. diff --git a/spec/draper/query_methods_spec.rb b/spec/draper/query_methods_spec.rb index 363df1b..3884d34 100644 --- a/spec/draper/query_methods_spec.rb +++ b/spec/draper/query_methods_spec.rb @@ -5,12 +5,13 @@ Post = Struct.new(:id) { } module Draper describe QueryMethods do + let(:fake_strategy) { instance_double(QueryMethods::LoadStrategy::ActiveRecord) } + + before { allow(QueryMethods::LoadStrategy).to receive(:new).and_return(fake_strategy) } + describe '#method_missing' do let(:collection) { [ Post.new, Post.new ] } let(:collection_decorator) { PostDecorator.decorate_collection(collection) } - let(:fake_strategy) { instance_double(QueryMethods::LoadStrategy::ActiveRecord) } - - before { allow(QueryMethods::LoadStrategy).to receive(:new).and_return(fake_strategy) } context 'when strategy allows collection to call the method' do let(:results) { spy(:results) } @@ -35,5 +36,28 @@ module Draper end end end + + describe "#respond_to?" do + let(:collection) { [ Post.new, Post.new ] } + let(:collection_decorator) { PostDecorator.decorate_collection(collection) } + + subject { collection_decorator.respond_to?(:some_query_method) } + + context 'when strategy allows collection to call the method' do + before do + allow(fake_strategy).to receive(:allowed?).with(:some_query_method).and_return(true) + end + + it { is_expected.to eq(true) } + end + + context 'when strategy does not allow collection to call the method' do + before do + allow(fake_strategy).to receive(:allowed?).with(:some_query_method).and_return(false) + end + + it { is_expected.to eq(false) } + end + end end end