Makes decorates_association work transparently with Plain Old Ruby Objects.

This commit is contained in:
Guilherme Cirne 2012-03-08 00:23:54 -03:00
parent d327038e1e
commit f7eca344cc
3 changed files with 47 additions and 13 deletions

View File

@ -64,15 +64,21 @@ module Draper
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)
elsif options[:polymorphic]
"#{orig_association.class}Decorator".constantize.decorate(orig_association)
return orig_association if orig_association.nil?
return options[:with].decorate(orig_association) if options[:with]
if options[:polymorphic]
klass = orig_association.class
elsif model.class.respond_to?(:reflect_on_association) && model.class.reflect_on_association(association_symbol)
klass = model.class.reflect_on_association(association_symbol).klass
elsif orig_association.respond_to?(:first)
klass = orig_association.first.class
else
reflection = model.class.reflect_on_association(association_symbol)
"#{reflection.klass}Decorator".constantize.decorate(orig_association, options)
klass = orig_association.class
end
"#{klass}Decorator".constantize.decorate(orig_association, options)
end
end

View File

@ -113,22 +113,31 @@ describe Draper::Base do
end
context(".decorates_association") do
context "for collection associations" do
context "for ActiveModel 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
context "for Plain Old Ruby Object collection associations" do
before(:each){ subject.class_eval{ decorates_association :poro_similar_products } }
it "causes the association's method to return a collection of wrapped objects" do
subject.poro_similar_products.each{ |decorated| decorated.should be_instance_of(ProductDecorator) }
end
end
context "for an ActiveModel 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
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
context "for a Plain Old Ruby Object singular association" do
before(:each){ subject.class_eval{ decorates_association :poro_previous_version } }
it "causes the association's method to return a single wrapped object" do
subject.poro_previous_version.should be_instance_of(ProductDecorator)
end
end
@ -145,6 +154,16 @@ describe Draper::Base do
subject.thing.should be_instance_of(SomeThingDecorator)
end
end
context "when the association is nil" do
before(:each) do
subject.class_eval{ decorates_association :previous_version }
source.stub(:previous_version){ nil }
end
it "causes the association's method to return nil" do
subject.previous_version.should be_nil
end
end
end
context('.decorates_associations') do

View File

@ -54,7 +54,7 @@ class Product < ActiveRecord::Base
end
def self.reflect_on_association(association_symbol)
OpenStruct.new(:klass => self)
association_symbol.to_s.starts_with?("poro") ? nil : OpenStruct.new(:klass => self)
end
def similar_products
@ -68,4 +68,13 @@ class Product < ActiveRecord::Base
def thing
SomeThing.new
end
def poro_similar_products
[Product.new, Product.new]
end
def poro_previous_version
Product.new
end
end