53

When do you use attr_reader/attr_writer/attr_accessor in Rails models?

Andrew Marshall
  • 95,083
  • 20
  • 220
  • 214
Ethan
  • 9,558
  • 5
  • 27
  • 24

5 Answers5

63

Never, unless you have specific need for it. Automatic database-backed accessors are created for you, so you don't need to worry.

Any attr_accessors you do create will change the relevant @attr on the rails object, but this will be lost when the object is destroyed, unless you stick it back in the database. Sometimes you do want this behavior, but it's unusual in a rails app.

Now in ruby, it's a different story, and you end up using these very frequently. But I'd be surprised if you need them in rails---especially initially.

Peter
  • 127,331
  • 53
  • 180
  • 211
  • 4
    perfect - thanks. (I'd plus vote you, but I just got on here and I seem to need 15pts first... That mechanic seems unfriendly to new users.) – Ethan May 08 '10 at 21:57
  • 3
    Note: as of Rails 3.x `attr_accessible` is required (by default) for each model whose attributes you want to allow writing to (e.g. via a form POST). This can be changed in the `application.rb` for backward compatibility, but was added as a security measure to require you to explicitly whitelist attributes that _should_ be updateable by users. As an added benefit, all of the attributes of a model (db columns) are visible right there in the model, so you don't have to remember what the heck that column was named :-) – Tom Harrison Jun 29 '12 at 15:25
59

attr_accessor can be used for values you don't want to store in the database directly and that will only exist for the life of the object (e.g. passwords).

attr_reader can be used as one of several alternatives to doing something like this:

def instance_value
  "my value"
end
Noah Thorp
  • 936
  • 8
  • 10
15

Rails models are just ruby classes that inherit from ActiveRecord::Base. ActiveRecord employs attr_accessors to define getters and setters for the column names that refer to the ruby class's table. It's important to note that this is just for persistence; the models are still just ruby classes.

attr_accessor :foo is simply a shortcut for the following:

def foo=(var)
  @foo = var
end

def foo
  @foo
end

attr_reader :foo is simply a shortcut for the following:

def foo
  @foo
end

attr_writer :foo is a shortcut for the following:

def foo=(var)
  @foo = var
end

attr_accessor is a shortcut for the getter and setter while attr_reader is the shortcut for the getter and attr_writer is a shortcut for just the setter.

In rails, ActiveRecord uses these getters and setters in a convenient way to read and write values to the database. BUT, the database is just the persistence layer. You should be free to use attr_accessor and attr_reader as you would any other ruby class to properly compose your business logic. As you need to get and set attributes of your objects outside of what you need to persist to the database, use the attr_s accordingly.

More info:

http://apidock.com/ruby/Module/attr_accessor

http://www.rubyist.net/~slagell/ruby/accessors.html

What is attr_accessor in Ruby?

Community
  • 1
  • 1
brycemcd
  • 4,343
  • 3
  • 26
  • 29
  • `attr_reader :foo` generates `foo` getter method, `attr_writer :foo` generates `foo=` setter method, `attr_accessor :foo` generates both `foo` and `foo=` methods. – Fatih Oct 07 '13 at 20:10
  • +1 Fatih. Thanks for the editing. I've edited my response to include your comment – brycemcd Oct 10 '13 at 20:52
2

If you are using it to validate the acceptance of the terms_of_service, you should really consider using validates :terms_of_service, :acceptance => true. It will create a virtual attribute and is much more concise.

http://guides.rubyonrails.org/active_record_validations.html#acceptance.

Akshay Mohite
  • 2,168
  • 1
  • 16
  • 22
0

One example is to have a number of options stored in one serialized column. Form builder would complain if you try to have a text field for one of these options. You can use attr_accessor to fake it, and then in the update action save it in the serialized column.

lulalala
  • 17,572
  • 15
  • 110
  • 169