Railsのアソシエーションと複数登録 ~新規登録~
前回の続き
登録画面と確認画面を作成し、新規登録まで出来るようにする。
ルーティングの作成
newとedit関連をまとめて設定
resource :profile, only: [:new, :create, :edit, :update] do post :confirm, on: :collection end
postでconfirmへ遷移するよう設定する。
プロフィールは一つしかないので、IDを指定する必要が無い。
resource :profileとし、confirmにもon: :collectionを指定
コントローラーの作成
def new @profile = current_user.build_profile @profile.game_careers.build @profile.possess_games.build end def confirm @profile = current_user.build_profile(profile_params) end def create @profile = current_user.build_profile(profile_params) if @profile.valid? @profile.save! redirect_to root_path end end
current_user.build_profile で ProfileにUserIDを入れることが出来る。
同時に○○.buildをしておくと、初期状態で入力欄が表示される。
(今回は動的に入力欄を追加出来るようにするのでなくてもOK。)
ビューの作成
今回は確認画面を挟むので、フォームでPostした場合にConfirmへ飛ぶように指定する。
<%= form_for profile, url: confirm_profile_path, method: :post do |f| %> -省略- <%= f.submit '確認画面へ', class: 'btn btn-primary' %> <% end %>
Confirm画面は入力した内容を表示する。
hiddenをセットし忘れると値を渡すことができないので注意。
項目が多い場合は↓のように書くとスッキリする。
-省略- <%= form_for @profile, url: profile_path, as: :profile do |f| %> <% [:email, :tell, :prefecture_id, :city ].each do |attr| %> <%= f.hidden_field attr %> <% end %> <%= f.submit '登録する', class: 'btn btn-primary' %> <% end %>
複数登録の実装
ゲーム経験と所有ゲーム機を複数登録出来るようにする。
Association先のモデル保存には accepts_nested_attributes_for
を使う。
※ accepts_nested_attributes_for はそのうち消える運命らしい。。
FormObjectを使うと良いらしいので、今度試してみる。
model/profile.rb
# 追加 accepts_nested_attributes_for :game_careers, :possess_games, allow_destroy: true
allow_destroy: true
を追加することで"_destory"がtrueのときに削除できるようになる。
controller/profiles_controller.rb
# ストロングパラメータに○○_attributesを追加する。 # _destroyも受け取れるようにする。 def profile_params params.require(:profile).permit( :email, :tell, :prefecture_id, :city, game_careers_attributes: [:id, :profile_id, :name, :_destroy], possess_games_attributes: [:id, :profile_id, :game_console_id, :_destroy] ) end
入力フォームにはnested_form_fields
を使用する。
Gemfile
# 追加してbundle install gem 'nested_form_fields'
app/assets/javascript
# 追加 //= require jquery //= require jquery_ujs //= require nested_form_fields
jqueryとjquery_ujsを使用するので追加。
逆だと動かないので順番にも注意。
views/profile/_form.html.erb
<%= form_for profile, url: confirm_profile_path, method: :post do |f| %> -省略- # テキストボックスに入力 <%= f.nested_fields_for :game_careers, wrapper_tag: :div do |career| %> <%= career.text_field :name, class:'form-control', id:'careers', placeholder: 'careers'%> <%= career.remove_nested_fields_link 'Delete', class: 'btn btn-danger', role: 'button' %> <% end %> <%= f.add_nested_fields_link :game_careers, 'Add new', class: 'btn btn-primary', role: 'button' %> # セレクトボックスから選択。選択肢はGameConsoleから取得 <%= f.nested_fields_for :possess_games, wrapper_tag: :div do |games| %> <%= games.collection_select :game_console_id,GameConsole.all, :id, :name, class:'form-control', placeholder: 'games'%> <%= games.remove_nested_fields_link 'Delete', class: 'btn btn-danger', role: 'button' %> <% end %> <%= f.add_nested_fields_link :possess_games, 'Add new', class: 'btn btn-primary', role: 'button' %> <% end %>
nested_fields_for内のremove_nested_fields_linkが削除ボタン、add_nested_fields_linkがフォーム追加ボタン。
追加したフォームをdivで囲むnested_fields_forにwrapper_tag: :div
を追加すればOK。
views/profile/confirm.html.erb
# 項目表示 ~ 省略 ~ <% @profile.game_careers.each do |c| %> <%= c.name %> <% end %> <% @profile.possess_games.each do |g| %> <%= g.game_console.name %> <% end %> # hidden追加 ~ 省略 ~ <%= f.fields_for :game_careers do |career| %> <%= career.hidden_field :name %> <%= career.hidden_field :_destroy %> <% end %> <%= f.fields_for :possess_games do |games| %> <%= games.hidden_field :game_console_id %> <%= games.hidden_field :_destroy %> <% end %>
表示とhiddenを追加。hiddenには'_destroy'も忘れず追加すること。
登録だけならこれで問題無いが、修正時に問題があるのでそのときに修正。
これで入力から登録までが完了。
次は編集画面を実装する。