我正在编写我的第一个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”(以及块及其相关的锻炼)。但是我找不到一种简洁,优雅的方式来做到这一点。
这称为事务,如果一件事创建失败,则所有记录将回滚https://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html
事务是仅SQL语句的保护块如果它们都可以作为一个原子动作成功,则为永久。
因此,您需要将代码包装到Rails事务中,如下所示:
Aula.transaction do
@aula = Aula.create!(...)
end
记住在失败的情况下使用带有感叹号的create!
会引发错误
首先,当您在该块中创建多个类的对象时,我建议在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
我认为这应该可以解决问题。