-
Notifications
You must be signed in to change notification settings - Fork 526
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Include ORM associations in CollectionDecorator (#845)
## Description Include all QueryMethods from the ORM in CollectionDecorator. The default adapter is :active_record * Why was this change required? It was necessary to delegate or define a method of the ORM which you are using in your decorator to make an instance of CollectionDecorator able to call it. * Is there something you aren't happy with or that needs extra attention? In order to support other ORM associations, we'll need to write a method `allowed?` for each strategy at `lib/draper/query_methods/load_strategy.rb` ## 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 any query method in the decorated instance ```ruby pry(main)> Order.last.decorate.order_histories.includes(:user) ``` ## References * Issue #702 * Issue #812
- Loading branch information
1 parent
b1974a8
commit 6b3e9bc
Showing
10 changed files
with
159 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
require_relative 'query_methods/load_strategy' | ||
|
||
module Draper | ||
module QueryMethods | ||
# Proxies missing query methods to the source class if the strategy allows. | ||
def method_missing(method, *args, &block) | ||
return super unless strategy.allowed? method | ||
|
||
object.send(method, *args, &block).decorate | ||
end | ||
|
||
private | ||
|
||
# Configures the strategy used to proxy the query methods, which defaults to `:active_record`. | ||
def strategy | ||
@strategy ||= LoadStrategy.new(Draper.default_query_methods_strategy) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
module Draper | ||
module QueryMethods | ||
module LoadStrategy | ||
def self.new(name) | ||
const_get(name.to_s.camelize).new | ||
end | ||
|
||
class ActiveRecord | ||
def allowed?(method) | ||
::ActiveRecord::Relation::VALUE_METHODS.include? method | ||
end | ||
end | ||
|
||
class Mongoid | ||
def allowed?(method) | ||
raise NotImplementedError | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
require 'spec_helper' | ||
require 'active_record' | ||
|
||
module Draper | ||
module QueryMethods | ||
describe LoadStrategy do | ||
describe '#new' do | ||
subject { described_class.new(:active_record) } | ||
|
||
it { is_expected.to be_an_instance_of(LoadStrategy::ActiveRecord) } | ||
end | ||
end | ||
|
||
describe LoadStrategy::ActiveRecord do | ||
describe '#allowed?' do | ||
it 'checks whether or not ActiveRecord::Relation::VALUE_METHODS has the given method' do | ||
allow(::ActiveRecord::Relation::VALUE_METHODS).to receive(:include?) | ||
|
||
described_class.new.allowed? :foo | ||
|
||
expect(::ActiveRecord::Relation::VALUE_METHODS).to have_received(:include?).with(:foo) | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
require 'spec_helper' | ||
require_relative '../dummy/app/decorators/post_decorator' | ||
|
||
Post = Struct.new(:id) { } | ||
|
||
module Draper | ||
describe QueryMethods do | ||
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) } | ||
|
||
before do | ||
allow(fake_strategy).to receive(:allowed?).with(:some_query_method).and_return(true) | ||
allow(collection).to receive(:send).with(:some_query_method).and_return(results) | ||
end | ||
|
||
it 'calls the method on the collection and decorate it results' do | ||
collection_decorator.some_query_method | ||
|
||
expect(results).to have_received(:decorate) | ||
end | ||
end | ||
|
||
context 'when strategy does not allow collection to call the method' do | ||
before { allow(fake_strategy).to receive(:allowed?).with(:some_query_method).and_return(false) } | ||
|
||
it 'raises NoMethodError' do | ||
expect { collection_decorator.some_query_method }.to raise_exception(NoMethodError) | ||
end | ||
end | ||
end | ||
end | ||
end |