1

I was confused about the different ways to access instance variables in rails models. For example, this will work:

def add_calories(ingredient)


    self.total_calories += ingredient.calories

    p total_calories

end

However this will results in errors:

def add_calories(ingredient)

    total_calories += ingredient.calories

end



Error: NoMethodError: undefined method "+" for nil:NilClass

Also this won't work either.

def add_calories(ingredient)

    total_calories = total_calories + ingredient.calories

end

If I can access the instance variable without self in the first case, how come that in the second case, total_calories becomes nil?

Could it be that the default value for total_calories is set to 0? However if that's the case, why does self.total_calories work?

t.integer  "total_calories", default: 0 

I read this post but it doesn't really explain why the third case won't work.

Thanks a lot.

Community
  • 1
  • 1
whales
  • 787
  • 1
  • 12
  • 24
  • Not so much instance variables here as accessible attributes. All attributes are contained in an instance_variable called `@attributes` which is actually a `Hash` as for why you have to call the getter methods with an explicit receiver I am not sure maybe someone else can assist with that part – engineersmnky Jul 18 '16 at 20:55
  • It works in the first case without an explicit receiver "self" when I used it in a print statement. So that makes me think that self is optional. However in the second and the third case, it wouldn't work without self. – whales Jul 18 '16 at 21:02

1 Answers1

1

This seems like less of a question about instance variable access in Rails and more a question about "setter" methods in Ruby (in your case, using the total_calories= method). Information about why an explicit self receiver is needed for setter methods is covered in other Stack Overflow answers, like this one.

In summary, though, the issue is that the intention of the statement total_calories = something could be ambiguous: are you defining a new local variable or calling the setter? Calling self.total_calories = something explicitly says you want to call the setter, while leaving off self and calling total_calories = something says you want a new local variable.

I think your third example should work if you change the method content to use both getter and setter methods explicitly:

def add_calories(ingredient)
  self.total_calories = total_calories + ingredient.calories
end
Community
  • 1
  • 1
Paul Fioravanti
  • 16,423
  • 7
  • 71
  • 122