アソシエーションとかで紐付いている複数モデルを、1つのフォームで入力させて登録・更新する方法について調べた。
Model
companyモデルに会社の経理情報を持ったcompany_financialモデルが1対1でリンクしている。
ポイントとしては、company更新時に付随するcompany_financialを、accepts_nested_attributes_forに指定するところ。
company.rb
class Company < ActiveRecord::Base
has_one :company_financial
accepts_nested_attributes_for :company_financial
end
company_financial.rb
class CompanyFinancial < ActiveRecord::Base
belongs_to :company
end
Controller
ポイントは以下の二つ。
- strong parameterに、company_financial_attributesを追加してあげる。(更新時のためにidもパラメータに含めておく)
- 付随するアソシエーションも同時に登録する場合はbuildであらかじめ作成しておくこと。(has_oneではbuildが使えないのでbuild_~~を使用します)
company_financial.rb
class CompaniesController < ApplicationController
before_action :find_company, only: [:show, :edit, :update, :destroy]
def new
@company = Company.new
@company.build_company_financial
end
def edit
end
def create
@company = Company.new(company_params)
@company.save!
redirect_to company_path(@company)
rescue
render action: 'new'
end
def update
@company.update!(company_params)
redirect_to company_path(@company)
rescue
render action: 'edit'
end
private
def find_company
@company = Company.find(params[:id])
end
def company_params
params.require(:company).permit(:name, company_financial_attributes: [:id, :bank_info])
end
end
View
fields_forでネストすることで、アソシエーションのフィールドを設置できる。
companies/new.html.slim
= form_for @company, url: companies_path do |f|
.form-group
= f.label :name
= f.text_field :name
= form.fields_for :company_financial: do |fin|
.form-group
= fin.label :bank_info
= fin.text_field :bank_info
Model間の関係はないが、1つのフォームで複数モデルの登録をしたい場合
strong parameterを分けて、それぞれでsaveすればOK.
company_financial.rb
class CompaniesController < ApplicationController
before_action :find_company, only: [:show, :edit, :update, :destroy]
def new
@company = Company.new
@user = User.new
end
def create
@company = Company.new(company_params)
@company.save!
@user = User.new(user_params)
@user.save!
redirect_to company_path(@company)
rescue
render action: 'new'
end
private
def company_params
params.require(:company).permit(:name)
end
def user_params
params.require(:user).permit(:name)
end
end
View
companies/new.html.slim
= form_for @company, url: companies_path do |f|
.form-group
= f.label :name
= f.text_field :name
= form.fields_for @user do |user|
.form-group
= user.label :name
= user.text_field :name