Ruby-on-rails 如何从字符串转换为对象属性名称?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/903763/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to convert from a string to object attribute name?
提问by Vicer
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_arrayturned into attribute names. The names "student_identification", "email", etc. are actual column names of my Studenttable. In the real scenario, column_arraywill be set by the user (by ticking check boxes). And new_arraywill be replaced by csv, as I want the data go into a csv file.
我正在尝试将字符串值转换为属于对象的属性的名称。例如,在下面的代码中,我需要将所有字符串值column_array转换为属性名称。名称"student_identification"、"email"等是我的Student表的实际列名。在实际场景中,column_array将由用户设置(通过勾选复选框)。并且new_array将被替换为csv, 因为我希望数据进入一个 csv 文件。
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.
我想"#{column_array[i]}"变成属性名称,以便我可以访问数据。
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
回答by rampion
Let's say column_array[i] = "foo", for an example.
比如说column_array[i] = "foo",举个例子。
If you want to call the methodr.foo, use Object#send:
如果要调用该方法r.foo,请使用Object#send:
r.send(column_array[i], arg1, arg2, arg3, ...)
If you want to access r's instance variable @foo, use Object#instance_variable_getand Object#instance_variable_set:
如果要访问r的实例变量@foo,请使用Object#instance_variable_get和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 ActiveRecordmagic going on with your models (and I'm guessing Studentis a subclass of ActiveRecord::Base) you probably want to use the former, since ActiveRecordcreates methods to access the database, and the values stored in instance variables may not be what you want or expect.
由于这是 rails,并且ActiveRecord您的模型(我猜Student是 的子类ActiveRecord::Base)有很多魔法,您可能想要使用前者,因为ActiveRecord创建了访问数据库的方法,以及存储在实例中的值变量可能不是您想要或期望的。
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.
所以你可以看到如何#send(field)访问记录信息,而尝试访问属性则不然。此外,我们可以使用#send(field+'=')更改记录信息。
回答by bmalets
Look at instance_eval method ...
看看 instance_eval 方法...
if you have 'attribute' and need do
如果你有“属性”并且需要做
object.attribute = 'ololo'
you can do:
你可以做:
object.instance_eval('attribute') = 'ololo'

