Antworten:
Dies ist eine Lösung, um mehrere Bilder mit Carrierwave in Rails 4 von Grund auf hochzuladen
Oder Sie finden eine funktionierende Demo: Multiple Attachment Rails 4
Befolgen Sie dazu einfach diese Schritte.
rails new multiple_image_upload_carrierwave
In Edelsteindatei
gem 'carrierwave'
bundle install
rails generate uploader Avatar
Postgerüst erstellen
rails generate scaffold post title:string
Erstellen Sie ein post_attachment-Gerüst
rails generate scaffold post_attachment post_id:integer avatar:string
rake db:migrate
In post.rb.
class Post < ActiveRecord::Base
has_many :post_attachments
accepts_nested_attributes_for :post_attachments
end
In post_attachment.rb
class PostAttachment < ActiveRecord::Base
mount_uploader :avatar, AvatarUploader
belongs_to :post
end
In post_controller.rb
def show
@post_attachments = @post.post_attachments.all
end
def new
@post = Post.new
@post_attachment = @post.post_attachments.build
end
def create
@post = Post.new(post_params)
respond_to do |format|
if @post.save
params[:post_attachments]['avatar'].each do |a|
@post_attachment = @post.post_attachments.create!(:avatar => a)
end
format.html { redirect_to @post, notice: 'Post was successfully created.' }
else
format.html { render action: 'new' }
end
end
end
private
def post_params
params.require(:post).permit(:title, post_attachments_attributes: [:id, :post_id, :avatar])
end
In Ansichten / Beiträge / _form.html.erb
<%= form_for(@post, :html => { :multipart => true }) do |f| %>
<div class="field">
<%= f.label :title %><br>
<%= f.text_field :title %>
</div>
<%= f.fields_for :post_attachments do |p| %>
<div class="field">
<%= p.label :avatar %><br>
<%= p.file_field :avatar, :multiple => true, name: "post_attachments[avatar][]" %>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
So bearbeiten Sie einen Anhang und eine Liste der Anhänge für einen Beitrag. In Ansichten / Beiträge / show.html.erb
<p id="notice"><%= notice %></p>
<p>
<strong>Title:</strong>
<%= @post.title %>
</p>
<% @post_attachments.each do |p| %>
<%= image_tag p.avatar_url %>
<%= link_to "Edit Attachment", edit_post_attachment_path(p) %>
<% end %>
<%= link_to 'Edit', edit_post_path(@post) %> |
<%= link_to 'Back', posts_path %>
Aktualisieren Sie das Formular, um die Ansichten eines Anhangs / post_attachments / _form.html.erb zu bearbeiten
<%= image_tag @post_attachment.avatar %>
<%= form_for(@post_attachment) do |f| %>
<div class="field">
<%= f.label :avatar %><br>
<%= f.file_field :avatar %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Ändern Sie die Aktualisierungsmethode in post_attachment_controller.rb
def update
respond_to do |format|
if @post_attachment.update(post_attachment_params)
format.html { redirect_to @post_attachment.post, notice: 'Post attachment was successfully updated.' }
end
end
end
In Rails 3 müssen keine starken Parameter definiert werden, und da Sie attribute_accessible sowohl im Modell als auch accept_nested_attribute für das Post-Modell definieren können, ist das Attribut access in Rails 4 veraltet.
Zum Bearbeiten eines Anhangs können nicht alle Anhänge gleichzeitig geändert werden. Daher ersetzen wir den Anhang nacheinander, oder Sie können ihn gemäß Ihrer Regel ändern. Hier zeige ich Ihnen nur, wie Sie einen Anhang aktualisieren.
create
Aktion? Schienen und Trägerwellen sind intelligent genug, um Sammlungen automatisch zu speichern.
:_destroy
Teil)
Wenn wir uns die Dokumentation von CarrierWave ansehen, ist dies jetzt tatsächlich sehr einfach.
https://github.com/carrierwaveuploader/carrierwave/blob/master/README.md#multiple-file-uploads
Ich werde Product als Modell verwenden, um die Bilder als Beispiel hinzuzufügen.
Holen Sie sich die Hauptniederlassung Carrierwave und fügen Sie sie Ihrer Gemfile hinzu:
gem 'carrierwave', github:'carrierwaveuploader/carrierwave'
Erstellen Sie eine Spalte im beabsichtigten Modell, um ein Array von Bildern zu hosten:
rails generate migration AddPicturesToProducts pictures:json
Führen Sie die Migration aus
bundle exec rake db:migrate
Fügen Sie Bilder zum Modellprodukt hinzu
app/models/product.rb
class Product < ActiveRecord::Base
validates :name, presence: true
mount_uploaders :pictures, PictureUploader
end
Fügen Sie Bilder zu starken Parametern in ProductsController hinzu
app/controllers/products_controller.rb
def product_params
params.require(:product).permit(:name, pictures: [])
end
Lassen Sie Ihr Formular mehrere Bilder akzeptieren
app/views/products/new.html.erb
# notice 'html: { multipart: true }'
<%= form_for @product, html: { multipart: true } do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
# notice 'multiple: true'
<%= f.label :pictures %>
<%= f.file_field :pictures, multiple: true, accept: "image/jpeg, image/jpg, image/gif, image/png" %>
<%= f.submit "Submit" %>
<% end %>
In Ihren Ansichten können Sie auf die Bilder verweisen, die das Bildarray analysieren:
@product.pictures[1].url
Wenn Sie mehrere Bilder aus einem Ordner auswählen, entspricht die Reihenfolge genau der Reihenfolge, in der Sie sie von oben nach unten aufnehmen.
UndefinedConversionError ("\x89" from ASCII-8BIT to UTF-8)
Bei SSR-Lösungen funktioniert sie einwandfrei Rails 4.xx, aber ich stehe vor Herausforderungen (mit Rails 5.xx), dh das Speichern ActionDispatch::Http::UploadedFile
in der Datenbank anstelle des Dateinamens. Es werden auch keine Dateien in öffentlichen Ordnern für einen bestimmten Pfad im Uploader gespeichert.
Einige kleinere Ergänzungen zur SSR- Antwort:
accepts_nested_attributes_for erfordert nicht, dass Sie den Controller des übergeordneten Objekts ändern. Also wenn zu korrigieren
name: "post_attachments[avatar][]"
zu
name: "post[post_attachments_attributes][][avatar]"
dann werden alle diese Controller-Änderungen wie diese überflüssig:
params[:post_attachments]['avatar'].each do |a|
@post_attachment = @post.post_attachments.create!(:avatar => a)
end
Außerdem sollten Sie PostAttachment.new
dem übergeordneten Objektformular Folgendes hinzufügen :
In Ansichten / Beiträge / _form.html.erb
<%= f.fields_for :post_attachments, PostAttachment.new do |ff| %>
<div class="field">
<%= ff.label :avatar %><br>
<%= ff.file_field :avatar, :multiple => true, name: "post[post_attachments_attributes][][avatar]" %>
</div>
<% end %>
Dies würde diese Änderung im Controller des übergeordneten Controllers überflüssig machen:
@post_attachment = @post.post_attachments.build
Weitere Informationen finden Sie unter Rails fields_for-Formular nicht angezeigt, verschachteltes Formular
Wenn Sie Rails 5 verwenden, ändern Sie den Rails.application.config.active_record.belongs_to_required_by_default
Wert von true
in false
(in config / initializers / new_framework_defaults.rb) aufgrund eines Fehlers in accepts_nested_attributes_for (andernfalls funktioniert accept_nested_attributes_for unter Rails 5 im Allgemeinen nicht).
EDIT 1:
Um über zerstören hinzuzufügen :
In models / post.rb.
class Post < ApplicationRecord
...
accepts_nested_attributes_for :post_attachments, allow_destroy: true
end
In Ansichten / Beiträge / _form.html.erb
<% f.object.post_attachments.each do |post_attachment| %>
<% if post_attachment.id %>
<%
post_attachments_delete_params =
{
post:
{
post_attachments_attributes: { id: post_attachment.id, _destroy: true }
}
}
%>
<%= link_to "Delete", post_path(f.object.id, post_attachments_delete_params), method: :patch, data: { confirm: 'Are you sure?' } %>
<br><br>
<% end %>
<% end %>
Auf diese Weise benötigen Sie einfach überhaupt keinen Controller für ein untergeordnetes Objekt! Ich meine, es wird nichts mehr PostAttachmentsController
benötigt. Der Controller ( PostController
) des übergeordneten Objekts wird ebenfalls fast nicht geändert. Das einzige, was Sie dort ändern, ist die Liste der Parameter auf der Whitelist (einschließlich der untergeordneten objektbezogenen Parameter) wie folgt:
def post_params
params.require(:post).permit(:title, :text,
post_attachments_attributes: ["avatar", "@original_filename", "@content_type", "@headers", "_destroy", "id"])
end
Deshalb accepts_nested_attributes_for
ist das so erstaunlich.
<%= d.text_field :copyright, name: "album[diapos_attributes][][copyright]", class: 'form-field' %>
schreibt das Copyright nur auf den letzten Datensatz und nicht auf alle.
Außerdem habe ich herausgefunden, wie der Upload mehrerer Dateien aktualisiert werden kann, und ich habe ihn auch ein wenig überarbeitet. Dieser Code gehört mir, aber Sie bekommen die Drift.
def create
@motherboard = Motherboard.new(motherboard_params)
if @motherboard.save
save_attachments if params[:motherboard_attachments]
redirect_to @motherboard, notice: 'Motherboard was successfully created.'
else
render :new
end
end
def update
update_attachments if params[:motherboard_attachments]
if @motherboard.update(motherboard_params)
redirect_to @motherboard, notice: 'Motherboard was successfully updated.'
else
render :edit
end
end
private
def save_attachments
params[:motherboard_attachments]['photo'].each do |photo|
@motherboard_attachment = @motherboard.motherboard_attachments.create!(:photo => photo)
end
end
def update_attachments
@motherboard.motherboard_attachments.each(&:destroy) if @motherboard.motherboard_attachments.present?
params[:motherboard_attachments]['photo'].each do |photo|
@motherboard_attachment = @motherboard.motherboard_attachments.create!(:photo => photo)
end
end
Hier ist mein zweiter Refaktor im Modell:
Regler:
def create
@motherboard = Motherboard.new(motherboard_params)
if @motherboard.save
@motherboard.save_attachments(params) if params[:motherboard_attachments]
redirect_to @motherboard, notice: 'Motherboard was successfully created.'
else
render :new
end
end
def update
@motherboard.update_attachments(params) if params[:motherboard_attachments]
if @motherboard.update(motherboard_params)
redirect_to @motherboard, notice: 'Motherboard was successfully updated.'
else
render :edit
end
end
Im Motherboard-Modell:
def save_attachments(params)
params[:motherboard_attachments]['photo'].each do |photo|
self.motherboard_attachments.create!(:photo => photo)
end
end
def update_attachments(params)
self.motherboard_attachments.each(&:destroy) if self.motherboard_attachments.present?
params[:motherboard_attachments]['photo'].each do |photo|
self.motherboard_attachments.create!(:photo => photo)
end
end
Wenn Sie die Zuordnung verwenden, müssen @post.post_attachments
Sie die nicht festlegen post_id
.