I’ve found using
attr_accessor on Rails projects is a stumbling block for many developers. We’ve been using
attr_accessible our entire Rails career, but then we jump on a project and see
attr_accessor defined in a Rails model. What the …? In this post we’ll talk about how to use
attr_accessor with Rails’
attr_accessible, where it can be useful, and things to watch out for.
Plain and simple,
attr_accessor is a plain old Ruby way to define getter and setter methods. It’s essentially
attr_writer combined. Specifically:
attr_reader only defines the getter, the
content method in this case, and
attr_writer only defines the setter, the
attr_accessor defines them both. And an instance variable. Woot!
This is great for setting instance variables on objects in Rails that you don’t plan on persisting.
(Warning, this applies to Rails 3.2. I’m pretty sure this changes because of strong parameters in Rails 4+, but I’m not exactly sure how. Updates to come.)
We all know and love
attr_accessible, but what does it do? In Rails 3.2, it’s very similar to
attr_accessor as it defines getters and setters, but it also lets you mass assign attributes. What does that mean? It simply means you can update multiple attributes at the same time, like you would with a params hash from within a controller. An example:
When you specify
attr_accessible, Rails assumes that this attribute has a corresponding column in your database, and defaults to saving it there. This means that your Post class tries to save the content attribute in
posts.content in your database. Makes sense.
Combining The Two
When you define
attr_accessible on the same attribute, you are telling Rails a couple things. First, you want to be able to mass assign this attribute. Second, that you don’t want to persist this attribute in the database, but store it in an instance variable instead. This can be useful for dictating logic in your model, like so:
In this example, the Post class will immediately publish this post upon creation. The attribute
publish_immediately would perhaps represent a checkbox on the create post form. Assuming we don’t want to persist this, the previous code block would let us store the value of the checkbox in an instance variable, which we access on the
after_create line. Again,
attr_accessor intercepts Rails’ attempt to store the attribute in the database, and stores it in an instance variable instead.
There are probably situations where this would come in handy, but my personal recommendation is to go ahead and persist your attributes. Database storage is cheap and you never know when your boss (or customer) will come to you and say, “Hey, was that one post published immediately?”.