Railsでソフトデリート機能を実装する際に遭遇する可能性のある2つの課題とその解決方法について説明します。一つ目は、特定の操作でバリデーションをスキップする方法、もう一つは、default_scope
を使用しているモデルでソフトデリートされたレコードを取得する方法です。
1. 特定の操作でバリデーションをスキップする
Railsでは、モデルのバリデーションが非常に強力で役立つ一方で、特定の条件下でバリデーションをスキップしたい場合があります。例えば、ソフトデリートの操作では、いくつかのバリデーションを適用したくないかもしれません。
class Reservation < ApplicationRecord
# バリデーション
validates :is_approved, inclusion: { in: [true, false] }
validate :unique_future_reservation_per_customer_and_company, unless: -> { @skip_validation }
# ソフトデリートメソッド
def soft_delete
@skip_validation = true
update(deleted_at: Time.current)
end
end
この方法では、インスタンス変数 @skip_validation
を使ってバリデーションの実行を制御します。この変数が true
の場合、unique_future_reservation_per_customer_and_company
バリデーションはスキップされます。
2. default_scope
が適用されるモデルでソフトデリートされたレコードを取得する
Railsで default_scope
を使用すると、そのモデルのすべてのクエリに自動的に適用されるため、特定の条件を除外することが難しくなることがあります。ソフトデリートされたレコードを取得するためには、unscoped
メソッドを使用して default_scope
を無視する必要があります。
class Reservation < ApplicationRecord
default_scope { where(deleted_at: nil) }
# ソフトデリートされたレコードを取得するスコープ
scope :deleted, -> { unscoped.where.not(deleted_at: nil) }
end
このスコープを使用すると、ソフトデリートされたレコードだけを簡単に取得できます。
Reservation.deleted
考慮点
これらの技術を使用する際は、@skip_validation
のようなインスタンス変数が他のメソッドやアクションに影響を与えないように注意する必要があります。また、unscoped
を使用する場合は、他の必要なスコープが誤って削除されないように、その使用範囲を明確に限定することが重要です。
補足: ->
について
->
は Ruby で ラムダ (lambda) を表す記法です。ラムダは無名関数または小さな関数オブジェクトを定義するために使用されます。Rails のコンテキストで使用されるとき、これは主にモデル内のバリデーションやスコープ定義で条件を指定するのに使われます。
ラムダ式の基本
ラムダ式は、次のように書くことができます:
-> { puts "Hello, world!" }
または、パラメータを取る場合は次のようになります:
->(name) { puts "Hello, #{name}!" }
Railsでの使用例
Rails のモデル内で unless:
オプションとともにラムダを使う一般的な使用例は、特定の条件下でのみバリデーションを実行する場合です。例えば:
validates :email, presence: true, unless: -> { self.name.blank? }
この例では、unless
オプションにラムダが使用され、name
属性が空の場合にのみ email
の存在チェックをスキップします。
ラムダとプロック
ラムダは Ruby の Proc クラスのインスタンスの一種ですが、プロック(ブロックをオブジェクトとして扱うためのもの)といくつか異なる点があります:
-
リターンの振る舞い: ラムダ内で
return
を呼び出すと、ラムダ自体から値が返されます。一方、プロック内でreturn
を呼び出すと、そのプロックを含む外側のスコープ(メソッドなど)から制御が抜けます。 -
引数の厳格性: ラムダは引数の数が正確でなければならず、指定した数と異なる引数を渡すとエラーになります。プロックはより柔軟で、余計な引数は無視され、不足している引数は
nil
で補われます。
これらの特性により、ラムダは特定の振る舞いを期待する小さな関数を定義する際に役立ち、コードの意図を明確に表現するのに適しています。