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じゃん……」と小一時間苦悶しました。検索力は大事。