Validations for Importing CSV data into MySql database in Rails 3.1? - mysql

i implemented the task of importing data from csv into MySQL database successfully. Now, my requirement is: i need to get error message with line number, if there is any mis match of data in csv file while importing.
This is my controller code:
**require 'csv' #at the top and followed by...
def load_csv
# no code
end
def import_csv
parsed_file = CSV.foreach(params[:csv].tempfile,:headers => true) do |row|
row = row.to_hash.with_indifferent_access
Institute.create!(row.to_hash.symbolize_keys)
redirect_to :action => :index
end
In my view/ load_csv.html.erb:
<%= form_for(:institute, :url => import_csv_institutes_path, :html => {:multipart => true}) do |f| %>
<div class="field">
<%= file_field_tag :csv %>
<%= f.submit 'Import' %>
</div>
<% end %>
These are the only two steps i used for importing. Model validations are working only for form and for csv, an error page displayed..
Please try to help me out.........................

Assign an error message to the flash[:notice] variable in the import_csv method. Do it before redirect.
http://guides.rubyonrails.org/action_controller_overview.html

Related

Validation problems while creating record through file import using Roo gem and following railscast

I am trying to create records through file imports format can be csv excel etc
and I have implemented it following the Railscast396. but as I import file it says
"Validation failed: Email can't be blank, Password can't be blank. Here is my code
class Student < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
has_many :quizzes
has_many :classrooms
#to import file
**def self.attr_names
[:email, :password, :password_confirmation]
end**
def self.import(file)
spreadsheet = open_spreadsheet(file)
header = spreadsheet.row(1)
(2..spreadsheet.last_row).each do |i|
row = Hash[[header, spreadsheet.row(i)].transpose]
row.inspect
student = find_by_id(row["id"]) || new
student.attributes = row.to_hash.slice(*attr_names)
student.save!
end
end
def self.open_spreadsheet(file)
case File.extname(file.original_filename)
when ".csv" then Roo::CSV.new(file.path, file_warning: :ignore)
when ".xls" then Roo::Excel.new(file.path, file_warning: :ignore)
when ".xlsx" then Roo::Excelx.new(file.path, file_warning: :ignore)
else raise "Unknown file type: #{file.original_filename}"
end
end
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
view is
<%= form_tag addStudents_classrooms_path, multipart: true do %>
<%= file_field_tag :file %>
<%= submit_tag "Import" %>
<% end %>
routes.rb
resources :classrooms do
collection { post :addStudents }
csv file i am trying to load
id,email,password,password_confirmation
22,jim#gmail.com,password,password
23,jimhanks#gmail.com,password,password
This is probably happening because #to_hash doesn't return a hash with indifferent access. You're trying to slice symbolized keys and #to_hash created keys as strings.
Try this:
def self.attr_names
%w(email password password_confirmation)
end

undefined method `user_revisers_path' "NoMethodError in Revisers#new "

I got this weird error I'm assuming this comes from the routes.rb part of my app. Im trying to give the chance for a user to become a reviser when they enter a form. a user can only become a reviser once so its a has_one reviser on user.rb model Thanks!
routes.rb:
Rails.application.routes.draw do
root 'pages#home'
devise_for :users ,
:path => '' ,
:path_names => { :sign_in => 'login', :sign_out => 'logout', :edit => 'profile' },
:controllers => { :omniauth_callbacks => 'omniauth_callbacks',
:registrations => 'registrations'
}
resources :users, only: [:index, :show] do
resource :reviser
end
revisers_controller:
class RevisersController < ApplicationController
before_action :set_reviser, only: [:show, :edit, :update]
before_action :authenticate_user!, except: [:show]
def index
#reviser = current_user.reviser
end
def show
end
def new
#reviser = current_user.build_reviser(params[:reviser])
#user = User.find(params[:user_id])
end
def create
#reviser = current_user.reviser.build(reviser_params)
if #reviser.save
redirect_to #reviser,notice: "saved...."
else
render :new
end
end
def edit
set_reviser
end
def update
set_reviser
if #reviser.update(reviser_params)
redirect_to #reviser, notice: "updated.."
else
render :edit
end
end
private
def set_reviser
#reviser = Reviser.find(params[:id])
end
def reviser_params
params.require(:reviser).permit(:description, :average_start, :average_end, :max_pages, :price_per, :active)
end
end
new.html
<%= form_for [current_user, #reviser] do |f| %>
<div class="row">
<div class="div.col-md-4 select">
<div class="form-group">
<label>dsd</label>
<%= f.input :description, label: false, class: 'controls',:input_html => { :id => 'description' } %>
</div>
</div>
</div>
<%= f.submit "Become Adviser", class: "btn btn-large btn-primary" %>
<% end %>
Error log:
Rendered revisers/_form.html.erb (14.7ms)
Rendered revisers/new.html.erb within layouts/application (15.9ms)
Completed 500 Internal Server Error in 48ms (ActiveRecord: 1.1ms)
ActionView::Template::Error (undefined method `user_revisers_path' for #<#<Class:0x007faf35f0cc60>:0x007faf35ee7e60>):
5: <div class="panel-body">
6: <div class="container">
7:
8: <%= form_for [current_user, #reviser] do |f| %>
9:
10: <div class="row">
11: <div class="div.col-md-4 select">
app/views/revisers/_form.html.erb:8:in `_app_views_revisers__form_html_erb___2471522092853631188_70195335070980'
app/views/revisers/new.html.erb:1:in `_app_views_revisers_new_html_erb___1451348464463745171_70195280947160'
Rake routes:
Prefix Verb URI Pattern Controller#Action
root GET / pages#home
new_user_session GET /login(.:format) devise/sessions#new
user_session POST /login(.:format) devise/sessions#create
destroy_user_session DELETE /logout(.:format) devise/sessions#destroy
user_omniauth_authorize GET|POST /auth/:provider(.:format) omniauth_callbacks#passthru {:provider=>/facebook/}
user_omniauth_callback GET|POST /auth/:action/callback(.:format) omniauth_callbacks#(?-mix:facebook)
user_password POST /password(.:format) devise/passwords#create
new_user_password GET /password/new(.:format) devise/passwords#new
edit_user_password GET /password/edit(.:format) devise/passwords#edit
PATCH /password(.:format) devise/passwords#update
PUT /password(.:format) devise/passwords#update
cancel_user_registration GET /cancel(.:format) registrations#cancel
user_registration POST / registrations#create
new_user_registration GET /sign_up(.:format) registrations#new
edit_user_registration GET /profile(.:format) registrations#edit
PATCH / registrations#update
PUT / registrations#update
DELETE / registrations#destroy
user_confirmation POST /confirmation(.:format) devise/confirmations#create
new_user_confirmation GET /confirmation/new(.:format) devise/confirmations#new
GET /confirmation(.:format) devise/confirmations#show
user_reviser POST /users/:user_id/reviser(.:format) revisers#create
new_user_reviser GET /users/:user_id/reviser/new(.:format) revisers#new
edit_user_reviser GET /users/:user_id/reviser/edit(.:format) revisers#edit
GET /users/:user_id/reviser(.:format) revisers#show
PATCH /users/:user_id/reviser(.:format) revisers#update
PUT /users/:user_id/reviser(.:format) revisers#update
DELETE /users/:user_id/reviser(.:format) revisers#destroy
users GET /users(.:format) users#index
user GET /users/:id(.:format) users#show
photos GET /photos(.:format) photos#index
POST /photos(.:format) photos#create
new_photo GET /photos/new(.:format) photos#new
edit_photo GET /photos/:id/edit(.:format) photos#edit
photo GET /photos/:id(.:format) photos#show
PATCH /photos/:id(.:format) photos#update
PUT /photos/:id(.:format) photos#update
DELETE /photos/:id(.:format) photos#destroy
pages GET /pages(.:format) pages#index
POST /pages(.:format) pages#create
new_page GET /pages/new(.:format) pages#new
edit_page GET /pages/:id/edit(.:format) pages#edit
page GET /pages/:id(.:format) pages#show
PATCH /pages/:id(.:format) pages#update
PUT /pages/:id(.:format) pages#update
DELETE /pages/:id(.:format) pages#destroy
autocomplete_user_country_suggestions GET /suggestions/autocomplete_user_country(.:format) suggestions#autocomplete_user_country
autocomplete_user_city_suggestions GET /suggestions/autocomplete_user_city(.:format) suggestions#autocomplete_user_city
autocomplete_user_school_suggestions GET /suggestions/autocomplete_user_school(.:format) suggestions#autocomplete_user_school
autocomplete_user_major_suggestions GET /suggestions/autocomplete_user_major(.:format) suggestions#autocomplete_user_major
suggestions GET /suggestions(.:format) suggestions#index
POST /suggestions(.:format) suggestions#create
new_suggestion GET /suggestions/new(.:format) suggestions#new
edit_suggestion GET /suggestions/:id/edit(.:format) suggestions#edit
suggestion GET /suggestions/:id(.:format) suggestions#show
PATCH /suggestions/:id(.:format) suggestions#update
PUT /suggestions/:id(.:format) suggestions#update
DELETE /suggestions/:id(.:format) suggestions#destroy
conversation_messages GET /conversations/:conversation_id/messages(.:format) messages#index
POST /conversations/:conversation_id/messages(.:format) messages#create
conversations GET /conversations(.:format) conversations#index
POST /conversations(.:format) conversations#create
post_comments GET /posts/:post_id/comments(.:format) comments#index
POST /posts/:post_id/comments(.:format) comments#create
new_post_comment GET /posts/:post_id/comments/new(.:format) comments#new
edit_post_comment GET /posts/:post_id/comments/:id/edit(.:format) comments#edit
post_comment GET /posts/:post_id/comments/:id(.:format) comments#show
PATCH /posts/:post_id/comments/:id(.:format) comments#update
PUT /posts/:post_id/comments/:id(.:format) comments#update
DELETE /posts/:post_id/comments/:id(.:format) comments#destroy
post_places GET /posts/:post_id/places(.:format) places#index
POST /posts/:post_id/places(.:format) places#create
new_post_place GET /posts/:post_id/places/new(.:format) places#new
edit_post_place GET /posts/:post_id/places/:id/edit(.:format) places#edit
post_place GET /posts/:post_id/places/:id(.:format) places#show
PATCH /posts/:post_id/places/:id(.:format) places#update
PUT /posts/:post_id/places/:id(.:format) places#update
DELETE /posts/:post_id/places/:id(.:format) places#destroy
posts GET /posts(.:format) posts#index
POST /posts(.:format) posts#create
new_post GET /posts/new(.:format) posts#new
edit_post GET /posts/:id/edit(.:format) posts#edit
post GET /posts/:id(.:format) posts#show
PATCH /posts/:id(.:format) posts#update
PUT /posts/:id(.:format) posts#update
DELETE /posts/:id(.:format) posts#destroy
You have a singular resource definition for your :reviser route. This makes sense for what you're trying to do, however the route generated by form_for [current_user, #reviser] will try to generate a route with both a :user_id, and an :id to identify your reviser.
So, the :id field isn't defined in your case since resource :reviser doesn't create an :id.
The solution is to explicitly set the url in your form_for to the route your want:
It should be something along the lines of:
form_for #reviser, url: edit_user_reviser_path(user_id: current_user.id)
The bigger issue with your code is that you're still directly referencing reviser by id in your controller. Under your current route settings, this will return an error on the Reviser.find() method. However, more importantly this presents a security concern since a malicious user could send an id param in the PATCH request to hijack and update a record that belongs to another user.
A simple solution is to just reference the reviser object directly on current_user.
def set_reviser
#reviser = current_user.reviser
end

undefined method `[]' for nil:NilClass while importing csv file in rails

I have an application on which I want to provide the feature to import the records from CSV and Excel file formats. I am using roo gem for it, but at the time of importing it gives the error "undefined method `[]' for nil:NilClass".
Here is the code :
student.rb :
require 'roo'
def self.import(file)
spreadsheet = open_spreadsheet(file)
header = spreadsheet.row(1)
(2..spreadsheet.last_row).each do |i|
row = Hash[[header, spreadsheet.row(i)].transpose]
product = find_by_id(row["id"]) || new
product.attributes = row.to_hash.slice(*accessible_attributes)
product.save!
end
end
def self.open_spreadsheet(file)
case File.extname(file.original_filename)
when ".csv" then Roo::CSV.new(file.path, nil, :ignore)
when ".xls" then Roo::Excel.new(file.path, nil, :ignore)
when ".xlsx" then Roo::Excelx.new(file.path, nil, :ignore)
else raise "Unknown file type: #{file.original_filename}"
end
end
student_controller.rb :
def import
Student.import(params[:file])
redirect_to students_path, notice: "Record imported Successfully."
end
new.html.erb :
<%= form_tag import_students_path, multipart: true do %>
<%= file_field_tag :file , :required=> true%> <br/>
<%= submit_tag "Import" , :class => "btn btn-primary btn-block" %>
<% end %>
Tell me what i am doing wrong?

ruby like query error

This is my code for mysql like query:
def search
params.permit!
#query = params[:query]
respond_to do |format|
#outlet = Outlet.select(:name).where("name like ?","%#{#query}%")
format.json { render json: #outlet }
end
end
It renders all of my data from table. It does not respond to the query. Do you have any ideas?
My route is:
namespace :api do
resources :outlets, :defaults => { :format => 'json'}
get 'outlets/auto_complete' => 'outlets#auto_complete', :defaults => { :format => 'json'}
post 'outlets/search' => 'outlets#search', :defaults => { :format => 'json' }
end
The development.log is
Started POST "/api/outlets/search" for 127.0.0.1 at 2015-05-30 16:56:22 +0530
Processing by Api::OutletsController#search as JSON
Parameters: {"outlet"=>{"query"=>"life"}}
[1m[35mOutlet Load (0.1ms)[0m SELECT `outlets`.`name` FROM `outlets` WHERE (name like '%%')
Completed 200 OK in 28ms (Views: 22.3ms | ActiveRecord: 1.7ms)
Looking at the log file and below trace :-
Parameters: {"outlet"=>{"query"=>"life"}}
I found the issue. You need to do #query = params[:outlet][:query].
It is because params[:query] is nil, so the resulting sql is
where name like '%%'
You do have a query parameter in params[:outlet][:query] which you could use without changing your view.
However, as you're not creating or updating an Outlet, and query probably isn't an attribute of the Outlet model, it doesn't really make sense to structure the form in this way.
Try using form_tag instead of form_for and don't pass it an instance of Outlet. Also use text_field_tag instead of form.text_field. This way params[:query] will be set, instead of being wrapped under params[:outlet].
The new form would look a bit like this:
<%= form_tag do %>
<%= text_field_tag :query %>
<%= submit_tag %>
<% end %>

RoR nested attributes produces duplicates when edit

I'm trying to follow Ryan Bates RailsCast #196: Nested model form part 1. There're two apparent differences to Ryans version: 1) I'm using built-in scaffolding and not nifty as he's using, and 2) I'm running rails 4 (I don't really know what version Ryans using in his cast, but it's not 4).
So here's what I did
rails new survey2
cd survey2
bundle install
rails generate scaffold survey name:string
rake db:migrate
rails generate model question survey_id:integer content:text
rake db:migrate
Then I added the associations to the models like so
class Question < ActiveRecord::Base
belongs_to :survey
end
and so
class Survey < ActiveRecord::Base
has_many :questions
accepts_nested_attributes_for :questions
end
Then I added the nested view part
<%= form_for(#survey) do |f| %>
<!-- Standard rails 4 view stuff -->
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.fields_for :questions do |builder| %>
<div>
<%= builder.label :content, "Question" %><br/>
<%= builder.text_area :content, :rows => 3 %>
</div>
<% end %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
and finally the controller so that 3 questions are created whenever a new survey is instantiated
class SurveysController < ApplicationController
before_action :set_survey, only: [:show, :edit, :update, :destroy]
# Standard rails 4 index and show
# GET /surveys/new
def new
#survey = Survey.new
3.times { #survey.questions.build }
Rails.logger.debug("New method executed")
end
# GET /surveys/1/edit
def edit
end
# Standard rails 4 create
# PATCH/PUT /surveys/1
# PATCH/PUT /surveys/1.json
def update
respond_to do |format|
if #survey.update(survey_params)
format.html { redirect_to #survey, notice: 'Survey was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #survey.errors, status: :unprocessable_entity }
end
end
end
# Standard rails 4 destroy
private
# Use callbacks to share common setup or constraints between actions.
def set_survey
#survey = Survey.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def survey_params
params.require(:survey).permit(:name, questions_attributes: [:content])
end
end
So, creating a new survey with three questions is fine. However, if I try to edit one of the surveys, the original three questions are maintained, while an additional three more are created. So instead of having 3 questions for the edited survey, I now have 6. I added
Rails.logger.debug("New method executed")
to the new method in the controller, and as far as I can tell, it is not executed when I'm doing an edit operation. Can anyone tell me what I'm doing wrong?
Any help is greatly appreciated!
I had to add :id to the permitted params in the survey_params method. It now looks like this:
# Never trust parameters from the scary internet, only allow the white list through.
def survey_params
params.require(:survey).permit(:name, questions_attributes: [:id, :content])
end
which works perfectly. I guess new id's were generated instead of being passed to the update action.
Using cocoon gem on Rails 4, I was still getting duplicate fields even after adding :id to the permitted list when editing. Noticed the following as well
Unpermitted parameters: _destroy
Unpermitted parameters: _destroy
So I added the :_destroy field to the permitted model_attributes: field and things worked smoothly after that.
For example...
def survey_params
params.require(:survey).permit(:name, questions_attributes: [:id, :content, :_destroy])
end