Merge pull request #85 from michaelfairley/decorate_associations
Automatically decorate associations with decorates_association
This commit is contained in:
commit
5c74b97b3b
|
@ -53,6 +53,32 @@ module Draper
|
|||
define_method(input){ @model }
|
||||
end
|
||||
|
||||
# Typically called withing a decorator definition, this method causes
|
||||
# the assocation to be decorated when it is retrieved.
|
||||
#
|
||||
# @param [Symbol] name of association to decorate, like `:products`
|
||||
# @option opts [Class] :with The decorator to decorate the association with
|
||||
def self.decorates_association(association_symbol, options = {})
|
||||
define_method(association_symbol) do
|
||||
orig_association = model.send(association_symbol)
|
||||
return orig_association if orig_association.nil?
|
||||
if options[:with]
|
||||
options[:with].decorate(orig_association)
|
||||
else
|
||||
reflection = model.class.reflect_on_association(association_symbol)
|
||||
"#{reflection.klass}Decorator".constantize.decorate(orig_association)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# A convenience method for decorating multiple associations. Calls
|
||||
# decorates_association on each of the given symbols.
|
||||
#
|
||||
# @param [Symbols*] name of associations to decorate
|
||||
def self.decorates_associations(*association_symbols)
|
||||
association_symbols.each{ |sym| decorates_association(sym) }
|
||||
end
|
||||
|
||||
# Specifies a black list of methods which may *not* be proxied to
|
||||
# to the wrapped object.
|
||||
#
|
||||
|
|
|
@ -74,6 +74,44 @@ describe Draper::Base do
|
|||
end
|
||||
end
|
||||
|
||||
context(".decorates_association") do
|
||||
context "for collection associations" do
|
||||
before(:each){ subject.class_eval{ decorates_association :similar_products } }
|
||||
it "causes the association's method to return a collection of wrapped objects" do
|
||||
subject.similar_products.each{ |decorated| decorated.should be_instance_of(ProductDecorator) }
|
||||
end
|
||||
end
|
||||
|
||||
context "for a singular association" do
|
||||
before(:each){ subject.class_eval{ decorates_association :previous_version } }
|
||||
it "causes the association's method to return a single wrapped object if the association is singular" do
|
||||
subject.previous_version.should be_instance_of(ProductDecorator)
|
||||
end
|
||||
|
||||
it "causes the association's method to return nil if the association is nil" do
|
||||
source.stub(:previous_version){ nil }
|
||||
subject.previous_version.should be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context "with a specific decorator specified" do
|
||||
before(:each){ subject.class_eval{ decorates_association :previous_version, :with => SpecificProductDecorator } }
|
||||
it "causes the association to be decorated with the specified association" do
|
||||
subject.previous_version.should be_instance_of(SpecificProductDecorator)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context('.decorates_associations') do
|
||||
subject { Decorator }
|
||||
it "decorates each of the associations" do
|
||||
subject.should_receive(:decorates_association).with(:similar_products)
|
||||
subject.should_receive(:decorates_association).with(:previous_version)
|
||||
|
||||
subject.decorates_associations :similar_products, :previous_version
|
||||
end
|
||||
end
|
||||
|
||||
context(".model / .to_model") do
|
||||
it "should return the wrapped object" do
|
||||
subject.to_model.should == source
|
||||
|
|
|
@ -13,5 +13,6 @@ require './spec/support/samples/namespaced_product.rb'
|
|||
require './spec/support/samples/namespaced_product_decorator.rb'
|
||||
require './spec/support/samples/product.rb'
|
||||
require './spec/support/samples/product_decorator.rb'
|
||||
require './spec/support/samples/specific_product_decorator.rb'
|
||||
require './spec/support/samples/widget.rb'
|
||||
require './spec/support/samples/widget_decorator.rb'
|
||||
|
|
|
@ -44,4 +44,16 @@ class Product < ActiveRecord::Base
|
|||
def block
|
||||
yield
|
||||
end
|
||||
|
||||
def self.reflect_on_association(association_symbol)
|
||||
OpenStruct.new(:klass => self)
|
||||
end
|
||||
|
||||
def similar_products
|
||||
[Product.new, Product.new]
|
||||
end
|
||||
|
||||
def previous_version
|
||||
Product.new
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
require './spec/support/samples/product_decorator'
|
||||
|
||||
class SpecificProductDecorator < ProductDecorator
|
||||
end
|
Loading…
Reference in New Issue