Using Rails 3 and ActiveModel, I am unable to use the self. syntax to get the value of an attribute inside an ActiveModel based object.
In the following code, in save method, self开发者_如何学Python.first_name evaluates to nil where @attributes[:first_name] evaluates to 'Firstname' (the value passed in from the controller when initializing the object).
In ActiveRecord this seems to work, but when building the same class in ActiveModel, it does not. How do you refer to a field using accessors in an ActiveModel based class?
class Card
include ActiveModel::Validations
extend ActiveModel::Naming
include ActiveModel::Conversion
include ActiveModel::Serialization
include ActiveModel::Serializers::Xml
validates_presence_of :first_name
def initialize(attributes = {})
@attributes = attributes
end
#DWT TODO we need to make sure that the attributes initialize the accessors properyl, and in the same way they would if this was ActiveRecord
attr_accessor :attributes, :first_name
def read_attribute_for_validation(key)
@attributes[key]
end
#save to the web service
def save
Rails.logger.info "self vs attribute:\n\t#{self.first_name}\t#{@attributes["first_name"]}"
end
...
end
I figured it out. The "hack" that I mentioned as a comment to Marian's answer actually turns out to be exactly how the accessors for ActiveRecord classes are generated. Here's what I did:
class MyModel
include ActiveModel::AttributeMethods
attribute_method_suffix "=" # attr_writers
attribute_method_suffix "" # attr_readers
define_attribute_methods [:foo, :bar]
# ActiveModel expects attributes to be stored in @attributes as a hash
attr_reader :attributes
private
# simulate attribute writers from method_missing
def attribute=(attr, value)
@attributes[attr] = value
end
# simulate attribute readers from method_missing
def attribute(attr)
@attributes[attr]
end
end
You can see the same thing if you look in ActiveRecord's source code (lib/active_record/attribute_methods/{read,write}.rb
).
You need ActiveModel::AttributeMethods
for that
精彩评论