alexandre-rousseau
alexandre-rousseau

Reputation: 2830

Does ActiveRecord object not have instance variables for it's attributes but only methods?

In Rails I have the following model:

class Recipe < ActiveRecord::Base
    attr_accessible :name , :description , 
        :t_baking , :t_cooling , :t_cooking ,:t_rest

    # other stuff here

end

with t_baking , t_cooling , t_cooking ,t_rest as Time.

So In my view I want to loop on each value.

<% ['cooking', 'baking', 'cooling' , 'rest'].each do |time| %>
    <% time_of_recipe = @recipe.instance_variable_get("@t_#{time}") %>
    <% if time_of_recipe.is_a? Time %>
        <%= time_of_recipe.strftime "%H:%M"  %>
    <% else %>
        <%= time_of_recipe %>
    <% end %>
<% end %>

It doesn't work because

@recipe.instance_variable_get("@t_cooking").class # give NilClass

but

@recipe.t_cooking.class # give Time

Why?

Upvotes: 2

Views: 323

Answers (1)

Andrey Deineko
Andrey Deineko

Reputation: 52357

@recipe.instance_variable_get("@t_cooking")

returns nil because there is no instance variable @t_cooking for @recipe.

It is a bunch of methods defined by ActiveRecord that you have access to, but these are not instance variables.

Applying it to your code, you'd want to change it to:

time_of_recipe = @recipe.public_send("t_#{time}")

Also, it is pointless to save single letter of typing.

It would be much more readable to do the following:

<% %w(t_cooking t_baking t_cooling t_rest).each do |time| %>
    <% time_of_recipe = @recipe.public_send(time) %>
    # ...

EDIT

If you want to check available instance variables (you look to be using Rails 3.2, so your output might be slightly different):

@recipe.instance_variables
#=> [:@attributes, <============ this one is of particular interest
#     :@aggregation_cache,
#     :@association_cache,
#     :@readonly,
#     :@destroyed,
#     :@marked_for_destruction,
#     :@destroyed_by_association,
#     :@new_record,
#     :@txn,
#     :@_start_transaction_state,
#     :@transaction_state
#   ]

So you see, that it defines one instance variable @attributes, that holds all attributes.

Upvotes: 2

Related Questions