Ini adalah solusi untuk mengunggah banyak gambar menggunakan gelombang pembawa di rel 4 dari awal
Atau Anda dapat menemukan demo yang berfungsi:
Multiple Attachment Rails 4
Untuk melakukan cukup ikuti langkah-langkah ini.
rails new multiple_image_upload_carrierwave
Dalam file permata
gem 'carrierwave'
bundle install
rails generate uploader Avatar
Buat perancah posting
rails generate scaffold post title:string
Buat perancah post_attachment
rails generate scaffold post_attachment post_id:integer avatar:string
rake db:migrate
Di post.rb
class Post < ActiveRecord::Base
has_many :post_attachments
accepts_nested_attributes_for :post_attachments
end
Di post_attachment.rb
class PostAttachment < ActiveRecord::Base
mount_uploader :avatar, AvatarUploader
belongs_to :post
end
Di 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
Dalam views / posts / _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 %>
Untuk mengedit lampiran dan daftar lampiran untuk setiap posting.
Dalam views / posts / 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 %>
Perbarui formulir untuk mengedit tampilan lampiran / post_attachments / _form.html.erb
<%= 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 %>
Ubah metode pembaruan di 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
Dalam rails 3 tidak perlu untuk menentukan parameter yang kuat dan karena Anda dapat mendefinisikan atribut_accessible di kedua model dan accept_nested_attribute to post model karena atribut yang dapat diakses sudah tidak digunakan lagi di rails 4.
Untuk mengedit lampiran, kami tidak dapat mengubah semua lampiran dalam satu waktu. jadi kami akan mengganti lampiran satu per satu, atau Anda dapat memodifikasi sesuai aturan Anda, Di sini saya hanya menunjukkan kepada Anda cara memperbarui lampiran apa pun.
create
tindakan? Rel dan gelombang pembawa cukup pintar untuk menyimpan koleksi secara otomatis.:_destroy
bagian penanganan )Jika kita melihat dokumentasi CarrierWave, ini sebenarnya sangat mudah sekarang.
https://github.com/carrierwaveuploader/carrierwave/blob/master/README.md#multiple-file-uploads
Saya akan menggunakan Produk sebagai model yang ingin saya tambahkan gambarnya, sebagai contoh.
Dapatkan Carrierwave cabang master dan tambahkan ke Gemfile Anda:
gem 'carrierwave', github:'carrierwaveuploader/carrierwave'
Buat kolom dalam model yang dimaksudkan untuk menghosting array gambar:
rails generate migration AddPicturesToProducts pictures:json
Jalankan migrasi
bundle exec rake db:migrate
Tambahkan gambar ke model Produk
app/models/product.rb class Product < ActiveRecord::Base validates :name, presence: true mount_uploaders :pictures, PictureUploader end
Tambahkan gambar ke parameter yang kuat di ProductsController
app/controllers/products_controller.rb def product_params params.require(:product).permit(:name, pictures: []) end
Izinkan formulir Anda menerima banyak gambar
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 %>
Dalam pandangan Anda, Anda dapat mereferensikan gambar yang mengurai larik gambar:
@product.pictures[1].url
Jika Anda memilih beberapa gambar dari sebuah folder, urutannya akan sama persis dengan yang Anda ambil dari atas ke bawah.
sumber
UndefinedConversionError ("\x89" from ASCII-8BIT to UTF-8)
Untuk solusi SSR, ini berfungsi dengan baik dengan Rails 4.xx, tetapi saya menghadapi tantangan (dengan Rails 5.xx) yaitu penyimpanannyaActionDispatch::Http::UploadedFile
dalam database, bukan nama file. Ini juga tidak menyimpan file di folder publik untuk jalur tertentu di pengunggah.Beberapa tambahan kecil pada jawaban SSR :
accepts_nested_attributes_for tidak mengharuskan Anda mengubah pengontrol objek induk. Jadi jika benar
name: "post_attachments[avatar][]"
untuk
name: "post[post_attachments_attributes][][avatar]"
maka semua perubahan pengontrol seperti ini menjadi mubazir:
params[:post_attachments]['avatar'].each do |a| @post_attachment = @post.post_attachments.create!(:avatar => a) end
Anda juga harus menambahkan
PostAttachment.new
ke bentuk objek induk:Dalam views / posts / _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 %>
Ini akan membuat perubahan ini menjadi mubazir di pengontrol induk:
@post_attachment = @post.post_attachments.build
Untuk info lebih lanjut lihat Rails fields_for form tidak muncul, formulir bersarang
Jika Anda menggunakan Rails 5, maka ubah
Rails.application.config.active_record.belongs_to_required_by_default
nilai daritrue
menjadifalse
(di config / initializers / new_framework_defaults.rb) karena bug di dalam accepts_nested_attributes_for (jika tidak, accepts_nested_attributes_for biasanya tidak akan berfungsi di bawah Rails 5).EDIT 1:
Untuk menambahkan tentang menghancurkan :
Di models / post.rb
class Post < ApplicationRecord ... accepts_nested_attributes_for :post_attachments, allow_destroy: true end
Dalam views / posts / _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 %>
Dengan cara ini Anda sama sekali tidak perlu memiliki pengontrol objek anak! Maksud saya tidak ada
PostAttachmentsController
lagi yang dibutuhkan. Adapun controller (PostController
) objek induk , Anda juga hampir tidak mengubahnya - satu-satunya hal yang Anda ubah di sana adalah daftar whitelist params (untuk menyertakan parameter terkait objek anak) seperti ini:def post_params params.require(:post).permit(:title, :text, post_attachments_attributes: ["avatar", "@original_filename", "@content_type", "@headers", "_destroy", "id"]) end
Itulah mengapa
accepts_nested_attributes_for
sangat menakjubkan.sumber
<%= d.text_field :copyright, name: "album[diapos_attributes][][copyright]", class: 'form-field' %>
menulis hak cipta hanya untuk rekaman terakhir dan tidak untuk semuanya.Saya juga menemukan cara memperbarui beberapa file yang diunggah dan saya juga sedikit merefaktornya. Kode ini milik saya tetapi Anda mengerti maksudnya.
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
sumber
Inilah refaktor kedua saya ke dalam model:
Pengontrol:
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
Dalam model motherboard:
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
sumber
Saat menggunakan pengaitan,
@post.post_attachments
Anda tidak perlu menyetelpost_id
.sumber