human_attribute_name<\/code>.<\/p>\nA minimal implementation could be:<\/p>\n
\r\nclass Person\r\n include ActiveModel::Model\r\n\r\n attr_accessor :name, :age\r\n validates_presence_of :name\r\nend\r\n\r\nperson = Person.new(:name => 'bob', :age => '18')\r\nperson.name # => 'bob'\r\nperson.age # => 18\r\nperson.valid? # => true\r\n<\/pre>\nThis is really handy, considering that before this addition, we’d have to add all that code to have a model up and running to use with ActionView's form_for<\/code>, for instance. Ok, it is not that much code to add, but now we don’t even need to remember which modules are required for such integration. And I have to add that I’ve been creating similar classes in different applications lately. Take a moment to think about a contact form, that does not need to be tied to a database: it’s a common scenario to implement using ActiveModel::Model<\/code>.<\/p>\nExtending Basic Model even more<\/h3>\n
Note that, by default, ActiveModel::Model<\/code> implements persisted?<\/code> to return false<\/code>, which is the most common case. For instance, when used with form_for<\/code>, this means that the generated url would post<\/code> to the create<\/code> action. You may want to override it in your class to simulate a different scenario:<\/p>\n\r\nclass Person\r\n include ActiveModel::Model\r\n attr_accessor :id, :name\r\n\r\n def persisted?\r\n self.id == 1\r\n end\r\nend\r\n\r\nperson = Person.new(:id => 1, :name => 'bob')\r\nperson.persisted? # => true\r\n<\/pre>\nBesides that, if for some reason you need to run code on initialize<\/code>, make sure you call super if you want the attributes hash initialization to happen.<\/p>\n\r\nclass Person\r\n include ActiveModel::Model\r\n attr_accessor :id, :name, :omg\r\n\r\n def initialize(attributes)\r\n super\r\n @omg ||= true\r\n end\r\nend\r\n\r\nperson = Person.new(:id => 1, :name => 'bob')\r\nperson.omg # => true\r\n<\/pre>\nAnd remember that, at the end, this is all Ruby: you can include any other module of your own and other ActiveModel<\/code> modules easily in your class. For instance, lets add callbacks<\/code> to our model to mimic ActiveRecord's save<\/code> functionality:<\/p>\n\r\nclass Person\r\n include ActiveModel::Model\r\n extend ActiveModel::Callbacks\r\n\r\n define_model_callbacks :save\r\n attr_accessor :id, :name\r\n\r\n # Just check validity, and if so, trigger callbacks.\r\n def save\r\n if valid?\r\n run_callbacks(:save) { true }\r\n else\r\n false\r\n end\r\n end\r\nend\r\n<\/pre>\nThis gives you before_save<\/code>, after_save<\/code> and around_save<\/code> callbacks. Quick and easy, huh?<\/p>\nWrapping up<\/h3>\n
ActiveModel::Model<\/code> is a really small, handy addition to Rails 4.0, which helps us to get classes that act more like ActiveRecord<\/code> and easily integrate with ActionPack<\/code>.<\/p>\nFor more detailed information on other features available, please refer to the specific modules included in ActiveModel::Model<\/code><\/a>. Each module includes plenty of docs explaining its functionality. Apart from these included modules, ActiveModel<\/code> itself has a bunch of useful stuff to add to your Ruby classes that are really worth checking out.<\/p>\nThis is the kind of thing that makes me a happier Rails developer every day. What about you, what makes you a happier Rails developer? Please take a moment to tell us in the comments section below \ud83d\ude42<\/p>\n","protected":false},"excerpt":{"rendered":"
Rails 4 will ship with ActiveModel::Model, a module that includes the minimum required by Action Pack to work in forms, urls and so forth. Learn more about this module, how to use and extend it in this blog post.<\/p>\n","protected":false},"author":7,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"footnotes":""},"categories":[1],"tags":[177,92,7,176],"aioseo_notices":[],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts\/2543"}],"collection":[{"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/comments?post=2543"}],"version-history":[{"count":23,"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts\/2543\/revisions"}],"predecessor-version":[{"id":2593,"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/posts\/2543\/revisions\/2593"}],"wp:attachment":[{"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/media?parent=2543"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/categories?post=2543"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.plataformatec.com.br\/wp-json\/wp\/v2\/tags?post=2543"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}