我有三种型号:
- 用户
- 难题
- 解决方案
解决方案代表用户首次解决给定难题。我只想记录第一次的时间-以后的尝试不算在内。该解决方案有一个关于用户谜题组合的索引。
我的迁移看起来是这样的:
class CreateSolutions < ActiveRecord::Migration[6.0]
def change
create_table :solutions do |t|
t.integer :time
t.integer :attempts
t.references :user
t.references :puzzle
t.timestamps
end
add_index :solutions, [:user_id, :puzzle_id], unique: true
end
end
我使用的是MySQL。Puzzle和User模型都有:has_many :solutions
。
在solutions_controller.rb
中,我有:
def create
@solution = Solution.new(solution_params)
@solution.user = current_user
@solution.puzzle = Puzzle.find(params["puzzle"])
respond_to do |format|
if @solution.save
format.json { render :show, status: :created }
else
format.json { render json: @solution.errors, status: :unprocessable_entity }
end
end
end
问题是,当我第二次尝试保存谜题时,我得到了一个例外:
ActiveRecord::RecordNotUnique in SolutionsController#create Mysql2::Error: Duplicate entry '28-13' for key 'index_solutions_on_user_id_and_puzzle_id'
目标:我希望它只是默默地忽略后续保存,而不是抛出异常。
以下是我尝试过的所有解决方案_controller.rb:
if @solution.save(validate: false)...
if @solution.save(:validate => false)...
if @solution.save(false)...
理想情况下,我只想跳过重复索引的验证-我想捕捉其他错误。
在解决方案模型中,您可以添加
validates_uniqueness_of :user_id, scope: :puzzle_id
每次您尝试保存解决方案记录时,它都会运行一个选择查询。如果所选查询解决方案存在记录,则保存将出错。
或者您可以使用first_Or_initialize
Solution.where(user_id: current_user.id, puzzle_id: params[:puzzle][:id]).first_or_initialize(solution_params)
这将检查给定查询的记录是否存在。如果不存在,它将在where条件和solution_params中分配属性。
更新
def create
@solution = Solution.where(user_id: current_user.id, puzzle_id: params[:puzzle][:id]).first_or_initialize(solution_params)
respond_to do |format|
if @solution.save
format.json { render :show, status: :created }
else
format.json { render json: @solution.errors, status: :unprocessable_entity }
end
end
end
如果你这样做,就不需要检查错误消息,如果表中已经存在记录,它将被分配给@solution,而solution params中的数据将不会被分配。如果记录不存在,@solution将被分配where condition和solution_params中的数据(user_id和puzzle_id值将取自where condition中给定的值,其他值来自solution_params(。如果在where condition和solution_params中给出属性数据,则将取solution_params值。