Rails 3. how to make a nested attribute query? - ruby-on-rails

I have shipment has one invoice; invoice belongs to shipment. The shipments table is the one that contains the customer_id.
I need to find all invoices...
for a particular customer and
that have customer_account_balance of 0
I have tried many different approaches but none seem to work, this last one got me error private method select or something like that...
reports_controller.rb
i = Invoice.where("customer_open_balance != 0")
s = Shipment.find_by_customer_id(#customer.id)
shipment_ids_from_invoices = i.map{|x| x.shipment_id}
#shipments = s.select{|z| shipment_ids_from_invoices.include? z.id}

Does this work?
#shipments = Shipment.joins(:invoice).where(:customer_id => #customer.id).where("customer_account_balance <> 0")
It sounds like your schema looks like this:
Shipment: (customer_id, ...)
Invoice: (customer_open_balance, shipment_id, ...)
Did you put has_one :invoice in Shipment.rb and belongs_to :shipment in Invoice.rb?

class Invoice
belongs_to :shipment
scope :with_customer, lambda { |customer_id| joins(:shipment).where(:customer_id => customer_id) }
scope :cero_balance, joins(:shipment).joins(:customer).where("customer_account_balance <> 0")
end
Then try
#for a particular customer with id 1
Invoice.with_customer 1
#that have customer_account_balance of 0
Invoice.cero_balance

Related

Rails, Has and belongs to many, match all conditions

I have two models Article and Category
class Article < ApplicationRecord
has_and_belongs_to_many :categories
end
I want to get Articles that have category 1 AND category 2 associated.
Article.joins(:categories).where(categories: {id: [1,2]} )
The code above won't do it because if an Article with category 1 OR category 2 is associated then it will be returned and thats not the goal. Both must match.
You can query only those articles of the first category, which are also the articles of the second category.
It's going to be something like this:
Article.joins(:categories)
.where(categories: { id: 1 })
.where(id: Article.joins(:categories).where(categories: { id: 2 }))
Note, that it can be:
Category.find(1).articles.where(id: Category.find(2).articles)
but it makes additional requests and requires additional attention to the cases when category can't be found.
The way to do it is to join the same table multiple times. Here is an untested class method on Article:
def self.must_have_categories(category_ids)
scope = self
category_ids.each do |category_id|
scope = scope.joins("INNER JOIN articles_categories as ac#{category_id} ON articles.id = ac#{category_id}.article_id").
where("ac#{category_id}.category_id = ?", category_id)
end
scope
end

Find associated model of all objects in an array

Using Rails 4, I have the following:
class Driver < ActiveRecord::Base
has_and_belongs_to_many :cars, dependent: :destroy
end
class Car < ActiveRecord::Base
has_and_belongs_to_many :drivers
end
I have a join table cars_drivers with car_id and patient_id.
I want to find drivers who are 30 years old and above (driver.age > 30), drives a Honda (car.brand = "Honda"), and sum the number of drivers found.
In a raw SQL fashion:
sql = "
SELECT
SUM (driver), age, brand
FROM cars_drivers
JOIN cars, drivers
ON cars_drivers.car_id = cars.id
ON cars_drivers.driver_id = drivers.id
where
age > 30
and brand = "Honda"
"
records_array = ActiveRecord::Base.connection.execute(sql)
This should count the cars:
Car.where(brand: BRAND).includes(:drivers).where('drivers.age > ?', AGE).count
This should count the drivers:
Driver.where('age > ?', AGE).includes(:cars).where('cars.brand = ?', BRAND).count
I do recommend not using has_and_belongs_to_many, it seems like you have a lot of logic between the Driver and Car but with this setup you cannot have validations, callbacks or extra fields.
I would create a join model called CarDriver or if there is something even more describing like Job or Delivery and save them in their own table. Here is an article on the subject.
Ended up with this:
#drivers =
Driver.
joins(:cars).
where(cars_drivers: {
driver_id: Driver.where('age > 30'),
complication_id: Car.find_by_model("Honda").id
}).
size

rails join on association and id

I want to achieve something that takes exactly 3 seconds on SQL, and I'm struggling with it for hours, I want to load all records and left join if it exists, if not, then don't give me the associated model.
the query I want to create is as follows:
"SELECT * FROM apartments LEFT JOIN comments ON apartments.id = comments.apartment_id AND comments.user_id = ?"
and when I call apartment.comments, it'll give me just the record (can only be one) for the specific user, not all the records for every user.
I tried
Apartment.joins("LEFT OUTER JOIN comments ON comments.apartment_id = apartments.id AND comments.user_id = #{user_id}")
but it doesn't work, as when I call apartments.comments it fires another query which returns all possible comments.
Apartment.includes(:comments).where("comments.user_id = ?", user_id)
doesn't work aswell, because it returns only apartments who has a comment from the specific user.
help is needed!
Maybe you could try this:
#app/models/apartment.rb
Class Apartment < ActiveRecord::Base
has_many :comments
scope :user, ->(id) { where("comments.user_id = ?", id }
end
#apartment = Apartment.find(params[:id])
#comments = #apartment.comments.user(user_id)

How to count has_and_belongs_to_many in Rails?

I am working on a simple Rails with the following structure:
Product
has_and_belongs_to_many :subscribers
Subscriber
has_and_belongs_to_many :products
How can I get all products that has subscribers which is products with subscribers > 0 ?
def self.has_subscribers
#subscribers > 0
end
well have you tried doing,
#product.subscribers.count > 0
so you can do something like
def has_subscribers?
subscribers.count > 0
end
def self.has_subscribers
Product.joins("LEFT JOIN products_subscribers ON products_subscribers.product_id = products.id").where("products_subscribers.product_id IS NOT NULL")
end
HTH
edit: I am not sure, if below will work, but you may try it:
def self.has_subscribers
Product.joins(:products_subscribers)
end
Since, joins use INNER JOIN, it should return only those records of products which have a relationship with subscribers in the joining table.
Edit 2: Just joining with joining table may not (in fact should not) work because joining table usually do not have a model.
The above is working for me, except I forgot to GROUP the results.
Product.joins("LEFT JOIN products_subscribers ON products_subscribers.product_id = products.id").where("products_subscribers.product_id IS NOT NULL").group("products.id")
If you are still getting Subscribers, then it is kinda odd. Please post your function and querying code.
Product.where( '(select count(1) from products_subscribers where product_id = products.id > 0)')

Help in ActiveRecord find with include on conditions

I have a Coach Model which:
has_many :qualifications
I want to find all coaches whose some attribute_id is nil and they have some qualifications. Something which is like.
def requirement
legal_coaches = []
coaches = find_all_by_attribute_id(nil)
coaches.each do |coach|
legal_coaches << coach if coach.qualifications.any?
end
legal_coaches
end
Is there a way to get all such records in one line ?
find_all_by_attribute_id(nil).select(&:qualification)
I think you can't do that via purely ruby syntax. I can only think of the following (ugly) way
Coach.find(:all, :conditions => "attribute_id IS NULL AND EXISTS(SELECT * FROM qualifications WHERE coach_id = coaches.id)")

Resources