Using attr_accessor and attr_accessible on the same field
Asked Answered
I

4

21

What happens in the background with the following code?

class User < ActiveRecord::Base

 attr_accessor :name
 attr_accessible :name

end

Hint: When instantiating the class, will it be persisted to the database? Why or why not?

Inglis answered 15/1, 2011 at 16:45 Comment(0)
I
4

Thanks everyone for quick answers! Your answers combined gave me the pieces I needed to understand this puzzle, I think.

(In a related problem, I was getting a lot of nil errors like "Object doesn’t support #inspect", and "undefined method ‘keys’ for nil:NilClass". I managed to solve it now, by removing the att_accessor field altogether.)

By experimenting with this particular case, this is what I've found out:

Actually, the :name field won't be persisted to the database.

user = User.new(:name=>"somename")

Will only set the attribute on the object, but not persist the :name column to the database. Like the following 'rails console' output shows:

> user
=> <User id: nil, created_at: nil, updated_at: nil>
> user.save
=> true
> user
=> <User id:1, created_at: 2011-01-19 12:37:21, updated_at: 2011-01-19 12:37:21>

I assume this is because *the setter made by attr_accessor will override ActiveRecord's setter* (which takes care of the database persistence). You can still retrieve the value from the :name field from the object though, like this:

> user.name
=> "somename"

So, in conclusion, I've learnt that using attr_accessor on fields might lead to them not being persisted to the database. And while I thought attr_accessible describes fields in the database that should be accessible from the outside, it doesn't seem to make a difference in this case.

Inglis answered 19/1, 2011 at 13:22 Comment(0)
A
70

attr_accessor is ruby code and is used when you do not have a column in your database, but still want to show a field in your forms. The only way to allow this is to attr_accessor :fieldname and you can use this field in your View, or model, if you wanted, but mostly in your View.

attr_accessible allows you to list all the columns you want to allow Mass Assignment, as andy eluded to above. The opposite of this is attr_protected which means this field i do NOT want anyone to be allowed to Mass Assign to. More then likely it is going to be a field in your database that you don't want anyone monkeying around with. Like a status field, or the like.

Abbreviated answered 15/1, 2011 at 18:22 Comment(2)
Single best answer I've seen to this massively important and basic question. For some reason this is just not usually spelled out for people. Thanks.Adamsun
This is a very good explanation of the differences between the two, but it doesn't the question: what happens when you use them both on the same field (or what happens with persistence). For that, se my summary answer below.Inglis
C
5

In most cases, you don't need to use attr_accessor if the field is a column in the users table in your database. ActiveRecord will figure it out for you.

attr_accessible simply allows to field to be assigned via mass assignment (e.g., with update_attributes). This is good for security purposes. More information from the MassAssignmentSecurity API docs.

Cathleencathlene answered 15/1, 2011 at 17:21 Comment(0)
I
4

Thanks everyone for quick answers! Your answers combined gave me the pieces I needed to understand this puzzle, I think.

(In a related problem, I was getting a lot of nil errors like "Object doesn’t support #inspect", and "undefined method ‘keys’ for nil:NilClass". I managed to solve it now, by removing the att_accessor field altogether.)

By experimenting with this particular case, this is what I've found out:

Actually, the :name field won't be persisted to the database.

user = User.new(:name=>"somename")

Will only set the attribute on the object, but not persist the :name column to the database. Like the following 'rails console' output shows:

> user
=> <User id: nil, created_at: nil, updated_at: nil>
> user.save
=> true
> user
=> <User id:1, created_at: 2011-01-19 12:37:21, updated_at: 2011-01-19 12:37:21>

I assume this is because *the setter made by attr_accessor will override ActiveRecord's setter* (which takes care of the database persistence). You can still retrieve the value from the :name field from the object though, like this:

> user.name
=> "somename"

So, in conclusion, I've learnt that using attr_accessor on fields might lead to them not being persisted to the database. And while I thought attr_accessible describes fields in the database that should be accessible from the outside, it doesn't seem to make a difference in this case.

Inglis answered 19/1, 2011 at 13:22 Comment(0)
K
1

Since it inherits ActiveRecord, it will be persisted when you call the save method (but not when it is instantiated).

If you don't have any attributes for that model, I assume ActiveRecord will simply save a new row in the database (i.e. your object will only have a persisted id). This makes sense, as you might later add attributes to your User model, and the persisted instances should still be retrievable.

Kori answered 15/1, 2011 at 16:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.