raj
raj

Reputation: 6094

"no implicit conversion of nil into String" error for carrierwave multiple image upload

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

Answers (3)

Diego
Diego

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:

  1. Add the gem as a dependency.
  2. Create an uploader that defines where the files will be stored.
  3. Add an attribute to our model to store the file location.
  4. 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

Flov
Flov

Reputation: 1587

I just ran into the same problem. I fixed it by using mount_uploaders not mount_uploader

Upvotes: 19

Albert.Qing
Albert.Qing

Reputation: 4625

Change <%= ff.file_field :image, multiple: true %>

to <%= ff.file_field :image %>

multiple: true not need add field.

Upvotes: 0

Related Questions