Dynamic method access from an Object

Hi Everyone,
I have a requirement where the method name of an Object will be
generated and accessed dynamically in code. When I tried to access it
showed me "undefined method". Am attaching a sample code of what i want
to accomplish:

@user_information = UserInformation.new
@table_fields = UserInformation.find_by_sql("DESC user_informations")
for table_field in @table_fields
    temp = table_field.Field # considering Field is `user_name`
    @user_information.temp = "vasanth"
    # referring to @user_information.user_name = "vasanth"
end

In the above example i will get an error like "undefined method `temp`"

Can anyone tell me how to do this in Ruby on Rails? (I need something
equivalent to "eval()" function present in Java Script)

Thanks in Advance.
Regards,
VASANTH

Guo Yangguang-2 wrote:

Hi Everyone,
I have a requirement where the method name of an Object will be
generated and accessed dynamically in code. When I tried to access it
showed me "undefined method". Am attaching a sample code of what i want
to accomplish:

@user_information = UserInformation.new
@table_fields = UserInformation.find_by_sql("DESC user_informations")
for table_field in @table_fields
    temp = table_field.Field # considering Field is `user_name`
    @user_information.temp = "vasanth"
    # referring to @user_information.user_name = "vasanth"
end

In the above example i will get an error like "undefined method `temp`"

Can anyone tell me how to do this in Ruby on Rails? (I need something
equivalent to "eval()" function present in Java Script)

instance_variable_set is one method you should investigate for doing dynamic
setters. You can find it sort of undocumented here:
http://www.ruby-doc.org/core/classes/Object.src/M000381.html. But seriously,
Google turns up lots on this topic.

Your code would then read:

for table_field in @table_fields
    @user_information.instance_variable_set("@#{table_field}", "vasanth")
    # referring to @user_information.send("@#{table_field}") # => "vasanth"
end

Vasanthakumar Csk wrote:

I have a requirement where the method name of an Object will be
generated and accessed dynamically in code. When I tried to access it
showed me "undefined method". Am attaching a sample code of what i want
to accomplish:

As well as Steve's suggestion for this case, there is a general method
available in Ruby for sending messages to invoke methods where the
method name is in a string. The method #send does this:

http://www.ruby-doc.org/core/classes/Object.html#M000334

However:

@user_information = UserInformation.new
@table_fields = UserInformation.find_by_sql("DESC user_informations")

Try to avoid embedding SQL in your code if possible. You'll make it
more readable and more portable (especially if you decide to change your
database at some point). The above will return an array of column
properties which is not what you're after anyway. To get the column
names for a model, use:

@table_fields = UserInformation.column_names

for table_field in @table_fields
    temp = table_field.Field # considering Field is `user_name`
    @user_information.temp = "vasanth"
    # referring to @user_information.user_name = "vasanth"
end

If you are using a standard Rails model, then one of your columns will
be called "id" and the above will try to overwrite this (numerical)
value with a string. Not a good idea.

This code is also very model oriented but gives the impression you are
wanting to put this into a controller. Whenever you find yourself doing
model logic like this, re-think your strategy. This sort of stuff
should be in the model. So, if you really want the model to be able to
set all attributes (except "id"!) to a particular string, then in your
model:

def set_to_string new_string
  attributes.keys.each do | attr |
    self.send "#{attr}=", new_string
  end
end

This form means that any setters you've overridden for any reason will
be used and using #attributes to get the names automatically excludes
"id".

This is, of course, dangerous. It assumes that all your attributes are
string values (does the model have "created_at" and "updated_at"?) and
that if you ever add columns, you'll want them to get the same
treatment.

Thanks a lot Steve and Bush. All the informations that you gave was new
and very useful to me. Here is a bit more explanation of what i am
trying to do:

This code is also very model oriented but gives the impression you are
wanting to put this into a controller. Whenever you find yourself doing
model logic like this, re-think your strategy. This sort of stuff
should be in the model. So, if you really want the model to be able to
set all attributes (except "id"!) to a particular string, then in your
model:

I understand that my code is model oriented, so its in model only.
Anyway thanks again for your suggestion.

This is, of course, dangerous. It assumes that all your attributes are
string values (does the model have "created_at" and "updated_at"?) and
that if you ever add columns, you'll want them to get the same
treatment.

Sorry that i couldn't explain you the real scenario or give the actual
code for you to analyse. But the case is like this,
I have a "table A" with columns a1,a2,a3,a4 & a5.
Now, there will be a procedure (user action) which will change only
one/two column(s) in that "table A" eg: a3. The need of this is to
generate a report based on changed value. Also i should not over-write
the original value of a3 in "table A".

Instead, i want to modify that object dynamically at run-time for
further calculations. However, i dont know which column that user is
going to change (till run-time).

So i have to write IF condition for all 5 columns of "table A". But this
will get tedious because i have more than 20 tables with 40 columns
each. Hope you understood my problem. As you said, the user wont/cant
modify "id" or "created_at" or "updated_at" etc.

Hope you can help me in minimizing the code further, if any methods
available.

Thanks in Advance.
Regards,
VASANTH

Vasanthakumar Csk wrote:

Instead, i want to modify that object dynamically at run-time for
further calculations. However, i dont know which column that user is
going to change (till run-time).

In your model:

def set_values columns, values
  (0...columns.length).each do |i|
    self.send "#{columns[i]}=", values[i]
  end
end

Then call this on the object you want to change with two arrays, one the
set of columns the user wants to change and the other with the values.
If the values will always be the same, then this reduces to:

def set_values columns, new_value
  columns.each do | attr |
    seld.send "#{attr}=", new_value
  end
end

You should be able to fit any of these to your particular situation.

Hi Mark,
Thanks a lot for your help. Its working fine. Learnt few new things in
ROR because of you, thanks once again for that.

Regards,
Vasanth