Using rails 3.2.8 I have a model setup with a couple attributes
class MyModel < ActiveRecord::Base
attr_accessible :foo, :bar
end
I have another class setup using the above as a delegate class
class MyModelPresenter < DelegateClass(MyModel)
def initialize(month, obj)
@month = month
super(obj)
end
def self.build(month, attributes = { })
new(month, MyModel.new).tap do |p|
p.attributes = attributes
end
end
def attributes=(attributes)
attributes.each { |k, v| send("#{k}=", v) }
end
end
When I create a new MyModelPresenter like so:
MyModelPresenter.build(Date.today, {:foo => 1})
I get the following back
NoMethodError: undefined method `foo=' for #<MyModel:0x1098f31a8>
from /Users/me/.rbenv/versions/ree-1.8.7-2011.03/lib/ruby/gems/1.8/gems/activemodel-3.2.8/lib/active_model/attribute_methods.rb:404:in `method_missing'
from /Users/me/.rbenv/versions/ree-1.8.7-2011.03/lib/ruby/gems/1.8/gems/activerecord-3.2.8/lib/active_record/attribute_methods.rb:149:in `method_missing'
from /Users/me/dev/temp/app/presenters/my_model_presenter.rb:23:in `send'
from /Users/me/dev/temp/app/presenters/my_model_presenter.rb:23:in `attributes='
from /Users/me/dev/temp/app/presenters/my_model_presenter.rb:23:in `each'
from /Users/me/dev/temp/app/presenters/my_model_presenter.rb:23:in `attributes='
from /Users/me/dev/temp/app/presenters/my_model_presenter.rb:17:in `build'
from /Users/me/dev/temp/app/presenters/my_model_presenter.rb:15:in `tap'
from /Users/me/dev/temp/app/presenters/my_model_presenter.rb:15:in `build'
For some reason the database attributes on the model aren't getting defined (setters or getters). Before upgrading to rails 3.2 this was all working in a rails 3.1 app.
Does anyone have any idea why the model's attribute methods aren't getting defined?
Inheriting from Delegator
instead of using DelegateClass
solved the problem. Here is what the final class looked like:
class MyModelPresenter < Delegator
def initialize(month, obj)
@month = month
super(obj)
@_sd_obj = obj
end
def __getobj__
@_sd_obj
end
def self.build(month, attributes = { })
new(month, MyModel.new).tap do |p|
p.attributes = attributes
end
end
def attributes=(attributes)
attributes.each { |k, v| send("#{k}=", v) }
end
end
As you can see I also had to add the def __getobj__
method. and set @_sd_obj
in the initializer to an instance of the class I'm delegating from.
See the SimpleDelegator
example.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With