如何在Rails中回滚所有最近的事务

问题描述 投票:1回答:2

我正在编写我的第一个Ruby on Rails应用程序,但是在管理整个记录关联方面遇到了麻烦。特别是在这个问题上,我想根据以下代码向社区征询有关如何将最近保存的内容回滚到数据库的建议。

def create
    @aula = Aula.create!(:name => aula_params[:name], :block_duration => aula_params[:block_duration], :rest_time => aula_params[:rest_time], :user_id => @current_user.id)

    if @aula.valid?
      JSON.parse(aula_params[:blocks]).each do |id, b|
        @block = @aula.blocks.create!(:name => b["name"], :sequence_number => id)

        if @block.valid?
          b["workouts"].each do |id, w|
            @block.block_workouts.create!(:workout_id => w["id"], :duration => w["duration"], :sequence_number => id, :repetitions_number => w["repetitions_number"])
          end
        else
          render :json => { message: "Não foi possível criar essa aula", status: 500 }
        end
      end

      render :json => { message: "Aula criada com sucesso", status: 200 }
    else
      render :json => { message: "Não foi possível criar essa aula", status: 500 }
    end
  end

这段代码基本上创建了一个“光环”,它由多个“块”组成,而这些“块”又由多个“锻炼”组成。

但是问题是:假设特定锻炼的创建失败。在这种情况下,应删除刚刚创建的“ aula”(以及块及其相关的锻炼)。但是我找不到一种简洁,优雅的方式来做到这一点。

sql ruby-on-rails
2个回答
1
投票

这称为事务,如果一件事创建失败,则所有记录将回滚https://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html

事务是仅SQL语句的保护块如果它们都可以作为一个原子动作成功,则为永久。

因此,您需要将代码包装到Rails事务中,如下所示:

Aula.transaction do
  @aula = Aula.create!(...)

end

记住在失败的情况下使用带有感叹号的create!会引发错误


0
投票

首先,当您在该块中创建多个类的对象时,我建议在ActiveRecord::Base.transaction上使用Aula.transaction而不是特定于该单个类。

在以下代码段中,根据您的关联,仅使用一行aula = @current_user...行。

def create
  ActiveRecord::Base.transaction do
    # Use only any one of below lines
    aula = @current_user.aulas.create!(aula_params) # if user has_many aulas
    aula = @current_user.create_aula!(aula_params) # if user has_one Paula

    JSON.parse(params[:aula][:blocks]).each do |id, b|
      block = aula.blocks.create!(name: b['name'], sequence_number: id)

      block.save!
      b['workouts'].each do |s_id, w|
        block.block_workouts.create!(workout_id: w['id'],
                                     duration: w['duration'],
                                     sequence_number: s_id,
                                     repetitions_number: w['repetitions_number'])
      end
    end

    render json: { message: 'Aula criada com sucesso', status: 200 }
  end
rescue ActiveRecord::RecordInvalid
  render json: { message: 'Não foi possível criar essa aula', status: 500 }
end

def aula_params
  params.require(:aula).permit(:name, :block_duration, :rest_time)
end

我认为这应该可以解决问题。

© www.soinside.com 2019 - 2024. All rights reserved.