mirror of
https://github.com/drapergem/draper
synced 2023-03-27 23:21:17 -04:00
Handle options properly in Decoratable#decorate
In 30104b0
I had accidentally nuked the options but didn't realise
as there was no spec coverage.
I then discovered that, due to memoization, `#decorate` did not
use options after the first call:
product.decorate(role: :admin)
product.decorate(role: :user) # still has admin role!
I ditched the `#decorator` alias since `#decorate` seems far more
canonical, and dropped the block passing syntax, since this seems
orthogonal to the main purpose of the method.
This commit is contained in:
parent
7748ce5fcb
commit
52daa3125b
2 changed files with 40 additions and 43 deletions
|
@ -1,11 +1,9 @@
|
||||||
module Draper::Decoratable
|
module Draper::Decoratable
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
def decorator(options = {})
|
def decorate(options = {})
|
||||||
@decorator ||= decorator_class.decorate(self)
|
decorator_class.decorate(self, options)
|
||||||
block_given? ? yield(@decorator) : @decorator
|
|
||||||
end
|
end
|
||||||
alias_method :decorate, :decorator
|
|
||||||
|
|
||||||
def decorator_class
|
def decorator_class
|
||||||
self.class.decorator_class
|
self.class.decorator_class
|
||||||
|
@ -25,8 +23,7 @@ module Draper::Decoratable
|
||||||
|
|
||||||
module ClassMethods
|
module ClassMethods
|
||||||
def decorate(options = {})
|
def decorate(options = {})
|
||||||
collection_decorator = decorator_class.decorate_collection(self.scoped, options)
|
decorator_class.decorate_collection(self.scoped, options)
|
||||||
block_given? ? yield(collection_decorator) : collection_decorator
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def decorator_class
|
def decorator_class
|
||||||
|
|
|
@ -3,17 +3,19 @@ require 'spec_helper'
|
||||||
describe Draper::Decoratable do
|
describe Draper::Decoratable do
|
||||||
subject { Product.new }
|
subject { Product.new }
|
||||||
|
|
||||||
describe '#decorator' do
|
describe "#decorate" do
|
||||||
its(:decorator) { should be_kind_of(ProductDecorator) }
|
it "returns a decorator for self" do
|
||||||
its(:decorator) { should be(subject.decorator) }
|
subject.decorate.should be_a ProductDecorator
|
||||||
|
subject.decorate.source.should be subject
|
||||||
|
end
|
||||||
|
|
||||||
it 'have abillity to pass block' do
|
it "accepts options" do
|
||||||
a = Product.new.decorator { |d| d.awesome_title }
|
decorator = subject.decorate(some: "options")
|
||||||
a.should eql "Awesome Title"
|
decorator.options.should == {some: "options"}
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'is aliased to .decorate' do
|
it "is not memoized" do
|
||||||
subject.decorator.model.should == subject.decorate.model
|
subject.decorate.should_not be subject.decorate
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -43,6 +45,27 @@ describe Draper::Decoratable do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe ".decorate" do
|
||||||
|
it "returns a collection decorator" do
|
||||||
|
Product.stub(:scoped).and_return([Product.new])
|
||||||
|
Product.stub(:decorator_class).and_return(WidgetDecorator)
|
||||||
|
decorator = Product.decorate
|
||||||
|
|
||||||
|
decorator.should be_a Draper::CollectionDecorator
|
||||||
|
decorator.decorator_class.should be WidgetDecorator
|
||||||
|
decorator.source.should be Product.scoped
|
||||||
|
end
|
||||||
|
|
||||||
|
it "accepts options" do
|
||||||
|
decorator = Product.decorate(some: "options")
|
||||||
|
decorator.options.should == {some: "options"}
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is not memoized" do
|
||||||
|
Product.decorate.should_not be Product.decorate
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe ".decorator_class" do
|
describe ".decorator_class" do
|
||||||
context "for non-ActiveModel classes" do
|
context "for non-ActiveModel classes" do
|
||||||
it "infers the decorator from the class" do
|
it "infers the decorator from the class" do
|
||||||
|
@ -57,39 +80,16 @@ describe Draper::Decoratable do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "for namespaced ActiveModel classes" do
|
||||||
|
it "infers the decorator from the model name" do
|
||||||
|
Namespace::Product.decorator_class.should be Namespace::ProductDecorator
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context "when the decorator can't be inferred" do
|
context "when the decorator can't be inferred" do
|
||||||
it "throws an UninferrableDecoratorError" do
|
it "throws an UninferrableDecoratorError" do
|
||||||
expect{UninferrableDecoratorModel.decorator_class}.to raise_error Draper::UninferrableDecoratorError
|
expect{UninferrableDecoratorModel.decorator_class}.to raise_error Draper::UninferrableDecoratorError
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe Draper::Decoratable::ClassMethods do
|
|
||||||
shared_examples_for "a call to Draper::Decoratable::ClassMethods#decorate" do
|
|
||||||
subject { klass.limit }
|
|
||||||
|
|
||||||
its(:decorate) { should be_kind_of(Draper::CollectionDecorator) }
|
|
||||||
|
|
||||||
it "decorate the collection" do
|
|
||||||
subject.decorate.size.should == 1
|
|
||||||
subject.decorate.to_ary[0].model.should be_a(klass)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "return a new instance each time it is called" do
|
|
||||||
subject.decorate.should_not == subject.decorate
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#decorate - decorate collections of AR objects' do
|
|
||||||
let(:klass) { Product }
|
|
||||||
|
|
||||||
it_should_behave_like "a call to Draper::Decoratable::ClassMethods#decorate"
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#decorate - decorate collections of namespaced AR objects' do
|
|
||||||
let(:klass) { Namespace::Product }
|
|
||||||
|
|
||||||
it_should_behave_like "a call to Draper::Decoratable::ClassMethods#decorate"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue