ruby on rails - permit - Rails 4.0 Strong Parameters anidados atributos con una clave que apunta a un hash
rails permit param (6)
Estaba jugando con Rails 4.x beta y tratando de obtener atributos anidados trabajando con carrierwave. No estoy seguro de si lo que estoy haciendo es la dirección correcta. Después de buscar, y luego mirar la fuente de los rieles y los parámetros fuertes, encontré las notas a continuación.
# 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.
Por lo tanto, es necesario especificar cada uno de los atributos del archivo has, intenté lo siguiente:
Ejemplo de 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"}
Controlador
def screenshot_params
params.require(:screenshot).permit(:title,
:assets_attributes => [:filename => [:@tempfile,:@original_filename,:@content_type,:@headers]
Lo anterior no está "funcionando" (no activando carrierwave), pero ya no recibo errores (parámetros no permitidos: nombre de archivo) cuando uso los ejemplos anidados estándar que encontré ex:
def screenshot_params
params.require(:screenshot).permit(:title, assets_attributes: :filename)
Si alguien pudiera ayudar, sería genial. No pude encontrar un ejemplo anidado con una clave que apunta a un hash.
Desinfecte antes de guardar en el controlador Sanitize accepts_nested_attributes_for attributes with index.
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
En realidad, hay una manera de simplemente listar todos los parámetros anidados.
params.require(:screenshot).permit(:title).tap do |whitelisted|
whitelisted[:assets_attributes ] = params[:screenshot][:assets_attributes ]
end
Este método tiene una ventaja sobre otras soluciones. Permite permitir parámetros anidados profundos.
Mientras que otras soluciones como:
params.require(:screenshot).permit(:title, :assets_attributes => [:filename, :id, :screenshot_id])
No lo hagas
Fuente:
https://github.com/rails/rails/issues/9454#issuecomment-14167664
Entonces, estás tratando con has_many forms y fuertes parámetros.
Esta es la parte del hash de params que importa:
"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">
}
}
cuando defines parámetros fuertes como este ...
permit(:assets_attributes => [:filename])
Las cosas se rompen, porque donde los rails esperan un filename
, está obteniendo este "0"
¿Qué significa ese número? Es la id
del activo que está enviando a través de su formulario. Ahora, inicialmente, podrías pensar que tienes que hacer algo como
permit(:assets_attributes => [:id => [:filename]])
Parece que sigue otras convenciones de sintaxis de parámetros fuertes. Sin embargo, para bien o para mal, han hecho las cosas un poco más fáciles, y todo lo que tiene que escribir es:
permit(:assets_attributes => [:asset_id, :filename])
Editar - Como jpwynn señaló en los comentarios, en Rails 4.2.4+ la sintaxis correcta es
permit(:assets_attributes => [:id, :filename])
y eso debería funcionar
Cuando llegue a las paredes con params fuertes, lo mejor que puede hacer es lanzar un depurador en su controlador y probar cosas. params.require(:something).permit(:other_things)
es solo una cadena de métodos para que pueda probar diferentes cosas en el hash de params completo hasta que encuentre lo que funciona.
Mi otra respuesta fue en su mayoría incorrecta, nueva respuesta.
en su parámetro hash, el nombre de archivo no está asociado con otro hash, está asociado con un objeto ActiveDispatch :: Http :: UploadedFile. Su última línea de código:
def screenshot_params
params.require(:screenshot).permit(:title, assets_attributes: :filename)
es en realidad correcto, sin embargo, no se permite el atributo de nombre de archivo ya que no es uno de los tipos escalares permitidos. Si abre una consola e inicializa un objeto params con esta forma:
params = ActionController::Parameters.new screenshot: { title: "afa", assets_attributes: {"0" => {filename: ''a string''}}}
y luego ejecutarlo contra tu última línea:
p = params.require(:screenshot).permit(:title, assets_attributes: :filename)
# => {"title" => "afa", "assets_attributes"=>{"0"=>{"filename"=>"abc"}}}
Sin embargo, si haces lo mismo contra un hash de params con el archivo cargado, obtienes
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"=>{}}}
Por lo tanto, es probable que valga la pena solicitar un error o extracción a Rails, y mientras tanto, tendrá que acceder directamente al parámetro de nombre de archivo utilizando el objeto raw params
:
params[:screenshot][:assets_attributes]["0"][:filename]
Tuve el mismo problema, lo arreglé ahora, todo lo que tienes que hacer es
params.require(:vehicle).permit(:user_id, assets_attributes: [:id, :image]).
Usa la gema de palanca para ver qué tipo de atributos tiene tu objeto activo para asegurarte de que tiene una identificación y agrega otro atributo que falta, que luego debería funcionar perfectamente. Estoy utilizando elementos de clip para papeles como mi objeto anidado dentro de la clase de vehículo y se agrega un archivo adjunto de imágenes al activo. asegúrese de hacer la validación en el modelo
accepts_nested_attributes_for :assets, allow_destroy: true
validates_attachment_content_type :image, content_type: //Aimage//.*/Z/
En su vista, recorra el activo para obtener cada imagen
<%= @vehicle.assets.size %>
<% for asset in @vehicle.assets %>
<%=link_to image_tag (asset.image.url(:thumb)) %>
<% end %>
Si estoy en lo correcto, su problema es que asset_attributes es una matriz con cada imagen con una columna de índice y una imagen
Su form_for debería tener algo similar a esto y, si lo desea, también puede incluir una vista previa para que la carga pueda ver sus imágenes, use el código inferior para ese
<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>
tratar
def screenshot_params
params.require(:screenshot).permit(:title, :assets_attributes => [:filename, :id, :screenshot_id])
end
Tuve este problema hace aproximadamente un mes y algunos buscaron esta solución. Estaba agregando: id o: screenshot_id que resolvió el problema (o ambos, no recuerdo). Esto funciona en mi código sin embargo.