Rails在控制器操作中自动保存关联

时间:2010-03-10 06:05:04

标签: ruby-on-rails ruby activerecord

我有以下一对多关联。文档有很多章节,章节有很多项目。

class Document < ActiveRecord::Base
  has_many :document_sections, :dependent => :destroy, :autosave => true
  has_many :document_items, :through => :document_sections
end

class DocumentSection < ActiveRecord::Base
  belongs_to :document
  has_many :document_items, :dependent => :destroy, :autosave => true
end

class DocumentItem < ActiveRecord::Base
  belongs_to :document_section
end

这是params hash:

-
Parameters: {"commit"=>"Submit Document", "authenticity_token"=>"4nx2B0pJkvavDmkEQ305ABHy+h5R4bZTrmHUv1setnc=", "id"=>"10184", "document"=>{"section"=>{"10254"=>{"seqnum"=>"3", "item"=>{"10259"=>{"comments"=>"tada"}}}}, "comment"=>"blah"}}

我有以下更新方法......

# PUT /documents/1                                                                                                                                                 
# PUT /documents/1.xml




def update
    @document = Document.find(params[:id])

    # This is header comment
    @document.comment = params[:document][:comment]

    params[:document][:section].each do |k,v|
       document_section =  @document.document_sections.find_by_id(k)
       if document_section

          v[:item].each do |key, value|
             document_item = document_section.feedback_items.find_by_id(key)
             if document_item

                # This is item comments
                document_item.comments = value[:comments]
             end
          end

       end
     end

    @document.save

  end

当我保存文档时,它只更新文档标题注释。它不保存document_item注释。自动保存选项也不应该更新关联。

在日志中只注册了以下DML:

UPDATE documents SET updated_at = TO_DATE('2010-03-09 08:35:59','YYYY-MM-DD HH24:MI:SS'), comment = 'blah' WHERE id = 10184

如何通过保存文档来保存关联。

1 个答案:

答案 0 :(得分:2)

我想我知道问题是什么。我很确定你不能执行以下操作:

# Triggers a database call
document_section =  @document.document_sections.find_by_id(k)

并期望ActiveRecord保持自动保存的关联。相反,您应该单独保存加载的记录。这当然不是原子的。

我相信自动保存就像你在想的那样工作,你想做这样的事情:

# untested...
@document.document_sections.collect { |s| s.id == k }.foo = "bar"

请注意,我实际上是在数组中修改伪参数foo,而不是调用find_by_id,它将重新查询数据库并返回一个新对象。

您拥有的第三个选项是,您当然可以执行您最初计划的操作,但可以自己处理所有事务,或使用嵌套事务等来获取atmoic save。如果您的数据太大而无法使用数组操作,那么这是必要的,因为自动保存可以触发所有相关数据加载到内存中。

这一切都取决于你的申请。


对基本问题的一些澄清:

如果您运行find_by_id方法,则要求ActiveRecord返回一组与该查询匹配的新对象。您从实例(document_sections)执行该方法的事实实际上只是另一种说法:

DocumentSection.find_by_id(k)

从一个对象实例调用它我认为只是一些语法上的好处,rails正在添加东西,但在我看来它没有多大意义;我认为它在某些应用程序中可能很方便,我不确定。

另一方面,collect是一个Ruby Array方法,它提供了一种使用块“切片”数组的方法。基本上是一个花哨的foreach循环。 :)通过直接与document_sections数组交互,您将更改已加载到包含对象(@document)中的相同对象,然后在save使用特殊autosave时提交该对象国旗集。

HTH!很高兴你回来了。 :)