2013-01-23 27 views
34

私はRails 4.xベータで遊んでいて、carrierwaveで動作するネストされた属性を取得しようとしていました。私がやっていることが正しい方向であるかどうかは分かりません。周りを探索した後、最終的にレールのソースと強力なパラメータを見て、私は以下のノートを見つけました。Rails 4.0 Strong Parametersハッシュを指すキーを持つネストされた属性

のParamの例:

{"utf8"=>"✓", 
"authenticity_token"=>"Tm54+v9DYdBtWJ7qPERWzdEBkWnDQfuAQrfT9UE8VD=", 
"screenshot"=>{ 
    "title"=>"afs", 
    "assets_attributes"=>{ 
    "0"=>{ 
     "filename"=>#<ActionDispatch::Http::UploadedFile:0x00000004edbe40 
         @tempfile=#<File:/tmp/RackMultipart20130123-18328-navggd>, 
         @original_filename="EK000005.JPG", 
         @content_type="image/jpeg", 
         @headers="Content-Disposition: form-data; name=\"screenshot[assets_attributes][0][filename]\"; filename=\"EK000005.JPG\"\r\nContent-Type: image/jpeg\r\n"> 
    } 
    } 
}, 
"commit"=>"Create Screenshot"} 

# Note that if you use +permit+ in a key that points to a hash, 
# it won't allow all the hash. You also need to specify which 
# attributes inside the hash should be whitelisted. 

https://github.com/rails/rails/blob/master/actionpack/lib/action_controller/metal/strong_parameters.rb

だから、あなたが持っている内のすべての単一のすべての単一の属性を指定する必要がありますと言って、私は次のことを試してみましたその

コントローラ

def screenshot_params 
    params.require(:screenshot).permit(:title, 
    :assets_attributes => [:filename => [:@tempfile,:@original_filename,:@content_type,:@headers] 

上記の「作業」されていません(そのトリガーないcarrierwave)しかし、私はもはや取得していますエラー(許可されていないパラメータ:ファイル名)の標準的なネストされた例を使用しているとき、私は元が見つかりました:

def screenshot_params 
    params.require(:screenshot).permit(:title, assets_attributes: :filename) 

もし誰かがそれを助けることができたらそれはすばらしいことだ。私は、ハッシュを指し示すキーを入れ子にした例を見つけることができませんでした。

答えて

32

私の他の答えはほとんど間違っていました - 新しい答えです。

あなたのparamsハッシュでは、:filenameは別のハッシュに関連付けられていないため、ActiveDispatch :: Http :: UploadedFileオブジェクトに関連付けられています。あなたの最後のコード行:

def screenshot_params 
    params.require(:screenshot).permit(:title, assets_attributes: :filename) 

はそれが許されscalar typesの一つではないので、しかし、filename属性が許可されていない、実際には正しいです。コンソールを開き、そしてこの形でのparamsオブジェクトを初期化する場合:その後、

params = ActionController::Parameters.new screenshot: { title: "afa", assets_attributes: {"0" => {filename: 'a string'}}} 

とあなたの最後の行に対してそれを実行します。

p = params.require(:screenshot).permit(:title, assets_attributes: :filename) 
# => {"title" => "afa", "assets_attributes"=>{"0"=>{"filename"=>"abc"}}} 

しかし、あなたはparamsハッシュに対して同じことをしている場合アップロードされたファイルで、あなたはそう

upload = ActionDispatch::Http::UplaodedFile.new tempfile: StringIO.new("abc"), filename: "abc" 
params = ActionController::Parameters.new screenshot: { title: "afa", assets_attributes: {"0" => {filename: upload}}} 
p = params.require(:screenshot).permit(:title, assets_attributes: :filename) 

# => {"title" => "afa", "assets_attributes"=>{"0"=>{}}} 

を取得し、それはおそらくバグの価値があるかのRailsに要求を引き出し、そしてその間に、あなたは直接生を使用して、ファイル名パラメータにアクセスする必要がありますオブジェクト:

params[:screenshot][:assets_attributes]["0"][:filename] 
+0

もう一度お手数をおかけください。私はやります、少なくとも、私は今、それを取り巻く馬鹿げた方法を持っています。 – John

+0

これはまだレール4.0.0rc1の場合(少なくとも私にとっては)そうであると思われます。 – courtsimas

+0

私はcarrierwaveを使用しているときにこれに問題があります。連絡あった? – ctilley79

6

は、私は1ヶ月前、この問題を持っていたし、いくつかの検索が周りにこのソリューションを掘っ

def screenshot_params 
    params.require(:screenshot).permit(:title, :assets_attributes => [:filename, :id, :screenshot_id]) 
end 

を試してみてください。これは、問題を修正した:idまたは:screenshot_idを追加していた(または両方、私は覚えていない)。しかし、これは私のコードで動作します。

14

したがって、has_manyフォームと強力なパラメータを扱っています。

この

は重要paramsハッシュの一部です:

あなたはこのような強力なパラメータを定義
"assets_attributes"=>{ 
    "0"=>{ 
      "filename"=>#<ActionDispatch::Http::UploadedFile:0x00000004edbe40 
        @tempfile=#<File:/tmp/RackMultipart20130123-18328-navggd>, 
        @original_filename="EK000005.JPG", 
        @content_type="image/jpeg", 
        @headers="Content-Disposition: form-data; name=\"screenshot[assets_attributes][0][filename]\"; filename=\"EK000005.JPG\"\r\nContent-Type: image/jpeg\r\n"> 
} 
} 

...レールがfilenameを期待どこので

permit(:assets_attributes => [:filename]) 

物事休憩、それはなってきましたこの"0"

この数字は何を意味していますか?フォーム経由で送信するアセットのidです。今、最初にあなたはそれが他の強いパラメータの構文規則を次のようにこれが見えます

permit(:assets_attributes => [:id => [:filename]]) 

ような何かをしなければならないと思うかもしれません。しかし、良くも悪くものために、彼らは物事が少し楽になりました、そしてあなたが書かなければならないすべては、次のとおりです。

permit(:assets_attributes => [:asset_id, :filename]) 

編集 - jpwynnとしてのRailsで、コメントで指摘4.2.4+正しい構文は

permit(:assets_attributes => [:id, :filename]) 

です。

強力なパラメータで壁を打つときは、コントローラにデバッガを投げて試してみるのが一番です。 params.require(:something).permit(:other_things)はちょうどメソッド連鎖にすぎないので、何が動作するかを見つけるまで、完全なparamsハッシュに対してさまざまなことを試すことができます。

+1

Rails 4.2.4では、後者の構文例はpermit(:assets_attributes => [:id、:filename])は許可されません(:assets_attributes => [:asset_id、:filename])。 'id'の前に接頭辞が付きません – jpwynn

4

実際には、ネストされたすべてのパラメータをホワイトリストにする方法があります。

params.require(:screenshot).permit(:title).tap do |whitelisted| 
    whitelisted[:assets_attributes ] = params[:screenshot][:assets_attributes ] 
end 

この方法は、他のソリューションよりも優れています。 ディープネストされたパラメータを許可することができます。以下のような他のソリューション

中:

params.require(:screenshot).permit(:title, :assets_attributes => [:filename, :id, :screenshot_id]) 

にはありません。ソース


:私は同じ問題を抱えていた

https://github.com/rails/rails/issues/9454#issuecomment-14167664

+1

特定のオブジェクトに50個のフィールドがあるようなら、このソリューションは素晴らしい方法です。その巨大なホワイトリストにattrsのリストを維持することは、あなたが本当に心配する主要な「エクスポージャー」の問題を持っていなければ、かなり面倒です。 – bwest87

+0

これは、強力なパラメータのセキュリティ目的を完全に破ります。 – jrochkind

0

はちょうどそれが今、あなたがしなければならないすべては

params.require(:vehicle).permit(:user_id, assets_attributes: [:id, :image]). 

使用てこ宝石は種類の属性がものを見るためにある固定だあなた資産オブジェクトはidを確実に識別し、他の欠落した属性を追加します。その属性は完全に機能するはずです。 ペーパークリップアセットを使用しているのは、車両クラス内のネストされたオブジェクトで、画像の添付ファイルがアセットに追加されます。 は午前が正しければ、あなたの問題はasset_attributesがそれぞれ有する画像を持つ配列であるということであるあなたは、各画像

<%= @vehicle.assets.size %> 
    <% for asset in @vehicle.assets %> 
     <%=link_to image_tag (asset.image.url(:thumb)) %> 
    <% end %> 

を取得するために、モデル資産を通して、あなたの視野ループで

accepts_nested_attributes_for :assets, allow_destroy: true 
validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/ 

に検証を行うことを確認してくださいインデックスの列と画像

あなたのform_forはこれに類似しているはずです。もしあなたが望むならば、アップロードが画像を見ることができるようにプレビューを含めることもできます。

<div class="field"> 
    <h3>Vehicle Image Upload</h3> 
    <%= f.fields_for :assets do |asset_fields| %> 

     <% if asset_fields.object.new_record? %> 
      <p> 
       <%= asset_fields.file_field :image %> 
      </p> 
     <% end %> 
    <% end %> 
</div> 

<div class="field"> 
    <h4>Vehicle Image</h4> 
    <%= f.fields_for :assets do |asset_fields| %> 

     <% unless asset_fields.object.new_record? %> 
      <%= link_to image_tag(asset_fields.object.image.url(:thumb)), 
        asset_fields.object.image.url(:original)%> 
      <%= asset_fields.check_box :_destroy %> 
     <% end %> 
    <% end %> 
</div> 
0

コントローラで保存する前にサニタイズしてください。サニタイズは、インデックス付き属性を受け入れる_nested_attributes_forです。

before_action :sanitize_fields_params, :only => [:create, :update] 

def sanitize_fields_params 

    product_free_shippings_attributes = params[:product][:product_free_shippings_attributes] 

    product_free_shippings_attributes.each do |index, key_value| 
     params[:product][:product_free_shippings_attributes]["#{index}"][:weight] = clear_decimal(key_value[:weight]) 
     params[:product][:product_free_shippings_attributes]["#{index}"][:height] = clear_decimal(key_value[:height]) 
     params[:product][:product_free_shippings_attributes]["#{index}"][:width] = clear_decimal(key_value[:width]) 
     params[:product][:product_free_shippings_attributes]["#{index}"][:depth] = clear_decimal(key_value[:depth]) 
    end 
end 

def clear_decimal(field) 
    return (field.to_s.gsub(/[^\d]/, '').to_d/100.to_d) unless field.blank? 
    end