Ruby on rails 如何设置;动态地;可变值?

Ruby on rails 如何设置;动态地;可变值?,ruby-on-rails,ruby,ruby-on-rails-3,variables,metaprogramming,Ruby On Rails,Ruby,Ruby On Rails 3,Variables,Metaprogramming,我正在使用RubyonRails3.0.9,并试图“动态”设置一些变量值。那就是 。。。在我的模型文件中,我有: attr_accessor :variable1, :variable2, :variable3 # The 'attributes' argument contains one or more symbols which name is equal to # one or more of the 'attr_accessor' symbols. def set_variab

我正在使用RubyonRails3.0.9,并试图“动态”设置一些变量值。那就是

。。。在我的模型文件中,我有:

attr_accessor :variable1, :variable2, :variable3


# The 'attributes' argument contains one or more symbols which name is equal to 
# one or more of the 'attr_accessor' symbols.

def set_variables(*attributes)

  # Here I should set to 'true' all ":variable<N>" attributes passed as symbol
  # in the 'attributes' array, but variable names should be interpolated in a 
  # string.
  # 
  # For example, I should set something like "prefix_#{':variable1'.to_s}_suffix".

end
属性访问器:variable1,:variable2,:variable3 #“attributes”参数包含一个或多个名称等于的符号 #一个或多个“属性访问器”符号。 def集合_变量(*属性) #在这里,我应该设置为'true'all:“variable”属性作为符号传递 #在“attributes”数组中,但变量名应插入 #绳子。 # #例如,我应该将“prefix#{”:variable1.设置为_s}_后缀。 结束 如何将这些变量值设置为
true



我尝试使用
self.send(…)
方法,但没有成功(但是,可能我根本不知道如何使用
send
方法…是否可以通过使用
send
方法来实现我所需的目的?!)。

您要使用的方法是
实例变量集

def set_variables(*attributes)
  attributes.each {|attribute| self.instance_variable_set(attribute, true)}
end

请记住,在Ruby中,setter方法名称以
=
结尾

以下是
send
instance\u variable\u set
的基准比较:

require 'benchmark'

class Test
  VAR_NAME = '@foo'
  ATTR_NAME = :foo

  attr_accessor ATTR_NAME

  def set_by_send i
    send("#{ATTR_NAME}=", i)
  end

  def set_by_instance_variable_set i
    instance_variable_set(VAR_NAME, i)
  end
end

test = Test.new

Benchmark.bm do |x|
  x.report('send                 ') do
    1_000_000.times do |i|
      test.set_by_send i
    end
  end
  x.report('instance_variable_set') do
    1_000_000.times do |i|
      test.set_by_instance_variable_set i
    end
  end
end
时间安排如下:

      user     system      total        real
send                   1.000000   0.020000   1.020000 (  1.025247)
instance_variable_set  0.370000   0.000000   0.370000 (  0.377150)
(使用1.9.2测量)

应该注意的是,只有在某些情况下(如本例,使用
attr\u accessor
定义了访问器),才是
send
instance\u variable\u set
功能等效的。如果所涉及的访问器中有一些逻辑,则会有差异,并且您必须决定需要这两个变量中的哪一个
instance\u variable\u set
只设置ivar,而
send
实际执行访问器方法,不管它做什么


另一句话-这两种方法在另一方面表现不同:如果你
实例变量集
一个还不存在的ivar,它将被创建。如果您使用
send
调用不存在的访问器,则会引发异常。

我知道问题是针对Rails 3的,但在搜索Rails 4关于“如何动态访问变量值”的答案时,出现了这个问题。我在我的模型上对此进行了测试,它非常适合作为建议解决方案的替代方案:

def set_variables(*attributes)
  attributes.each {|attribute| self["#{attribute}"] = true}
end

我认为
send
是这里更好的选择。为什么?这里的字符串插值非常难看。也应该慢一些,因为您有额外的方法调用。我认为不会再慢了。而
instance\u variable\u set
与对象的内部结构太过混乱,而
send
通过接口工作<代码>实例变量集
是危险的,很少是个好主意。我想得越多,就越觉得这应该被否决,因为它弄乱了内部结构。@MladenJablanović重新阅读了你最初的评论。存在“附加方法调用”的想法是不正确的——以我的方式执行的每个
send
调用都对应于一个
实例变量集
调用。您正在比较苹果和橙子。正如我在另一篇评论中所解释的,属性名没有前导
@
,因此您需要将
send(“{ATTR\u NAME}=”,I)
实例变量集(“@{ATTR\u NAME}”,I)
进行比较,以复制OP的实际用例。那些数字看起来怎么样?我没有忘记。现在,我的问题的答案是什么?你对Skworks的答案的第一个评论是你认为
send
是更好的选择,然后否决了“搞乱内部结构”。看在上帝的份上,它是一个实例方法,它的工作是“搞乱内部”,即改变对象的内部状态。这两种方法都能起到作用,它们改变了IVAR,所以选择其中一种是可以的,但否决票是不行的。因此,请还原否决票,然后我们可以继续。您对实例方法的工作提出了一个很好的观点,即处理内部问题。然而,我认为你们把这次讨论作为我改变投票的人质是应该受到谴责的。如果我有充分的理由相信我会改变我的投票;我不会仅仅为了继续讨论而改变它。这将损害投票系统的完整性。没有必要争论不投反对票。你需要为否决投票提供可信的理由。OP的问题非常广泛,可以提供不止一种可能的解决方案。我们可以争论哪一个更好或更适合特定的需要。但给出的答案没有一个既没有错误也没有误导。
      user     system      total        real
send                   1.000000   0.020000   1.020000 (  1.025247)
instance_variable_set  0.370000   0.000000   0.370000 (  0.377150)
def set_variables(*attributes)
  attributes.each {|attribute| self["#{attribute}"] = true}
end