A company has many locations (Location has company_id column). A location has many items and an item has many locations (join table).
company.rb
has_many :locations
location.rb
belongs_to :company
has_many :items, through: :item_locations
has_many :item_locations, :dependent => :destroy
item.rb
has_many :item_locations, :dependent => :destroy
has_many :locations, through: :item_locations
item_location.rb
belongs_to :item
belongs_to :location
Can I retrieve all items for a company, without adding company_id to Item?
Sure, just change your Company relationships to:
has_many :locations
has_many :item_locations, through: :locations
has_many :items, through: :item_locations
This should let you call company.items
Related
I have three models. A collection has many searches through items.
When a collection is destroyed, I'd like its items to be destroyed, but searches to be nullified, since they are still valid objects on their own.
Can this be done?
Here are my models:
class Collection < ApplicationRecord
has_many :searches, through: :items
has_many :items
has_many :searches, through: :suggestions
has_many :suggestions
end
class Item < ApplicationRecord
belongs_to :collection
belongs_to :search
end
class Search < ApplicationRecord
has_many :collections, through: :items
has_many :items
has_many :collections, through: :suggestions
has_many :suggestions
end
You can just delete the items, just add dependent: :destroy to has_many :items.
class Collection < ApplicationRecord
has_many :searches, through: :items
has_many :items, dependent: :destroy
end
After destroying a collection, the item is destroyed but the search will remain.
second solution
You could even apply dependent: :nullify to has_many :searches - getting the same result.
class Collection < ApplicationRecord
has_many :searches, through: :items, dependent: :nullify
has_many :items
end
From the docs:
collection.delete(object, …)
Removes one or more objects from the collection by setting their foreign keys to NULL. Objects will be in addition destroyed if they're associated with dependent: :destroy, and deleted if they're associated with dependent: :delete_all.
If the :through option is used, then the join records are deleted (rather than nullified) by default, but you can specify dependent: :destroy or dependent: :nullify to override this.
I have a self join table on my product model using a model called matches as the join table. What I would like to do is when deleting a product to have the associated product removed but not deleted. Right now I am trying dependent: :destroy which doesn't work, but I know its not what I want because I don't want to delete the self associated product.
product.rb
class Product < ApplicationRecord
...
has_many :variations, -> { order(:order) }, dependent: :destroy
has_and_belongs_to_many :categories
has_and_belongs_to_many :tags
has_many :matches
has_many :matched_products, through: :matches, dependent: :destroy
...
end
match.rb
class Match < ActiveRecord::Base
belongs_to :product
belongs_to :matched_product, class_name: 'Product', dependent: :destroy
has_many :variations, :through => :matched_product
end
I suggest you update your models as follows:
product.rb
class Product < ApplicationRecord
...
has_many :variations, -> { order(:order) }, dependent: :destroy
has_and_belongs_to_many :categories
has_and_belongs_to_many :tags
has_many :matches, dependent: :destroy
has_many :product_matches, class_name: 'Match', foreign_key: :matched_product_id, dependent: :destroy
has_many :matched_products, through: :matches
...
end
This will ensure that all matches records are deleted when deleting a product whether the product is a product or matched_product in the match record. Removing dependent: :destroy from has_many :matched_products will prevent deletion of the, well, matched_products.
match.rb
class Match < ActiveRecord::Base
belongs_to :product
belongs_to :matched_product, class_name: 'Product'
has_many :variations, :through => :matched_product
end
Similar to above, removing dependent: :destroy from belongs_to :matched_product, class_name: 'Product' will prevent deletion of the matched_product.
I have two models: Player and Event with two join tables between them, participants and lessons.
class Event
has_many :participants
has_many :players, through: :participants
has_many :lessons
has_many :players, through: :lessons
end
class Player
has_many :participants
has_many :events, through: :participants
has_many :lessons
has_many :events, through: lessons
end
Not all events have lessons but all events have participants hence why I split the join table into two.
The problem is that if I were to do #player.events the resulting query would use the lessons join table instead of the participants.
Is there a better way to do this this?
EDIT: Here are the join table models:
class Lesson
belongs_to :player
belongs_to :event
end
class Participant
belongs_to :player
belongs_to :event
end
You can use the class_name option to change the name of one of the has_many associations but still associate with the other class. In my example I am using students for players on an event through lessons, and lectures for events on a player through lessons. But what you name them can be different.
class Event
has_many :participants
has_many :players, through: :participants
has_many :lessons
has_many :students, through: :lessons, class_name: "Player"
end
class Player
has_many :participants
has_many :events, through: :participants
has_many :lessons
has_many :lectures, through: lessons, class_name: "Event"
end
I have four models:
User
Listing
Order
OrderGroup
User:
has_many :listings
has_many :orders
Listing:
belongs_to :seller, class_name: "User", foreign_key: :user_id
has_many :order_groups, through: :orders
has_many :orders
Order:
has_one :seller, through: :listing
belongs_to :listing
belongs_to :order_group
OrderGroup:
has_many :listings, through: :orders
has_many :orders
has_many :sellers, through: :orders
When I try to pull Order.where(seller: User.find(3)), I get an empty collection. However, when I do Order.last.seller, I get the seller's user_id.
How can I pull Order.where(seller: User.find(3))' ?
You can write query as
Order.joins(:listing).where('listings.user_id = ?', 3)
Models:
class User < ActiveRecord::Base
has_many :reports
has_many :social_accounts
has_one :api_client
has_many :integrations
has_many :profiles, through: :integrations
has_many :tags
has_many :profiles, through: :tags
end
class Tag < ActiveRecord::Base
belongs_to :user
belongs_to :profile
end
class Profile < ActiveRecord::Base
has_many :integration_profiles
has_many :integrations, through: :integration_profiles
has_many :users, through: :integrations
belongs_to :api_client
has_many :tags
ene
At times I want to retrieve all of the user's profiles through the integrations and other times through tags. How?
The answer:
has_many :profiles_tagged, through: :tags, source: :profile
On the User model