【问题标题】:Ruby Metaprogramming ActiveRecordRuby 元编程 ActiveRecord
【发布时间】:2013-08-03 13:10:12
【问题描述】:

假设我有两个相似的模型。一个称为 Primer3Template,它包含 Primer3Parameter 上的字段子集。

我想只放置 Primer3Parameter 中存在的 Primer3Template 中的字段,以及大写字段名称并添加一些字符串插值。我的代码部分工作,如下所示:

> t = Primer3Template.new
> @primer3_parameter = Primer3Parameter.where(:batch_detail_id => 7146)
> t.attributes.each  do | name, value |
>     puts "#{name.upcase}="
>   end

到目前为止一切顺利,这个输出:

ID=
TYPE=
USER_ID=
BATCH_DETAIL_ID=
GENERATED=
STATUS=
P3_FILE_TYPE=
....etc

接下来我尝试从@primer3_parameter 变量中输出字段的值,该变量与循环处理的当前名称具有相同的名称。我试过这个:

> t.attributes.each  do | name, value |
>     puts "#{name.upcase}=#{@primer3_parameter.name}"
>   end

但是这是输出类名,这不是我想要的:

ID=Primer3Parameter
TYPE=Primer3Parameter
USER_ID=Primer3Parameter
BATCH_DETAIL_ID=Primer3Parameter
GENERATED=Primer3Parameter

我希望它跳过一些字段,并打印字段的值,如下所示:

BATCH_DETAIL_ID=7146
GENERATED=true
STATUS=active
P3_FILE_TYPE=Type2

我也试过这个:

>  t.attributes.each  do | name, value |
> x = "@primer3_parameters.first.#{name}"
> puts "#{name.upcase}=#{x}"
> end

这给了我:

ID=@primer3_parameters.first.id
TYPE=@primer3_parameters.first.type
USER_ID=@primer3_parameters.first.user_id
BATCH_DETAIL_ID=@primer3_parameters.first.batch_detail_id
GENERATED=@primer3_parameters.first.generated

【问题讨论】:

    标签: ruby-on-rails ruby metaprogramming


    【解决方案1】:

    这个:

    @primer3_parameters = Primer3Parameter.where(:batch_detail_id => 7146)
    

    返回一个集合关联。如果要遍历 Primer3Parameter 关联记录,则必须遍历它们。像这样:

    @primer3_parameters.each do |primer3_parameter|
      primer3_parameter.attributes.each do |name, value|
      .....
    

    剩下的就是你以前的做法。

    【讨论】:

    • 嗨@ChuckE,感谢您的回答。我想遍历 t 变量(Primer3Template)并使用名称来检索 Primer3Parameter 上相同字段的值。我在想 instance_variable_get 会这样做,但我不能完全正确地理解语法。
    • 但是你的 @primer3_parameter 变量不是 Primer3Parameter 实例,它是许多的集合。
    【解决方案2】:

    不要为此使用 eval。你可能会受伤!

    这是一个不错的选择

    attribute_names = Primer3Template.accessible_attributes
    @primer3_parameter = Primer3Parameter.where(:batch_detail_id => 7146)
    attribute_names.each do |attr_name|
      puts "#{attr_name.upcase}=#{@primer3_parameter.read_attribute(attr_name)}"
    end
    

    我认为您可以使用@primer3_parameter[attr_name] 而不是@primer3_parameter.read_attribute(attr_name),但我不确定是否有任何缺点

    【讨论】:

      【解决方案3】:

      知道了!!!

      > t = Primer3Template.new
      > p = Primer3Parameter.where(:batch_detail_id => 7146).first
      > t.attributes.each do |name, value|
      >     x = eval("p.#{name}")
      >     puts "#{name.upcase}=#{x}"
      >   end
      

      输出

      ID=15
      TYPE=Primer3Parameter
      USER_ID=
      BATCH_DETAIL_ID=7146
      GENERATED=false
      STATUS=ready
      P3_FILE_TYPE=settings
      P3_FILE_ID=
      P3_FILE_FLAG=false
      P3_COMMENT=
      SEQUENCE_EXCLUDED_REGION=
      SEQUENCE_FORCE_LEFT_END=-1000000
      SEQUENCE_FORCE_LEFT_START=-1000000
      

      我有没有提到我 Ruby?我希望这对其他人有帮助。

      编辑 - 改进的解决方案

      • 不需要实例化模板类
      • 只返回我想要的可访问字段

      .

       Primer3Template.accessible_attributes.each do |name|
            x = eval("p.#{name}")
            puts "#{name.upcase}=#{x}"
       end
      

      【讨论】:

      • 也许您可以使用x = p.send(name) 来处理动态调度,而不是使用eval
      • ` Primer3Template.accessible_attributes.each do |name| x = p.send(name) puts "#{name.upcase}=#{x}" end`Object#send
      • 诀窍并不是真正回答您的问题,只是一种避免eval 功能的方法。如果改进有用,我的目标就达到了;)
      • 即使Primer3Parameter 中没有相应的可访问属性,您是否希望打印出来自Primer3Template 的所有可访问属性名称?
      • @Peter Alfvin 是的,这正是我想要的。 Primer3Parameter 是 Primer3Template 的超集(两个模型都通过 STI 映射到同一个物理表)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-09-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-18
      • 2015-06-03
      • 1970-01-01
      相关资源
      最近更新 更多