Script to Update field in rails - ruby-on-rails

I have a csv file which containing parent and their children data.Parent has many children association. What I want is if the family_situation/gross_income or both are different for different children I want the last family_situation/gross_income for that parent to be saved into the database. Like in this case below I want family_situation to be "family of three" and gross income to be "16775". What I current have in my parent model is as below. How can I achieve this please help.
parent.rb
def self.import(file)
CSV.foreach(file.path, headers:true) do |row|
parent = Parent.find_or_create_by(
parent_1_firstname: row["parent_1_firstname"],
parent_1_lastname: row["parent_1_lastname"],
family_situation: row["family_situation"],
gross_income: row["gross_income"],
)
parent.children.find_or_create_by(
firstname: row["firstname"],
gender: row["gender"]
)
end
end
parent.csv
parent_1_firstname,parent_1_lastname,family_situation,gross_income,childfirstname,childgender
Josh,Wilson,"family of two",13000,Jessica,Female
Josh,Wilson,"family of three",16775,Jamie,Male

As you want to save only last value for family_situation and gross_income you can just find existing parent and update it:
parent = Parent.find_or_initialize_by(
parent_1_firstname: row["parent_1_firstname"],
parent_1_lastname: row["parent_1_lastname"]
).tap do |p|
p.family_situation = row["family_situation"]
p.gross_income = row["gross_income"]
p.save
end
Here you're trying to find a parent with particular first&last names. If it exists, it is instantiated, if not - it is builded with given names. After it you're assigning family_situation and gross_income and save the instance.

Related

How to append an array in parameters after Rails form submit?

I have a form with checkboxes that get passed as an array "list_person_ids" on form submit. My models are "Occurance" which has an n:m relationship with "ListPerson" through the Model "Person". "list_person_ids" are saved in Person with the Occurance id and the ListPerson id.
I want to append one or more values to the array before this gets saved. The reason I need to do this is because the user can also add a new value in ListPerson using a textbox with the name "person_name".
def create
#occurance = Occurance.new(occurance_params)
add_person_id(#occurance)
...
# save
end
def add_person_id(object)
if params[:person_check] == '1'
object.list_person_ids.push( ListPerson.find_or_create_by(person: params[:person_name]).id )
end
end
def occurance_params
params.require(:occurance).permit(:person_check, :person_name, dim_person_ids: [])
end
find_or_create_by is successful, but nothing gets pushed to the array "list_person_ids". There is also no error message. Do I have to give permission somewhere to append this array? Please let me know if some information is missing.
on your model you can do something like below:
....
before_create :create_lists
private
def create_lists
ListPerson.find_or_create_by(list_person_ids: person_name.id)
end

Creating a variable number of new ActiveRecord records at once Rails

I have a concept called Transactions. Each transaction can consist of a specific number_of_stocks- say 10.
What I'm now looking at doing, is creating a new record (Share) for each of that number_of_stocks.
Example: If #transaction.number_of_stocks = 10 then we should create 10 new records of Share.
The code below works if I just create one at a time, but I haven't found a way to create a variable number of new records depending on the #transaction.number_of_stocks variable.
In addition, and to make things trickier - each Share has an attribute share_number. What I would like to do is that for each new Share record created, the share_number should increment, but it should also check if there are any existing share_numbers belonging to the cap-table already, and "start there".
Just for context, I'll probably wrap this functionality into a TransactionsHelper somewhere so I can use it elsewhere.
#number_of_share_numbers_to_create = #transaction.number_of_stocks # Example: 10
Share.create( #TODO: Now we need to create 10 records here
owner_id: params[:buying_shareholder_id],
captable_id: #transaction.captable.id,
company_id: #transaction.company.id,
share_number: #TODO: Increment based on the latest share_number linked to this captable and then for each new record in this transaction
)
The model
class Share < ApplicationRecord
belongs_to :captable
belongs_to :company
end
You'll want to look at the times method on Integer. Something, perhaps, like:
#transaction.number_of_stocks.times do |i|
Share.create( #TODO: Now we need to create 10 records here
owner_id: params[:buying_shareholder_id],
captable_id: #transaction.captable.id,
company_id: #transaction.company.id,
share_number: #TODO: Increment based on the latest share_number linked to this captable and then for each new record in this transaction
)
end
If number_of_stocks is really a decimal and not an integer, as you state in your comment above, then you'll need to fiddle in order to make times work and to manage fractional shares. But, that's a different issue.
As an aside, will you always be transacting only stocks? What about other asset forms (e.g., bonds), derivatives (e.g., options), or other transactable assets/instruments? If at some point you will be transacting other assets/instruments, you might want to think about that now. Just a thought.
I solved the share_number piece with the following
A quick method to get the latest share_number
def get_latest_share_number_from_captable(captable)
#captable = Captable.find(captable.id)
#shares = #captable.shares
#share_numbers = []
#shares.each do |s|
#share_numbers.push(s.share_number)
end
#latest_share = #share_numbers.max
return #latest_share
end
Then I use that method and the .times solution suggested in order to create new records.
# Add share numbering for this transaction
#number_of_share_numbers_to_create = #transaction.number_of_stocks.to_i
# Get last sharenumber in captable
#latest_share = get_latest_share_number_from_captable(#transaction.captable)
#number_of_share_numbers_to_create.times do |i|
Share.create(
owner_id: params[:buying_shareholder_id],
captable_id: #transaction.captable.id,
company_id: #transaction.company.id,
share_number: #latest_share += 1 #Increment for each new record
)
end

How can I build out child associations on my object in Rails without saving the parent?

I'm trying to initialize an object, but I don't want to create the object to the database until the user has click saved. I've gotten this to work with the parent object only, but I can't seem to get my child objects to associate to the parent because I don't have an id yet for the parent object. What am I doing wrong in the code below? Thanks.
def new
# Build a new report object with the default type of "draft" and assign it to the player
report_options = { player_id: #player.id,
author_id: current_user.id,
position: #player.position,
type: "draft",
submitted: false }
#report = Report.new(report_options)
#skills.where('disabled = (?)',FALSE).each do |skill|
# On the line below I get an evaluation record with a proper skill id,
# but report_id is `nil` because I'm guessing the report hasn't been
# created yet. Is there a way to reserve an id for it without actually
# committing the record to the database until the user saves the record?
#report.evaluations.build(skill_id: skill.id)
end
end
The model of evaluations is not quite clear to me, but basically if you do something like
#report.evaluations.build
#skills.where('disabled = (?)', FALSE).each do |skill|
#report.evaluations << Evaluation.new(skill_id: skill.id)
end
it will add objects to evaluations without saving and won't require the report.id to exist at the moment of adding.

Rails 4 CSV upload into multiple models

I am trying to upload a csv file that has data that belongs in two different models: Project and PurchaseOrder. I am using a has_many, :through relationship between the models.
I'm having problems with the upload. I have whitelisted the shared attributes in both controllers and have included the accepts_nested_attributes in both models.
Here's my code to read in the csv.
def self.import(file)
CSV.foreach(file.path, headers: true) do |row|
project_hash = row.to_hash
project = Project.where(project_name: project_hash["project_number"]).first
if project.present?
project.first.update_attributes(project_hash)
else
Project.create! (project_hash)
end
purchase_order = PurchaseOrder.where(po_number: project_hash["po_number"]).first
if purchase_order.present?
PurchaseOrder.create!
end
I have two questions/problems.
I cannot read in the po_number attribute. I get this error unknown attribute 'po_number' for Project.
I do not know how to push the created purchase order into the project hash so that it updates the nested attribute value.
Thank you in advance to anyone who is able to help!
**** Update
With this method, the data is saved to the correct tables. However, the association between PurchaseOrder and Project is not saved. Any thoughts?
def self.import(file)
CSV.foreach(file.path, headers: true) do |row|
project_hash = row.to_hash
po_hash = {}
po = PurchaseOrder.new
project_hash.each { |k, v| po_hash[k] = project_hash.delete(k) if po.respond_to?(k) }
project = Project.where(project_name: project_hash["project_number"]).first
if project.present?
project.first.update_attributes(project_hash)
else
Project.create! (project_hash)
end
po = PurchaseOrder.where(po_number: po_hash["po_number"]).first
if po.present?
po.first.update_attributes(po_hash)
else
PurchaseOrder.create! (po_hash)
end
end
end
These lines are attempting to update / create the project using all the values in the hash...
project.first.update_attributes(project_hash)
...
Project.create! (project_hash)
But clearly some hash elements (such as "po_number") don't have columns in the projects table.
You need to split out the csv hash elements based on which elements belong to which model...
e.g.
po_hash = {}
po = PurchaseOrder.new
project_hash.each { |k, v| po_hash[k] = project_hash.delete(k) if po.respond_to?(k) }
This will remove the purchase order fields from project_hash and add them to po_hash so you can use the correct hash to update the correct table.
To establish the association...
change
Project.create!(project_hash)
into
project = Project.create!(project_hash)
so that regardless of whether the project exists or is newly created, it's stored in the variable "project". Similarly, do
po = PurchaseOrder.create!(po_hash)
Then after you have created or updated the purchase order, you can simply assign the po to the project...
project.purchase_orders << po

How to get random ids, that are not on X list

So I have a code snippet that essentially finds a random List, and prints it out. However in the loop it also saves that id into a table called statuses.
Now I want to be able to go through that list again, and this time print out 150 randoms. However, this time I want it to check through statuses first to make sure that List item haven't been printed out before.
Here's the code I have now:
class ScheduleTweets
#queue = :schedules_queue
def self.perform(user_token, user_id)
client = Buffer::Client.new(user_token)
user = user_id
list = List.all.sample(150)
profiles = client.profiles
profile_ids = profiles.map(&:id)
list.each do |list|
list.statuses.create(:user_id => user)
client.create_update(body: {text: "#{list.text}", profile_ids: profile_ids })
end
end
end
If I were to guess I should add something after List.all.sample(150) where it checks if the list has a list_id that is present in Status.
Gather the list items from the statues table and make an array with that result.
stat_ids = Status.all.collect{|s| s.list_id}
now loop through the random 150 list and check the list id contains in stat_ids or not.
random_lists.each do |rl|
if stat_ids.include?(rl.id)
//do something
end
end
As I don't know your database architecture, I assumed it as above.

Resources