Using ActiveRecord with DelegateClass

Using rails 3.2.8 I have a model with two attributes

class MyModel < ActiveRecord::Base attr_accessible :foo, :bar end 

I have another class setting 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, for example:

 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, database attributes are not defined on the model (setters or getters). Before upgrading to rails 3.2, all this worked in the rails 3.1 application.

Does anyone know why model attribute methods are not defined?

+4
source share
1 answer

Inheriting from Delegator instead of using DelegateClass solved the problem. Here's what the last 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 an instance of the class I am delegating from.

See the SimpleDelegator example.

+1
source

Source: https://habr.com/ru/post/1444705/


All Articles