web-dev-qa-db-ja.com

Rails-空の配列を持つ強力なパラメータ

アソシエーションIDの配列をfoo_idsとコントローラーに送信します。値の配列を許可するには、以下を使用します。

params.permit(foo_ids: [])

ここでの問題は、foo_idsの空の配列を送信すると、パラメーターが無視されることです。空の配列のようにすべてのfoosをクリアする代わりに、foo_idsが許可されていないため、関連付けはそのままになります。

空の配列はRailsでnilに変換される であり、強いパラメーターは単一のスカラー値ではなくスカラー値の配列を探しているため、そのnil値は無視されます。

誰かがこれを解決する良い方法を提案できますか?ありがとう!

追加情報

コントローラー更新アクションでは、2つのケースを処理できる必要があります。 foo_idsを空の配列に設定できるようにする必要があります。別のフィールドを更新するだけの場合は、foo_idsを無視できるようにする必要もあります。この2番目のケースでnilが機能しない場合は、foo_idsを空の配列に設定します。

38
Rahul Sekhar

私が降りてきた一時的な解決策は:

params[:foo_ids] ||= [] if params.has_key?(:foo_ids)
params.permit(foo_ids: [])

ここに、 foo_idsは、渡された場合にのみ空の配列に設定されます。リクエストで渡されない場合は無視されます。

この種のことは私が取り組んでいるプロジェクトではかなり一般的であるため、私はまだこれに対するより良い解決策を見つけたいと思っています-もしあれば、より良いアイデアを提案してください。

19
Rahul Sekhar

これはかなり遅いですが、自分でこの問題を抱えていました。以下のように、permitステートメントにスカラーバージョンと配列バージョンの両方を含めることで解決しました。

params.require(:photo).permit(:tags, tags: [])

参考までに-同じhasを同じ許可ステートメントに含める必要があります-チェーンすると、何らかの理由でスローされます。

編集:私はこのメソッドを介して送信された空の配列がnilに変わることに気づきました-私はnilである空の配列であるべきフィールドの束を手に入れました。したがって、私が投稿したソリューションは実際には機能しません。

2番目の編集:私はこれを既に追加したと思ったが、この問題はRails paramsハッシュでdeep_mungeを実行することに関連しています。このコメントはそれを修正する方法を説明します: https:// stackoverflow .com/a/25428800/130592

32
Nathan

このソリューションは、すべての場合に機能するわけではありません。

params.require(:photo).permit(:tags, tags: [])

たとえば、MongoDBを使用していて、has_manyコレクションにIDを格納するtag_ids配列がある場合、モデルの属性に「type:Array」を指定する場合、tag_ids属性は配列でなければなりません。したがって、これを行ったとしても、nil値を含むtag_idを送信することはできません。

 params.require(:photo).permit(:tag_ids, tag_ids: [])

モンゴイド、公式のRubyアダプタ)はtag_idsの値が配列でなければならないという文句を言うでしょう。

解決策は、フォームを介して空の配列を送信できることです。そして、それはjsonリクエストである必要はありません。フォームで単にremote:trueを使用して、type::jsで送信できます。どうやってするの?シンプル。フォームに非表示の入力を追加し、その値を空の文字列に設定するだけです。

<%= form_for @user, remote: true, html: { class: 'form' } do |f| %>
  <%= select_tag("#{f.object_name}[tag_ids][]", options_for_select(Tag.all.collect {|t| [t.name, c.id]}, selected: f.object.tag_ids), { class: 'form-control', multiple: 'multiple' }) %>
  <%= hidden_field_tag "#{f.object_name}[tag_ids][]", '' %>
  <%= f.submit class: 'btn ink-reaction btn-raised btn-primary' %>
<% end %>

これが鍵です:

<%= hidden_field_tag "#{f.object_name}[tag_ids][]", '' %>

属性は空の配列としてデータベースに保存されます。注意:これはMongoidでのみテストしましたが、ActiveRecordでも同じ機能を実行すると想定しています。

0
Donato

最近同じ問題が発生しましたが、ここでの答えはどれもうまくいきませんでした。これが私の解決策です。 HTTPリクエストを処理するJavaScriptがある場合、これもうまくいくかもしれません。

クライアント側:

if (photo.tags.length === 0){
  photo.tags = ["null"]
}

そしてあなたのPhotosControllerに

def photo_params
  p = params.require(:photo).permit(tags: [])
  p["tags"].reject! { |tag| tag == "null" }
  p
end
0
sung