diff --git a/lib/draper/base.rb b/lib/draper/base.rb index 78342ee..6b9a1c8 100644 --- a/lib/draper/base.rb +++ b/lib/draper/base.rb @@ -53,6 +53,22 @@ 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` + def self.decorates_association(association_symbol) + define_method(association_symbol) do + orig_association = model.send(association_symbol) + return nil if orig_association.nil? + if orig_association.respond_to? :proxy_reflection # The association is a collection + "#{orig_association.proxy_reflection.klass}Decorator".constantize.decorate(orig_association) + else + "#{orig_association.class}Decorator".constantize.decorate(orig_association) + end + end + end + # Specifies a black list of methods which may *not* be proxied to # to the wrapped object. # diff --git a/spec/draper/base_spec.rb b/spec/draper/base_spec.rb index 6a5e18b..87b5c44 100644 --- a/spec/draper/base_spec.rb +++ b/spec/draper/base_spec.rb @@ -74,6 +74,27 @@ 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 + end + context(".model / .to_model") do it "should return the wrapped object" do subject.to_model.should == source diff --git a/spec/support/samples/product.rb b/spec/support/samples/product.rb index 42f9062..992d0f7 100644 --- a/spec/support/samples/product.rb +++ b/spec/support/samples/product.rb @@ -44,4 +44,16 @@ class Product < ActiveRecord::Base def block yield end + + def similar_products + result = [Product.new, Product.new] + def result.proxy_reflection + OpenStruct.new(:klass => Product) + end + result + end + + def previous_version + Product.new + end end