csv uploader throwing nil or empty error - ruby-on-rails

I have a site that has an a table called orders, the order model, and a csv_files_controller (separate from the orders controller).
in the model I have the following:
def self.import(csv_file)
CSV.foreach(csv_file.path, headers: true) do |row|
Order.create! row.to_hash
end
end
in the csv_files_controller I have the following:
class CsvFilesController < ApplicationController
def new
#csv_file = CsvFile.new
end
def create
#csv_file = CsvFile.new(params[:csv_file])
if #csv_file.save
Order.import
redirect_to csv_file, notice: "Orders uploaded successfully"
end
end
def show
#csv_file = CsvFile.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #csv_file }
end
end
end
my upload_form partial being rendered by a page in the orders views from csv_files views:
<%= form_for #csv_file do |f| %>
<div class="controls">
<%= f.file_field :csv_file, accept: 'csv', :class => 'btn btn-xs btn-info' %>
<%= f.submit "Upload Orders", :class => 'btn btn-xs btn-success' %>
</div>
<% end %>
my routes.rb also has
resources :csv_files
when I try to load the page for the uploading I am getting a First argument in form cannot contain nil or be empty error. I am not sure what I have done wrong for it to say that.
Now if I change the form_for to :csv_files the page will load, but it is blank; no browse for file or submit button appear, but the error goes away. Doesn't matter though if the form isn't working. I am using rails 4 so I shouldn't need he :html => {multipart: true} and even when it was there it didn't change anything.
I can't figure out why it is throwing the error.
Update 9-1-15:
I have made a ton of changes, but now I get
No route matches [POST] "/orders/upload_page"
but my rake routes shows I have set my post route to :import.
resources :orders do
collection do
post :import
get :upload_page, as: 'upload_page'
get :search, as: 'search'
get :csv_report, as: 'csv_report'
get :overdue_csv_report, as: 'overdue_csv_report'
end
end
I don't understand why it is routing post to the upload_page.

The answer was threfold:
I got rid of the csv_files controller, etc. and moved all the code to the original orders controller.
I was trying to use a form_for .... do |f| and I had to revert to form_tag .... do for the form and spell everything out to get the post to work.
code snips:
Model:
def self.import(csv_file)
CSV.foreach(csv_file, headers: true) do |row|
Order.create! row.to_hash
end
end
Controller:
def import
Order.import(params[:csv_file].tempfile)
redirect_to orders_path, notice: "Orders imported"
end
form partial:
<%= form_tag import_orders_path, multipart: true do %>
<div class="controls">
<%= file_field_tag :csv_file, accept: 'csv', :class => 'btn btn-xs btn-info' %>
<%= submit_tag "Upload Orders", :class => 'btn btn-xs btn-success' %>
</div>
<% end %>
Routes:
resources :orders do
collection do
post :import
I am now working on ensuring that the uploads are using the validations in the model as it seems to be skipping it.

Related

No method error rails

please try to understand my question:
when i shut down the webrick server and again restart it ,then in my index view file there are some records after starting server if i click on any of three option (show,edit,delete)it gives me error "undefined method id' for nil:NilClass" and for "show" option "undefined methodname' for nil:NilC"
but if i add new record then every thing works fine i dont know what is the error
this is delete file
<%= link_to("<< Back to List", {:action => 'index'}, :class => 'back-link') %>
<div>
<h2>Delete vendor</h2>
<%= form_for(:vendor, url: {action:'destroy', id: #vendor.id}) do |f| %>
<p>Are you sure you want to permanently delete this vendor?</p>
<p><%= #vendor.name %></p>
<div>
<%= submit_tag("Delete vendor") %>
</div>
<% end %>
</div>
and this is controller
class VendorController < ApplicationController
def index
#vendors=Vendor.all
end
def new
#initiate new vendor which hits back to create
#vendor=Vendor.new
end
def create
#vendor=Vendor.new(vendor_params)
if#vendor.save
flash[:notice]="vendor ceated"
redirect_to(action: 'index')
else
flash[:notice]="there is error"
render('new')
end
def show
#vendor=Vendor.find(params[:id])
end
def edit
#vendor=Vendor.find(params[:id])
end
def update
#vendor=Vendor.find(params[:id])
if #vendor.update_attributes(vendor_params)
flash[:notice]='record updated'
redirect_to(action:'index')
else
flash[:notice]='there is some error'
render('edit')
end
end
def delete
#vendor=Vendor.find(params[:id])
end
def destroy
#vendor=Vendor.find(params[:id]).destroy
if #vendor.destroy
redirect_to(action: 'index')
else
render('delete')
end
end
end
private
def vendor_params
params.require(:vendor).permit(:name ,:image_url)
end
end
this is edit
<%= link_to("<< Back to List", {:action => 'index'}) %>
<div>
<h2>update Vendor</h2>
<%= form_for(:vendor, :url => {:action => 'update', id: #vendor.id }) do |f| %>
<%= render(partial:"form" , locals: {f: f}) %>
<div class="form-buttons">
<%= submit_tag("Update vendor") %>
</div>
<% end %>
</div>
this is show
<%= link_to("<<BAck to main",{action:"index"}) %>
<div>
<h1>showing <%=#vendor.name %></h1>
<p><%=#vendor.image_url %></p>
</div>
Good to see you fixed the problem.
--
For the benefit of future visitors, the error was caused by your controller name being singular, rather than plural.
All controllers should be named in the plural; all models in the singular:
#app/models/vendor.rb
class Vendor < ActiveRecord::Base
end
#app/controllers/vendors_controller.rb
class VendorsController < ApplicationController
end
As an added recommendation, your forms could be tidied up considerably by using the #vendor variable:
#app/views/vendors/edit.html.erb
<%= form_for #vendor do |f| %>
This will auto-fill the path and method, depending on the construct of the object you've passed.

No route matches - missing required keys: [id] ?

I'm doing a Rails tutorial, and trying to figure out why this is happening.
I'm making a to-do list, and everytime I try and insert a record into my Todo model, I get the following:
Here is the new.html.erb view that this is from:
<h1>Add new item to your todo listM</h1>
<%= form_for #todo, :url=>todo_path(#todo) do |f| %>
<%= f.label :name %> <%= f.text_field :name%>
<%= f.hidden_field :done, :value => false %>
<%= f.submit "Add to todo list" %>
<% end %>
Here is index.html.erb from where the user is linked to new.html.erb
<h1>TASKS</h1>
<h3> TO DO </h3>
<ul>
<% #todos.each do |t| %>
<li>
<strong><%= t.name %></strong>
<small><%= link_to "Mark as Done", todo_path(t), :method => :put %></small>
</li>
<% end %>
</ul>
<h3> DONE </h3>
<ul>
<% #todones.each do |t| %>
<li>
<strong><%= t.name %></strong>
<small><%= link_to "Remove", t, :confirm => "You sure?", :method => :delete %></small>
</li>
<% end %>
</ul>
<%= link_to "Add new task", new_todo_path %>
Here is the TodoController I have managing these actions:
class TodoController < ApplicationController
def index
#todos = Todo.where(done:false)
#todones = Todo.where(done:true)
end
def new
#todo = Todo.new
end
def todo_params
params.require(:todo).permit(:name, :done)
end
def create
#todo = Todo.new(todo_params)
if #todo.save
redirect_to todo_index_path, :notice => "Your todo item was created!"
else
render "new"
end
end
def update
#todo = Todo.find(params[:id])
if #todo.update_attribute(:done, true)
redirect_to todo_index_path, :notice => "Your todo item was marked done!"
else
redirect_to todo_index_path, :notice => "Couldn't update your task"
end
end
def destroy
#todo = Todo.find(params[:id])
#todo.destroy
redirect_to todo_index_path, :notice => "Your todo item was deleted"
end
end
And finally the routes.rb
Oneday::Application.routes.draw do
devise_for :users
root 'home#index'
resources :todo
end
Any input as to why this is happening and how to rectify it would be great.
You do not comply with the rails convention. Use plural form for resources. Then, your action is correct.
TodosController, todos_controller.rb, resources :todos
( Rails use singular/plural format to support RESTful links and to recognize named actions )
This
<%= form_for #todo, :url=>todo_path(#todo) do |f| %>
will set (or leave) the form http method to get. You could change it to:
<%= form_for #todo, :url=>todo_path(#todo), method: :post do |f| %>
or even shorter, leave it to Rails to find out what method is needed:
<%= form_for #todo do |f| %>
I found a fix to this exact issue if anyone is still curious, i know its an old issue and an easy one at that, but still figured id solve it. the original route todo_path leads to todo#show. todo_index however is assigned to todo#index and todo#create so its what we want. the line should look like this:
<%= form_for #todo, :url => todo_index_url(#todo), method: :post do |f| %>
I encountered a similar issue with one of my applications and stumbled across this post as a fix. None of the suggestions worked for me, but i was able to fix it with a little tinkering on the routes.

Rails Copy Button Error

I have an object "device" that contains a good deal of attributes. When editing one of the devices, I want to to have a copy button that when pressed will create a new device and load its "edit page" with the old devices parameters filled into the text_field. But I am very confused on how to called action control methods with buttons and I am currently getting an error saying
"No route matches {:action=>"clone", :controller=>"device", :id=>"1"}"
If I could just get the call to the "clone" method to work then I think I would be in good shape. Any help would be greatly appreciated! My current code is as followed:
edit.html.erb
<div class="row">
<%= form_for(#device) do |f| %>
<div class="span3 offset0">
<%= f.label "Unit Name" %>
<%= f.text_field :unitName %>
.
.
.
<%= f.label "Router Terminal Server IP" %>
<%= f.text_field :routerTerminalServerIp %>
</div>
<div class="span3 offset0">
<%= f.label "N2x Server" %>
<%= f.text_field :n2xServer %>
.
.
.
<%= f.label "Last Changed On" %>
<%= f.text_field :updated_at %>
<%= f.label "Update, Copy, or Delete Device" %>
<%= f.submit "Update", class: "btn btn-medium btn-info" %>
<%= link_to "Clone", :controller => "device", :action => "clone" %>
<%= link_to "Delete", device_path, class: "btn btn-medium btn-danger" %>
</div>
<% end %>
</div>
routes.rb
App::Application.routes.draw do
resources :devices
root 'static_pages#home'
match 'devices/clone', to: 'devices#clone', via: 'get'
end
devices_controller.rb
class DevicesController < ApplicationController
def new
#device = Device.new
end
def clone
oldDevice = Device.find(params[:id])
#device = Device.new
#device = #oldDevice.dup
#device.save
redirect_to edit_device_path(#device.id)
end
def create
#device = Device.new(device_params)
#device.lastChangedBy = request.remote_ip
if #device.save
redirect_to edit_device_path(#device.id)
else
render 'new'
end
end
def show
#device = Device.find(params[:id])
end
def edit
#device = Device.find(params[:id])
end
def update
#device = Device.find(params[:id])
#device.lastChangedBy = request.remote_ip
if #device.update_attributes(device_params)
redirect_to edit_device_path(#device)
else
render "edit"
end
def destroy
Device.find(params[:id]).destroy
redirect_to root_url
end
end
private
def device_params
params.require(:device).permit(:unitName, ...., :owner)
end
end
You should specify the route like this:
resources :devices do
member do
get :clone
end
end
Then you can use the clone_device_path(id) helper.
Also, you should consider using post method for this action and use button instead of link.
You're going to have no end of obscure problems if you name your controller method 'clone', as that is already defined in ruby on Object: http://ruby-doc.org/core-2.0.0/Object.html#method-i-clone
It used to be overridden in ActiveRecord, but lately ActiveRecord uses #dup for this functionality. You can still use 'clone' in your route and in the link label, but use something else for the actual method in your controller; you might want to use an ' :as => 'my_clone' ' option in your routes, if you call your method 'my_clone" for instance.

Wicked gem cannot find wedding ID in update action

I'm trying to implement the 'Wicked' gem for wizards and cannot figure out this error for the life of me. Already referenced Ryan bates railscast #346 and the step by step tutorial by schneems.
I have 2 controllers: Weddings and Wedding_steps. The user initially creates a Wedding and after the create action is redirected to the Wedding_steps controller (which uses Wicked) to update the wedding model with additional info.
The wedding_id is successfully detected in the first step weddingdetails, but after submitting that step, I get the following error:
ERROR
ActiveRecord::RecordNotFound in WeddingStepsController#update
Couldn't find Wedding without an ID:
app/controllers/wedding_steps_controller.rb:11:in `update'
Parameters:
{"utf8"=>"✓",
"_method"=>"put",
"authenticity_token"=>"JMd+8gf4rVqOSNMSFrKcD3WxK+X3zvYliSMWqTg0SkE=",
"wedding"=>{"bridename"=>"",
"groomname"=>"",
"weddingdate"=>"",
"weddingcity"=>"",
"weddingstate"=>"",
"url"=>""},
"commit"=>"Next",
"id"=>"wedding_id=11"}
It is supposed to continue to the next step /wedding_steps/eventdetails?wedding_id=11 but instead gives the error and goes to /wedding_steps/wedding_id=11
Also of note is that without the Update action in place, the information successfully saves and redirects to the Wedding Show action.
Here is the relevant code:
wedding_steps_controller.rb
class WeddingStepsController < ApplicationController
include Wicked::Wizard
steps :weddingdetails, :eventdetails
def show
#wedding = Wedding.find(params[:wedding_id])
render_wizard
end
def update
#wedding = Wedding.find(params[:wedding_id])
#wedding.update_attributes(params[:wedding])
render_wizard #wedding
end
end
weddings_controller.rb
def create
#wedding = current_user.weddings.new(params[:wedding])
respond_to do |format|
if #wedding.save
format.html { redirect_to wedding_steps_path(:id => "weddingdetails", :wedding_id => #wedding.id) }
format.json { render json: #wedding, status: :created, location: #wedding }
else
format.html { render action: "new" }
format.json { render json: #wedding.errors, status: :unprocessable_entity }
end
end
end
STEP 1: wedding_steps/weddingdetails.html.erb
<%= simple_form_for(#wedding, :url => wizard_path(wedding_id: #wedding.id), :method => :put, html: { class: 'form-horizontal'}) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<div class="formrow center">
<%= f.input :bridename, placeholder: "The Bride's Name", label: false %>
<h2 class="inline"> &</h2>
<%= f.input :groomname, placeholder: "The Groom's Name", label: false %>
</div>
<div class="formrow center">
<%= f.text_field :weddingdate %>
<!-- OLD STYLE DATE FORMAT <%= f.input :weddingdate, label: "Wedding Date" %> -->
<%= f.input :weddingcity, label: "City" %>
<%= f.input :weddingstate, label: "State" %>
</div>
<div class="formrow center">
<%= f.input :url, placeholder: "i.e. 'johnandkate' ", label: false %>
</div>
</div>
<div class="form-actions center">
<%= f.button :submit, value: "Next" %>
</div>
<% end %>
<%= link_to 'skip', next_wizard_path(wedding_id: #wedding.id) %>
STEP 2: wedding_steps/eventdetails.html.erb
EVENT DETAILS STEP <!--PLACEHOLDER FOR NOW -->
Routes.rb
Jobshop::Application.routes.draw do
resources :pins
resources :weddings
resources :wedding_steps
get "users/show"
root :to => 'pages#home'
get 'about' => 'pages#about'
devise_for :admin_users, ActiveAdmin::Devise.config
ActiveAdmin.routes(self)
resources :inviterequests
devise_for :views
ActiveAdmin.routes(self)
devise_for :users
ActiveAdmin.routes(self)
match 'users/:id' => 'users#show'
This line:
<%= simple_form_for(#wedding, :url => wizard_path, :method => :put, html: { class: 'form-horizontal'}) do |f| %>
Should be:
<%= simple_form_for(#wedding, :url => wizard_path(wedding_id: #wedding.id), :method => :put, html: { class: 'form-horizontal'}) do |f| %>
Note the wizard_path(wedding_id: #wedding.id) When you submit the form you should see parameters = {:wedding_id => some_number} in the logs.
Paste the output of the params for the update action if it doesn't work.
Edit:
You should have ":wedding_id" as part of the required url this will make it impossible to even generate a link to that controller unless it has a properly formatted url.
Replace this
resources :wedding_steps
with this
scope "weddings/:wedding_id" do
resources :wedding_steps
end
So now a correct url would look like weddings/83/wedding_steps/weddingdetails. Likely one or more of your view helpers isn't including wedding_id properly and with this new constraint you will raise an error in the view, but this is a good thing since it will show you where the malformed link is.
I tried the solution provided by Schneems, however it is not running completely without errors. I implemented the following way.
Change
resources :wedding_steps
To
scope "weddings/:wedding_id" do
resources :wedding_steps
end
The problem is parameters are displayed as forbidden based on the error that has been thrown as ActiveModel::ForbiddenAttributesError
To get rid off this,
Change
def update
#wedding = Wedding.find(params[:wedding_id])
#wedding.update_attributes(params[:wedding])
render_wizard #wedding
end
To
def update
#wedding = Wedding.find(params[:wedding_id])
#wedding.update_attributes(wedding_params)
render_wizard #wedding
end
private
def wedding_params
params.require(:wedding).permit(........your parameters here.................)
end

Why am I unable to save an associated object in a has_one relationship?

I've got a pickem object that has one result. I'm having an issue getting the result to save properly to the database.
pickems_controller.rb
def results
#pickem = Pickem.find params[:id]
# #pickem.result = #pickem.build_result if #pickem.result.blank?
#pickem.result = Result.new
end
def update_results
#pickem = Pickem.find params[:id]
#pickem.result = Result.new params[:pickem][:result_attributes]
if #pickem.result.update_attributes params[:pickem][:result_attributes]
redirect_to edit_pickem_results_path(#pickem), :notice => 'The results have been successfully updated.'
else
render "edit"
end
end
results.html.erb
<%= simple_form_for #pickem, :url => edit_pickem_results_path(#pickem), :method => :put, do |f| %>
<%= f.simple_fields_for :result do |r| %>
<%= r.input :first_name %>
...
<% end %>
<%= f.submit :class => 'btn btn-success', :label => 'Submit Results' %>
<% end %>
pickem.rb
has_one :result, :dependent => :destroy
accepts_nested_attributes_for :result
result.rb
belongs_to :pickem
I was initially using the build_result code that is commented out in the controller but had to back out of that. With build_result a result record was saved to the database the instant somebody clicked into the results form. There are rules in place in the application that don't allow users to make any picks if a result has been entered. So even if a user clicked into the result form but didn't submit, the result was still being created.
How can I build my form and save the result record only when the user clicks save, and not when the form is loaded? The current solution I've pasted above does not work. It saves a result record with the appropriate foreign key but never gets the form data. If I dump #pickem.result the correct form data is in the result object, I just can't get it to save right. Other solutions I've tried save the form data correctly but have a foreign key of 0.
EDIT:
For whatever reason #pickem.result = Result.new was still saving a record to the database so I changed it to #result = Result.new and updated the form as follows:
<%= simple_form_for #result, :url => edit_pickem_results_path(#pickem), :method => :put, do |r| %>
<%= r.input :first_name %>
<%= r.submit :class => 'btn btn-success', :label => 'Submit Results' %>
<% end %>
Then using the suggestion from Chuck W of #result = #pickem.result.build params[:result], I get undefined methodbuild' for nil:NilClass`.
pickems_controller.rb
def results
#pickem = Pickem.find params[:id]
#pickem.result.blank? ? #result = Result.new : #result = #pickem.result
end
def update_results
#pickem = Pickem.find params[:id]
 #result = #pickem.result.build params[:pickem][:result]
if #result.save
redirect_to edit_pickem_results_path(#pickem), :notice => 'The results have been successfully updated.'
else
render "edit"
end
end
Then, your view should look something like this:
<%= simple_form_for #pickem, :url => edit_pickem_results_path(#pickem), :method => :put, do |f| %>
<%= f.simple_fields_for #result do |r| %>
<%= r.input :first_name %>
...
<% end %>
<%= f.submit :class => 'btn btn-success', :label => 'Submit Results' %>
<% end %>
You might have to play around with how the parameters are being passed back to the update_results action (I'm pretty new to rails), but I think you get the gist of it.

Resources