web-dev-qa-db-ja.com

Rails 4 Carrierwaveを使用した複数の画像またはファイルのアップロード

Rails 4とCarrierWaveを使用して、ファイル選択ウィンドウから複数の画像をアップロードするにはどうすればよいですか? post_controllerモデルとpost_attachmentsモデルがあります。これどうやってするの?

誰かが例を提供できますか?これに簡単なアプローチはありますか?

86
SSR

これは、Rails 4のCarrierwaveを使用して複数の画像をゼロからアップロードするソリューションです

または作業デモを見つけることができます: Multiple Attachment Rails 4

これらの手順に従うだけです。

Rails new multiple_image_upload_carrierwave

gemファイル内

gem 'carrierwave'
bundle install
Rails generate uploader Avatar 

ポスト足場を作成する

Rails generate scaffold post title:string

post_attachment scaffoldを作成

Rails generate scaffold post_attachment post_id:integer avatar:string

rake db:migrate

post.rb

class Post < ActiveRecord::Base
   has_many :post_attachments
   accepts_nested_attributes_for :post_attachments
end

post_attachment.rb

class PostAttachment < ActiveRecord::Base
   mount_uploader :avatar, AvatarUploader
   belongs_to :post
end

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

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 %>

投稿の添付ファイルと添付ファイルのリストを編集します。 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 %>

添付ファイルを編集するためのフォームの更新views/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 %>

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

Rails 3では、強力なパラメーターを定義する必要はありません。また、Railsでアクセス可能な属性が非推奨になったため、モデルとpost_modelにaccept_nested_attributeの両方でattribute_accessibleを定義できます。

添付ファイルを編集するには、一度にすべての添付ファイルを変更することはできません。添付ファイルを1つずつ置き換えるか、ルールに従って変更できます。ここでは、添付ファイルを更新する方法を示します。

194
SSR

CarrierWaveのドキュメントを見ると、これは実際には非常に簡単です。

https://github.com/carrierwaveuploader/carrierwave/blob/master/README.md#multiple-file-uploads

例として、写真を追加するモデルとしてProductを使用します。

  1. マスターブランチCarrierwaveを取得し、Gemfileに追加します。

    gem 'carrierwave', github:'carrierwaveuploader/carrierwave'
    
  2. 目的のモデルに列を作成して、画像の配列をホストします。

    Rails generate migration AddPicturesToProducts pictures:json
    
  3. 移行を実行する

    bundle exec rake db:migrate
    
  4. モデル製品に写真を追加する

    app/models/product.rb
    
    class Product < ActiveRecord::Base
      validates :name, presence: true
      mount_uploaders :pictures, PictureUploader
    end
    
  5. ProductsControllerの強力なパラメーターに画像を追加します

    app/controllers/products_controller.rb
    
    def product_params
      params.require(:product).permit(:name, pictures: [])
    end
    
  6. フォームが複数の写真を受け入れることを許可する

    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 %>
    
  7. ビューで、ピクチャ配列を解析する画像を参照できます。

    @product.pictures[1].url
    

フォルダーから複数の画像を選択した場合、順序は、上から下に撮影した正確な順序になります。

30
drjorgepolanco

また、複数ファイルのアップロードを更新する方法を考え出し、少しリファクタリングしました。このコードは私のものですが、ドリフトが発生します。

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
6
Chris Habgood

モデルへの2番目のリファクタリングを次に示します。

  1. プライベートメソッドをモデルに移動します。
  2. @motherboardをselfに置き換えます。

コントローラ:

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

マザーボードモデル:

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
2
Chris Habgood

関連付け@post.post_attachmentsを使用する場合、post_idを設定する必要はありません。

2
Chris Habgood