I have a form where people can either create one cardrequest or many via uploading a csv file with ids. I have it working to simply create the requests. There are two things left I need to do in this routine that I am not sure how to do and looking for advice on.
1.) I need to check the ids either from the file upload or the single form field against an active table. If they are not active alert the person of that.
2.) If a combination of empid and cardholdergroup already exist update that request with the new params that were passed through.
Here is my action. Any thoughts on how/where I should do those? Any advice is appreciated.
def create
if cardrequest_params[:file].present?
file_path = cardrequest_params[:file].path
#cardholdergroups = cardrequest_params[:cardholdergroup_ids].map do |cardholdergroup_id|
CSV.foreach(file_path) do |row|
#cardrequest = Cardrequest.create(empid: row[0], startdate: cardrequest_params[:startdate], enddate: cardrequest_params[:enddate], user_id: current_user.id, cardholdergroup_ids: cardholdergroup_id)
end
end
else
#cardholdergroups = cardrequest_params[:cardholdergroup_ids].map do |cardholdergroup_id|
#cardrequest = Cardrequest.create(empid: cardrequest_params[:empid], startdate: cardrequest_params[:startdate], enddate: cardrequest_params[:enddate], user_id: current_user.id, cardholdergroup_ids: cardholdergroup_id)
end
end
respond_to do |format|
if #cardrequest.save
format.html { redirect_to cardrequests_path, notice: "Cardrequest was successfully created." }
format.json { render :show, status: :created, location: #cardrequest }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: #cardrequest.errors, status: :unprocessable_entity }
end
end
end
Well, there's a couple different ways you could go about this. If it were me, I would take the CSV parsing out of the server end entirely and do it with something like the JS library PapaParse. Have it send each of the fields to your create function one at a time. You could then easily use the find_or_create_by function or whatever logic you needed there to respond with a js message.
Then when they 'upload' with a csv file you could easily display a table of each of the csv line items and they're save/update results.
However, if you aren't a big javascript guy, I would at least separate the CSV upload from the create function into its own form.
# Cardrequest Controller
def csv_import
Cardrequest.import(params[:file])
end
Make a route for it...
Then put clean things up further by putting the CSV parse logic into the model:
# Cardrequest Model
def self.import(file)
# import logic here
CSV.foreach(file, headers: true) do |row|
row_hash = row.to_hash
match = Cardrequest.find_or_create_by(unique: row_hash["unique"])
match.update(#the rest of your data)
end
end
Hopefully this helps point you in the right direction.
Related
I have the following code that responds to GET /something.json:
def index
#something = Something.all
respond_to do |format|
format.json { render json: #something }
end
end
That runs a SELECT * FROM something in the database, formats the result into a JSON, and responds with it.
The request might ask for another field through a query parameter, which is in a different table than something. I managed to retrieve the desired field doing this:
def index
#something = Something.all
if params[:get_field_from_some_other_table] == "true"
#something.each do |i|
some_other_table = SomeOtherTable.find(i.some_other_table_id)
the_field_i_want = some_other_table.the_field
end
end
respond_to do |format|
format.json { render json: #something }
end
end
But I haven't found a way to add the field to the JSON string. How can I do that? Or is there a better way to retrieve the field with the contents of the something table through a JOIN or something like that?
something and other_table should be related at active_record somehow... maybe a has_one?
Try that and then just use #something.all.includes(:other_table_attribute)
Apart from that, please post your code properly with some readable examples, that helps a lot and will give you faster responses :)
I am struggling to get this working. I have three models
Student
Classroomattnd
Classroom
Using the has_many :through relationship. All my relationships are defined correctly and I have setup the nested form using the accepts_nested_attributes.
So when creating a new student I want to select from a list of classrooms instead of creating a new classroom. The form part also works fine the part I am not getting is when I create the student it complains about the following error.
Couldn't find Classrooom with ID=3 for Student with ID=
I have searched around for few days now but can not get the answer I need to get this working.
def new
#student = Student.new
#student.classrooms.build
end
def edit
end
def create
#student = Student.new(student_params)
respond_to do |format|
if #student.save
format.html { redirect_to #student, notice: 'Student was successfully created.' }
format.json { render :show, status: :created, location: #student }
else
format.html { render :new }
format.json { render json: #student.errors, status: :unprocessable_entity }
end
end
end
Can someone help here, someone must of face this issue before?
Also in the rails console when I run the following it works:
classroom = Classroom.last
student = Student.create(name: 'Dave', classrooms:[classroom])
Your parameter handling isn't supporting nesting. You can look at request parameters in your server log or inspect the fieldnames of your generated form to be sure of your target. It's going to be something along the lines of
def student_params
params.require(:student).permit(:student => [:name, :classroom => [:id, :name]])
end
Or maybe as below. In this second case I'm not assuming everything in the form is nested under a student container. Also note the switch from classroom to classroom_attributes which is a change I have sometimes needed to make even though the form above is what the docs indicate.
def student_params
params.require(:name).permit(:classroom_attributes => [:id, :name])
end
Hopefully that gives you a notion of how to tailor your parameter definition to what your form is generating. Also note your error messages give you indication of what part of your definition is failing, eg the missing Student id in the error you quote.
I am building a Rails app. And in my app, there are Projects where users can "Follow". When a user follows one of the pages, he/she will get updates if somebody uploads/creates a folder/file.
Below is the screenshot when somebody just created a new folder:
And below is the code for "Create" action in my Folder controller:
def create
#folder = current_user.folders.where(project_id: params[:project_id]).create(folder_params)
respond_to do |format|
if #folder.save
#folder.create_activity :create, owner: current_user, :params => {
:project_id => proc {|controller, project| #folder.project.id},
:project_name => proc {|controller, project| #folder.project.name},
}
format.html { redirect_to #folder.project, notice: 'Folder was successfully created.' }
format.json { render :show, status: :ok, location: #folder }
else
format.html { render :new }
format.json { render json: #folder.errors, status: :unprocessable_entity }
end
end
end
As you can see :project_id and :project_name are the parameters for the public_activity when a new folder being created.
And below is the screenshot on how this parameters value looks like in the database after they were saved:
QUESTION:
So my question is, how do i use this parameters values in my activities_controller?
Here is the code for my activities controller right now:
class ActivitiesController < ApplicationController
def index
#activities = PublicActivity::Activity.order("created_at desc").where(owner_id: current_user.following_users, owner_type: "User")
end
end
Instead of using "owner_id:", I want to use the "project_id" value from parameters column. So how can i do this?
Thank you very much in advanced! :)
The parameters field contains a simple yaml dump, so not really easy to search efficiently.
A simple solution would be to use LIKE operator, for instance
PublicActivity::Activity.where("parameters LIKE '%project_id: #{#project.id}%'")
You might want to consider to add custom fields instead.
Thanks for the answer, but I got a better solution than using the parameters value or custom field.
Here is how my activities_controller looks like right now:
class ActivitiesController < ApplicationController
def index
activity_table = PublicActivity::Activity.arel_table
# We want to view all activity of folders related to projects we are follwing
folder_ids = Folder.where(project_id: current_user.following_projects.pluck(:id)).pluck(:id)
# Generate query for all activity related to folders we care about
folders_query = activity_table[:trackable_type].eq('Folder').and(
activity_table[:trackable_id].in(folder_ids)
)
# Generate query for all users that we follow
users_query = activity_table[:owner_id].in(current_user.following_users.pluck(:id))
activity_query = folders_query.or(users_query)
#activities = PublicActivity::Activity.where(activity_query)
end
end
By using this way, I could easily combine the activities from the "Users" and also from the "Projects" that the user follows.
You can modify it to add any other activities such as from the "Comments" or "Voting".
Hope this will help other people out there that are using public_activity gem! :)
This is the field on form, I am using
<%= f.file_field :file ,:url=>{:controller=>"retailers",:action=>"csv_import"}%>
The following is the controller code
def create
#retailer = Retailer.new(params[:retailer])
respond_to do |format|
if verify_recaptcha(:model =>#retailer ) && #retailer .save
# To notify newly registered user.
retailer_ids = [#retailer.id]
Emailer.on_notify_retailer(retailer_ids, 1, 0)
sign_in #retailer
format.html { redirect_to pages_about_path}
flash[:notice1] = "Thank you for registering with Chindi."
flash[:notice2] = "We will process your application and get back to you within 48 hours. Once approved, you will be able to create negotiable deals that Consumers can tailor to their needs."
flash[:notice3] = "You will be able to create, manage and administer your deals and your buyers in this easy to use control panel."
format.json { render json: pages_about_path, status: :created, location: #retailer }
else
#title = "Sign up"
format.html { render action: "new"}
flash[:notice1] = "Incorrect word verification. Are you sure you\'re human?"
format.json { render json: #retailer.errors, status: :unprocessable_entity }
end
end
csv_parse()
end
The above code is used to save the data into database. The CSV file #retailer.file_file_name is to be stored in database as well as it needs to be parsed and the values need to be stored in fields
csv_parse is used to parse the csvfile
I am able to save file in data
now i need to parse the csv file and store the individual fields in another database.
the code for csv_parse is as follows.
def csv_parse
#parsed_file=CSV.foreach(params[:dump][:file].original_filename)
n=0
#parsed_file.each do |row|
User_list.create(
:email=>row[0],
:first_name=>row[1],
:last_name=>row[2]).save
flash.now[:message]="CSV parse Successful, #{n} new records added to data base"
end
end
when I run this it gives the following error/s.
You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.[]
please help me with the above error why is it throwing such an error
thanks in advance.
I just paste some peace of working for me code and hope it will help you:
first_line = true
file = File.open File.join(Rails.root, 'tmp/import/category.csv')
file.each do |line|
unless first_line
row = CSV::parse_line(line, ';')
category = Category.find_by_name(row[1]) || Category.create(:name => row[1], :target => 'basic')
category.update_attribute(:import_id, row[0])
else
first_line = false
end
end
I sometime wrote this code to import categories to my DB. Here you can change CSV file name and block for each iterator. Also first_line is description for fields and I was ignoring it.
def create
#retailer = Retailer.new(params[:retailer])
respond_to do |format|
# ... same as above
end
csv_parse(params[:retailer][:file].path)
private
def csv_parse(path)
rows = CSV.read(path)
rows.each do |row|
User_list.create(:email=> row[0], :first_name=>row[1], :last_name=>row[2])
end
flash.now[:message]= "CSV parse Successful, #{rows.size} new records added"
end
end
I have a generic import table that allows the loading of csv files into different columns in my import table. The same import table is used for multiple types of imports, so I don't process the individual fields until the user is ready and tells me where to process it.
So in this case I have an import table with many cells that I will use to create (or update) donors in my donors table. How do I send my import_table data associated with the import_table model and controller to the create method of my donors_controller?
the create method of my donors_controller:
def create
# need to find donor by id if given, else use find_or_create_by_blahblahblah
unless #donor = Donor.find_by_id(params[:donor][:id])
#donor = Donor.find_or_initialize_by_company_and_prefix1_and_first_name1_and_last_name1_and_address1(params[:donor])
end
if #donor.new_record?
respond_to do |format|
if #donor.save
format.html { redirect_to #donor, notice: 'Donor was successfully created.' }
format.json { render json: #donor, status: :created, location: #donor }
else
format.html { render action: "new" }
format.json { render json: #donor.errors, status: :unprocessable_entity }
end
end
else
respond_to do |format|
if #donor.save
format.html { redirect_to #donor, notice: 'Donor already exists. Please edit donor if needed.'}
format.json { render json: #donor, status: :created, location: #donor }
else
format.html { render action: "new" }
format.json { render json: #donor.errors, status: :unprocessable_entity }
end
end
end
end
Then in my import_tables controller I have this method:
def process_import
#import = ImportTable.find(params[:id])
if #import.import_type == 'Prospects'
#do something here....
elsif #import.import_type == 'Donations'
#do something here...
end
end
I am not sure what exactly I should do in the #do something here... parts.
I was thinking I should pick out the right columns from #import and put them in [:donor] array and send them to the create method of my donors_controller, but I am not sure exactly how to do that or if that is the right way to go about this.
The missing link is that you need to get to the Class from it's name..
There are several ways to do this, e.g. with an "eval' , but a cleaner and simpler way to do this is to:
# do something:
class_name = #import.import_type
klass = ActiveRecord.const_get(class_name) # now you have a reference to your class
#... then do whatever you like with your symbolic klass, e.g. create your new entry
# klass.find_or_create(...) , klass.find(1), klass.first ,
# klass.create( {attributes for new instance of klass} )
this works so conveniently because in your model you do YourClass < ActiveRecord::Base ,
your class is part of the ActiveRecord module, Classes in Ruby are constants which are stored in the context in which they are defined (=in their module), therefore you can query that context, e.g. ActiveRecord, and find your class.
If your class was not derived from ActiveRecord::Base , you could still do a:
klass = Kernel.const_get( class_name )
see also:
http://infovore.org/archives/2006/08/02/getting-a-class-object-in-ruby-from-a-string-containing-that-classes-name/
if you are going line by line, Keep count of which line you are processing.
then in your #do something areas just call Prospect.new, Donation.new, etc.
validate or save it, and gather up all the errors reported by the object so that you can spit them back to the user with a line number of where the error occured.
You don't need to goto the specific controller methods for each type. Your import logic will basically handle it.