Как загружать несколько файлов одним запросом в CarrierWave/Sinatra?

Я не первый, кто спросил, но и не последний. Как реализовать загрузку нескольких файлов в CarrierWave и Sinatra? У меня такой экшн:
post '/create' do
  params.delete 'submit'
  d = Dcmnt.new(
    :published   => params[:published],
    :name        => params[:name],
    :description => params[:description],
    :created_at  => Time.now
  )
  d.attachment = params[:attachments]
  d.save
  redirect '/success'
end

Вот такая модель:
class Dcmnt
  include Mongoid::Document
  store_in collection: 'dcmnts'
  field :published,   type: Boolean
  field :name,        type: String
  field :description, type: String
  field :created_at,  type: Date
  mount_uploader :attachment, Uploader, type: String
end

С такой вот формой:
%form{:method => "post", :action => "/create", :enctype => "multipart/form-data"}
  %input{:type => "checkbox", :name => "published", :value => "true"} Published?
  %input{:name => "name"}
  %textarea{:name => "description", :rows => "5"}
  %div.form-group
    %label Attachments
    %input{:type => "file", :name => "attachments[]"}
    %input{:type => "file", :name => "attachments[]"}
    %input{:type => "file", :name => "attachments[]"}
    %input{:type => "file", :name => "attachments[]"}
    %input{:type => "file", :name => "attachments[]"}

CarrierWave настроен так:
class Uploader < CarrierWave::Uploader::Base
  storage :file
  def store_dir
    'attachments/' + model.id
  end
end

Выглядит корректно, но не работает. При попытке загрузить несколько файлов, впрочем, как и один файл, Pow возвращает no implicit conversion of nil into String на строке d.attachment = params[:attachments]. Кстати, .each и .map вызванные на params[:attachments] - не помогают.
Что делать, подскажите?
  • Вопрос задан
  • 2851 просмотр
Решения вопроса 1
Вы немного не понимаете, как работает Carrierwave. В будущем для решения подобных проблем имеет смысл почитать исходники используемой вами библиотеки. Метод mount_uploader :attachment добавляет в модель метод
def attachment=(blabla)
...
end


При этом не ожидается, что blabla - это массив.

На Вашем месте я бы связал Вашу модель связью one_to_many как то так:

class Dcmnt
  include Mongoid::Document
  ...
  has_many :attachments
  accepts_nested_attributes_for :attachments
end

class Attachment
  include Mongoid::Document
  ...
  belongs_to :dcmnt
  mount_uploader :file, Uploader
end


В контроллере вместо:

d = Dcmnt.new(
    :published   => params[:published],
    :name        => params[:name],
    :description => params[:description],
    :created_at  => Time.now
  )
  d.attachment = params[:attachments]


сделать:

d = Dcmnt.new(
    :published   => params[:published],
    :name        => params[:name],
    :description => params[:description],
    :attachments_attributes => params[:attachments_attributes]
    :created_at  => Time.now
  )


Кстати, вместо :created_at => Time.now можно добавить в модель include Mongoid::Timestamps::Created

Во вьюхе как-то так:

%div.form-group
    %label Attachments
    %input{:type => "file", :name => "attachments_attributes[0][file]"}
    %input{:type => "file", :name => "attachments_attributes[1][file]"}
    %input{:type => "file", :name => "attachments_attributes[2][file]"}


Прим.:
1. Для форм желательно все же использовать хелперы
2. Название Вашей модели слишком уж неочевидное. Рубисты этого не любят.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы
22 нояб. 2024, в 12:53
25000 руб./за проект
22 нояб. 2024, в 12:20
10000 руб./за проект
22 нояб. 2024, в 11:53
3000 руб./за проект