前回の続き。
今回は、子が0件でも更新されてしまうことを防ぐ方法を考えます。
子が0件でもエラーにならない
多くの紹介記事のとおりに導入すると子が0件でも通ってしまう
掲題のとおりですが、なぜエラーにならないのでしょうか?
モデルapp/models/project.rb
を覗いてみます。
●app/models/project.rb
class Project < ApplicationRecord has_many :tasks, dependent: :destroy accepts_nested_attributes_for :tasks, reject_if: :all_blank, allow_destroy: true end
何が問題なのでしょうか?
解決方法(モデル側の制御)
一般的なエラーロジックを追加しても解決はしない
すべての項目がブランクの場合はエラーにするといったバリデーションを入れても上手くは行かないです。
●app/models/project.rb
# 子のバリデーション validate :check_tasks private # 子供側のバリデーション def check_tasks tasks.each_with_index do |task, idx| if idx == 0 if task.description.blank? && task.他の入力項目.blnak? errors.add(:base, '1行目は入力してください。') end end end
このロジックは除去します。
バリデーションの前にすでに行が除去されていることに気づく
他の障害が発生した際に気が付きましたが、未入力行はバリデーションの前に除去されていることに気が付きました。
ということは、それ以前の定義の問題でしょうか?
reject_if: :all_blank
を除去すれば0件出力は防げる
モデル内にあるreject_if: :all_blank
の記述を除去すれば、バリデーション前の未入力行の除去が防げます。
●app/models/project.rb
class Project < ApplicationRecord has_many :tasks, dependent: :destroy accepts_nested_attributes_for :tasks, allow_destroy: true end
このロジックは除去します。
あとは、このモデル側でvalidates :カラム名, presence: true
を追加してあげれば、良いでしょう。
解決方法(追記1:コントロール側の制御)
新規時に1行目(空白行)を表示させたい
新規時に1行目(空白行)を表示させたいは以下のようにします。
●app/models/project.rb
# GET /projects/new def new @project = Project.new # 子モデルも作成 @project.tasks.build end
@project.tasks.build
を挿入してあげれば、1行空行が表示されます。
解決方法(追記2:ビュー側の制御)
1行目のみ削除ボタンを表示させない
全行に削除ボタンを表示させてしまうと、(0件エラーは表示できても)なんかちょっと…と言われる可能性はあります。
この場合、1行目のみ削除ボタンを表示させないという手法がありそうです。
●app/views/projects/_task_fields.html.haml
- if f.options[:child_index] != 0 .field %br = link_to_remove_association "明細削除", f
if f.options[:child_index] != 0
の:child_index
が行番(0〜)なので、0を除いて削除ボタンを表示させるようにします。
次回
次回はこのモデルの件数に制限をかける手法を考えます。