前提・実現したいこと
ruby on railsで、フォームオブジェクトとfields_forを使って
一つのフォーム入力画面から複数の異なったモデルを更新したいと考えています。
ただ、パラメータでネストした(fields_forで子モデルに入力する)日時の情報を
FormObjectに渡して正しい日時情報に変換したいのですが、やり方がわからず困っています。
現状のソースコード
ビュー側
html
1 <%= form_for @contract_master, as: :edit_dract_contract_form do |fb| %> 2 3 <div class="form-group"> 4 <%= fb.label :契約名, class: "label-inline" %> 5 <%= fb.text_field :name, class:'form-control' %> 6 </div> 7 <!-- 子モデルへの入力フォーム --> 8 <%= fb.fields_for :temp_cont_item_stock do |f2| %> 9 <div class="form-group"> 10 <%= f2.label :契約受付説明文, class: "label-inline" %><span class="badge badge-pill badge-danger">必須</span> 11 <%= f2.text_area :description, class:'form-control', rows:"5" %> 12 </div> 13 <div class="form-group"> 14 <%= f2.label :使用期限, class: "label-inline" %> 15 <%= f2.datetime_select :expiration_date, start_year: now.year, end_year: now.year + 1000, class:'form-control' %> 16 </div> 17 <% end %> 18<% end %>
コントローラでフォームオブジェクトに渡すストロングパラメータの設定
ruby
1 def edit_contract_master_params 2 params.require(:edit_dract_contract_form).permit(:name, temp_cont_item_stock: [:description, :expiration_date]) 3 end
生成されたストロングパラメータの内容
<ActionController::Parameters {"name"=>"テスト契約", "temp_cont_item_stock"=><ActionController::Parameters {"description"=>"契約説明文です", "expiration_date(1i)"=>"2021", "expiration_date(2i)"=>"4", "expiration_date(3i)"=>"18", "expiration_date(4i)"=>"22", "expiration_date(5i)"=>"40"} permitted: true>} permitted: true>
フォームオブジェクトに日時情報(expiration_date)を渡そうとすると5つに分割された状態になってしまいます。
このままでは日時情報をフォームオブジェクト側でうまく受け取ることができません。
そこで5つに分かれてしまった日時情報を一つにまとまった日時情報に変換し直そうとしたのですがうまくいきませんでした。
フォームオブジェクト側
ruby
1class EditDractContractForm 2 include ActiveModel::Model 3 attr_accessor :name, :temp_cont_item_stock, :expiration_date 4 5 #年・月・日・時・分に分割されて渡されている日時を一つの日時情報に自動変換する 6 def initialize(params = {}) 7 8 if params.is_a?(ActionController::Parameters) 9 [:expiration_date].each do |attribute| 10 datetime_parts = (1..5).map { |i| params.delete("#{attribute}(#{i}i)") } 11 params[attribute] = Time.zone.local(*datetime_parts) if datetime_parts.any? 12 end 13 end 14 super 15 end 16#以下省略
ちなみに、パラメータの日時情報がネストしていないときは、上記のinitializeメソッドで日時情報に変換してくれます。
おそらくパラメータ内のネストした日時情報をinitializeメソッド内で取得すればいいのですが、その方法がわからなくて困っています。
どうすれば、うまく変換できるでしょうか。
回答をよろしくお願いします。
###追記(最終的に成功したコード)
回答者からのアドバイスをもとに最終的に成功したコードをここに記します。
(コメント欄だと見ずらいのでここに記します)。
class EditDractContractForm include ActiveModel::Model attr_accessor :name, :temp_cont_item_stock, :expiration_date def initialize(attributes={})#attributesにはパラメータが入る。 if attributes.present? attrs = attributes.to_unsafe_h.dup#受け取ったストロングパラメータをハッシュ化 if attrs["temp_cont_item_stock"]["expiration_date(1i)"].present? #日時作成 attrs[:expiration_date] = DateTime.new( attrs["temp_cont_item_stock"]["expiration_date(1i)"].to_i, attrs["temp_cont_item_stock"]["expiration_date(2i)"].to_i, attrs["temp_cont_item_stock"]["expiration_date(3i)"].to_i, attrs["temp_cont_item_stock"]["expiration_date(4i)"].to_i, attrs["temp_cont_item_stock"]["expiration_date(5i)"].to_i ) end super(attrs) end end
これでフォームオブジェクト内なら、expiration_dateとすれば日時情報を取得できます。
回答1件
あなたの回答
tips
プレビュー