Get row of inserted id in rails transaction with postgres - ruby-on-rails

I have the following code:
#which receives Group objects and saves them in a transaction
def saveGroup(group_buffer)
self.transaction do
output = group_buffer.each(&:save)
if(!output)
return false
break
elsif( #I want the inserted row id as they are inserted)
#put inserted row id in array
end
end
return #the_array
end
Is this possible? Basically, what I want is to obtain the inserted row id in a transaction as the objects are saved and push it into an array. What is the best way to do this? Thank you very much...

Is this what you are looking for? if any instance will not save, the transaction will roll back, so you don't have to brake it manually.
def saveGroup(group_buffer)
ids = []
self.transaction do
group_buffer.each do |i|
i.save
ids << i.id
end
end
if ids.empty?
false
else
ids
end
end

Related

Update record if exists with roo gem

I have an import working correctly from a Spreadsheet using Roo gem.
The problem is every time I call the rake task, new records are created.
I want to update_attributes of the records in case the record exists.
Is there any way to approach this? I've tried this with no luck:
namespace :import do
desc "Import data from spreadsheet" # update this line
task data: :environment do
data = Roo::Spreadsheet.open('lib/t3.xlsx') # open spreadsheet
headers = data.row(1) # get header row
data.each_with_index do |row, idx|
next if idx == 0 # skip header
# create hash from headers and cells
product_data = Hash[[headers, row].transpose]
product = Product.new(product_data)
puts "Guardando Producto #{product.name}"
if product?
product.update_attributes
else
product.save!
end
rescue ActiveRecord::RecordInvalid => invalid
puts invalid.record.errors
end
end
end
if product? will never return false. You're testing whether the variable contains a falsy value (nil/false) or any other value. After calling product = Product.new, the value stored in product can never be nil or false.
What you want is to first find, and if not found, new, and then update_attributes on the resulting object:
product = Product.find_by(product_data.name) || Product.new
product.update_attributes(product_data)

Rails saving arrays to separate rows in the DB

Could someone take a look at my code and let me know if there is a better way to do this, or even correct where I'm going wrong please? I am trying to create a new row for each venue and variant.
Example:
venue_ids => ["1","2"], variant_ids=>["10"]
So, I would want to add in a row which has a venue_id of 1, with variant_id of 10. And a venue_id of 2, with variant_id of 10
I got this working, and it's now passing in my two arrays. I think I am almost there I'm not sure the .each is the right way to do it, but I think that I'm on the right track haha. I have it submitting, however, where would I put my #back_bar.save? because this might cause issues as it won't redirect
Thanks in advance.
def create
#back_bar = BackBar.new
#venues = params[:venue_ids]
#productid = params[:product_id]
#variants = params[:variant_ids]
# For each venue we have in the array, grab the ID.
#venues.each do |v|
#back_bar.venue_id = v
# Then for each variant we associate the variant ID with that venue.
#variants.each do |pv|
#back_bar.product_variant_id = pv
# Add in our product_id
#back_bar.product_id = #productid
# Save the venue and variant to the DB.
if #back_bar.save
flash[:success] = "#{#back_bar.product.name} has been added to #{#back_bar.venue.name}'s back bar."
# Redirect to the back bar page
redirect_to back_bars_path
else
flash[:alert] = "A selected variant for #{#back_bar.product.name} is already in #{#back_bar.venue.name}'s back bar."
# Redirect to the product page
redirect_to discoveries_product_path(#back_bar.product_id)
end
end # Variants end
end # Venues end
end
private
def back_bar_params
params.require(:back_bar).permit(:venue_id,
:product_id,
:product_variant_id)
end
as i said in comments
this is untested code and just showing you how it's possible to do with ease.
class BackBar
def self.add_set(vanue_ids, variant_ids)
values = vanue_ids.map{|ven|
variant_ids.map{|var|
"(#{ven},#{var})"
}
}.flatten.join(",")
ActiveRecord::Base.connection.execute("INSERT INTO back_bars VALUES #{values}")
end
end
def create
# use in controller
BackBar.add_set(params[:venue_ids], params[:variant_ids])
# ...
end

Rails Check If Record Is First

I am iterating through a list of records. I need to check that if a record is first do XYZ and if not do ABC. Unfortunately I cant do this:
user = User.first
or
user = User.find(:id)
user.first?
Solution posted below
1. Make method to grab next and previous records
def next
[Model].where("id > ?", id).first
end
def prev
[Model].where("id < ?", id).last
end
2. Make method to check if record is first
def first?(record)
[Model].first == record
end
3. check if record is first
records.each do |record|
if record.first?(record)
record.update_attributes(attr: record.attr + record.attr)
else
prev_rec = [Model].find(record.id).prev
record.update_attributes(attr: prev_rec.attr + record.attr )
end
end
returns true or false
One improvement i would make sure that [Model].first is persistent so that it doesn't make a call to the database each time the loop is run.

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.

Using ruby 1.9.2 and rails 3, how do I collect activerecord errors to display later? Or better yet, hold off on the commit until ready?

In a single operation, I am inserting multiple rows into a table. It is possible for one or more of those rows to cause an ActiveRecord::RecordInvalid issue. When this happens, I would like to be able to back out all the transactions for this particular operation and have the user fix the data before proceeding. What is the best way to go about doing this?
Right now, if it fails on the 2nd row of data, the 1st one has already been committed to the database so the user will not know if they should reload that first row or not. I can just inform the user how many rows succeeded and they can know to fix and reload only from that part on, but it would be better for me if I could just undo everything and have the user start over after they fix their data.
FYI, the user initially loads a CSV file into a table that contains on row for every row*column of their csv file and I import from that import_table.
This is a piece of my method in the controller:
def process_import
#import = ImportTable.find(params[:id])
#cells = #import.import_cells
#new_donors = Array.new
#existing_donors = Array.new
class_name = 'Donor'
klass = ActiveRecord.const_get(class_name) # get access to class
#loop through rows
0.upto(#import.row_count - 1) do |row_index|
donor = {}
donation = {}
record_status = 'new'
row = #cells.select { |cell| cell.row_index == row_index }
#loop through columns
0.upto(#import.column_count - 1) do |column_index|
contents = row.select { |cell| cell.column_index == column_index}[0].contents
case column_index
when 0 then record_status = contents
when 1 then donor["id"] = contents
when 2 then donor["prefix1"] = contents
when 3 then donor["first_name1"] = contents
when 4 then donor["middle_name1"] = contents
...
end #case
end #columns
unless #donor = Donor.find_by_id(donor["id"])
donor.delete("id")
#donor = klass.find_or_initialize_by_company_and_prefix1_and_first_name1_and_last_name1_and_address1(donor)
end
#donor.new_record? ? #new_donors.push(#donor) : #existing_donors.push(#donor)
#donor.save!
if !donation["amount"].blank?
#donation = #donor.donations.build(donation)
#donation.save!
end
end #rows
#import.processed_date = Time.now
#import.save
end
I would just have the user resubmit the entire data
Wrap the import process in a transaction. If an error occurs then you can back out of the entire commit by raising an ActiveRecord::Rollback
klass.transaction do
# loop through rows
# You might want to call #donor.save rather than #donor.save! so that you do not raise errors, yet still have invalid records.
raise ActiveRecord::Rollback if (#new_donors+#existing_donors).any?{|donor| !donor.valid? }
end

Resources