axios.POSTした配列オブジェクトをRailsのモデルオブジェクトとして保存する
1つのレースオブジェクト
{ name: 桜花賞, location: 阪神, weather: 晴 }
複数のレコードオブジェクト(配列)
[ { name: 馬A, jockey: 騎手A }, { name: 馬B, jockey: 騎手B }, ...... ]
これらを同時にVue.jsから投げ、Railsで取得してそれぞれのモデルオブジェクトとして保存する方法です。
Vue.jsでは、それぞれのプロパティがこのように入っている状態です。
略 data: { raceConfirmation: { name: "桜花賞", location: "阪神", weather: "晴" }, recordsConfirmation: [ { name: 馬A, jockey: 騎手A }, { name: 馬B, jockey: 騎手B }, ...... ] }
これをaxiosでPOSTします。第二引数に格納するデータを記述できるので
Vue.jsのメソッド内に
axios.post('/api/get_race_records/create', { race: raceConfirmation, records: recordsConfirmation })
と書きます。
そうするとRails側では、params.require(:race)
とparams.require(:records)
でそれぞれのデータを受け取れるので、以下のように処理をします。
def create #(Raceオブジェクトは普通にnewできる) @race = Race.new(race_params) #Recordオブジェクトの処理は #空の配列を作り @records = [] #受け取った配列データをeach do params.require(:records).each do |record| #ひとつずつパラメータを許可 permitted = records_permit(record) #@raceに関連づいたRecordオブジェクトとして作成し new_record = @race.records.build(permitted) #再び配列に入れる @records.push(new_record) end #@raceと@recordsの作成が完了したら、可否をJSONで返す if @race.save && @records.each{|record| record.save} @result = "success" else @result = "fail" end render 'create', formats: 'json', handlers: 'jbuilder' end private def race_params params.require(:race).permit(:name, :location, :weather) end def records_permit(params) params.permit(:name, :jockey) end
saveする前に再び配列に入れ直すのは、最後にまとめてsaveしてその結果をVue.jsに返すためです。
Vue.js側では返ってきた結果によって処理を分岐します。
Railsにはaccepts_nested_attributes_for
という便利な?関連付けがあるようなんですが、半日ほど奮闘して上手く使えなかったので上記のように書きました。
あとajaxでPOSTができるという考えに至らなくて「Vueからどうやってデータ渡そう。URLに全部乗せるの?二郎系URLじゃん……」と小一時間苦悶しました。検索力は大事。