instance_variable_set(:@ attribute,{:brand.to_s =>“Apple”})覆盖所有属性而不是添加

时间:2010-12-08 04:07:37

标签: ruby-on-rails

...背景

我正在编写一个解析字符串并尝试确定它们可能包含哪些产品的解析器。我已经创建了自己的Token课程来帮助。

class Token < ActiveRecord::BaseWithoutTable

  attr_accessor :regex
  attr_accessor :values

end

令牌示例:

Token.new(:regex => /apple iphone 4/, :values => { :brand => "Apple", :product => "iPhone", :version => 4})

(其中散列键都对应于products表中的数据库列。)

问题出在以下问题:在我的Parser中,当找到Token时,我会尝试将相关值添加到Product实例,如下所示:

token.values.each do |v|
   attrib, value = v[0], v[1]
   my_product.instance_variable_set(:@attributes, { attrib.to_s => value })
end

这样做除了看起来好像我必须同时设置所有属性。如果我分阶段进行(即:当我发现新标记时),它会用nil覆盖任何未指定的属性。我错过了什么吗?有更好的方法吗?

2 个答案:

答案 0 :(得分:1)

修改现有值(如果存在)而不是覆盖它:

if attr = my_product.instance_variable_get :@attributes
  attr[attrib.to_s] = value
else
  my_product.instance_variable_get :@attributes, { attrib.to_s => value }
end

instance_variable_set的使用似乎很粗略;为什么你没有Product本身的访问者?

class Product
  def attributes
    @attributes ||= {}
  end
end

...

token.values.each do |attr,v|
   my_product.attributes.merge!( attr.to_s => v )
end

答案 1 :(得分:0)

如果my_productactive_record个对象,则可以使用write_attribute代替instance_variable_set。请注意,这只会写属性,即数据库列:

token.values.each do |v|
   attrib, value = v[0], v[1]
   my_product.write_attribute attrib.to_s, value # attrib.to_sym would work too
end

此外,如果token.values返回Hash,则可以迭代:

token.values.each do |k, v|
   my_product.write_attribute k, v
end