これが私がやろうとしていることです。これはよくある問題だと思っていましたが、どういうわけか関連するトピックが見つかりませんでした...
範囲指定された一意性制約を持つモデルがあります。次のように、移行でテーブルに一意のインデックスを定義することで、これを行うことにしました。
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 が処理されても、オブジェクトはそれ自体が有効であると見なされ、保存試行が失敗した後にタイムスタンプが設定されます。望ましくない副作用を引き起こす可能性はありますか?