0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Railsの論理削除機能におけるバリデーションスキップとデータ取得時に論理削除分も含める方法

Posted at

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 で補われます。

これらの特性により、ラムダは特定の振る舞いを期待する小さな関数を定義する際に役立ち、コードの意図を明確に表現するのに適しています。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?