Compare rows with similar data from two models - ruby-on-rails

A DealerCommission table has the following attributes, among others:
phone_id, commission_name, payment, status, discrepancy, created_at
A CarrierCommission table has the following attributes, among others:
phone_id, commissions_name, payment, created_at
I want to select a range of dates for dealer commissions and compare records with the same phone_id to see if the payment amount match. If they match, I want to update the status to "paid." If they don't match, I want to update the status to "overpaid" or "underpaid." If there is no matching phone_id in the carrier_commission, update the status to "nonpaid." The discrepancy value is updated accordingly.
This is all set off by the user clicking a "reconcile" link that is linked to a "reconcile" action in the dealer commissions controller
I have the following non-working code:
# Dealer Commissions index
<%= link_to 'Reconcile', reconcile_dealer_commissions_path %>
# Dealer Commissions controller
def reconcile
DealerCommission.reconciliation
end
# Dealer Commission model
class DealerCommission < ActiveRecord::Base
belongs_to :dealer
def self.reconciliation
dealer_commissions = DealerCommission.where("created_at > Date.yesterday")
carrier_commissions = CarrierCommission.where("created_at > Date.yesterday")
dealer_commissions.find_each do |com|
if com.payment == carrier_commissions.payment
com.update(status: "Paid")
elsif com.payment < carrier_commissions.payment
com.update(status: "Underpaid")
elsif com.payment > carrier_commissions.payment
com.update(status: "Overpaid")
end
end
end
end
Obviously, the code doesn't reflect the full requirements but I at least wanted to get the comparison working.

I would be looking for a way to retrieve both carrier and dealer commissions in a single database query, using eager_load, and specifying a join condition with a sql fragment and using references.
http://guides.rubyonrails.org/active_record_querying.html#specifying-conditions-on-the-joined-tables
That ought to get you the matching dealer and carrier commission instances, and you can then perform your comparison and update the dealer commission appropriately.

Related

Calculate SUM based on a column from associated model

I have a table called vehicles, which has a column called vehicle_id and price.
I have a table called sales, which references the vehicles table. It has the columns vehicle_id (references the vehicle table) and sale_status which can equal to 'sold' or 'loan'.
I am trying to calculate the total price of vehicles which equal to 'sold' in the sales table. Help is much appreciated!
This is what I have so far but it returns the wrong number.
vehicle.rb:
def self.vehicles_price_sum
vehicles_sold.sum(:price).to_f
end
def self.vehicles_sold
Vehicle.where(id: Sale.where(sale_status: 'Sold'))
end
You can try with a subquery (which is close to you solution, yet you need to provide a column name explicitly for in clause with select, otherwise sales' id column is going to be provided):
Vehicle.where(id: Sale.where(status: "Sold").select(:vehicle_id)).sum(:price)
# SELECT SUM(`vehicles`.`price`) FROM `vehicles` WHERE `vehicles`.`id` IN (SELECT `sales`.`vehicle_id` FROM `sales` WHERE `sales`.`sale_status` = 'Sold')

Rails: filtering based on a child & parent's attribute calculation

I have 2 associated tables and would like to apply a filter based on tshirts (child table) length attribute which is +/- %5 of the parent object Student's height attribute
Unfortunately I receive an undefined method error for the parent table's name.
DB TABLES:
Student
------
id
name
height
Tshirt
------
id
color
student_id
length
MODELS:
class Student < ApplicationRecord
has_many :tshirts
class Tshirt < ApplicationRecord
belongs_to :student
def self.suitablesize
joins(:student).where('length < ? AND length > ?', (1.05*self.student.height),(0.95*self.student.height))
end
Controller:
def index
#tshirts = Tshirt.all.suitablesize
end
Error Message:
undefined method `student' for #<Class:0xc88cdc0>
EDIT:
I would like to get all tshirts which are suitable which are suitabile to owner student(s). Hence I do not want to find a single student to be an input parameter to scope method. Do you have any idea how I can solve this problem?
Explanation for the error
You are calling student on the Tshirt class, although it is an instant method:
joins(:student).where('length < ? AND length > ?', (1.05*self.student.height),(0.95*self.student.height))
Here self.student is the offending part.
Option 1: Shirts of a single student
If you want to take a student's height into account you would have to change the scope method to take a parameter:
def self.suitablesize(student)
where('length < ? AND length > ?', (1.05*student.height),(0.95*student.height))
end
And then provide the student in your controller method
def index
#tshirts = Tshirt.suitablesize([SOME STUDENT INSTANCE])
end
The part where I inserted [SOME STUDENT INSTANCE] would need to be a student instance that was e.g. retrieved via a parameter provided by the request before
def index
#student = Student.find(params[:id])
#tshirts = Tshirt.suitablesize(#student)
end
The exact parameter depends on your application (amongst other things the routes) so I can only offer general pointers.
Option 2: Shirts of all students
If it is not desired to find suitable shirts for an individual student one would have to place the calculations into the database:
def self.suitable_size
joins(:student)
.where('tshirts.length < 1.05 * students.height AND tshirts.length > 0.95 * students.height')
end
This would then return all shirts belonging to a student where the shirts length is +/- 5% of the students height.

Check if value in one table is present in another

So this is probably easy but I haven't been able to find the right method for it. I have 2 models. One called monitor, and one called follower.
In 'monitor' I have a column called owner_id.
In 'follower' I have a column called follower_id.
What I would like to do is check if any of these match up (I'd like to get a count, not a boolean output). Both belongs_to Users.
How do I go about doing this?
Situation
I am trying to calculate a conversion rate from Twitter. Where the follower and the follower ids are the users who is following your account.
On the monitor I let you monitor keyword and interactions, where I save the owner_id (the person you're communicating with).
Now I count all the conversations you have had. Then I want to see how many of those that have turned into following your company.
I have a model called campaigns where you can monitor certain keywords.
<% #campaigns.each do |campaign| %>
<%= campaign.keyword %>
<% end %>
The model looks like this:
class Campaign < ActiveRecord::Base
has_many :alerts
end
now what I want to do is track the conversion rate for that specific campaign.
( CODE HERE* / campaign.alerts.count ) * 100
where CODE HERE* should be the count of how many that exists between :
campaign.alerts.map(&:owner_id)
and
current_user.followers.map(&:follower_id)
so what you are trying to do is just to compare two big arrays of ids (campagin.alerts.map(&:owner_id) and current_user.followers.map(&:follower_id)) and count how many ids are the same, you can use count and count everything that your block expression evaluates as true, and save that on a variable that you will use on your division, something like this:
result = (campagin.alerts.map(&:owner_id).count do |id|
current_user.followers.map(&:follower_id)).include?(id)
end
( result / campaign.alerts.count ) * 100
There are many other ways like using Array#all or other methods, maybe you can look at them here and see what fits you most:
http://ruby-doc.org/core-2.2.0/Array.html#method-i-2D

How to return the next record?

In my Rails app I have a function next which I am using in my show templates to link to the next product (ordered by price):
class Product < ActiveRecord::Base
belongs_to :user
def next
Product.where("user_id = ? AND price > ?", user_id, price).order("price ASC").first
end
end
The problem is that this function works only when all products have different prices. The moment there are multiple products with the same price, the next function picks one product randomly (?) thereby skipping all the others.
Is there a way to make this function return the next product, even though it has the same price? (if the price is the same, the products could be ordered simply by ID or date)
I tried replacing > with >= but that didn't work.
Thanks for any help.
You have to use id in where clause and in order as well
def next
Product.where("user_id = ? AND price >= ? AND id > ?", user_id, price, id).order("total, id").first
end

See if one person is before another in the alphabet, ruby, rails

I'm doing an app for a membership database.
Each person may have a partner. When it comes to displaying the list, I only want to have one row for each family, so at the moment I'm comparing first names and not displaying the row if the person's name is second. Like this
person.first_name != [person.first_name, person.partner.first_name].sort[0]
This means each family only gets displayed once, not twice - once for each partner.
And I'm doing this in the view.
There must be a better way of doing this, and it'd be really great if I could do it at the database level. I'm using postgresql if that makes a difference.
Edit
Sorry if it was unclear.
Say Person 1 has the first_name "Edward" and Person 2 has the first_name "Fay". Edward and Fay are married.
I only want to show them once in my list - I want a row to look like this
Surname First name Address etc
Mysurname Edward ....
Fay
I don't want to display it again with Fay first because I've got both Fay and Edward in list of people, so I use the ruby in the first part of the question to check if I should display the row - it compares their first names and only does the row if the person has a fist name that's before his/her partner's first name.
Here's the relevant part of my person model
class Person < ActiveRecord::Base
has_one :relationship_link, :foreign_key => :person_id, :dependent => :destroy, :include => :partner
has_one :partner, :through => :relationship_link, :source => :person_b, :class_name => "Person"
I hope that's clearer
You need to use DISTINCT ON or GROUP BY. In postgres you need to be careful to group by everything that you are selecting. If you only need to get the last names you can select("DISTINCT ON(last_name) last_name").pluck("last_name"). You will only get an array of last names though.
Maybe you can get records if you order by every other fields in your table, like this:
select("DISTINCT ON(people.last_name) people.*").order("people.last_name ASC, people.first_name ASC, people.field2 DESC, people.field3 ASC...")
You need to order by every attribute so the result is not ambigious.
For this case, i would create a data structure (a Hash) to store people instances given a specific surname. Something like this:
def build_surnames_hash(people_array)
surnames_hash = {}
people_array.each do |person|
last_name = person.last_name
surnames_hash[last_name] ||= []
surnames_hash[last_name] << person
end
surnames_hash
end
That way, you can iterate over the hash and display people using their surnames stored as hash's keys:
surnames_hash = build_surnames_hash(Person.all)
surnames_hash.each do |surname, person_instances_array|
# display the surname once
# iterate over person_instances_array displaying their properties
end

Resources