Skip to content

Commit

Permalink
Wrap relation calls and scope calls in decorators
Browse files Browse the repository at this point in the history
* wrap model in decorator when scope is called on decorator
* decorate named scope calls on decorators and enumerable proxies
  • Loading branch information
jhsu committed Aug 22, 2012
1 parent beb14be commit e4595d9
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 7 deletions.
14 changes: 10 additions & 4 deletions lib/draper/base.rb
Expand Up @@ -255,7 +255,12 @@ def method_missing(method, *args, &block)

if model.respond_to?(method)
self.class.send :define_method, method do |*args, &blokk|
model.send method, *args, &blokk
result = model.send method, *args, &blokk
if result.class.name == "ActiveRecord::Relation"
self.class.new(model,self.options)
else
result
end
end

send method, *args, &block
Expand All @@ -269,10 +274,11 @@ def method_missing(method, *args, &block)
end

def self.method_missing(method, *args, &block)
if method.to_s.match(/^find_((all_|last_)?by_|or_(initialize|create)_by_).*/)
self.decorate(model_class.send(method, *args, &block), :context => args.dup.extract_options!)
model_result = model_class.send(method, *args, &block)
if model_result.is_a?(model_class) || model_result.class.name == 'ActiveRecord::Relation'
self.decorate(model_result, :context => args.dup.extract_options!)
else
model_class.send(method, *args, &block)
model_result
end
end

Expand Down
19 changes: 18 additions & 1 deletion lib/draper/decorated_enumerable_proxy.rb
Expand Up @@ -25,7 +25,24 @@ def find(ifnone_or_id = nil, &blk)
end

def method_missing (method, *args, &block)
@wrapped_collection.send(method, *args, &block)
if @wrapped_collection.respond_to?(method)
self.class.send :define_method, method do |*args, &blokk|
scoped_result = @wrapped_collection.send(method, *args, &block)
if scoped_result.class.name == "ActiveRecord::Relation"
self.class.new(scoped_result, @klass, @options)
else
scoped_result
end
end

send method, *args, &block
else
super
end

rescue NoMethodError => no_method_error
super if no_method_error.name == method
raise no_method_error
end

def respond_to?(method, include_private = false)
Expand Down
31 changes: 29 additions & 2 deletions spec/draper/base_spec.rb
Expand Up @@ -50,6 +50,22 @@
ProductDecorator.new(product_decorator).model.should be_instance_of Product
end

it "returns a Decorator when a scope is called on decorated object" do
class ActiveRecord::Relation; end
proxy = ProductDecorator.new(source)
klass = proxy.model.class
klass.class_eval { def some_scope ; ActiveRecord::Relation.new ; end }
proxy.some_scope.should be_instance_of(proxy.class)
end

it "returns a Decorator when a scope is called on the decorator" do
class ActiveRecord::Relatio; end
proxy = ProductDecorator
klass = source.class
klass.class_eval { def self.some_scope ; ActiveRecord::Relation.new ; end }
proxy.some_scope.should be_instance_of(proxy)
end

it "handle plural-like words properly'" do
class Business; end
expect do
Expand Down Expand Up @@ -162,6 +178,18 @@ class CustomDecorator < Draper::Base
end
end

context "with a scope applied after decoration" do
it "returns a DecoratedEnumerableProxy when a scope is called" do
class ActiveRecord::Relation
def some_scope; self ;end
end
klass = subject.model.class
klass.class_eval { def self.some_scope ; ActiveRecord::Relation.new ; end }
proxy = Draper::DecoratedEnumerableProxy
proxy.new(ActiveRecord::Relation.new, klass).some_scope.should be_instance_of(proxy)
end
end

context "for a polymorphic association" do
before(:each){ subject.class_eval{ decorates_association :thing, :polymorphic => true } }
it "causes the association to be decorated with the right decorator" do
Expand Down Expand Up @@ -352,8 +380,7 @@ class CustomDecorator < Draper::Base

it "uses the options hash in the decorator instantiation" do
Product.should_receive(:find_by_name_and_size).with("apples", "large", {:role => :admin})
pd = ProductDecorator.find_by_name_and_size("apples", "large", {:role => :admin})
pd.context[:role].should == :admin
ProductDecorator.find_by_name_and_size("apples", "large", {:role => :admin})
end
end

Expand Down

0 comments on commit e4595d9

Please sign in to comment.