Ruby - How to find Customer with nested join - ruby

I have the following relationships:
class Location < ApplicationRecord
has_many :weddings
class Wedding < ApplicationRecord
has_many :wedding_memberships
class WeddingMembership < ApplicationRecord
belongs_to :wedding
belongs_to :customer
class Customer < ApplicationRecord
has_many :wedding_memberships
And what I would like to find is the Customers in Location with id: 1
My attempts WeddingMembership.joins(:wedding).where(wedding: {location_id: 1}) are giving me the following errors: Caused by PG::UndefinedTable: ERROR: missing FROM-clause entry for table "wedding"

Try this one, it's a multiple join with a where clause on your location_id
Customer.joins(wedding_memberships: :wedding)
.where(weddings: { location_id: 1 })
.distinct

Related

searching through joined polymorphic association with table_name defined

i have two models
class Profession < ApplicationRecord
has_many :users
end
class User < ApplicationRecord
self.table_name = 'accounts'
belongs_to :scope, polymorphic: true
end
and a query:
Profession.joins(:users).where(accounts: {scope: some_scope_variable })
when I run that i get
Mysql2::Error: Unknown column 'accounts.scope' in 'where clause'
what i also tried is
Profession.joins(:users).where(users: {scope: some_scope_variable })
but it also doesnt work and gives similar error
Mysql2::Error: Unknown column 'users.scope' in 'where clause'
According to the documentation, polymorphic associations rely on two columns being present on the model. Example
class User < ApplicationRecord
belongs_to :thingable, polymorphic: true
end
These columns should exist on users:
thingable_id
thingable_type
If you want to query them through an association, you may use the columns directly, like:
Profession.joins(:user).where(users: { thingable_id: 42, thingable_type: 'Foo' })
Also, I'd reconsider the name scope, since this is used by Rails already.
EDIT:
After submitting the answer above, I started understanding your question, sorry about this.
I reproduced it and made it work like this:
class Profession < ApplicationRecord
has_many :users, as: :thingable # <-- this is missing in your case
end
class User < ApplicationRecord
self.table_name = 'accounts'
belongs_to :profession
belongs_to :thingable, polymorphic: true
end
Now we can do this:
Profession.joins(:users).where(accounts: { age: (20..30) })
The WHERE-clause on the joined table is translated to SQL without any magic and checks:
WHERE `accounts`.`age` BETWEEN 20 AND 30
Whereas, the WHERE-clause on self-columns are sometimes magically modified:
User.where(thingable: 42)
results in
WHERE `accounts`.`thingable_id` = 42
-- ^^^ added by Rails
So, if we want to filter on any of these polymorphic columns, we do
Profession.joins(:users).where(accounts: { thingable_id: 111 })

Joint table with optional relation

I have three models:
Company;
Investor;
Broker.
in real world each investor can invest in many companies, but in some he/she can invest with broker assistance.
I made it through joint table.
def change
create_join_table :companies, :investors do |t|
t.references :broker, index: true, optional: true
end
end
class Company < ApplicationRecord
has_and_belongs_to_many :investors
end
class Investor < ApplicationRecord
has_and_belongs_to_many :companies
end
class Broker < < ApplicationRecord
has_many :companies
end
How should I configure my models/migrations to have next information:
Company.first.investors.first.broker
broker is not belongs to investor, in each company/investor pair can be different broker.
Use has_many through associations and add the broker on the join model. After adding the proper migrations your models will look like this:
class Company < ApplicationRecord
has_many :company_investors
has_many :investors, through: :company_investors
end
class Investor < ApplicationRecord
has_many :company_investors
has_many :companies, through: :company_investors
end
class Broker < ApplicationRecord
has_many :company_investors
has_many :companies, through: :company_investors
end
class CompanyInvestor < ApplicationRecord
belongs_to :broker
belongs_to :investor
belongs_to :company
end
With this models, you can add Investor to Company associations with or without Broker, and also discriminate them. I also recommend naming the join model (which in my code I named CompanyInvestor) a more significant name, like Investment

Retrieve records count from has_many relation

I have the following models
Bookrack.rb
has_many :faculties
Faculty.rb
belongs_to :bookrack
has_many :books
Book.rb
belongs_to :faculty
has_many :barcodes
Barcode.rb
belongs_to :book
I have a controller name bookrack controller. I can extract record of barcode in Bookrack using loop and empty array. Is there any simpler method to extract barcode record from Bookrack.
Did you try this (for example for counting barcodes of the first book in the first faculty in the first bookrack):
b = Bookrack.first.faculties.first.books.first.barcodes.count
This should probably help..
Bookrack.rb
has_many :faculties
has_many :books, through: :faculties
has_many :barcodes, through: :books
Then you can do,
Bookrack.find(1).barcodes.count
Also to note that, has_many relations has to be plural, your model seems inappropriate..or correct it if it's a typo..
With model relationships like:
# app/models/bookrack.rb
has_many :faculties
# app/models/faculty.rb
belongs_to :bookrack
has_many :books
# app/models/book.rb
belongs_to :faculty
has_many :barcodes
# app/models/barcode.rb
belongs_to :book
You could use joins in a "nested" way:
Bookrack.joins(faculties: [books: :barcodes]).count
# => SELECT COUNT(*) FROM "bookracks"
# INNER JOIN "faculties" ON "faculties"."bookrack_id" = "bookracks"."id"
# INNER JOIN "books" ON "books"."faculty_id" = "faculties"."id"
# INNER JOIN "barcodes" ON "barcodes"."book_id" = "books"."id"
# => 1

Rails 4 query a reference via n:n relation

following structure
Production
belongs_to :offer
has_many :production_positions
has_many :products, through: :production_positions
Product
has_many :production_positions
has_many :productions, through: :production_positions
ProductionPosition
belongs_to :production
belongs_to :product
Now i want to get all offers which contains the product_id 1. How did i have to query the database?
To get the productions is quite easy:
Production.includes(:products).where("products.id" => 1)
but how do i get the offers which are referenced?
Offer.includes(:production).includes(:products).where("products.id" => 1)
the line above produces the following error:
Association named 'products' was not found on Offer
Add has_many :products, through: :production in your Offer class and try with the following:
Offer.select('offers.*').joins(:products).where('products.id = ?', 1)
I assumed you had has_one :production in your Offer class. You could add a scope to perform the query:
class Offer < ActiveRecord::Base
has_one :production
has_many :products, through: :production
scope :with_product_id, ->(id) do
select('offers.*').
joins(:products).
where('products.id = ?', id)
end
end
Example (Offers with Product 1):
Offer.with_product_id(1)

ActiveRecord - Finding all objects with shared attributes in a join model

I have three models
class Boat < ActiveRecord::Base
belongs_to :captain
has_many :boat_classifications
has_many :classifications, through: :boat_classifications
end
class Classification < ActiveRecord::Base
has_many :boat_classifications
has_many :boats, through: :boat_classifications
end
class BoatClassification < ActiveRecord::Base
belongs_to :boat
belongs_to :classification
end
I'm trying to write a simple ActiveRecord query to find all the boats of type sailboat. Something like Boat.where(classifications: "Sailboat")
I think this could work:
Boat.joins(:classifications).where(classifications: { name: 'Sailboat' }) # name or whatever field contains Sailboat
Generates this query:
SELECT `boats`.* FROM `boats` INNER JOIN `boat_classifications` ON `boat_classifications`.`boat_id` = `boats`.`id` INNER JOIN `classifications` ON `classifications`.`id` = `boat_classifications`.`classification_id` WHERE `classification`.`name` = 'Sailboat'
I think you want something like this:
Boat.includes(:classifications).where(classifications: {id: Classification.sailboats})
For this to work, you also need a scope on Classification like this:
def self.sailboats
where(name: "Sailboat")
end

Resources