質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

バリデーション

Validationとは特定の入力データが、求められた条件に当てまっているかをチェックするために使われます。

Q&A

解決済

1回答

2902閲覧

Rails | 子モデルの1つ目のレコードのみにバリデーションをかけたい。

ruby510

総合スコア15

Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

バリデーション

Validationとは特定の入力データが、求められた条件に当てまっているかをチェックするために使われます。

0グッド

0クリップ

投稿2019/01/29 02:07

編集2019/01/29 02:29

前提

簡易的な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

以上です。よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2019/01/29 02:12

ビューの中身はどのようなものでしょうか?
Stan_Dma

2019/01/29 02:30

Could you get the User model defined having two attributes for books, one for a mandatory book, other for an arbitary?
ruby510

2019/01/29 02:30

失礼しました。 フォーム画面と一覧画面のビューを追加しました。
guest

回答1

0

ベストアンサー

子要素の数を変動させる場合、フォームから値そのものを送信しないというのが手っ取り早いです。

フォーム側にJavaScriptを仕込んで処理する必要があります(空の値を送信してしまえば、accepts_nested_formがinvalidな子モデルを生成してしまいます)。

投稿2019/01/29 02:44

maisumakun

総合スコア145183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ruby510

2019/01/29 02:54 編集

ご回答ありがとうございます。 そういう発想は全く思い浮かびませんでした。 実際、子モデルに対して値が入ってるのか確認すると、空の値でも入ってることになっていたのはそういうことだったんですね。 ちなみにこの機能を実装するためのJavascriptでの処理は初心者には難しいでしょうか?
ruby510

2019/01/29 03:04

coccoonの存在は知りませんでしたが、nested_formと同じ機能を持っているんですね。 これらをヒントに本情報を追加したり、削除したりする機能を付けて実装してみようかと思います。 ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問