कार्वेलवे का उपयोग करके 4 मल्टीपल इमेज या फाइल अपलोड करें


86

मैं रेल्स 4 और कैरियरवे का उपयोग करके फ़ाइल चयन विंडो से कई छवियां कैसे अपलोड कर सकता हूं? मैं एक है post_controllerऔर post_attachmentsमॉडल। मैं यह कैसे कर सकता हूँ?

क्या कोई उदाहरण दे सकता है? क्या इसका कोई सरल तरीका है?

जवाबों:


195

यह खरोंच से 4 पटरियों में वाहक का उपयोग करके कई छवियों को अपलोड करने का समाधान है

या आप कार्यशील डेमो पा सकते हैं: मल्टीपल अटैचमेंट रेल 4

इन चरणों का पालन करने के लिए।

rails new multiple_image_upload_carrierwave

मणि फ़ाइल में

gem 'carrierwave'
bundle install
rails generate uploader Avatar 

पोस्ट मचान बनाएं

rails generate scaffold post title:string

पोस्ट_टैचमेंट मचान बनाएं

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

विचारों / पदों / _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 %>

किसी भी पोस्ट के लिए अटैचमेंट और लिस्ट को एडिट करना। विचारों / पोस्ट / 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 %>

अनुलग्नक दृश्य / पोस्ट_टैचमेंट / _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

रेल में 3 को मजबूत मापदंडों को परिभाषित करने की आवश्यकता नहीं है और जैसा कि आप मॉडल में दोनों में attribute_accessible को परिभाषित कर सकते हैं और मॉडल पोस्ट करने के लिए accept_nested_attribute क्योंकि 4 में विशेषता सुलभ पदावनत है।

अनुलग्नक संपादित करने के लिए हम एक बार में सभी अनुलग्नकों को संशोधित नहीं कर सकते। इसलिए हम अनुलग्नक को एक-एक करके बदल देंगे, या आप अपने नियम के अनुसार संशोधित कर सकते हैं, यहाँ मैं आपको केवल दिखाता हूँ कि किसी भी अनुलग्नक को कैसे अपडेट किया जाए।


2
पोस्ट कंट्रोलर के शो एक्शन में मुझे लगता है कि आप @post = Post.find (params [: id]) भूल गए हैं
wael

1
@SSR आप createकार्रवाई में प्रत्येक पोस्ट अटैचमेंट के माध्यम से लूपिंग क्यों करते हैं ? स्वचालित रूप से संग्रह सहेजने के लिए रेल और कैरियरवाहक पर्याप्त स्मार्ट हैं।
बाज़

3
संपादन देखना पसंद करेंगे (विशेषकर :_destroyभाग को संभालना )
ट्यून

5
@SSR - आपका उत्तर बहुत मददगार है। क्या आप कृपया अपना उत्तर संपादित कार्रवाई के साथ भी अपडेट कर सकते हैं।
raj_on_rails

2
जब मैं post_attachment मॉडल में सत्यापन जोड़ देता हूं, तो वे पोस्ट मॉडल को सहेजने से नहीं रोकते हैं। इसके बजाय पोस्ट सहेजा गया है, और उसके बाद ActiveRecord अमान्य त्रुटि केवल अनुलग्नक मॉडल के लिए फेंक दिया है। मुझे लगता है कि यह बनाने के कारण है! तरीका। लेकिन बजाय बनाने का उपयोग चुपचाप विफल रहता है। किसी भी विचार को पोस्ट पर संलग्नक में कैसे पहुँचना है?
dchess

32

यदि हम CarrierWave के प्रलेखन पर एक नज़र डालें, तो यह वास्तव में अब बहुत आसान है।

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

मैं उत्पाद का उपयोग उस मॉडल के रूप में करूंगा जिसे मैं चित्रों को जोड़ना चाहता हूं, उदाहरण के रूप में।

  1. मास्टर ब्रांच कैरियरवे को प्राप्त करें और इसे अपने जेमफाइल में जोड़ें:

    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 में मजबूत params के लिए चित्रों को जोड़ें

    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
    

यदि आप किसी फ़ोल्डर से कई छवियां चुनते हैं, तो आदेश सटीक क्रम होगा जिसे आप उन्हें ऊपर से नीचे तक ले जा रहे हैं।


9
इस समस्या के लिए कैरियरवे का समाधान मुझे संकटग्रस्त बनाता है। इसमें एक सरणी में फ़ाइलों के सभी संदर्भों को एक क्षेत्र में रखना शामिल है! यह निश्चित रूप से "रेल रास्ता" नहीं माना जाएगा। क्या होगा अगर आप तब कुछ हटाना चाहते हैं, या पोस्ट में अतिरिक्त फाइलें जोड़ना चाहते हैं? मैं यह नहीं कह सकता कि यह संभव नहीं होगा, मैं सिर्फ यह कह रहा हूं कि यह बदसूरत होगा। एक ज्वाइन टेबल एक बेहतर विचार है।
टॉबी 1 केनोबी

3
मैं अधिक टोबी सहमत नहीं हो सका। क्या आप उस समाधान को प्रदान करने के लिए इतने दयालु होंगे?
drjorgepolanco

2
यह समाधान पहले से ही SSR द्वारा प्रदान किया गया है। अपलोड की गई फ़ाइल को रखने के लिए एक और मॉडल रखा जाता है, फिर जिस चीज़ को अपलोड की जाने वाली कई फ़ाइलों की आवश्यकता होती है, वह उस मॉडल से एक-से-कई या कई-से-कई संबंधों से संबंधित होती है। (मेरे पहले की टिप्पणी में उल्लिखित तालिका में कई-कई संबंधों के मामले में होगा)
टोबी 1 केनोबी

धन्यवाद @ Toby1Kenobi, मैं सोच रहा था कि कॉलम सरणी विधि छवि संस्करणों के लिए कैसे होगी (मुझे नहीं पता कि यह कैसे हो सकता है)। आपकी रणनीति उल्लेखनीय है।
चोस्तोरी

मैंने Carrierwave के इस फीचर को Rails 5.xx, github.com/carrierwaveuploader/carrierwave/blob/master/… के साथ लागू किया है, लेकिन मैं इसे सफलतापूर्वक चलाने में सक्षम नहीं हूं, और यह त्रुटि उत्पन्न कर रहा है, UndefinedConversionError ("\x89" from ASCII-8BIT to UTF-8) SSR समाधान के लिए, यह ठीक काम करता है 4.xx रेल्स, लेकिन मुझे चुनौतियों का सामना करना पड़ रहा है (पटरियों 5.xx के साथ) यानी ActionDispatch::Http::UploadedFileफाइलनाम के बजाय डेटाबेस में इसका भंडारण । यह भी अपलोडर में दिए गए पथ के लिए सार्वजनिक फ़ोल्डर में फ़ाइलों को संग्रहीत नहीं कर रहा है।
मानसी शाह

8

SSR के उत्तर में कुछ मामूली जोड़ :

ac Accept_nested_attributes_for आपको मूल ऑब्जेक्ट के नियंत्रक को बदलने की आवश्यकता नहीं है। तो अगर सही करने के लिए

name: "post_attachments[avatar][]"

सेवा

name: "post[post_attachments_attributes][][avatar]"

फिर ये सभी नियंत्रक परिवर्तन जैसे ये निरर्थक हो जाते हैं:

params[:post_attachments]['avatar'].each do |a|
  @post_attachment = @post.post_attachments.create!(:avatar => a)
end

इसके अलावा, आपको PostAttachment.newमूल ऑब्जेक्ट फॉर्म में जोड़ना चाहिए :

विचारों / पदों / _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 %>

यह अभिभावक के नियंत्रक में इस बदलाव को बेमानी करेगा:

@post_attachment = @post.post_attachments.build

अधिक जानकारी के लिए Rails फ़ील्ड्स देखें। ऐसा फ़ॉर्म दिखाई नहीं देगा, नेस्टेड फ़ॉर्म

आप रेल 5 का उपयोग करते हैं, तो बदलने Rails.application.config.active_record.belongs_to_required_by_defaultसे मूल्य trueके लिए false(में config / initializers / new_framework_defaults.rb) एक बग के अंदर की वजह से accepts_nested_attributes_for (अन्यथा accepts_nested_attributes_for होगा आम तौर पर रेल 5 के तहत नहीं काम)।

संपादित करें 1:

विनाश के बारे में जोड़ने के लिए :

मॉडल / पोस्ट.आरबी में

class Post < ApplicationRecord
    ...
    accepts_nested_attributes_for :post_attachments, allow_destroy: true
end

विचारों / पदों / _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 %>

इस तरह से आपको बस चाइल्ड ऑब्जेक्ट के नियंत्रक होने की आवश्यकता नहीं है ! मेरा मतलब है कि अब किसी PostAttachmentsControllerकी जरूरत नहीं है। माता-पिता ऑब्जेक्ट के नियंत्रक ( PostController) के लिए, आप भी इसे लगभग नहीं बदलते हैं - केवल एक चीज जिसे आप वहां बदलते हैं, इस तरह से श्वेतसूचीबद्ध पाराम्स (बच्चे के ऑब्जेक्ट से संबंधित पार्म्स को शामिल करने की सूची) है:

def post_params
  params.require(:post).permit(:title, :text, 
    post_attachments_attributes: ["avatar", "@original_filename", "@content_type", "@headers", "_destroy", "id"])
end

इसीलिए accepts_nested_attributes_forयह इतना अद्भुत है।


वे वास्तव में @SSR उत्तर के लिए प्रमुख जोड़ हैं, ना कि मामूली :) स्वीकार_न्यास_नेत्रिकी_पर काफी कुछ है। वास्तव में बच्चे नियंत्रक की कोई आवश्यकता नहीं है। आपके दृष्टिकोण का अनुसरण करते हुए, केवल एक चीज जो मैं करने में असमर्थ हूं, वह है बच्चे के लिए फ़ॉर्म त्रुटि संदेश प्रदर्शित करना जब अपलोड में कुछ गलत हो जाता है।
लुईस फर्नांडो एलेन

आपके सहयोग के लिए धन्यवाद। मुझे अपलोड काम कर रहा है, लेकिन मैं सोच रहा हूं कि मैं पोस्ट /attachments फॉर्म फ़ील्ड को विचारों / पोस्ट / _form.html.erb में अतिरिक्त विशेषताओं को कैसे जोड़ सकता हूं? <%= d.text_field :copyright, name: "album[diapos_attributes][][copyright]", class: 'form-field' %>कॉपीराइट को केवल पिछले रिकॉर्ड के लिए लिखते हैं और उन सभी को नहीं।
सेज्यू

6

इसके अलावा मैंने यह भी पता लगाया कि एकाधिक फ़ाइल अपलोड को कैसे अपडेट किया जाए और मैंने इसे थोड़ा सा रिफ्लेक्ट किया। यह कोड मेरा है लेकिन आपको बहाव मिलता है।

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

1
अपना कोड साझा करने के लिए धन्यवाद। जब आपको समय मिले तो मेरे गिहबो रेपो पर कोड अपडेट करें और प्रत्येक विधि के लिए टिप्पणी करना न भूलें ताकि हर कोई आसानी से कोड को समझ सके।
SSR

1
मैंने रिपॉज को क्लोन किया, क्या आप मुझे पीआर करने की अनुमति देंगे?
क्रिस हबगड जूल

हाँ यकीनन। आपका github यूज़रनेम क्या है
SSR

क्या आपको मुझे एक्सेस देने का मौका मिला है?
क्रिस हबगूड

2

यहाँ मॉडल में मेरा दूसरा रिफ्लेक्टर है:

  1. मॉडल के लिए निजी तरीकों को स्थानांतरित करें।
  2. स्वयं के साथ @motherboard बदलें।

नियंत्रक:

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

एसोसिएशन का उपयोग करते समय @post.post_attachmentsआपको सेट करने की आवश्यकता नहीं है post_id

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.