Ruby loop problems - ruby-on-rails

I am working on a script that is supposed to be writing a list of items to a hash, but for some reason its only placing the last item in the loop in the hash... I have been working on this script all day, so I am pretty sure its something I am just missing.
Here is the script
#mr = MediaRating.where("user_id = ?", session['user_credentials_id'])
#mr.each do |rating|
#m = Media.where("id = ?", rating.media_id)
#m.each do |m|
s = Profile.find_by_subscriber_id(m.subscriber_id)
#h_lang = Language.find_by_code(s.language)
#history = {m.title => #h_lang.english}
end
end
There are multiple records in the MediaRating table so I know it has to do something with how my loop is. Thanks in advance for the help!
Working code:
#mr = MediaRating.where("user_id = ?", session['user_credentials_id'])
#mr.each do |rating|
#m = Media.find(rating.media_id)
s = Profile.find_by_subscriber_id(#m.subscriber_id)
#h_lang = Language.find_by_code(s.language)
#history[#m.title] = #h_lang.english
end

In the last line, you are over-writing the entire #history hash instead of adding a new key/value pair to it. I'm guessing that isn't what you intended. Change this line:
#history = {m.title => #h_lang.english}
to this:
#history[m.title] = #h_lang.english

Related

how append an object to association relation in rails?

In a rails 4.1 application I need to add an object to an "AssociationRelation"
def index
employee = Employee.where(id_person: params[:id_person]).take
receipts_t = employee.receipts.where(:consent => true) #gives 3 results
receipts_n = employee.receipts.where(:consent => nil).limit(1) #gives 1 result
#I would need to add the null consent query result to the true consent results
#something similar to this and the result is still an association relation
#receipts = receipts_t + receipts_n
end
Is there a simple way to do this?
A way of solving this:
def index
employee_receipts = Employee.find_by(id_person: params[:id_person]).receipts
receipts_t = employee_receipts.where(consent: true)
receipts_n = employee_receipts.where(consent: nil).limit(1)
#receipts = Receipt.where(id: receipts_t.ids + receipts_n.ids)
end
Unfortunately .or() can't be used here because it's only available from Rails v5.0.0.1
you could do this way
receipts_t_ids = employee.receipts.where(:consent => true).pluck(:id)
receipts_n_ids = employee.receipts.where(:consent => nil).limit(1).pluck(:id)
#receipts = Receipt.where(id: receipts_t_ids + receipts_n_ids)
To avoid extra queries and keeping arrays in memory, you can use or
Like this:
def index
employee_receipts = Employee.find_by(id_person: params[:id_person]).receipts
#receipts =
employee_receipts.where(consent: true).or(
employee_receipts.where(consent: nil).limit(1)
)
end

Array of hashes is overriding data directly to array

I want to make an array of hashes. But the problem is after first iteration when code goes to next line then it directly replaces the content of array.
#item_name =[]
item = {}
#invoiceinfo.each do |invoice|
item[:name] = Invoiceinfo.find(#invoiceinfo.id).item.name
item[:desc] = Invoiceinfo.find(#invoiceinfo.id).desc
item[:unit_price] = Invoiceinfo.find(#invoiceinfo.id).unit_price
byebug
#item_name.push (item)
end
This is what i am getting
after first iteration suppose i have this data
#item_name = [{:name=>"usman", :desc=>"sample ", :unit_price=>100}]
As soon as next line is executed it directly changes #item_name(name variable)
After executing item[:name] = Invoiceinfo.find(#invoiceinfo.id).item.name
the content of the #item_name is changed
#item_name = [{:name=>"next_name", :desc=>"sample ", :unit_price=>100}]
Any help would be appreciated.
Thannks
Try something like this
#item_name = []
#invoiceinfo.each do |invoice|
invoice_info = Invoiceinfo.find(#invoiceinfo.id)
item = {}
item[:name] = invoice_info.item.name
item[:desc] = invoice_info.desc
item[:unit_price] = invoice_info.unit_price
#item_name.push(item)
end
If you consider using ruby paradigms and best practices in ruby code, this mistake won’t happen in the future.
#item_name = #invoiceinfo.each_with_object([]) do |invoice, acc|
invoice_info = Invoiceinfo.find(#invoiceinfo.id)
acc.push(
name: invoice_info.item.name,
desc: invoice_info.desc
unit_price: invoice_info.unit_price
)
end

rails conditions based on attributes presence

I was wondering if there's a better way to do this:
def conditions(obj)
if self.setor.present?
obj = obj.joins(:negocios_setores).where("setor_id = ?", self.setor.id)
end
if self.uf.present?
obj = obj.joins(localizacao: [:uf]).where("uf_id = ?", self.uf_id)
end
if self.municipio.present?
obj = obj.joins(localizacao: [:municipio]).where("municipio_id = ?", self.municipio_id)
end
if !self.lucro_liquido_min.to_f.zero?
obj = obj.where("lucro_liquido_anual BETWEEN ? and ?", self.lucro_liquido_min, self.lucro_liquido_max)
end
if !self.faturamento_min.to_f.zero?
obj = obj.where("faturamento_bruto_anual BETWEEN ? and ?", self.faturamento_min, self.faturamento_max)
end
if !self.valor_min.to_f.zero?
obj = obj.where("valor BETWEEN ? and ?", self.valor_min, self.valor_max)
end
obj
end
Does rails 4 provide something to only do the condition if the value is present instead of placing it with a NULL value?
I don't believe that there is any way to do exactly what you mentioned. I've run into the same type of concatenation of queries.
To clean up a bit and make this tighter, you can use one-line if and unless. I think this is a bit cleaner and still readable.
def conditions(obj)
obj = obj.joins(:negocios_setores).where(setor: setor) if setor.present?
obj = obj.joins(localizacao: [:uf]).where("uf_id = ?", uf_id) if uf.present?
obj = obj.joins(localizacao: [:municipio]).where("municipio_id = ?", municipio_id) if municipio.present?
obj = obj.where("lucro_liquido_anual BETWEEN ? and ?", lucro_liquido_min, lucro_liquido_max) unless lucro_liquido_min.to_f.zero?
obj = obj.where("faturamento_bruto_anual BETWEEN ? and ?", faturamento_min, faturamento_max) unless faturamento_min.to_f.zero?
obj = obj.where("valor BETWEEN ? and ?", valor_min, valor_max) unless valor_min.to_f.zero?
obj
end
I also changed the first query to use Rails style queries rather than SQL in the where.

Order model objects by an attr_accessor

I thought that attr_accessor has the same behavior as the other when I have to sort a list of objects, but it seems that is different:
dataRecords = MyData.where("day = ?", Time.now.yesterday.strftime("%Y%m%d").to_i)
dataRecords.each do |data|
data.accessor_var = func(data.x, data.y)
end
#sortedData = dataRecords.order('accessor_var DESC')
but #sortedData is not being sorted...
You need to keep in mind that when you apply a scope or order to an ActiveRecord::Relation the data is reloaded from the table. This means that when you loop through them and change an attribute, unless you save the result the changes will not be available to the next scope call.
You can use sort_by instead which will work on the objects in memory rather than the database.
Option 1: Save as you loop (probably not much use with an accessor!)
dataRecords = MyData.where("day = ?", Time.now.yesterday.strftime("%Y%m%d").to_i)
dataRecords.each do |data|
data.accessor_var = func(data.x, data.y)
data.save
end
#sortedData = dataRecords.order('accessor_var DESC') # Reload from table will include the saved values.
Option 2: sort_by
dataRecords = MyData.where("day = ?", Time.now.yesterday.strftime("%Y%m%d").to_i)
dataRecords.each do |data|
data.accessor_var = func(data.x, data.y)
end
#sortedData = dataRecords.sort_by{|data| data.accessor_var}
Also, toro2k has some nice optimisation for your sorting once you understand the situation.
It doesn't work because accessor_var is not a column in the database. You can use the method sort_by:
dataRecords.each { ... }
#sortedData = dataRecords.sort_by(&:accessor_var).reverse
Or, to save an interation over dataRecords:
#sortedData = dataRecords.sort_by { |data| data.accessor_var = func(data.x, data.y) }.reverse

ruby - writing an array to a hash without overwriting

I do the following
my_hash = Hash.new
my_hash[:children] = Array.new
I then have a function that calls itself a number of time each time writing to children
my_hash[:children] = my_replicating_function(some_values)
How do I write without overwriting data that is already written ?
This is what the entire function looks like
def self.build_structure(candidates, reports_id)
structure = Array.new
candidates.each do |candidate, index|
if candidate.reports_to == reports_id
structure = candidate
structure[:children] = Array.new
structure[:children] = build_structure(candidates, candidate.candidate_id)
end
end
structure
end
Maybe this:
structure[:children] << build_structure(candidates, candidate.candidate_id)
structure[:children] << build_structure(candidates, candidate.candidate_id)

Resources