はじめに
フロントにNuxt.js、バックエンドにRailsを使用してサービスを作っているのですが、データ量が多くなり一個ずつデータを送るのに時間がかかってしまったので配列でまとめてRailsに送って処理をしてもらおうと思ったのですが躓いたので記事にします。
目次
JSから送るデータ
今回のケースではJSから60または250個のデータをバックエンド側に送る必要がありました。
実際のデータは以下のような感じです。
[
{"id":7,"name":"","color":"#2196F3","start":1649115900000,"end":1649116800000,"timed":true,"long_time":true,"post_id":null,"long_term_id":1,"created_at":"2022-04-05T08:44:01.049+09:00","updated_at":"2022-04-05T08:44:01.049+09:00"},
・
・ // 250個のデータ
・
{"id":256,"name":"","color":"#2196F3","start":1670629500000,"end":1670630400000,"timed":true,"long_time":true,"post_id":null,"long_term_id":1,"created_at":"2022-04-05T08:44:02.329+09:00","updated_at":"2022-04-05T08:44:02.329+09:00"}
]
私の場合はカレンダー機能を作成していて、たくさんの予定を入れる必要がありました。データは連想配列になっています。
最初はJSONに変換してから送ろうとしていたのですが、Railsで上手く変換できなかったので配列で送ることにしました。送るときにheaderでContent-Type
を指定するとJSONを勝手に解釈してハッシュに変換してくれる機能がRailsにはありますが、ネストしている値は上手く変換してくれませんでした。(ここ気付くのに時間かかりました。)
Railsでの実際の処理
Railsでは値を取り出すのに苦労しました。
①paramsでの処理
def schedule_params
params.permit(post: [:id, :name, :start, :end, :color, :timed, :long_time, :post_id, :long_term_id])
end
post
が配列のため、permit
は使えませんでした。なのでpermitの後に直接パラメーターを記載する必要がありました。
②アクションを追加する
今回の場合、通常保存する場合(create)と、まとめて配列で大量のデータを保存する場合でアクションを分けたかったのでオリジナルのアクションを追加しました。
オリジナルアクションの追加はroutes
にmember
またはcollection
で追加できます
今回はmember
とcollection
どちらも追加したかったのでon:
を使って追加していますが、まとめて追加したい場合はブロックを使います。
一個ずつ追加
post :create_many_schedule, on: :collection
post :delete_many_schedule, on: :member
まとめて追加
member do
get 'preview'
get 'sample'
end
collection do
get 'preview'
get 'sample'
end
memberとcollectionの違い
routing
にidが付くか付かないかの違いです。
私のコードの例だとschedules
の後にid
がついているのがmember
、ついていないのがcollection
です
collection
/api/v1/schedules/create_many_schedule(.:format)
member
/api/v1/schedules/:id/delete_many_schedule(.:format)
④アクションでの処理
ここで難しかったのが、レコードを一つのまとまりとして管理する方法でした。JSから受け取った250個の値には同じIDを付与したかったのですが、やり方が分からず苦労しました。もしかしたらそういったライブラリもあるのかもしれませんが、見つけられなかったので我流で対処しました。
結局、以下の流れで値を処理しました
-taransactionを使用して250個の値の処理をした後にエラーまたは成功のレスポンスを返す。
-成功の場合は更に一番最後に登録したレコードのidに+1したものを共通の管理IDとして付与する(long_term_id)
model
def self.create_schedule(params, array)
# 送られてきた複数のイベントを保存
index = Schedule.order(created_at: :desc).limit(1).ids.sum(1)
Schedule.transaction do
params.each do |data|
schedule = Schedule.new(data)
schedule.save!
array.push(schedule)
end
# イベントにidを付与
array.each do |data|
data.long_term_id = index
data.save!
end
return array
end
end
controller
def create_many_schedule
schedule_array = []
begin
Schedule.create_schedule(schedule_params[:post], schedule_array)
render json: schedule_array, status: :created
rescue => e
render e
end
end
第一引数で受けった値(第一引数がparams、第二引数が空の配列)をeachで保存して、保存できたら第二引数の配列に保存していきます。更にその配列をeach使って値を取り出してIDを付与していきます。
これで送った複数のデータに対して同じIDを付与して管理することができました!
参考文献
2.10 RESTfulなアクションをさらに追加する
パラメーターが配列の場合、ストパラのparams.permitに含める方法
railsのroutes.rbのmemberとcollectionの違いは?
トランザクション