Reputation: 3025
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
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
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
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