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

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

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

Ruby on Rails4はRubyによって書かれたオープンソースのウェブフレームワークです。 Ruby on Railsは「設定より規約」の原則に従っており、効率的に作業を行うために再開発を行う必要をなくしてくれます。

Q&A

解決済

1回答

3560閲覧

Railsで`accepts_nested_attributes_for`と`fields_for`を使って、マルチセレクトフォームを実現する方法

shyamahira

総合スコア19

Ruby on Rails 4

Ruby on Rails4はRubyによって書かれたオープンソースのウェブフレームワークです。 Ruby on Railsは「設定より規約」の原則に従っており、効率的に作業を行うために再開発を行う必要をなくしてくれます。

0グッド

0クリップ

投稿2017/03/18 08:20

編集2017/03/18 08:22

Railsでaccepts_nested_attributes_forfields_forを使ってhas_many関連の子レコードを作成/更新するフォームの作成例は多くみかけますが、子のアトリビュートをマルチセレクトフォームを使った場合、どのようにやるのかがわからず質問させていただきました。

モデル

  • 親(GroupNumber)
class GroupNumber < ActiveRecord::Base has_many :order_numbers, dependent: :destroy accepts_nested_attributes_for :order_numbers
  • 子(OrderNumber)
class OrderNumber < ActiveRecord::Base belongs_to :group_number end

コントローラ

def new @group_number = GroupNumber.new @group_number.order_numbers.build end ... private def group_number_params params.require(:group_number).permit( :group_number, :group_name, order_numbers_attributes: [:id, :order_number] ) end

ビュー

... <% orders = { "オーダー1" => "1", "オーダー2" => "2", "オーダー3" => "3", "オーダー4" => "4", "オーダー5" => "5" } %> <div class="form-group"> <%= f.fields_for :order_numbers do |ff| %> <%= ff.label :order_number, "契約番号", class: "col-sm-3 control-label required" %> <div class="col-sm-6 col-md-6 col-lg-6"> <%= ff.select :order_number, orders, {include_blank: false}, {class: 'form-control', multiple: true} %> </div> <% end %> </div>

ff.select :order_numberのところがシングルセレクトフォームであればこのままでOKなのですが、上記のようにマルチセレクトにした場合、saveした時点でエラーになってしまいます。

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

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

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

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

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

guest

回答1

0

自己解決

色々調べましたがRailsだけの機能では無理っぽいので、jqueryを使って対応することにしました。

selectされたらhiddenフィールドにどんどん追記していく手法です。

モデル

参照先モデル(GroupNumber)

app/models/group_number.rb

  • viewでDBカラムに存在しない選択フォームを表示するため、attr_accessor :select_order_numberを追加。
  • select_order_numberフォームの選択項目はORDERS定数を定義
class GroupNumber < ActiveRecord::Base attr_accessor :select_order_number ORDERS = %w(オーダー1 オーダー2 オーダー3 オーダー4 オーダー5) has_many :order_numbers, dependent: :destroy accepts_nested_attributes_for :order_numbers

参照元モデル(OrderNumber)

app/models/order_number.rb

class OrderNumber < ActiveRecord::Base belongs_to :group_number end

コントローラ

app/controllers/group_numbers_controler.rb

  • createメソッドでparamsを操作し、viewから渡ってくる空の値を削除しています。これをしないとorder_numberがブランクのレコードが作成されてしまいます。
  • 先ほどGroupNumberモデルでつくったselect_order_numberをStrong Parametersに追加します。これを追加しないと、validationエラーなどでフォーム画面にリダイレクトがかかった時、select_order_numberセレクトフォームが未選択の状態になってしまいます。
def new @group_number = GroupNumber.new @group_number.order_numbers.build end def create params[:group_number][:order_numbers_attributes].delete_if { |key, order_number| order_number[:order_number].blank? } @group_number = GroupNumber.new(group_number_params) respond_to do |format| if @group_number.save format.html { redirect_to @group_number, notice: 'GroupNumber was successfully created.' } format.json { render :show, status: :created, location: @group_number } else format.html { render :new } format.json { render json: @group_number.errors, status: :unprocessable_entity } end end end ... private def group_number_params params.require(:group_number).permit( :group_number, :group_name, :select_order_number => [], order_numbers_attributes: [:id, :order_number] ) end

ビュー

**app/views/group_numbers/_form.html.erb

... <div class="form-group"> <%= f.label :group_number %> <%= f.text_field :group_number %> </div> <div class="form-group"> <%= f.label :group_name %> <%= f.text_field :group_name %> </div> <div class="form-group"> <%= f.label :group_numbers, "契約番号" %><br> <%= f.select :select_order_number, GroupNumber::ORDERS, {include_blank: false}, multiple: true %> <%= f.fields_for :order_numbers do |ff| %> <%= ff.hidden_field :order_number, class: "from-select-to-hidden", "data-id" => 0 %><br /> <% end %> </div>

jquery

app/assets/javascripts/group_numbers.js

  • select_order_numberセレクトフォームの選択内容が変化したらhiddenに選択されたvalueを入れていきます。
$(function () { $('form').on('change', 'select', function (event) { var $this = $(this), vals = $this.val(), $next = $this.next(); $this.siblings(".from-select-to-hidden").each(function (i) { if (i == 0) { $(this).val(""); } else { $(this).remove(); } }); $.each(vals, function (i, val) { var time = new Date().getTime(), regexp = new RegExp($next.data('id'), 'g'), id = $next.attr('id'), name = $next.attr('name'), newId = id.replace(regexp, time), newName = name.replace(regexp, time); $next.after($('<input type="hidden">').attr('id', newId).attr('name', newName).val(val).addClass("from-select-to-hidden")); }); event.preventDefault(); }); });

このjqueryが思惑どおりに動くにはfrom-select-to-hiddenというhiddenフィールドで指定ているクラス名をviewとjqueryできちんと書くことがポイントになりますが、この辺りがいまいち気に入っていません。何かコメントいただけると幸いです。

投稿2017/04/14 01:29

shyamahira

総合スコア19

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.51%

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

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

質問する

関連した質問