21

I am trying to convert a string value into a name of an attribute that belongs to an object. For example, in the following code, I need all the string values in the column_array turned into attribute names. The names "student_identification", "email", etc. are actual column names of my Student table. In the real scenario, column_array will be set by the user (by ticking check boxes). And new_array will be replaced by csv, as I want the data go into a csv file.

At the moment I am really struggling at the following line:

   new_array << r."#{column_array[i]}"

I want "#{column_array[i]}" to be turned into the attribute name so I can access the data.

def exp_tst

  @records =  Student.find(:all, :conditions=> session[:selection_scope],
                                 :order => sort_order('laboratory_id'))

  column_array = ["student_identification", "laboratory_id", "email", "current_status"]

  new_array = Array.new()

  @records.each do |r|

    (0..(column_array.size-1)).each do |i|
       new_array << r."#{column_array[i]}"
    end
  end

end
1
  • (0..(column_array.size-1)).each can be replaced with column_array.each_index. Commented Jan 11, 2012 at 21:49

2 Answers 2

45

Let's say column_array[i] = "foo", for an example.

If you want to call the method r.foo, use Object#send:

 r.send(column_array[i], arg1, arg2, arg3, ...)

If you want to access r's instance variable @foo, use Object#instance_variable_get and Object#instance_variable_set:

 r.instance_variable_get('@'+column_array[i])
 r.instance_variable_set('@'+column_array[i], new_value)

In this case we have to prepend the given name with an @ sigil, since that is required at the start of all instance variable names.

Since this is rails, and there's a whole lot of ActiveRecord magic going on with your models (and I'm guessing Student is a subclass of ActiveRecord::Base) you probably want to use the former, since ActiveRecord creates methods to access the database, and the values stored in instance variables may not be what you want or expect.

I'll use an example from some test data I've got lying around:

% script/console
Loading development environment (Rails 2.3.2)
irb> Customer
#=> Customer(id: integer, date_subscribed: datetime, rental_plan_id: integer, name: string, address: string, phone_number: string, credit_limit: decimal, last_bill_end_date: datetime, balance: decimal)
irb> example_customer = Customer.find(:all)[0]
#=> #<Customer id: 6, date_subscribed: "2007-12-24 05:00:00", rental_plan_id: 3, name: "Evagation Governessy", address: "803 Asbestous St, Uneradicated Stannous MP 37441", phone_number: "(433) 462-3416", credit_limit: #<BigDecimal:191edc0,'0.732E3',4(12)>, last_bill_end_date: "2009-05-15 04:00:00", balance: #<BigDecimal:191e870,'0.743E3',4(12)>>
irb> example_customer.name
#=> "Evagation Governessy"
irb> field = 'name'
#=> "name"
irb> example_customer.instance_variable_get(field)
NameError: `name` is not allowed as an instance variable name
from (irb):8:in `instance_variable_get`
from (irb):8
irb> example_customer.instance_variable_get('@'+field)
#=> nil
irb> example_customer.send(field)
#=> "Evagation Governessy"
irb> example_customer.send(field+'=', "Evagation Governessy Jr.")
#=> "Evagation Governessy Jr."
irb> example_customer.send(field)
#=> "Evagation Governessy Jr."
irb> example_customer.name
#=> "Evagation Governessy Jr."

So you can see how #send(field) accesses the record information, and trying to access the attributes doesn't. Also, we can use #send(field+'=') to change record information.

Sign up to request clarification or add additional context in comments.

4 Comments

Hi, yes Student is subclass of 'ActiveRecord::Base' class Student < ActiveRecord::Base thanks for your prompt reply, but the above does not work. Here's the situation, I have model named 'Student' That Student table in my database has columns named "student_identification", "laboratory_id", "email", "current_status" etc.. So I want to access them. The above are not methods or instance variables as you have specified. They are just columns names of the Student table. I hope I am clear to you. Please excuse the terms I am using to explain my code as i am completely new to rails. :)
You access the contents of columns through accessor methods in ActiveRecord. There is no concept of "just columns names" in Ruby.
Hi, Just to take make problem a little more advanced.. let's say your 'example_customer' object has a method called 'get_details_of_membership('membership_type')'. Here the 'membership_type' can be 'platinum', 'yearly', 'monthly' etc.. But if I used this command: example_customer.send('get_details_of_membership('platinum')') ,it won't work. actually I want to store the string 'get_details_of_membership('platinum')' in a variable like: field = 'get_details_of_membership('platinum')' and then do: example_customer.send(field) Can someone show me a way to tackle this one?
When using send, if you want to pass arguments to the method you're invoking, pass them as later arguments to send. In this case do example_customer.send('get_details_of_membership', 'platinum'). If you want, you could prestore the arguments to send in an Array: field = ['get_details_of_membership', 'platinum'] and then call send using the splat operator: example_customer.send(*field). For more info see 'ri Object#send'
7

Look at instance_eval method ...

if you have 'attribute' and need do

 object.attribute = 'ololo'

you can do:

object.instance_eval('attribute') = 'ololo'

1 Comment

itteration through a model... and attr is a string <% Model.all.each do |el| %> #... <% if Model.has_attribute?(attr.to_sym) %> <%= el.instance_eval(attr) %> <% else %> #... <% end %> <% end %>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.