1

これが私がやろうとしていることです。これはよくある問題だと思っていましたが、どういうわけか関連するトピックが見つかりませんでした...

範囲指定された一意性制約を持つモデルがあります。次のように、移行でテーブルに一意のインデックスを定義することで、これを行うことにしました。

class CreateLossRatios < ActiveRecord::Migration
  def up
    ...
    add_index :loss_ratios, [ :tool_id, :ends_at ], :unique => true
  end

  def down
    ...
  end
end

これにより、インデックスの一意性に違反するレコードを保存しようとすると、ActiveRecord が例外をスローします。ここで、検証エラーとして表示させたいと思います。最良の方法は、ActiveRecord::RecordNotUnique を LossRatio モデルでキャッチし、エラー ハッシュに意味のあるメッセージを入力することだと考えました。私はそのようにしました:

class LossRatio < ActiveRecord::Base
  belongs_to :tool

  validates :rate, :ends_at, :tool, :presence => true
  validates_numericality_of :rate
  validates_inclusion_of :rate, :in => (0..1)

  %w{ create save }.each do |name|
    %W{ #{name} #{name}! }.each do |method|
      define_method(method) do |*args|
        begin
          super(*args)
        rescue ActiveRecord::RecordNotUnique => ex
          self.errors.add(:ends_at, I18n.t('activerecord.errors.models.loss_ratio.attributes.ends_at.not_unique'))
        end
      end
    end
  end

end

これは機能しますが、少し面倒です。ここで仮定をしていることは理解していますが (つまり、別の DB レベルの一意性制約を追加するとどうなるかなど)、これを回避する方法がわかりません。このようなシナリオに対処する際に、より洗練されたソリューション/ベスト プラクティスはありますか? 私が考えることができる 1 つの代替手段は、rescue_from を使用することですが、私はこれを行いたくありません。

  • このロジックはコントローラーに属しているとは思わないので、アプリケーション ロジックに対して透過的にしたい
  • ほとんどの場合、関連付けられたコントローラーはありません (これらのオブジェクトは、別のモデルを介した関連付けとしてのみ作成されます)。これは、私の観点からはさらに間違っています。

インスタンス メソッドからスローされた例外からこのモデルをレスキューする方法はありますか? クラス レベルのレスキュー句を使用してみましたが、何もキャッチされません。


もう 1 つの質問は、ends_at に対して AR スコープの検証を引き続き使用する必要があるかどうかです。RecordNotUnique が処理されても、オブジェクトはそれ自体が有効であると見なされ、保存試行が失敗した後にタイムスタンプが設定されます。望ましくない副作用を引き起こす可能性はありますか?

4

2 に答える 2

2

モデルの一意性も検証する必要があります (gmalette が提案したように)。そうすれば、データベースにヒットする前にほとんどのエラーを取得できます。追加料金が 1SELECTつかかりますが、実際の検証が確実に行われます。

これにより、データベース インデックスは、2 つの独立したプロセスが競合するデータをほぼ同時に挿入しようとした場合にのみ、競合状態を解決する必要があります。私は通常、ユーザーに再試行を求めるエラー メッセージを表示することで、これらのエラーを処理します。

データベース エラーを選択的に処理することは、通常、エラーが発生しやすいため、あまりお勧めできません。代わりに、Ruby レイヤーでできるだけ多くの検証を処理し、データベース レイヤーはセーフティ ネットとしてのみ使用してください。

于 2012-04-10T14:25:46.243 に答える
1

検証の問題を解決するには、試すことができます

validates_uniqueness_of :ends_at, :scope => :tool_id

于 2012-04-10T14:17:13.040 に答える