analyticsPierce
analyticsPierce

Reputation: 3025

No route matches error while uploading a file with Carrierwave

I have a simple file upload form where a user should be able to select a csv file from their machine and then save it to a file folder. I am trying to user Carrierwave and my app is built in Ruby on Rails.

When I try to save the file, I get the error "No route matches [POST] "/customers/new".

Here are the various components.

/new.html.erb

<%= form_for :dataload, :html => {:multipart => true}  do |f| %>

 <p>
   <%= f.file_field :file %>
 </p>
 <p><%= f.submit %></p>
<% end %>

/models/dataload.rb

class Dataload < ActiveRecord::Base
    attr_accessible :file_name, :request_user, :source
    mount_uploader :file, CustomerWarrantyUploader
end

*/uploaders/customer_warranty_uploader.rb*

class CustomerWarrantyUploader < CarrierWave::Uploader::Base
  storage :file
  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end
  def extension_white_list
   %w(csv)
  end

*customers_controller.rb (new method; I haven't done anything to this)*

  def new
    @customer = Customer.new

    respond_to do |format|
      format.html # new.html.erb
      format.json { render json: @customer }
    end
  end

Here are the current routes for customers

  resources :customers

I am not sure what the issue is, having tried various similar approaches. Any advice is appreciated.

Upvotes: 3

Views: 3569

Answers (3)

Brad Werth
Brad Werth

Reputation: 17647

The reason is because that route really doesn't exist. Resources creates the following routes ( http://guides.rubyonrails.org/routing.html ):

GET     /customers          index   display a list of all photos
GET     /customers/new      new     return an HTML form for creating a new photo
POST    /customers          create  create a new photo
GET     /customers/:id      show    display a specific photo
GET     /customers/:id/edit edit    return an HTML form for editing a photo
PUT     /customers/:id      update  update a specific photo
DELETE  /customers/:id      destroy delete a specific photo 

As you can see, the only POST path is /customers. A simple adjustment to your form should do the trick. Something like the following should work:

<%= form_for :dataload, { :url => customers_path , :html => {:multipart => true} }  do |f| %>

Edit: Adding additional information as a result of user comments.

You will also need to add some logic to your controller, to deal with the uploaded file. Basically, in the Railscast, he states "Part of the site is already built: there is a page that lists the galleries, with a link to each gallery and a page that shows a gallery’s pictures.". This apparently includes a new and edit page, as well. The code from his controller ( from the project source code - http://media.railscasts.com/assets/episodes/sources/253-carrierwave-file-uploads.zip ) is:

@gallery = Gallery.new(params[:gallery])

So, when he added his file, he did it as an attribute on the model, so all he had to add was the attr_accessible :image bit to the model to make the controller automagically start handling the image (as it comes through in the same params). As yours is coming through in different params (:dataload), and not as an attribute on the model, you will likely need to add more code than he has, using your current technique. Maybe something along the lines of:

@dataload = Dataload.create(params[:dataload])

or even:

@dataload = Dataload.process_uploaded_file(params[:dataload])

Then, you would add a process_uploaded_file method to your Dataload to kick off your relevant Customer creation logic...

Another thing not really handled, yet, is what will happen when there are errors in the data. For example, what will you do (and how will you present the errors) if 2 out of 10 entries in the uploaded file create invalid records?

Upvotes: 3

achempion
achempion

Reputation: 814

you create file via other controller and must use
accepts_nested_attributes_for :dataload, allow_destroy: true
and use field_for in your form. you also can use the nested_form gem

Upvotes: 0

Chris Salzberg
Chris Salzberg

Reputation: 27374

I'm pretty sure it's the redirect_to :back in your Dataload model, which must be redirecting to /customer/new but keeping the same HTTP action, i.e. a POST instead of a GET, hence the routing error.

I don't think you should have a redirect there (redirects are the territory of controllers), but wherever you put it, you'll probably need a 303 status code to force a GET:

redirect_to :back, :status => 303, alert: "your file is being processed"

From the docs:

If you are using XHR requests other than GET or POST and redirecting after the request then some browsers will follow the redirect using the original request method. This may lead to undesirable behavior such as a double DELETE. To work around this you can return a 303 See Other status code which will be followed using a GET request.

Upvotes: 1

Related Questions