フォームオブジェクト(ActiveModelをincludeしている)が保持している特定の値だけ、DBに保存したいというケースがあったので参考までにまとめてみます。
DetailFormというフォームオブジェクトそれぞれにa_type~d_typeまでの値が保持されている。また下記の内容を親フォームがdetailsというaccessor名で保持しているとする。
[#<DetailForm:xxxxx
@attributes=#<ActiveModel::AttributeSet:xxxxx @attributes={}>,
@a_type="aaa_1",
@b_type="bbb_1",
@c_type="ccc_1"
@d_type="ddd_1">,
#<DetailForm:xxxxx
@attributes=#<ActiveModel::AttributeSet:xxxxx @attributes={}>,
@a_type="aaa_2",
@b_type="bbb_2",
@c_type="ccc_2",
@d_type="ddd_2">]
これを今回は下記のような形で、d_typeを除く、a_type~c_typeまでの値を保存したいとする。
[
{
"a_type"=>"aaa_1",
"b_type"=>"bbb_1",
"c_type"=>"ccc_1"
},
{
"a_type"=>"aaa_2",
"b_type"=>"bbb_2",
"c_type"=>"ccc_2"
}
]
実装方法
class DetailForm
include ActiveModel::Model
include ActiveModel::Callbacks
include ActiveModel::Attributes
define_model_callbacks :initialize
attr_accessor :a_type
attr_accessor :b_type
attr_accessor :c_type
attr_accessor :d_type
def initialize(param)
run_callbacks :initialize do
self.a_type = param['a_type']
self.b_type = param['b_type']
self.c_type = param['c_type']
self.d_type = param['d_type']
super
end
end
#
# ハッシュ指定をして、DetailFormの保持しているa_type~c_typeまでの値を詰める
#
def attributes
{
'a_type' => a_type,
'b_type' => b_type,
'c_type' => c_type
}
end
end
attributesメソッド用意(関数名は何でも良い)してやって、各DetailFormインスタンスの保持している値を今回保存したい形式に合わせてセットする。最終的な呼び出しは以下のようになった。
save_type = details.map(&:attributes)
detailsには最上部で話したように、各DetailFormオブジェクトのインスタンスを保持しているので、それぞれのインスタンスからattributesを呼び出して、mapしてそれぞれのインスタンスが保持している値をattributesを通してセットしてやるような流れができた。これでsave_typeには当初の保存したい形式で格納することができた。後はこれをsaveしてやるだけで完了。
終わりに
以上簡単ではありますが、今回のようなケースがあれば参考にして頂ければと思います。こうして後から見てみると難しいことはやってないのですが、ここに至るまでの発想には思ったより時間がかかったので、まだまだ勉強していかないとですね...