2

I'm a newbie rails programer and i have a problem when get data. My User model

class User < ActiveRecord::Base 
attr_accessor :name

My UserController

@users = User.all

My view users/index.html.erb

 <% @users.each do |user| %>
<%= user.name %> //error: undefined method `name`

but if i remove attr_accessor :name in User model, my app is run. Please, tell me what is wrong

My rails version is 5.

1 Answers1

3

attr_accessor is a class level method. You are trying to use it on an instance level.

Try cattr_accessor instead. Although you dont need an attr_accessor orcattr_accessor to access attributes of anActiveRecord::Base model that are defined in the schema.

====> EDIT <==== Corrected Answer Below

Disregard the advice above. It's not accurate. Im leaving it for reference. The reason you are getting the undefined method: name error is because you have set an attr_accessor on a model that already has a getter set dynamically via ActiveRecord::Base.

Setting attr_accessor on an attribute of an ActiveRecord::Base models DB column causes some sort of conflict. When you remove the attr_accessor method and instead add whats supposed to be its exact equivalent...

def name
  name
end

and then try to call that you get an infinitely recursive looping of your call because the .name getter method we defined above is calling itself and not accessing the ActiveRecord getter method that actually pulls data from your DB.

Im guessing that somehow active_record model classes will just throw you an undefined method error rather than make the recursive call that ends in a stack level too deep error.

However since you arent getting a stack too deep error my next guess is that the attr_accessor you defined overrides the dynamically created ActiveRecord::Base getter while rails is still attempting to access the overridden method ( which dosnt exist anymore ). Possibly resulting in the undefined method 'name' error.

But...

When you add your own getter method this way... then it works...

def name
  super
end

this is because with super your class is just inheriting the behavior of its dynamically defined ActiveRecord::Base getter method. You can test this by adding...

def name
  super
  'Foo'
end

And when you call @model.name you'll see that Foo is returned. Remove the 'Foo' from the method and what you have being returned is a super call to the dynamically created ActiveRecord::Base getter method.

Im open to edits and input on this answer. This is my logical conclusion from testing in my console and doing some reading.

When to use attr_accessor

Also, to answer your question further about when to use attr_accessor...

You would use this when you want to create and store information that is business-logic as well as model related, and only lasts for the duration of the request/instance life cycle.

For example raw passwords ( although I cringe at anyone manipulating raw passwords )

or something like...

@stock.current_price

where @stock is a ActiveRecord::Base object but .current_price is calculated or retrieved from an API upon instantiation of the @stock object because it doesn't make sense to persist and retrieve from the DB an ever changing value such as the price of a stock at any given point in time.

Verty00
  • 726
  • 5
  • 16
  • 1
    can you help me to explain when i need to use attr_accessor ? – thiên lâm trần Sep 12 '18 at 04:01
  • this is a really good explanation. [https://stackoverflow.com/questions/4370960/what-is-attr-accessor-in-ruby](https://stackoverflow.com/questions/4370960/what-is-attr-accessor-in-ruby) – Verty00 Sep 12 '18 at 04:04
  • @thiênlâmtrần You're welcome. Give an upvote to answers and comments that were helpful :) – Verty00 Sep 12 '18 at 04:09
  • @thiênlâmtrần Also please mark this as the answer if it was correct :) – Verty00 Sep 12 '18 at 04:11
  • @thiênlâmtrần I updated my answer as the original answer was wrong. While you still dont need an `attr_accessor` for an `ActiveRecord::Base` model... I got wrong the reason you were getting the error. Ive corrected my answer and this should be more helpful. – Verty00 Sep 12 '18 at 13:15