轨。使用在更新对象时失败的范围调试唯一性验证

时间:2018-03-29 03:56:41

标签: ruby-on-rails validation activerecord controller

我有一个模型Prediction,其实例通过属性Participant Match引用其他模型:participant_id:match_id

这个想法是@participant每个@match只能有一个@prediction(每个@participant允许每个@match最多一个预测)。

所以我在预测模型中包含了以下验证

validates :match_id, uniqueness: { scope: [:participant_id] }

当相同的@match和@participant已经是@prediciton时,验证可以禁止创建@prediction对象。问题在于,即使我没有改变原始对象的那些指定ID,它也会阻止更新对象。另外,它让我只更新一个预测实例,所有其他实例都是错误的。

令人费解的是,它工作正常,但由于某种原因,我一直无法跟踪,它停止工作,我已经没有关于如何调试的想法。你能提供任何想法吗?低于我检查/尝试的内容:

请求失败的相关参数:

"prediction"=><ActionController::Parameters {"participant_id"=>"1", "match_id"=>"2", "local_score"=>"2", "visitant_score"=>"0"}

我得到的错误:

 @details={:match_id=>[{:error=>:taken, :value=>2}]},
 @messages={:match_id=>["has already been taken"]}>

数据库中有match_id: 2的大量预测。但是,尽管数据库中没有match_id: 2participant_id: 1的其他@prediction,但这种情况正在发生,当然,除了在更新时抛出此错误的实例。

有趣的是,如果我在控制台中尝试相同的操作(如下所示),它会成功更新。

@prediction = Prediction.find_by(participant_id: 1, match_id: 2)
@prediction.update_attributes(local_score: 8, visitant_score: 8)

建议问题出在控制器操作中:

应用程序/控制器/ predicitons_controller.rb

  def update
    respond_to do |format|
      if @prediction.update(prediction_params)
        format.json { render :show, status: :ok, location: @prediction }
        format.js
      else
        @errorMessages = []
        @prediction.errors.full_messages.each do |message|
            @errorMessages << message
        end
        format.js {render template: 'predictions/update_error'}
      end
    end
  end

我认为那里没有问题。此外,似乎发送到成功更新的控制器的唯一请求是:

 "prediction"=><ActionController::Parameters {"participant_id"=>"1", "match_id"=>"1", "local_score"=>"1", "visitant_score"=>"1"}

如果我做其他人,例如,它没有:

"prediction"=><ActionController::Parameters {"participant_id"=>"2", "match_id"=>"1", "local_score"=>"0", "visitant_score"=>"0"}

"prediction"=><ActionController::Parameters {"participant_id"=>"2", "match_id"=>"2", "local_score"=>"9", "visitant_score"=>"9"}

"prediction"=><ActionController::Parameters {"participant_id"=>"4", "match_id"=>"1", "local_score"=>"1", "visitant_score"=>"1"

所有这些失败的请求都会抛出&#34; match_id已经采取&#34;错误并在控制台中更新。

控制器请求正在使用以下方法触摸正确的操作:put。我试图改变pool_id的验证切换match_id的语法(这当然不应该有所作为),但没有成功。

任何,帮助将不胜感激。

应用程序/模型/ prediction.rb

class MatchPrediction < ApplicationRecord
  belongs_to :participant
  belongs_to :match
  validates :match_id, uniqueness: { scope: [:pool_participant_id] }
  def correct_score?
    if match.official_outcome
      local_score == match.local_score && visitant_score == match.visitant_score ? true : false
    end
  end
  def correct_outcome?
    if match.official_outcome
      predicted_outcome == match.official_outcome ? true : false
    end
  end
end

和服务器输出预回滚:

Started PUT "/pools/1/predictions/19" for 127.0.0.1 at 2018-03-29 18:17:11 +1100
Processing by PredictionsController#update as JS
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"SagJX+a7m0eCAdH7AdA0eYz6BVL1cesXYXOUkoe2FRynta6wyiWdskrC1007V1vyrIApPtdEQnVHWlzhSeJs5Q==", "prediction"=>{"participant_id"=>"4", "match_id"=>"2", "local_score"=>"7", "visitant_score"=>"0"}, "pool_id"=>"1", "id"=>"19"}
  User Load (1.4ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 4], ["LIMIT", 1]]
  ↳ /Users/andres/.rvm/gems/ruby-2.5.0@global/gems/rack-2.0.4/lib/rack/tempfile_reaper.rb:15
  Prediction Load (0.4ms)  SELECT  "predictions".* FROM "predictions" WHERE "predictions"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
  ↳ app/controllers/predictions_controller.rb:86
   (0.2ms)  BEGIN
  ↳ app/controllers/predictions_controller.rb:55
  Participant Load (0.2ms)  SELECT  "participants".* FROM "participants" WHERE "participants"."id" = $1 LIMIT $2  [["id", 4], ["LIMIT", 1]]
  ↳ app/controllers/predictions_controller.rb:55
  Match Load (0.3ms)  SELECT  "matches".* FROM "matches" WHERE "matches"."id" = $1 LIMIT $2  [["id", 2], ["LIMIT", 1]]
  ↳ app/controllers/predictions_controller.rb:55
  Prediction Exists (1.8ms)  SELECT  1 AS one FROM "predictions" WHERE "predictions"."match_id" = $1 AND "predictions"."id" != $2 AND "predictions"."participant_id" = $3 LIMIT $4  [["match_id", 2], ["id", 1], ["participant_id", 4], ["LIMIT", 1]]
  ↳ app/controllers/predictions_controller.rb:55
  Pool Load (0.5ms)  SELECT  "pools".* FROM "pools" WHERE "pools"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
  ↳ app/models/prediction.rb:35
  Round Load (0.6ms)  SELECT  "rounds".* FROM "rounds" INNER JOIN "groups" ON "rounds"."id" = "groups"."round_id" WHERE "groups"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
  ↳ app/models/prediction.rb:21
   (0.2ms)  ROLLBACK
  ↳ app/controllers/predictions_controller.rb:55

1 个答案:

答案 0 :(得分:0)

真的令人尴尬的错误。我错过了检查Predictions Controller如何设置@prediction。由于@GorillaApe的建议,我抓住了params找不到对象:

def set_match_prediction
  @prediction = Prediction.find(params[:pool_id])
end 

而不是:

def set_match_prediction
  @prediction = Prediction.find(params[:id])
end

这反过来总是设置相同的对象,从而在除了一个实例之外的所有实例中引发验证错误,偶然地,它的:id与:pool_id一致。