Rails:如何通过适当的回滚(一种手动嵌套属性)一起更新多个模型

Rails: How to update multiple models together, with proper rollback (kind of manual nested attributes)

我(出于各种原因)决定不使用 nested_attributes。这是我当前的控制器:

def update

    # Update snippet
    @snippet.update(snippet_params)

    # Update hotspot
    @snippet.hotspot.update(hotspot_params)

    # Update text
    @snippet.text.update(medium_params_with(:text))

    # Update audio
    if params[:audio] {
      @snippet.audio.destroy
      @snippet.media << Audio.new(medium_params_with(:audio))
    }

    respond_to do |format|
      if success = true #fix this up
        format.html { redirect_to @project, notice: 'Snippet was successfully updated.' }
        format.json { render :show, status: :ok, location: @snippet }
      else
        format.html { redirect_to @project, warning: 'Highlight was not updated.' }
        format.json { render json: @snippet.errors, status: :unprocessable_entity }
      end
    end
end

如果没有问题,这或多或少是可以的。

如何将其包装成如下内容:

try {
  update everything
} else {
  undo any changes I made while trying to update everything
}

if success {
  etc
} else {
  etc
}

如果您要更改的是使用 SQL 数据库的 ActiveRecord 模型,那么 http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html 可能会提供您正在寻找的内容。

根据@Jonah 的回答,我将数据库更改包装在 ActiveRecord::Base.transaction:

def update

  success = ActiveRecord::Base.transaction do

    # Update snippet
    @snippet.update(snippet_params)

    # Update text
    @snippet.text.update(medium_params_with(:text))

    # Update audio
    if params[:audio]
      @snippet.audio.destroy
      @snippet.media << Audio.new(medium_params_with(:audio))
    end
  end

  respond_to do |format|
    if success
      format.html { redirect_to @project, notice: 'Snippet was successfully updated.' }
      format.json { render :show, status: :ok, location: @snippet }
    else
      format.html { redirect_to @project, warning: 'Highlight was not updated.' }
      format.json { render json: @snippet.errors, status: :unprocessable_entity }
    end
  end
end