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?

More than 3 years have passed since last update.

子モデルで親モデルの関連データがバリデーションができない問題

Last updated at Posted at 2021-02-14

作ろうとした機能は、タグに応じて投稿フォームの種類を切り替えるやつ。

モデルの関係はこんな感じ(子モデルの名前は適当です)
スクリーンショット 2021-02-14 15.36.24.png

タグに応じて子モデルが変わり、投稿フォームも変わるようになっています。
しかしこのモデル設計だと、タグの種類によってバリデーションが変えられない問題が生じました。

例えば、子モデルでバリデーションをする場合

One.rb
class One < ApplicationRecord
    belongs_to :post

    with_options if: :one? do |one|
        one.validates :url, presence: true
    end

   def one?
        tag_id == 1
    end
end

このようなエラーがでます。

undefined local variable or method `tag_id' 

tag_idが見つからないと怒られてしまいました。
いろいろ調べたところ、上のコードが機能するようにするためには、子モデルが親モデルを継承する必要があるそうです。

しかし、機能追加・機能変更のための継承はよくないとのこと。
参考:https://qiita.com/tonluqclml/items/c0110098722763caa556

そこで、Postモデルを消す形でモデルを修正しました。
Postモデルの子モデルは全て並列の関係になっていたので、モデル設計的にも正しいと思います。
スクリーンショット 2021-02-14 16.35.48.png

##モデルを書き換えない方法
とはいえ、モデルを書き換えるのは大変なので、緊急的に動作するコードも書いてみました。
結論から言うとカスタムバリデーションを用いると実装できます。
ただ、バリデーションが増えると重複コードが増えて汚くなってしまいます。

app/validtors/three_valiator.rb
class ThreeValidator < ActiveModel::EachValidator
    def validate(record)      
    #先生の紹介のバリデーション
      if record.tag_id == 4
        unless record.teacher.name.present?
            record.errors[:base] << "名前を入力してください"
        end

        unless record.teacher.job.present?
            record.errors[:base] << "職業を入力してください"
        end
      end
    end
  end

もっと良い方法とかあれば、教えてください。

##参考文献
https://railsguides.jp/active_record_validations.html
https://qiita.com/tonluqclml/items/c0110098722763caa556
https://qiita.com/kikunantoka/items/61ab74c7f50dedace211

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?