Je jouais avec la version bêta de Rails 4.x et essayais de faire fonctionner les attributs imbriqués avec carrierwave. Je ne sais pas si ce que je fais est la bonne direction. Après avoir cherché autour de nous, puis finalement examiné la source Rails et les paramètres importants, j'ai trouvé les notes ci-dessous.
# 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.
Donc, il faut dire que vous devez spécifier chaque attribut au sein du has, j'ai essayé ce qui suit:
Exemple 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"}
Manette
def screenshot_params
params.require(:screenshot).permit(:title,
:assets_attributes => [:filename => [:@tempfile,:@original_filename,:@content_type,:@headers]
Ce qui précède ne fonctionne pas (il ne déclenche pas carrierwave), mais je ne reçois plus d'erreurs (paramètres non autorisés: nom de fichier) lorsque j'utilise les exemples imbriqués standard que j'ai trouvés, par exemple:
def screenshot_params
params.require(:screenshot).permit(:title, assets_attributes: :filename)
Si quelqu'un pouvait aider, ce serait génial. Je n'ai pas été en mesure de trouver un exemple avec imbriqué avec une clé qui pointe vers un hachage.
Mon autre réponse était la plupart du temps erronée - nouvelle réponse.
dans votre hachage params,: nomfichier n'est pas associé à un autre hachage, il est associé à un objet ActiveDispatch :: Http :: UploadedFile. Votre dernière ligne de code:
def screenshot_params
params.require(:screenshot).permit(:title, assets_attributes: :filename)
est en fait correct, cependant, l’attribut filename n’est pas autorisé car il ne s’agit pas d’un des types autorisés scalar . Si vous ouvrez une console et initialisez un objet params sous cette forme:
params = ActionController::Parameters.new screenshot: { title: "afa", assets_attributes: {"0" => {filename: 'a string'}}}
puis lancez-le contre votre dernière ligne:
p = params.require(:screenshot).permit(:title, assets_attributes: :filename)
# => {"title" => "afa", "assets_attributes"=>{"0"=>{"filename"=>"abc"}}}
Cependant, si vous faites la même chose avec un hachage params avec le fichier téléchargé, vous obtenez
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"=>{}}}
Donc, il vaut probablement la peine de demander un bogue ou une requête d'extraction à Rails, et entre temps, vous devrez accéder directement au paramètre filename à l'aide de l'objet raw params
:
params[:screenshot][:assets_attributes]["0"][:filename]
Donc, vous avez affaire à de nombreuses formes has_ et de nombreux paramètres.
C'est la partie du hachage params qui compte:
"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">
}
}
quand vous définissez des paramètres forts comme celui-ci ...
permit(:assets_attributes => [:filename])
Les choses se cassent, parce que quand Rails s'attend à une filename
, il obtient ce "0"
Qu'est-ce que ce nombre signifie? Il s'agit de la id
de l'actif que vous soumettez via votre formulaire. Maintenant, au début, vous pourriez penser que vous devez faire quelque chose comme
permit(:assets_attributes => [:id => [:filename]])
Cela semble suivre les autres conventions de syntaxe de paramètres forts. Cependant, pour le meilleur et pour le pire, ils ont rendu les choses un peu plus faciles, et tout ce que vous avez à écrire est:
permit(:assets_attributes => [:asset_id, :filename])
Edit - Comme jpwynn a été souligné dans les commentaires, dans Rails 4.2.4+, la syntaxe correcte est
permit(:assets_attributes => [:id, :filename])
et cela devrait fonctionner.
Lorsque vous frappez des murs avec des paramètres puissants, la meilleure chose à faire est de lancer un débogueur dans votre contrôleur et de tester les choses. params.require(:something).permit(:other_things)
est juste une chaîne de méthodes vous permettant d’essayer différentes choses sur le hash complet de params jusqu’à ce que vous trouviez ce qui fonctionne.
essayer
def screenshot_params
params.require(:screenshot).permit(:title, :assets_attributes => [:filename, :id, :screenshot_id])
end
J'ai eu ce problème il y a environ un mois et certaines recherches ont permis de découvrir cette solution. L'ajout de: id ou screenshot_id a résolu le problème (ou les deux, je ne me souviens plus). Cela fonctionne dans mon code cependant.
En fait, il existe un moyen de simplement mettre en liste blanche tous les paramètres imbriqués.
params.require(:screenshot).permit(:title).tap do |whitelisted|
whitelisted[:assets_attributes ] = params[:screenshot][:assets_attributes ]
end
Cette méthode présente un avantage par rapport aux autres solutions. Il permet d'autoriser des paramètres imbriqués en profondeur.
Alors que d'autres solutions comme:
params.require(:screenshot).permit(:title, :assets_attributes => [:filename, :id, :screenshot_id])
Ne pas.
La source:
https://github.com/Rails/rails/issues/9454#issuecomment-14167664
J'ai eu le même problème vient de le réparer maintenant tout ce que vous avez à faire est
params.require(:vehicle).permit(:user_id, assets_attributes: [:id, :image]).
Utilisez pry gem pour voir le type d'attribut que votre objet d'actif a pour vous assurer qu'il possède un identifiant et ajoute un autre attribut manquant, qui devrait alors fonctionner parfaitement. est ajouté à la ressource ..__, assurez-vous de valider le modèle
accepts_nested_attributes_for :assets, allow_destroy: true
validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/
Dans votre vue, parcourez l'actif pour obtenir chaque image
<%= @vehicle.assets.size %>
<% for asset in @vehicle.assets %>
<%=link_to image_tag (asset.image.url(:thumb)) %>
<% end %>
Si vous avez raison, votre problème est que asset_attributes est un tableau avec chaque image ayant une colonne d’index et une image.
Votre form_for devrait avoir quelque chose de similaire à celui-ci et si vous le souhaitez, vous pouvez également inclure un aperçu afin que le téléchargement puisse afficher leurs images, utilisez le code du bas pour cela.
<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>
Désinfectez avant d'enregistrer dans le contrôleur Désinfectez les attributs avec index avec les attributs accept_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