2013-01-23 37 views
34

Tôi đang chơi xung quanh với Rails 4.x beta và cố gắng nhận các thuộc tính lồng nhau làm việc với carrierwave. Không chắc chắn nếu những gì tôi đang làm là đúng hướng. Sau khi tìm kiếm xung quanh, và sau đó cuối cùng nhìn vào nguồn đường ray và thông số mạnh mẽ tôi tìm thấy các ghi chú bên dưới.Rails 4.0 Tham số mạnh Các thuộc tính lồng nhau với một khóa trỏ đến một băm

# 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

Vì vậy, nó nói rằng bạn phải chỉ rõ mỗi duy nhất mỗi thuộc tính duy nhất trong có, tôi đã thử sau:

Param của ví dụ:

{"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"} 

Bộ điều khiển

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

Trên đây không phải là "làm việc" (nó carrierwave không kích hoạt) tuy nhiên tôi không còn nhận được lỗi (thông số Unpermitted: filename) khi sử dụng các ví dụ lồng chuẩn mà tôi tìm thấy ví dụ:

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

Nếu bất cứ ai có thể giúp nó sẽ là tuyệt vời. Tôi đã không thể tìm thấy một ví dụ với lồng nhau với một khóa trỏ đến một băm.

Trả lời

32

Câu trả lời khác của tôi hầu hết là sai - câu trả lời mới.

trong băm params của bạn,: tên tệp không được liên kết với một băm khác, nó được liên kết với đối tượng ActiveDispatch :: Http :: UploadedFile. Dòng mã cuối cùng của bạn:

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

thực sự là chính xác, tuy nhiên, thuộc tính tên tệp không được phép vì nó không được phép là scalar types. Nếu bạn mở ra một giao diện điều khiển, và khởi tạo một đối tượng params trong tình trạng này:

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

và sau đó chạy nó chống lại dòng cuối cùng của bạn:

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

Tuy nhiên, nếu bạn làm như vậy đối với một băm params với các tập tin tải lên, bạn sẽ có được

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"=>{}}} 

Vì vậy, nó có lẽ là giá trị lỗi hoặc kéo yêu cầu Rails, và trong khi chờ đợi, bạn sẽ phải truy cập trực tiếp tham số tên tập tin bằng cách sử dụngliệuđối tượng:

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

Cảm ơn bạn đã giúp đỡ. Tôi sẽ làm, ít nhất tôi có một cách hackish xung quanh nó ngay bây giờ. – John

+0

điều này dường như vẫn là trường hợp (đối với tôi ít nhất) trong đường ray 4.0.0rc1 và nó sucks. – courtsimas

+0

Tôi đang gặp sự cố khi sử dụng carrierwave. Có tin gì không? – ctilley79

6

thử

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

Tôi có vấn đề này khoảng một tháng trước và một số tìm kiếm xung quanh đào lên giải pháp này. Nó đã được thêm vào: id hoặc: screenshot_id đã khắc phục sự cố (hoặc cả hai, tôi không thể nhớ). Điều này hoạt động trong mã của tôi mặc dù.

14

Vì vậy, bạn đang xử lý các biểu mẫu has_many và thông số mạnh.

Đây là một phần của băm params mà quan trọng:

"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"> 
} 
} 

khi bạn xác định các thông số mạnh mẽ như thế này ...

permit(:assets_attributes => [:filename]) 

Những điều phá vỡ, bởi vì nơi đường ray hy vọng một filename nó nhận được này "0"

Số đó có nghĩa là gì? Đó là số id cho nội dung bạn đang gửi qua biểu mẫu của mình. Lúc đầu, bạn có thể nghĩ rằng bạn phải làm điều gì đó như

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

Điều này có vẻ như nó tuân theo các quy ước cú pháp thông số mạnh khác. Tuy nhiên, cho tốt hơn hoặc tồi tệ hơn, họ đã làm cho mọi việc dễ dàng hơn một chút, và tất cả các bạn phải viết là:

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

Sửa - Như jpwynn chỉ ra trong các ý kiến, trong Rails 4.2.4+ cú pháp chính xác là

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

và điều đó sẽ hoạt động.

Khi bạn nhấn tường với thông số mạnh, điều tốt nhất cần làm là ném một trình gỡ lỗi trong bộ điều khiển của bạn và kiểm tra mọi thứ. params.require(:something).permit(:other_things) chỉ là một chuỗi phương pháp để bạn có thể thử những điều khác nhau trên băm params đầy đủ cho đến khi bạn tìm thấy những gì hoạt động.

+1

Trong Rails 4.2.4 ví dụ cú pháp sau phải được cho phép (: asset_attributes => [: id,: filename]) không cho phép (: asset_attributes => [: asset_id,: filename]), ví dụ tên model không phải là tiền tố trước 'id' – jpwynn

4

Thực tế có một cách để chỉ danh sách trắng tất cả các tham số lồng nhau.

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

Phương pháp này có lợi thế hơn các giải pháp khác. Nó cho phép cho phép tham số lồng sâu.

Trong khi các giải pháp khác như:

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

Đừng.


Nguồn:

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

+1

Vâng, ngoài ra, giải pháp này là tốt đẹp nếu bạn đã có 50 trường trên một đối tượng nhất định, theo cách tôi làm. Duy trì một danh sách các attrs để danh sách trắng mà rất lớn là khá khó chịu nếu bạn không thực sự có vấn đề "tiếp xúc" lớn để lo lắng về. – bwest87

+0

Điều này đánh bại mục đích an toàn của các tham số mạnh mẽ hoàn toàn. – jrochkind

0

tôi đã cùng một vấn đề chỉ có nó cố định bây giờ tất cả bạn phải làm là

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

Sử dụng nâng lên đá quý để xem những loại thuộc tính của bạn đối tượng tài sản đã làm cho chắc chắn theres một id và thêm thuộc tính còn thiếu, mà sau đó nên làm việc hoàn hảo. Đang sử dụng tài sản kẹp giấy là vật lồng trong lớp xe và phần đính kèm hình ảnh được thêm vào nội dung đó. chắc chắn rằng bạn làm xác nhận trong mô hình

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

Trong vòng tầm nhìn của bạn thông qua các tài sản để có được mỗi hình ảnh

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

Nếu am sửa vấn đề của bạn là asset_attributes là một mảng với mỗi hình ảnh có cột chỉ mục và hình ảnh

Biểu mẫu của bạn nên có thứ gì đó tương tự như vậy và nếu bạn muốn bạn cũng có thể bao gồm bản xem trước để tải lên có thể xem hình ảnh của họ sử dụng mã dưới cùng cho số

<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

Vệ sinh trước khi lưu trong bộ điều khiển Vệ sinh accept_nested_attributes_for thuộc tính có chỉ mục.

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 
Các vấn đề liên quan