Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
27
Help us understand the problem. What is going on with this article?
@tbaba

ActiveRecordのdestroyでバリデーションをやりたい

More than 5 years have passed since last update.

どうも、ばばです。

destroyするときにバリデーションを走らせたい

たとえば、『destroy出来る条件』みたいなのがあって、その条件をパスしないと消せない、的な感じにしたいとする。
あり得るとしたら、『TwitterとGitHubの両方の認証手段がある(Qiitaみたいにね)んだけど、両方消しちゃったらログインする方法が無くなっちゃうから、両方とも消すことは出来ない』みたいな事がしたかったとする。
方法としては、

  1. destroyアクションの中で弾く
  2. バリデーションを書く

の2つの方法がぱっと思いつくと思う。ただ、バリデーションの方はちょっと特殊なことをやらなきゃいけないし、アクションの中で書くのは『えーそれモデルの仕事でしょー』感がハンパない。負けた感ある。

というわけで、今回はバリデーション側でなんとかスマートに解決させることは出来ないか、っていうのをやってみようと思う。

before_destroyを活用する

before_destroyについては、ActiveRecord::Callbacksに詳しく書いてある。

たとえば、こんな使い方をする。

user.rb
class User < ActiveRecord::Base
  before_destroy { |record| Post.destroy_all(user_id: record.id) }
end

いや、dependentオプションでやれよ、っていうのは気にしないで。

また、こいつ、メソッド名を渡すことも可能だ。

user.rb
class User < ActiveRecord::Base
  before_destroy :delete_all_his_posts

  private

  def destroy_all_his_posts
    self.posts.delete_all
  end
end

これを利用してどうにかしてみよう。

たとえば、saveメソッドは、truefalseを返してくる。trueなら保存成功、falseなら保存失敗だ。
しかし、destroyは基本的に自分自身を返してくる。これに『もし何かに引っかかってエラーになったら、falseを返す』ようにしたら、saveと同じような挙動にすることが出来るのではないか。

login_provider.rb
class LoginProvider < ActiveRecord::Base
  belongs_to :user

  before_destroy :user_should_have_at_least_one_login_provider

  private

  def user_should_have_at_least_one_login_provider
    # もしユーザーのLoginProviderが1つしか無いのに、消そうとしていたら
    if self.user.login_providers.length == 1
      errors.add :base, '少なくとも1つ、ログイン用の認証が必要です'
      return false
    end
  end
end

すると、

if @login_provider.destroy
  redirect_to user_login_providers_path, notice: '削除しました'
else
  redirect_to user_login_providers_path, notice: '削除できませんでした'
end

こんなことが出来るようになる。
もちろん、Viewで@login_provider.errorsを表示すれば、ちゃんと『少なくとも1つ、ログイン用の認証が必要です』と表示される。
ちょっと強引だけど、こんなことをしなきゃいけない時点でだいぶレール踏み抜いてる感があるので、まぁ仕方ないかなぁ。

だいたいそんな感じ( ˘ω˘)

27
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
tbaba
プログラマー。ウェブアプリケーションとか。 https://forkwell.com の中の人。仕事道具は VSCode と Git。Git は綺麗な歴史を作る派。
grooves
エンジニア向けサービス「Forkwell」などを開発・運営しています。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
27
Help us understand the problem. What is going on with this article?