4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

様々なユニーク対応

4
Posted at

ユニーク対応時の色々なパターンでよく詰まるのでメモします。

通常のユニーク

user.rb
class User < ApplicationRecord

# 省略

  validates :code, uniqueness: true

end
user.schema
 # 省略
  t.string 'code'

  t.index ["code"], name: "code", unique: true
end

これが一般的によく記事にあるような書き方ですが、
これだとうまく行かないことが多いと思います。

論理削除は見ないユニーク

user.rb
class User < ApplicationRecord

# 省略

  validates :code, allow_blank: true,
                 uniqueness: { scope: :deleted_at }

end
user.schema
 # 省略
  t.string 'code'

  t.index ["code", "deleted_at"], name: "code", unique: true
end

複合ユニークにすることによって、
codeカラムとdeleted_atカラム両方を見て
データが全く同じものがあればバリデーションが発生。

deleted_atは年月日から秒数まで見るので、
deleted_atカラムにデータが入っている時点で被ることは無いです。

つまり、
**「(論理)削除してないけどcodeが被った」**データがあった時に codeカラムが同じ、deleted_at`カラムが同じ(nil同士)となって
バリデーションが発生します。

nilだけ見ないユニーク

user.rb
class User < ApplicationRecord

# 省略

  validates :code, uniqueness: { allow_blank: true, conditions: -> { with_deleted } }
  before_save :code_to_empty

  private

    # ""(空文字)をnilに
    def code_to_empty
      self.code = nil if code.blank?
    end

end
user.schema
 # 省略
  t.string "code", null: true

  t.index ["code"], name: "code", unique: true
end

nilを見ない場合はこちらです。
1番上のやり方に近いですが、
実装時にバリデーションがうまく通りませんでした。

原因としては、
nilがどこかで""(空文字)になってしまい、
「ユニークはnilを見ない」という性質をうまく適用できず、
モデル側のバリデーションがうまく使えなかったです。

そのためメソッドを作って
""(空文字)を無理矢理nilに変更しています。

これで通るようになりました。

4
1
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
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?