Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Restore context #385

Merged
merged 4 commits into from

4 participants

@haines
Collaborator

Includes #384 but after rebasing master it wouldn't merge cleanly back into @tovodeverett's branch, sorry! One less merge commit this way I guess.

I just changed it so it wasn't storing context in the options hash unnecessarily, which was one of my main objections with the original implementation that I removed.

I also came up with a neater way to avoid forcing enumeration in CollectionDecorator when changing the context.

I'd still like to refactor DecoratedAssociation#decorator_options but it's all in the private interface so it's not a blocker.

@tovodeverett

I even thought about doing that when I started to make the change, but then forgot to do it.

Collaborator

Yeah, I don't think it's really necessary, but since we do it here for extract_options! I figured we might as well be consistent.

Also, we're relying on it for slice in DecoratedAssociation#decorator_options.

@tovodeverett

This is a question regarding what is the most idiomatic Ruby - I haven't read enough code to have come to a conclusion on this one, so I'm mostly asking for future reference.

Is it fairly common to use attr_accessor to implement a bi-directional accessors and then to replace one of them with an explicit method later? I can see both sides of the argument. If one uses attr_reader at the top, one is implying that the attribute is read-only, which is contradicted by the code later in the file. On the other hand, if one uses attr_accessor at the top, then one is implying that it is a simple attribute and that the setter has no interesting behavior, which isn't the case. Another alternative would be to use attr_reader, but to use it right above the explicit setter. But that goes against the grain of having the attr_* lines all in one nice block up at the top.

I'm not sure which is better, to be honest.

@tovodeverett

I like the extraction of all options (including context) in Decorator#initialize and CollectionDecorator#initialize, while retaining options as an ivar in DecoratedAssociation. I also really like using @decorated_collection as cleaner way to avoid forcing enumeration - I think that was my initial plan several days ago when I was looking at the code (I need to start making more notes), but when I got to implementation I latched on to loaded? for some reason.

@steveklabnik steveklabnik merged commit 9609156 into drapergem:master

1 check passed

Details default The Travis build passed
@steveklabnik

Thank you @haines ! Also, with this merge, I did something that I think is long overdue: welcome to Team Draper! :heart: You've been making a lot of badass contributions lately.

@haines
Collaborator

Cool! Thanks Steve!! :sparkling_heart:

@tovodeverett

One thing just occurred to me. This is a interface change. Should we update the Changelog and declare this as 1.0.0.beta4 so as to make it a little more obvious to anyone who might be using the beta code?

@steveklabnik

There should be a CHANGELOG entry for sure, and I plan on knocking out a beta4 as soon as we're back to zero issues. Lately, I've just been making CHANGELOGs right before release, but I want to change that with 1.0.

@tovodeverett

Oh, and congrats to @haines :clap:

I'd been wondering why he wasn't officially on the team, since it was evident that he was effectively on it!

@elado

This feature eliminates the option to pass custom options to decorators.

I used it a couple of times, ProductDecorator.new(p, my_option: true) and now it says "Unknown key: my_option".

Is the validation really necessary? The custom options can be really useful.

Or is it now context's job to pass options

@tovodeverett

There was a lot of discussion on this - this change reverts the behavior back to the way it existed prior to aeac106. Yes, it does require code changes, but after some debating back and forth it was decided that it was better to get the interface changes done before the code exits beta.

You'll need to modify code that looks like this:

decorator = model.decorate(current_user: current_user)
decorator.options[:current_user]

To be rewritten to look like this:

decorator = model.decorate(context: {current_user: current_user})
decorator.context[:current_user]

The benefits are:

  • We can add options in the future without worrying about colliding with keys in the context
  • There are no longer off-limits keys in the context for decorated collections (i.e. :with and :scope)
  • Child objects of decorated associations automatically inherit their parent's context unless the decorated association explicitly sets the context. Passing a lambda in for the context allows the decorated association to get a dynamically generated context that gets the parent's context as input (i.e. you can filter context before handing it off to the association).
@haines
Collaborator

@elado Yep, now you should write ProductDecorator.new(p, context: {my_option: true}) and access it via the context method instead of options. It's a bit longer, unfortunately, but, as @tovodeverett points out, there are a number of benefits.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Dec 13, 2012
  1. @tovodeverett @haines

    Restore context. Collections inherit context by default, but associat…

    tovodeverett authored haines committed
    …ions
    
    can specify either a static context or a lambda.  Validation for options
    in a number of methods.
  2. @tovodeverett @haines
  3. @haines
  4. @haines

    Extract context in initialize

    haines authored
This page is out of date. Refresh to see the latest.
View
2  lib/draper.rb
@@ -14,6 +14,8 @@
require 'draper/collection_decorator'
require 'draper/railtie' if defined?(Rails)
+require 'active_support/core_ext/hash/keys'
+
module Draper
def self.setup_action_controller(base)
base.class_eval do
View
23 lib/draper/collection_decorator.rb
@@ -3,20 +3,21 @@ class CollectionDecorator
include Enumerable
include ViewHelpers
- attr_accessor :source, :options, :decorator_class
+ attr_accessor :source, :context, :decorator_class
alias_method :to_source, :source
delegate :as_json, *(Array.instance_methods - Object.instance_methods), to: :decorated_collection
# @param source collection to decorate
- # @param options [Hash] passed to each item's decorator (except
- # for the keys listed below)
- # @option options [Class,Symbol] :with the class used to decorate
+ # @param [Hash] options (optional)
+ # @option options [Class, Symbol] :with the class used to decorate
# items, or `:infer` to call each item's `decorate` method instead
+ # @option options [Hash] :context context available to each item's decorator
def initialize(source, options = {})
+ options.assert_valid_keys(:with, :context)
@source = source
- @decorator_class = options.delete(:with) || self.class.inferred_decorator_class
- @options = options
+ @decorator_class = options.fetch(:with) { self.class.inferred_decorator_class }
+ @context = options.fetch(:context, {})
end
class << self
@@ -56,18 +57,18 @@ def to_s
"#<CollectionDecorator of #{decorator_class} for #{source.inspect}>"
end
- def options=(options)
- each {|item| item.options = options }
- @options = options
+ def context=(value)
+ @context = value
+ each {|item| item.context = value } if @decorated_collection
end
protected
def decorate_item(item)
if decorator_class == :infer
- item.decorate(options)
+ item.decorate(context: context)
else
- decorator_class.decorate(item, options)
+ decorator_class.decorate(item, context: context)
end
end
View
23 lib/draper/decorated_association.rb
@@ -1,11 +1,12 @@
module Draper
class DecoratedAssociation
- attr_reader :source, :association, :options
+ attr_reader :base, :association, :options
- def initialize(source, association, options)
- @source = source
+ def initialize(base, association, options)
+ @base = base
@association = association
+ options.assert_valid_keys(:with, :scope, :context)
@options = options
end
@@ -14,6 +15,10 @@ def call
decorate
end
+ def source
+ base.source
+ end
+
private
def undecorated
@@ -25,7 +30,7 @@ def undecorated
end
def decorate
- @decorated ||= decorator_class.send(decorate_method, undecorated, options)
+ @decorated ||= decorator_class.send(decorate_method, undecorated, decorator_options)
end
def decorate_method
@@ -51,5 +56,15 @@ def decorator_class
end
end
+ def decorator_options
+ decorator_class # Ensures options[:with] = :infer for unspecified collections
+
+ dec_options = collection? ? options.slice(:with, :context) : options.slice(:context)
+ dec_options[:context] = base.context unless dec_options.key?(:context)
+ if dec_options[:context].respond_to?(:call)
+ dec_options[:context] = dec_options[:context].call(base.context)
+ end
+ dec_options
+ end
end
end
View
28 lib/draper/decorator.rb
@@ -5,14 +5,15 @@ class Decorator
include Draper::ViewHelpers
include ActiveModel::Serialization if defined?(ActiveModel::Serialization)
- attr_accessor :source, :options
+ attr_accessor :source, :context
alias_method :model, :source
alias_method :to_source, :source
# Initialize a new decorator instance by passing in
# an instance of the source class. Pass in an optional
- # context inside the options hash is stored for later use.
+ # :context inside the options hash which is available
+ # for later use.
#
# A decorator cannot be applied to other instances of the
# same decorator and will instead result in a decorator
@@ -23,11 +24,13 @@ class Decorator
#
# @param [Object] source object to decorate
# @param [Hash] options (optional)
+ # @option options [Hash] :context context available to the decorator
def initialize(source, options = {})
+ options.assert_valid_keys(:context)
source.to_a if source.respond_to?(:to_a) # forces evaluation of a lazy query from AR
@source = source
- @options = options
- handle_multiple_decoration if source.is_a?(Draper::Decorator)
+ @context = options.fetch(:context, {})
+ handle_multiple_decoration(options) if source.is_a?(Draper::Decorator)
end
class << self
@@ -72,9 +75,15 @@ def self.decorates_finders
# @param [Symbol] association name of association to decorate, like `:products`
# @option options [Class] :with the decorator to apply to the association
# @option options [Symbol] :scope a scope to apply when fetching the association
+ # @option options [Hash, #call] :context context available to decorated
+ # objects in collection. Passing a `lambda` or similar will result in that
+ # block being called when the association is evaluated. The block will be
+ # passed the base decorator's `context` Hash and should return the desired
+ # context Hash for the decorated items.
def self.decorates_association(association, options = {})
+ options.assert_valid_keys(:with, :scope, :context)
define_method(association) do
- decorated_associations[association] ||= Draper::DecoratedAssociation.new(source, association, options)
+ decorated_associations[association] ||= Draper::DecoratedAssociation.new(self, association, options)
decorated_associations[association].call
end
end
@@ -82,7 +91,8 @@ def self.decorates_association(association, options = {})
# A convenience method for decorating multiple associations. Calls
# decorates_association on each of the given symbols.
#
- # @param [Symbols*] associations name of associations to decorate
+ # @param [Symbols*] associations names of associations to decorate
+ # @param [Hash] options passed to `decorate_association`
def self.decorates_associations(*associations)
options = associations.extract_options!
associations.each do |association|
@@ -128,7 +138,9 @@ def self.allows(*methods)
# for the keys listed below)
# @option options [Class,Symbol] :with (self) the class used to decorate
# items, or `:infer` to call each item's `decorate` method instead
+ # @option options [Hash] :context context available to decorated items
def self.decorate_collection(source, options = {})
+ options.assert_valid_keys(:with, :context)
Draper::CollectionDecorator.new(source, options.reverse_merge(with: self))
end
@@ -244,9 +256,9 @@ def allow?(method)
self.class.security.allow?(method)
end
- def handle_multiple_decoration
+ def handle_multiple_decoration(options)
if source.instance_of?(self.class)
- self.options = source.options if options.empty?
+ self.context = source.context unless options.has_key?(:context)
self.source = source.source
elsif source.decorated_with?(self.class)
warn "Reapplying #{self.class} decorator to target that is already decorated with it. Call stack:\n#{caller(1).join("\n")}"
View
69 spec/draper/collection_decorator_spec.rb
@@ -16,33 +16,70 @@
subject.map{|item| item.source}.should == source
end
- context "with options" do
- subject { Draper::CollectionDecorator.new(source, with: ProductDecorator, some: "options") }
+ context "with context" do
+ subject { Draper::CollectionDecorator.new(source, with: ProductDecorator, context: {some: 'context'}) }
- its(:options) { should == {some: "options"} }
+ its(:context) { should == {some: 'context'} }
- it "passes options to the individual decorators" do
+ it "passes context to the individual decorators" do
subject.each do |item|
- item.options.should == {some: "options"}
+ item.context.should == {some: 'context'}
end
end
- describe "#options=" do
- it "updates the options on the collection decorator" do
- subject.options = {other: "options"}
- subject.options.should == {other: "options"}
+ it "does not tie the individual decorators' contexts together" do
+ subject.each do |item|
+ item.context.should == {some: 'context'}
+ item.context = {alt: 'context'}
+ item.context.should == {alt: 'context'}
+ end
+ end
+
+ describe "#context=" do
+ it "updates the collection decorator's context" do
+ subject.context = {other: 'context'}
+ subject.context.should == {other: 'context'}
end
- it "updates the options on the individual decorators" do
- subject.options = {other: "options"}
- subject.each do |item|
- item.options.should == {other: "options"}
+ context "when the collection is already decorated" do
+ it "updates the items' context" do
+ subject.decorated_collection
+ subject.context = {other: 'context'}
+ subject.each do |item|
+ item.context.should == {other: 'context'}
+ end
+ end
+ end
+
+ context "when the collection has not yet been decorated" do
+ it "does not trigger decoration" do
+ subject.should_not_receive(:decorated_collection)
+ subject.context = {other: 'context'}
+ end
+
+ it "sets context after decoration is triggered" do
+ subject.context = {other: 'context'}
+ subject.each do |item|
+ item.context.should == {other: 'context'}
+ end
end
end
end
end
describe "#initialize" do
+ describe "options validation" do
+ let(:valid_options) { {with: ProductDecorator, context: {}} }
+
+ it "does not raise error on valid options" do
+ expect { Draper::CollectionDecorator.new(source, valid_options) }.to_not raise_error
+ end
+
+ it "raises error on invalid options" do
+ expect { Draper::CollectionDecorator.new(source, valid_options.merge(foo: 'bar')) }.to raise_error(ArgumentError, 'Unknown key: foo')
+ end
+ end
+
context "when the :with option is given" do
context "and the decorator can't be inferred from the class" do
subject { Draper::CollectionDecorator.new(source, with: ProductDecorator) }
@@ -123,14 +160,14 @@
end
describe "#localize" do
- before { subject.helpers.should_receive(:localize).with(:an_object, {some: "options"}) }
+ before { subject.helpers.should_receive(:localize).with(:an_object, {some: 'parameter'}) }
it "delegates to helpers" do
- subject.localize(:an_object, some: "options")
+ subject.localize(:an_object, some: 'parameter')
end
it "is aliased to #l" do
- subject.l(:an_object, some: "options")
+ subject.l(:an_object, some: 'parameter')
end
end
View
12 spec/draper/decoratable_spec.rb
@@ -9,9 +9,9 @@
subject.decorate.source.should be subject
end
- it "accepts options" do
- decorator = subject.decorate(some: "options")
- decorator.options.should == {some: "options"}
+ it "accepts context" do
+ decorator = subject.decorate(context: {some: 'context'})
+ decorator.context.should == {some: 'context'}
end
it "is not memoized" do
@@ -153,9 +153,9 @@
decorator.source.should be Product.scoped
end
- it "accepts options" do
- decorator = Product.decorate(some: "options")
- decorator.options.should == {some: "options"}
+ it "accepts context" do
+ decorator = Product.decorate(context: {some: 'context'})
+ decorator.context.should == {some: 'context'}
end
it "is not memoized" do
View
183 spec/draper/decorated_association_spec.rb
@@ -1,10 +1,52 @@
require 'spec_helper'
describe Draper::DecoratedAssociation do
- let(:decorated_association) { Draper::DecoratedAssociation.new(source, association, options) }
+ let(:decorated_association) { Draper::DecoratedAssociation.new(base, association, options) }
let(:source) { Product.new }
+ let(:base) { source.decorate }
let(:options) { {} }
+ describe "#initialize" do
+ describe "options validation" do
+ let(:association) { :similar_products }
+ let(:valid_options) { {with: ProductDecorator, scope: :foo, context: {}} }
+
+ it "does not raise error on valid options" do
+ expect { Draper::DecoratedAssociation.new(base, association, valid_options) }.to_not raise_error
+ end
+
+ it "raises error on invalid options" do
+ expect { Draper::DecoratedAssociation.new(base, association, valid_options.merge(foo: 'bar')) }.to raise_error(ArgumentError, 'Unknown key: foo')
+ end
+ end
+ end
+
+ describe "#base" do
+ subject { decorated_association.base }
+ let(:association) { :similar_products }
+
+ it "returns the base decorator" do
+ should be base
+ end
+
+ it "returns a Decorator" do
+ subject.class.should == ProductDecorator
+ end
+ end
+
+ describe "#source" do
+ subject { decorated_association.source }
+ let(:association) { :similar_products }
+
+ it "returns the base decorator's source" do
+ should be base.source
+ end
+
+ it "returns a Model" do
+ subject.class.should == Product
+ end
+ end
+
describe "#call" do
subject { decorated_association.call }
@@ -128,5 +170,144 @@
subject.source.should be scoped
end
end
+
+ context "base has context" do
+ let(:association) { :similar_products }
+ let(:base) { source.decorate(context: {some: 'context'}) }
+
+ context "when no context is specified" do
+ it "it should inherit context from base" do
+ subject.context.should == {some: 'context'}
+ end
+
+ it "it should share context hash with base" do
+ subject.context.should be base.context
+ end
+ end
+
+ context "when static context is specified" do
+ let(:options) { {context: {other: 'context'}} }
+
+ it "it should get context from static option" do
+ subject.context.should == {other: 'context'}
+ end
+ end
+
+ context "when lambda context is specified" do
+ let(:options) { {context: lambda {|context| context.merge(other: 'protext')}} }
+
+ it "it should get generated context" do
+ subject.context.should == {some: 'context', other: 'protext'}
+ end
+ end
+ end
+ end
+
+ describe "#decorator_options" do
+ subject { decorated_association.send(:decorator_options) }
+
+ context "collection association" do
+ let(:association) { :similar_products }
+
+ context "no options" do
+ it "should return default options" do
+ should == {with: :infer, context: {}}
+ end
+
+ it "should set with: to :infer" do
+ decorated_association.send(:options).should == options
+ subject
+ decorated_association.send(:options).should == {with: :infer}
+ end
+ end
+
+ context "option with: ProductDecorator" do
+ let(:options) { {with: ProductDecorator} }
+ it "should pass with: from options" do
+ should == {with: ProductDecorator, context: {}}
+ end
+ end
+
+ context "option scope: :to_a" do
+ let(:options) { {scope: :to_a} }
+ it "should strip scope: from options" do
+ decorated_association.send(:options).should == options
+ should == {with: :infer, context: {}}
+ end
+ end
+
+ context "base has context" do
+ let(:base) { source.decorate(context: {some: 'context'}) }
+
+ context "no options" do
+ it "should return context from base" do
+ should == {with: :infer, context: {some: 'context'}}
+ end
+ end
+
+ context "option context: {other: 'context'}" do
+ let(:options) { {context: {other: 'context'}} }
+ it "should return specified context" do
+ should == {with: :infer, context: {other: 'context'}}
+ end
+ end
+
+ context "option context: lambda" do
+ let(:options) { {context: lambda {|context| context.merge(other: 'protext')}} }
+ it "should return specified context" do
+ should == {with: :infer, context: {some: 'context', other: 'protext'}}
+ end
+ end
+ end
+ end
+
+ context "singular association" do
+ let(:association) { :previous_version }
+
+ context "no options" do
+ it "should return default options" do
+ should == {context: {}}
+ end
+ end
+
+ context "option with: ProductDecorator" do
+ let(:options) { {with: ProductDecorator} }
+ it "should strip with: from options" do
+ should == {context: {}}
+ end
+ end
+
+ context "option scope: :decorate" do
+ let(:options) { {scope: :decorate} }
+ it "should strip scope: from options" do
+ decorated_association.send(:options).should == options
+ should == {context: {}}
+ end
+ end
+
+ context "base has context" do
+ let(:base) { source.decorate(context: {some: 'context'}) }
+
+ context "no options" do
+ it "should return context from base" do
+ should == {context: {some: 'context'}}
+ end
+ end
+
+ context "option context: {other: 'context'}" do
+ let(:options) { {context: {other: 'context'}} }
+ it "should return specified context" do
+ should == {context: {other: 'context'}}
+ end
+ end
+
+ context "option context: lambda" do
+ let(:options) { {context: lambda {|context| context.merge(other: 'protext')}} }
+ it "should return specified context" do
+ should == {context: {some: 'context', other: 'protext'}}
+ end
+ end
+ end
+ end
end
end
View
85 spec/draper/decorator_spec.rb
@@ -7,13 +7,25 @@
let(:source) { Product.new }
describe "#initialize" do
+ describe "options validation" do
+ let(:valid_options) { {context: {}} }
+
+ it "does not raise error on valid options" do
+ expect { decorator_class.new(source, valid_options) }.to_not raise_error
+ end
+
+ it "raises error on invalid options" do
+ expect { decorator_class.new(source, valid_options.merge(foo: 'bar')) }.to raise_error(ArgumentError, 'Unknown key: foo')
+ end
+ end
+
it "sets the source" do
subject.source.should be source
end
- it "stores options" do
- decorator = decorator_class.new(source, some: "options")
- decorator.options.should == {some: "options"}
+ it "stores context" do
+ decorator = decorator_class.new(source, context: {some: 'context'})
+ decorator.context.should == {some: 'context'}
end
context "when decorating an instance of itself" do
@@ -23,16 +35,16 @@
end
context "when options are supplied" do
- it "overwrites existing options" do
- decorator = ProductDecorator.new(source, role: :admin)
- ProductDecorator.new(decorator, role: :user).options.should == {role: :user}
+ it "overwrites existing context" do
+ decorator = ProductDecorator.new(source, context: {role: :admin})
+ ProductDecorator.new(decorator, context: {role: :user}).context.should == {role: :user}
end
end
context "when no options are supplied" do
- it "preserves existing options" do
- decorator = ProductDecorator.new(source, role: :admin)
- ProductDecorator.new(decorator).options.should == {role: :admin}
+ it "preserves existing context" do
+ decorator = ProductDecorator.new(source, context: {role: :admin})
+ ProductDecorator.new(decorator).context.should == {role: :admin}
end
end
end
@@ -55,10 +67,31 @@
end
end
+ describe "#context=" do
+ it "modifies the context" do
+ decorator = decorator_class.new(source, context: {some: 'context'})
+ decorator.context = {some: 'other_context'}
+ decorator.context.should == {some: 'other_context'}
+ end
+ end
+
describe ".decorate_collection" do
subject { ProductDecorator.decorate_collection(source) }
let(:source) { [Product.new, Widget.new] }
+ describe "options validation" do
+ let(:valid_options) { {with: :infer, context: {}} }
+ before(:each) { Draper::CollectionDecorator.stub(:new) }
+
+ it "does not raise error on valid options" do
+ expect { ProductDecorator.decorate_collection(source, valid_options) }.to_not raise_error
+ end
+
+ it "raises error on invalid options" do
+ expect { ProductDecorator.decorate_collection(source, valid_options.merge(foo: 'bar')) }.to raise_error(ArgumentError, 'Unknown key: foo')
+ end
+ end
+
it "returns a collection decorator" do
subject.should be_a Draper::CollectionDecorator
subject.source.should be source
@@ -77,11 +110,11 @@
end
end
- context "with options" do
- subject { ProductDecorator.decorate_collection(source, with: :infer, some: "options") }
+ context "with context" do
+ subject { ProductDecorator.decorate_collection(source, with: :infer, context: {some: 'context'}) }
- it "passes the options to the collection decorator" do
- subject.options.should == {some: "options"}
+ it "passes the context to the collection decorator" do
+ subject.context.should == {some: 'context'}
end
end
end
@@ -104,14 +137,14 @@
end
describe "#localize" do
- before { subject.helpers.should_receive(:localize).with(:an_object, {some: "options"}) }
+ before { subject.helpers.should_receive(:localize).with(:an_object, {some: 'parameter'}) }
it "delegates to #helpers" do
- subject.localize(:an_object, some: "options")
+ subject.localize(:an_object, some: 'parameter')
end
it "is aliased to #l" do
- subject.l(:an_object, some: "options")
+ subject.l(:an_object, some: 'parameter')
end
end
@@ -223,8 +256,26 @@
describe "overridden association method" do
let(:decorated_association) { ->{} }
+ describe "options validation" do
+ let(:valid_options) { {with: ProductDecorator, scope: :foo, context: {}} }
+ before(:each) { Draper::DecoratedAssociation.stub(:new).and_return(decorated_association) }
+
+ it "does not raise error on valid options" do
+ expect { decorator_class.decorates_association :similar_products, valid_options }.to_not raise_error
+ end
+
+ it "raises error on invalid options" do
+ expect { decorator_class.decorates_association :similar_products, valid_options.merge(foo: 'bar') }.to raise_error(ArgumentError, 'Unknown key: foo')
+ end
+ end
+
it "creates a DecoratedAssociation" do
- Draper::DecoratedAssociation.should_receive(:new).with(source, :similar_products, {with: ProductDecorator}).and_return(decorated_association)
+ Draper::DecoratedAssociation.should_receive(:new).with(subject, :similar_products, {with: ProductDecorator}).and_return(decorated_association)
+ subject.similar_products
+ end
+
+ it "receives the Decorator" do
+ Draper::DecoratedAssociation.should_receive(:new).with(kind_of(decorator_class), :similar_products, {with: ProductDecorator}).and_return(decorated_association)
subject.similar_products
end
View
32 spec/draper/finders_spec.rb
@@ -15,9 +15,9 @@
decorator.source.should be found
end
- it "passes options to the decorator" do
- decorator = ProductDecorator.find(1, some: "options")
- decorator.options.should == {some: "options"}
+ it "passes context to the decorator" do
+ decorator = ProductDecorator.find(1, context: {some: 'context'})
+ decorator.context.should == {some: 'context'}
end
end
@@ -55,10 +55,10 @@
ProductDecorator.find_or_create_by_name_and_size("apples", "large")
end
- it "passes options to the decorator" do
- Product.should_receive(:find_by_name_and_size).with("apples", "large", {some: "options"})
- decorator = ProductDecorator.find_by_name_and_size("apples", "large", some: "options")
- decorator.options.should == {some: "options"}
+ it "passes context to the decorator" do
+ Product.should_receive(:find_by_name_and_size).with("apples", "large", context: {some: 'context'})
+ decorator = ProductDecorator.find_by_name_and_size("apples", "large", context: {some: 'context'})
+ decorator.context.should == {some: 'context'}
end
end
@@ -84,9 +84,9 @@
collection.first.should be_a ProductDecorator
end
- it "passes options to the collection decorator" do
- collection = ProductDecorator.all(some: "options")
- collection.options.should == {some: "options"}
+ it "passes context to the collection decorator" do
+ collection = ProductDecorator.all(context: {some: 'context'})
+ collection.context.should == {some: 'context'}
end
end
@@ -104,9 +104,9 @@
decorator.source.should be first
end
- it "passes options to the decorator" do
- decorator = ProductDecorator.first(some: "options")
- decorator.options.should == {some: "options"}
+ it "passes context to the decorator" do
+ decorator = ProductDecorator.first(context: {some: 'context'})
+ decorator.context.should == {some: 'context'}
end
end
@@ -124,9 +124,9 @@
decorator.source.should be last
end
- it "passes options to the decorator" do
- decorator = ProductDecorator.last(some: "options")
- decorator.options.should == {some: "options"}
+ it "passes context to the decorator" do
+ decorator = ProductDecorator.last(context: {some: 'context'})
+ decorator.context.should == {some: 'context'}
end
end
Something went wrong with that request. Please try again.