前提
簡易的なCRUDアプリケーションを質問用に作成しました。
機能
ユーザー登録時に本情報も同時に登録できる。
本情報はコントローラーを編集すれば増やしたり減らしたりできる。
本当は、追加ボタンを押すと本情報を追加で登録できるようにしたいですが、今は保留。
現在、1つのユーザーに対して、2つの本情報を登録する仕様になっています
Model
親モデル: Userモデル
子モデル: Bookモデル
accepts_nested_attributes_for
で紐づけています。
実現したいこと
本情報を一つだけでも登録できるようにする。
つまり、
本情報の登録 0 → バリデーションかかる
本情報の登録 1つ以上 → バリデーションかからない
(本情報の2つ目は任意で、入力しなくてもいいようにしたい)
現状
本情報を2つ登録しないとバリデーションがかかる。
text
1ユーザー登録画面 22件のエラーがあります。 3Books title can't be blank 4Books content can't be blank 5 6Name: test 7Email:test@gmail.com 8 9本: 1 10Title:aaa 11Content:aaa 12本: 2 13Title:空白 14Content:空白 15 16戻る
該当のソースコード
lang
1#<user.rb> 2 3class User < ApplicationRecord 4 validates :name, presence: true 5 validates :email, presence: true 6 7 has_many :books 8 accepts_nested_attributes_for :books,allow_destroy: true 9end 10
lang
1#<book.rb> 2 3class Book < ApplicationRecord 4 validates :title, presence: true 5 validates :content, presence: true, length: {maximum: 150} 6 7 belongs_to :user, optional: true 8end
lang
1#<users_controller.rb> 2 3class UsersController < ApplicationController 4 before_action :set_user, only: [:show, :edit, :update, :destroy] 5 6 def index 7 @users = User.all.order(updated_at: :desc) 8 end 9 10 def new 11 @user = User.new 12 2.times { @user.books.build } 13 end 14 15 def create 16 @user = User.new(user_params) 17 if @user.save 18 redirect_to users_path, notice: "登録が完了しました" 19 else 20 render "new" 21 end 22 end 23 24 def show 25 end 26 27 def edit 28 end 29 30 def update 31 if @user.update(user_params) 32 redirect_to users_path, notice: "編集が完了しました" 33 else 34 render "edit" 35 end 36 end 37 38 def destroy 39 @user.destroy 40 redirect_to users_path, notice: "ユーザー情報を削除しました" 41 end 42 43 private 44 45 def set_user 46 @user = User.find(params[:id]) 47 end 48 49 def user_params 50 params.require(:user).permit( 51 :name, :email, 52 books_attributes: [:id, :title, :content] 53 ) 54 end 55 56end 57
ruby
1#<_form.html.erb> 2 3<% if @user.errors.any? %> 4 <div id="error_explanation"> 5 <h2><%= @user.errors.count %>件のエラーがあります。</h2> 6 7 <ul> 8 <% @user.errors.full_messages.each do |message| %> 9 <li><%= message %></li> 10 <% end %> 11 </ul> 12 </div> 13<% end %> 14 15<%# ユーザー情報 %> 16<div class="form"> 17 <%= form_for @user do |f| %> 18 <div class="user-form"> 19 <div class="field"> 20 <%= f.label :name %> 21 <%= f.text_field :name %> 22 </div> 23 <div class="field"> 24 <%= f.label :email %> 25 <%= f.text_field :email %>円 26 </div> 27 </div> 28 29 <%# 本情報 %> 30 <div class="book-form"> 31 <%= f.fields_for :books do |book| %> 32 <h2>本: <%= book.index+1 %></h2> 33 <div class="field"> 34 <%= book.label :title %> 35 <%= book.text_field :title %> 36 </div> 37 <div class="field"> 38 <%= book.label :content %> 39 <%= book.text_field :content %> 40 </div> 41 <% end %> 42 </div> 43 44 <div class="actions"> 45 <%= f.submit %> 46 </div> 47 <% end %> 48</div> 49
ruby
1#<index.html.erb> 2<div class="container"> 3 <div class="user-index"></div> 4 <h1>ユーザー一覧</h1> 5 6 <table> 7 <tr> 8 <th id="name">名前</th> 9 <th id="rent">メールアドレス</th> 10 </tr> 11 12 <% @users.each do |user| %> 13 <tr> 14 <td><%= user.name %></td> 15 <td><%= user.email %></td> 16 17 <td><%= link_to "詳細", user_path(user.id) %></td> 18 <td><%= link_to "編集", edit_user_path(user.id) %></td> 19 <td><%= link_to "削除", user_path(user.id), method: :delete, data: { confirm: '本当に編集していいですか?' } %></td> 20 </tr> 21 <% end %> 22 </table> 23 24 <%= link_to "ユーザーを登録する", new_user_path %> 25</div> 26
試したこと
before_save
を使って、1つだけ登録できるように条件分岐などもしてみましたが、うまくいきませんでした。イマイチ使い方を把握していなかったのかと思います...
自分自身が考えた処理の流れとしては、
バリデーションをかける条件を書いてあげて、それを登録・更新時に発動させるという発想しか今のところ思い浮かびませんでした。ただ、どんな条件式を書けばいいのか、どこにそれを入れればいいのかが思い浮かびません。
一応、考えた条件式としてはこんな感じです。
if @user.books[0].nil? && @user.books[1].nil? #どちらの値も空白の時に、バリデーションをかける else #それ以外は、バリデーションをかけない end
きっと他に最良のやり方があると思いますので、ご教授いただければと思います。
どうかよろしくお願いします。
環境
Rails 5.0.0
Ruby 2.3.1
以上です。よろしくお願いします。
回答1件
あなたの回答
tips
プレビュー