🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

Q&A

解決済

2回答

2687閲覧

Railsのupdate_allを使ってSQLの発行回数を抑えてデータを一括更新したい

im05ttbbh

総合スコア18

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

0グッド

0クリップ

投稿2021/02/20 08:35

前提・実現したいこと

Railsのupdate_allを使ってSQLの発行回数を抑えてデータを一括更新したい。
具体的には、更新予定のIDを配列で受け取り、Attributeであるitem_group_idを一括で変更したい。

発生している問題・エラーメッセージ

以下のようなエラーメッセージと共にデータが更新できない。

ExampleItemsController::error_json no implicit conversion of Hash into String

該当のソースコード

【example_items_controller.rb】

Ruby

1 def update 2 ids = params[:example_item]&.[]("update_ids") 3 ExampleItem.where(id: ids).update_all(update_params.except(:update_ids)) 4 end 5 6 private 7 8 def update_params 9 params.require(:example_item).permit( 10 :item_group_id, update_ids: [] 11 ) 12 end

【パラメーター】

Processing by ExampleItemsController#update as JSON Parameters: {"example_item"=>{"update_ids"=>["1", "2", "3"], "item_group_id"=>"2"}}

試したこと

①update_allではなくupdateを使用

これで更新自体はできましたが、update_ids一つ一つを更新するSQLの為、『少ないSQLでのデータ一括更新』は実現できませんでした。

②パラメーターをJSONに変換

参考記事
↑等を参照に、RailsのHashをJSONにパースする必要があるのでは?と考え、

Ruby

1 def update 2 ids = params[:example_item]&.[]("update_ids") 3 ExampleItem.where(id: ids).update_all(JSON.parse(update_params.except(:update_ids))) 4 end

とするも、全く同じエラーになり一括更新が出来ませんでした。
ExampleItemsController::error_json no implicit conversion of ActionController::Parameters into String

③ストロングパラメーターを使わずにデータを更新

以下のようにストロングパラメーターを使用しないで実装するとupdate_allで更新できましたが、今後item_group_id以外も更新することがあればその度に処理を追加しなければならないので、ストロングパラメーターを定義したいと考えております。

【example_items_controller.rb】

Ruby

1 def update 2 ids = params[:example_item]&.[]("update_ids") 3 ExampleItem.where(id: ids).update_all(item_group_id: params[:example_item]&.[]("item_group_id")) 4 end

ご教示いただきたいこと

  • リストメソッドはupdate_allを使用
  • ストロングパラメーターを定義

以上の2つの条件を満たした上で、
『更新予定のIDを配列で受け取り、Attributeであるitem_group_idを一括で変更したい。』
について、ご教示いただけませんでしょうか。

お手数をおかけし大変恐縮ですが、何卒宜しくお願い申し上げます。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

なんか複雑にしている。。。
def update ids = params[:example_item][:update_ids] ExampleItem.where(id: ids).update_all(item_group_id: params[:example_item][:item_group_id]) end
この場合のようにどの項目を変更するのかを明示的に指定する場合はstrong paramater は不要です。
もしどうしても使いたいなら
update_params params.require(:example_item).permit(:item_group_id) end
として update_all(update_params)

`

投稿2021/02/20 11:42

winterboum

総合スコア23567

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

im05ttbbh

2021/02/20 12:38

ご回答頂きありがとうございます!! おっしゃる通り今回は設定は不要かもしれません。ストロングパラメーターの意義を正しく理解できておりませんでした。今一度勉強し直したいと思います。 一応ストロングパラメーターを実装(idsは記載せずに)してupdate_allで処理したところ、やはり error_json no implicit conversion of Hash into String のエラーが出て更新できませんでした。 このエラーは昨日から調べて出る情報をいくつか実践するも中々解決できず、質問で記載したコード以外に原因があるかもしれないので、調査の上、ストロングパラメーター無しの方向で進めたいと思います。
winterboum

2021/02/20 13:26

json? JSON変換なし、ですよ、私の解は
im05ttbbh

2021/02/20 22:55

何度もご返信いただく形になり申し訳ございません。 JSONparseも記載を外しましたがこのエラーが出ました。 また、 Processing by ExampleItemsController#update as JSON Parameters: {"example_item"=>{"update_ids"=>["1", "2", "3"], "item_group_id"=>"2"}} とパラメーターをセットしていましたが、as JSONの部分をas HTMLで送信してみても結果は変わらずです。 こちらのアプリがフロントはReactで動いているのでパラメーターのセット側に何か問題があるかもしれないので、それを含めて調査するということでした。お忙しい中、ご回答をいただき誠に有難うございます。
winterboum

2021/02/20 23:28

view の <%= form_なんたら のところ、 local: true とか remote: false とかしてありますか?
im05ttbbh

2021/02/21 11:07

返信が遅れ申し訳ありません。 フロントのフォームとPostAPIはReactで実装しているので、<%= form %>を使ってるないです。なのでReactのコードに問題があるかもしれません。 そういう意味では、フロントバックでどちらに原因があるか特定できていないまま質問してしまっておりました。申し訳ありません。
winterboum

2021/02/21 12:00

ああ、そうすると以下の情報ください。 APIからのリクエストの時の Started からエラーで終わるまでの log
im05ttbbh

2021/02/21 22:26

有難うございます、ログは以下になります。SQL分は質問用にモデル名等を単純化していたので、『====』で記載しております。 お手数おかけし恐縮ですが、何卒宜しくお願い申し上げます。 app_1 | Started PATCH "/example_items/update" for XXX.XX.X.X at 2021-02-22 07:19:04 +0900 app_1 | Cannot render console from XXX.XX.X.X! Allowed networks: XXX.X.X.X, ::X, XXX.X.X.X/XXX.XXX.XXX.XXX =============SQL分============= app_1 | Processing by ExampleItemsController#update as HTML app_1 | Parameters: {"example_item"=>{"update_ids"=>["17", "16", "15"], "item_group_id"=>"2"}} app_1 | Unpermitted parameter: :update_ids app_1 | Completed 500 Internal Server Error in 677ms (ActiveRecord: 39.5ms) app_1 | app_1 | app_1 | app_1 | TypeError (no implicit conversion of Hash into String): app_1 | app_1 | app/controllers/example_items_controller.rb:79:in `update'
winterboum

2021/02/21 22:57

SQL全体省略では。。。 wher部は===でもよいですが。。。 このlogの時の 79行目ってどんなのでしょう Unpermitted parameter: :update_ids が出てくるのが??? 以下にしてますか? その結果としての UPDATE が無いのが??なのです。 ids = params[:example_item][:update_ids] ExampleItem.where(id: ids).update_all(item_group_id: params[:example_item][:item_group_id])
im05ttbbh

2021/02/23 22:01 編集

SQLも必要ですよね。。失礼いたしました。貼り直します。 後述しますが、Unpermitted parameter: :update_idsは解消した上でのログを記載しております。 【as HTMLで送信】 app_1 | Started PATCH "/example_items/update" for XXX.XX.X.X at 2021-02-22 08:23:45 +0900 app_1 | Cannot render console from XXX.XX.X.X! Allowed networks: XXX.X.X.X, ::X, XXX.X.X.X/XXX.XXX.XXX.XXX app_1 | Processing by ExampleItemsController#update as HTML app_1 | Parameters: {"example_item"=>{"update_ids"=>["17", "16", "15"], "item_group_id"=>"2"}} app_1 | app_1 | TypeError (no implicit conversion of Hash into String): app_1 | app_1 | app/controllers/example_items_controller.rb:79:in `update' 【as JSONで送信】 app_1 | Started PATCH "/example_items/update.json" for XXX.XX.X.X at 2021-02-22 08:33:43 +0900 app_1 | Cannot render console from XXX.XX.X.X! Allowed networks: XXX.X.X.X, ::X, XXX.X.X.X/XXX.XXX.XXX.XXX app_1 | Processing by ExampleItemsController#update as JSON app_1 | Parameters: {"example_item"=>{"update_ids"=>["53", "52", "51"], "item_group_id"=>"1"}} app_1 | app_1 | TypeError (no implicit conversion of Hash into String): app_1 | app_1 | app/controllers/example_items_controller.rb:79:in `update' 【現在の状況】 いただいたコードの ids = params[:example_item][:update_ids] ExampleItem.where(id: ids).update_all(item_group_id: params[:example_item][:item_group_id]) ですと成功します。そちらお伝えできておりませんでした。申し訳ありません。 今失敗しているのが、今後item_group_idにも更新項目が増えてストロングパラメーターで実装が必要になった時のためにストロングパラメーターで実装しようとすると、うまく行かないということです。 コードとしては以下の実装になります。 ==================================== def update ids = params[:example_item][:update_ids] ExampleItems.where(id: ids).update_all(update_params) end private def update_params params.require(:example_item).permit( :item_group_id ) end ==================================== ちなみにUnpermitted parameter: :update_idsは、以下に変更すると解消されます。 ==================================== def update ids = params[:example_item][:update_ids] ExampleItems.where(id: ids).update_all(update_params.except(:update_ids)) end private def update_params params.require(:example_item).permit( :item_group_id, update_ids: [] ) end ==================================== その上でるエラが、 app_1 | TypeError (no implicit conversion of Hash into String): という状況です。 整理してお伝えできておらず、申し訳ありませんでした。
winterboum

2021/02/22 04:15

app_1 | app/controllers/example_items_controller.rb:79:in `update' の79行ってどの行ですか
im05ttbbh

2021/02/22 04:31

def update ids = params[:example_item][:update_ids] ExampleItems.where(id: ids).update_all(update_params.except(:update_ids)) end ↑こちらです。
im05ttbbh

2021/02/22 04:33 編集

先程まで間違えて def bulk_update ids = params[:example_item][:update_ids] ExampleItems.where(id: ids).update_all(update_params.except(:update_ids)) end にしてしまっていましたが、修正しました。正しくはdef update〜、でエラー該当箇所もそのメソッドです。紛らわしく申し訳ありません。
im05ttbbh

2021/02/22 04:53 編集

def update_params params.require(:example_item).permit( :item_group_id ).to_hash end としたらupdate_allが通りました!rubyのhashとして認識されていなかったようです。 これで解決なのかはっきりしていないので引き続き調査します!ありがとうございます。
guest

0

winterboum様のご回答を参考に以下の実装で通りました。
誠に有難うございました。

【①ストロングパラメーターを使わない場合】

Ruby

1def update 2 ids = params[:example_item][:update_ids] 3 ExampleItem.where(id: ids).update_all(item_group_id: params[:example_item][:item_group_id]) 4end

【②ストロングパラメーターを使う場合】

Ruby

1def update 2 ids = update_params["update_ids"] 3 ExampleItem.where(id: ids).update_all(update_params.except("update_ids").to_hash) 4end 5 6private 7 8def update_params 9 params.require(:example_item).permit( 10 :item_group_id, update_ids: [] 11 ) 12end

↓等も参照にし、
参照
update_allとストロングパラメーターを併用する場合には
error_json no implicit conversion of ActionController::Parameters into String
というエラーが出るのでこちらで型指定をする必要があると理解しました。

ただ
update_params.except(:update_ids)
と無理やり実装している感も否めないので、今回の場合は①での実装が望ましいのではないかと思いました。

あとストロングパラメーターのpermit以降へのアクセスは
update_params[:update_ids]
だとエラーが出たので、
update_params["update_ids"]
とクオーテーションで括ることでアクセスできました。

投稿2021/02/22 22:48

im05ttbbh

総合スコア18

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問