Reputation: 6094
This is bugging me for days now. I have tried different method . So I would go with the simplest form , that should be working but doesnt.
I have two models. Institute
, and VirtualTour
.
class Institute < ActiveRecord::Base
mount_uploader :virtual_images, VirtualPicUploader
has_many :virtual_tours, dependent: :destroy
accepts_nested_attributes_for :virtual_tours,allow_destroy: true
end
class VirtualTour < ActiveRecord::Base
belongs_to :institute
mount_uploader :image, VirtualPicUploader
end
I amusing devise
for institute. Strong Parameters are not being considered for this simpler version so I will keep it like this.
def account_update
default_params.permit!
end
This upload happens in while editing thats why account_update is used.
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put , multipart: true }) do |f| %>
<%= f.fields_for :virtual_tours do |ff| %>
<%= ff.file_field :image, multiple: true %>
<%= ff.hidden_field :institute_id, value: f.object.id %>
<% end %>
<% end %>
I get this error in browser when I submit.
no implicit conversion of nil into String
def cache_path
File.expand_path(File.join(cache_dir, cache_name), root)
end
And in the log , Completed 500 Internal Server Error in 91ms (ActiveRecord: 1.8ms)
TypeError (no implicit conversion of nil into String):
carrierwave (0.10.0) lib/carrierwave/uploader/cache.rb:159:in `join'
carrierwave (0.10.0) lib/carrierwave/uploader/cache.rb:159:in `cache_path'
carrierwave (0.10.0) lib/carrierwave/uploader/cache.rb:131:in `block in cache!'
carrierwave (0.10.0) lib/carrierwave/uploader/callbacks.rb:17:in `with_callbacks'
carrierwave (0.10.0) lib/carrierwave/uploader/cache.rb:122:in `cache!'
carrierwave (0.10.0) lib/carrierwave/mount.rb:329:in `cache'
carrierwave (0.10.0) lib/carrierwave/mount.rb:163:in `image='
carrierwave (0.10.0) lib/carrierwave/orm/activerecord.rb:39:in `image='
activerecord (4.2.4) lib/active_record/attribute_assignment.rb:54:in `public_send'
activerecord (4.2.4) lib/active_record/attribute_assignment.rb:54:in `_assign_attribute'
activerecord (4.2.4) lib/active_record/attribute_assignment.rb:41:in `block in assign_attributes'
actionpack (4.2.4) lib/action_controller/metal/strong_parameters.rb:185:in `each_pair'
actionpack (4.2.4) lib/action_controller/metal/strong_parameters.rb:185:in `each_pair'
activerecord (4.2.4) lib/active_record/attribute_assignment.rb:35:in `assign_attributes'
activerecord (4.2.4) lib/active_record/nested_attributes.rb:513:in `assign_to_or_mark_for_destruction'
activerecord (4.2.4) lib/active_record/nested_attributes.rb:479:in `block in assign_nested_attributes_for_collection_association'
activerecord (4.2.4) lib/active_record/nested_attributes.rb:460:in `each'
Have been working on this for the last two days . Any help would be appreciated.
Upvotes: 3
Views: 8769
Reputation: 610
I have included the documentation here for reference.
The getting started can help us get started. I'm assuming your error is happening when you try to upload multiple images at the same time?
Nonetheless this is the steps i take when implementing file uploading using carrier wave.
The documentation for CarrierWave walks us through the process of integrating it with our application, but the essential steps are listed here:
Integrate the uploader with the model. Assuming we wanted to add a profile photo to an application with a User model, we can first install the gem by adding it to our Gemfile:
gem "carrierwave"
or
gem 'carrierwave', github: 'carrierwaveuploader/carrierwave'
for multiple image uplaods.
Download and install the gem with the bundle command:
$ bundle
Installing carrierwave ...
....
Now we need an uploader that will store the profile photos. We can create one using a generator that comes with CarrierWave:
$ rails generate uploader ProfilePhoto
This will create a new file in app/uploaders/profile_photo_uploader.rb. If we take a look at the file we'll see lots of options for configuring the uploader but right now we're concerned with where the file is stored:
class ProfilePhotoUploader < CarrierWave::Uploader::Base
storage :file
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
end
The storage :file
option specifies that the file is stored locally on the web server (i.e. our laptops). This is fine for development but we'll want to change this later when we deploy to our production servers.
The store_dir
method specifies the directory that we can find our uploaded files in. By default the path will start in the public folder so that the uploaded files are accessible. If we mount this uploader on the User model, the full path would be /public/uploads/user/profile_photo/#{user.id}/file_name
. Each user will have their own directory to prevent other users from overwriting files with the same name.
Now that we have the uploader, we need to add a column to our users table so that we can store the location of the file. Let's create a migration to add the profile_photo
column:
$ rails generate migration add_profile_photo_to_users
We can modify our migration file to include the following:
class AddProfilePhotoToUsers < ActiveRecord::Migration
def change
add_column :users, :profile_photo, :string
end
end
Once we run this migration we'll now have a place to store the profile photo associated with each user.
The final step is to attach the ProfilePhotoUploader
we created with the User
model via the profile_photo
column. We can add the following line to the User
model:
class User < ActiveRecord::Base
mount_uploader :profile_photo, ProfilePhotoUploader
end
Now we can call the profile_photo
method on a User
model and it will return the details of the uploaded file.
To complete the profile photo upload feature we'll also need to add a place on our user registration form that allows the user to select an image on their computer. With form_for
we can add something like:
<%= f.file_field :profile_photo %>
These methods will add the <input type="file">
element to our forms so that it will present a dialog to the user for selecting a file.
One final step is to ensure that the profile photo can pass through the strong parameters on the users controller. If we're using Devise we can inject new attributes for the sign up process using a before filter that we can define in app/controllers/application_controller.rb
:
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :profile_photo
end
end
At this point a user should be able to select a profile photo when creating or updating their registration and the image will be associated with the user.
NOTE: Note that carrierwave will use the naming convention rails uses. If you name your file Uploader class AvatarUploader, it will look for a file named after avatar avatar_uploader.rb
(singular like models).
UPDATE: for multiple image uploaders, make sure you have mount_uploaders
instead of the singular form in your model.
Upvotes: 0
Reputation: 1587
I just ran into the same problem. I fixed it by using
mount_uploaders
not mount_uploader
Upvotes: 19
Reputation: 4625
Change <%= ff.file_field :image, multiple: true %>
to <%= ff.file_field :image %>
multiple: true
not need add field.
Upvotes: 0