Ruby on rails 尝试在rails中添加具有重复索引的条目时避免异常

Ruby on rails 尝试在rails中添加具有重复索引的条目时避免异常,ruby-on-rails,Ruby On Rails,我有3种型号: 使用者 谜题 解决方案 解决方案表示用户第一次解决给定的难题。我只想记录第一次的时间-后续尝试不算数。该解决方案有一个关于用户拼图组合的索引 我的迁移如下所示: class CreateSolutions < ActiveRecord::Migration[6.0] def change create_table :solutions do |t| t.integer :time t.integer :attempts t

我有3种型号:

  • 使用者
  • 谜题
  • 解决方案
解决方案表示用户第一次解决给定的难题。我只想记录第一次的时间-后续尝试不算数。该解决方案有一个关于用户拼图组合的索引

我的迁移如下所示:

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
问题是,第二次尝试保存拼图时,我遇到了一个异常:

目标:我希望它只是默默地忽略后续的保存,而不是抛出异常

以下是我在solutions_controller.rb中尝试过的内容:

  • if@solution.save(验证:false).
  • if@solution.save(:validate=>false).
  • if@solution.save(false).

理想情况下,我只想跳过重复索引的验证-我想捕获其他错误。

在解决方案模型中,您可以添加

验证以下内容的唯一性:用户id,范围::谜题id
每次尝试保存解决方案记录时,它都会运行select查询。如果存在select query solution.save的记录,则会出现错误

或者您可以使用first\u或\u初始化

Solution.where(user\u id:current\u user.id,puzzle\u id:params[:puzzle][:id])。首先\u或\u初始化(Solution\u params)
这将检查给定查询的记录是否存在。如果该记录不存在,它将在where条件和解决方案参数中分配属性

更新
def创建
@解决方案=解决方案。其中(用户\u id:current\u user.id,拼图\u id:params[:拼图][:id])。首先\u或\u初始化(解决方案\u参数)
回应待办事项|格式|
如果@solution.save
format.json{render:show,status::created}
其他的
format.json{render json:@solution.errors,status::unprocessable_entity}
结束
结束
结束

如果这样做,则无需检查错误消息,如果表中已存在该记录,则会将其分配给@solution,而不会分配solution params中的数据。如果记录不存在@solution将被分配where条件和解决方案参数中的数据(用户id和谜题id值将取自where条件中给出的值,其他值取自解决方案参数)。如果在where条件和解决方案参数中给出属性数据,则将采用解决方案参数值。

在解决方案模型中,您可以添加

验证以下内容的唯一性:用户id,范围::谜题id
每次尝试保存解决方案记录时,它都会运行select查询。如果存在select query solution.save的记录,则会出现错误

或者您可以使用first\u或\u初始化

Solution.where(user\u id:current\u user.id,puzzle\u id:params[:puzzle][:id])。首先\u或\u初始化(Solution\u params)
这将检查给定查询的记录是否存在。如果该记录不存在,它将在where条件和解决方案参数中分配属性

更新
def创建
@解决方案=解决方案。其中(用户\u id:current\u user.id,拼图\u id:params[:拼图][:id])。首先\u或\u初始化(解决方案\u参数)
回应待办事项|格式|
如果@solution.save
format.json{render:show,status::created}
其他的
format.json{render json:@solution.errors,status::unprocessable_entity}
结束
结束
结束

如果这样做,则无需检查错误消息,如果表中已存在该记录,则会将其分配给@solution,而不会分配solution params中的数据。如果记录不存在@solution将被分配where条件和解决方案参数中的数据(用户id和谜题id值将取自where条件中给出的值,其他值取自解决方案参数)。如果在where条件和解决方案参数中给出了属性数据,则将采用解决方案参数值。

谢谢-第一个
验证唯一性
方法似乎捕捉到错误,但它可以工作。我可以检查
@solution.errors.messages[:user\u id]
是否为“已采取”并仅忽略该情况。第二种方法也有效,但我对此感到困惑。只有当我仍然在控制器中使用
@solution=solution.new(solution_params)
等初始化模型时,它才起作用。但我看不出我在哪里实际使用了我初始化的
@解决方案。我的if块现在看起来是这样的:
if Solution.where(user\u id:current\u user.id,puzzle\u id:@Solution.puzzle.id)。首先\u或\u初始化(Solution\u params).
-我不再调用
@Solution.save
。我已经更新了答案,请查看。如果记录已经存在,我相信您不想更新它。我现在明白了-再次感谢。与您的示例不同的唯一一件事是指定
puzzle\u id:params[:puzzle]
,而不是
params[:puzzle][:id]
params
只是POST参数,所以它们是简单的名称/值对。除非有一种方法可以让拼图对象得到扩展,而我却忽略了这种方法?我的错误被弄糊涂了,理想情况下,它应该作为puzzle\u id发送到解决方案对象中。因为它被命名为puzzle,我认为它可能是来自params的puzzle对象。谢谢-第一个
验证了
方法的唯一性似乎捕捉到了错误,但它可以工作。我可以检查
@solution.errors.messages[:user\u id]
是否为“已采取”并仅忽略该情况。第二种方法也有效,但我对此感到困惑。只有当我仍然在控制器中使用
@solution=solution.new(solution_params)
等初始化模型时,它才起作用。但我看不出我在哪里实际使用了我初始化的
@解决方案。我的if块现在看起来像这样:
if解决方案。其中(user\u id:current\u user.id,puzzle\u id:@solu
  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'