在Rails中,update_attributes的反转是什么?

时间:2014-01-28 15:58:50

标签: ruby-on-rails ruby activerecord

在Rails中,update_attributes!的反转是什么?

换句话说,是什么将记录映射到将重新创建该记录及其所有子记录的属性哈希?

答案不是ActiveRecord.attributes,因为它不会递归到子对象中。

澄清您是否有以下内容:

class Foo < ActiveRecord::Base
  has_many :bars
  accepts_nested_attributes_for :bars
end

然后你可以传递像

这样的哈希值

{"name" => "a foo", "bars_attributes" => [{"name" => "a bar} ...]}

update_attributes。但目前尚不清楚如何以编程方式为此目的轻松生成此类哈希。

编辑:
正如我在评论中提到的,我可以做类似的事情:
foo.as_json(:include => :bars)

但我想要一个使用accepts_nested_attributes_for :bars声明的解决方案,以避免必须明确包含关联。

2 个答案:

答案 0 :(得分:1)

不确定那是怎样的“反向”,但是当Rails可能没有“看到答案”时,没有什么可以阻止你遍历一个对象并有效地创建它。

让你入门的东西:

http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html#method-i-accepts_nested_attributes_for

您会注意到accepts_nested_attributes_for方法中,rails会在nested_attributes_options中为嵌套的所有模型设置哈希值。因此,我们可以使用它来获取这些嵌套关联,以填充此新哈希。

def to_nested_hash
  nested_hash = self.attributes.delete_if {|key, value| [:id, :created_at, :deleted_at].include? key.to_sym } # And any other attributes you don't want

  associations = self.nested_attributes_options.keys
  associations.each do |association|
    key = "#{association}_attributes"
    nested_hash[key] = []
    self.send(association).find_each do |child|
      nested_hash[key] << child.attributes.delete_if {|key, value| [:id, :created_at, :deleted_at].include? key.to_sym }
    end
  end

  return nested_hash
end

或者只是想到了这个:

使用上面的示例:

foo.as_json(:include => foo.nested_attributes_options.keys)

有一点需要注意,这不会给我bars_attributes我的第一个建议。 (serializable_hash

都不会

答案 1 :(得分:0)

您可以使用以下方法在哈希

中包含嵌套选项
class Foo < ActiveRecord::Base
  has_many :bars
  accepts_nested_attributes_for :bars

  def to_nested_hash(options = nil)
    options ||= {}
    if options[:except]
      incl = self.nested_attributes_options.keys.map(&:to_s) - Array(options[:except]).map(&:to_s)
    else
      incl = self.nested_attributes_options.keys
    end
    options = { :include => incl }.merge(options)
    self.serializable_hash(options)
  end
end

如果在某些情况下你不想要酒吧,你可以传递选项

foo.to_nested_hash(:except => :bars)


修改:如果您在as_jsonto_jsonto_xml

中需要相同的行为,则可以使用其他选项
class Foo < ActiveRecord::Base
  has_many :bars
  accepts_nested_attributes_for :bars

  def serializable_hash(options = nil)
    options ||= {}
    if options[:except]
      incl = self.nested_attributes_options.keys.map(&:to_s) - Array(options[:except]).map(&:to_s)
    else
      incl = self.nested_attributes_options.keys
    end
    options = { :include => incl }.merge(options)
    super(options)
  end

  def to_nested_hash(options = nil)
    self.serializable_hash(options)
  end
end