Active record: Querying nested many to many models - ruby-on-rails

I have a Store that has many Catalogs and in turn each catalog has many Products.
The Product and Catalog shares many to many relationship.
One product can belong to many catalogs and vice-verse.
So, my model definition goes like this:
class Store < ActiveRecord::Base
has_many :store_catalogs
has_many :catalogs, :through => :store_catalogs
end
class StoreCatalog < ActiveRecord::Base
belongs_to :store
belongs_to :catalog
end
class Catalog < ActiveRecord::Base
has_many :store_catalogs
has_many :stores, :through => :store_catalogs
has_and_belongs_to_many :product_set, :class_name => "Product"
end
class Product < ActiveRecord::Base
has_and_belongs_to_many :catalogs
end
Now, I would like to access all the products that belongs to a store.
How do I link those together so that I get that? please suggest.
I am trying out various combinations from the rails console to pull the data, not sure if the console itself limits the relation based querying by any chance(though i would like to believe it doesn't).

I think this should solve your problem
class Store < ActiveRecord::Base
has_many :catalogs
has_many :products, :through => :catalogs
end
class Catalog < ActiveRecord::Base
belongs_to :store
has_and_belongs_to_many :products
end
class Product < ActiveRecord::Base
has_and_belongs_to_many :catalogs
end
And then you just need a table in your database called catalogs_products with catalog_id and product_id to link the has_and_belongs_to_many association.
Then in order to get all the products from a store just do
Store.find(id).products

Related

Rails model has and belongs to many list types

I have two models, User and Product
class User < ActiveRecord::Base
has_and_belongs_to_many :products
end
class Product < ActiveRecord::Base
has_and_belongs_to_many :users
end
Now I want to make three lists for each user, products they've checked out recently, products that are in their shopping cart and products which they have bought. How do I make a distinction between these relations? Could I add some sort of type column to the relation table? And how could I then later check this type?
Thanks
If you and to add other columns to the relation table perhaps you should consider using has_many on both User and Products, then you can add your columns on Cart
class User < ActiveRecord::Base
has_many :carts
has_many :products, through: :carts
end
class Cart < ActiveRecord::Base
belongs_to :user
belongs_to :product
end
class Product < ActiveRecord::Base
has_many :carts
has_many :users, through: :carts
end

Rails habtm joins

I have this relationship between categories, products & brands:
class Brand < ActiveRecord::Base
has_many :products
end
class Category < ActiveRecord::Base
has_and_belongs_to_many :products
end
class Product < ActiveRecord::Base
has_and_belongs_to_many :categories
belongs_to :brand
end
How can I select all categories by specified brand with this relations?
I try this but get an error
b = Brand.find(1)
Category.joins(:products).where(:products => b.products)
You did the right thing with the join, just add a more complex where definition:
Category.joins(:products).where(:products => {:brand_id => 1})
Controversially HABTM's are rarely, if ever, a good design and IMO just about the only thing Rails got wrong.
Introduce an xref table to join products and categories and use has_many :through on both sides of the relationship so you end up with
class Brand < ActiveRecord::Base
has_many :products
has_many categories :through => products # This is now allowed in Rails 3.x and above
end
class Category < ActiveRecord::Base
belongs_to :product_category
has_many :products :through => product_category
end
class Product < ActiveRecord::Base
belongs_to :brand
belongs_to :product_category
has_many :categories :through => product_category
end
class ProductCategory < ActiveRecord::Base
has_many :products
has_many :categories
end
This gives you the best flexibility with the least amount of code re-factoring for you plus a much more intuitive path to get whatever data you need on either side of the relationship and will enable you to achieve the following
b = Brand.find(1)
b.categories.all
Update
The above is totally untested code and I have just corrected a glaringly stupid mistake I made. If you have any issues implementing this then come back

Polymorphic associations and/or has_many_through

I need to create relationships between a user, product and a photo-model. A user can add photos to a product. Therefore, a user has_many photos and a product has_many photos, but each photo belongs_to both a product and a user. How can I achieve this in Rails? As far as I understand a polymorphic association would only allow a photo to belong to a product or a user. Do I have to instead using separate has_many_through relationships for the user-photo and product-photo relationships?
You can have multiple belongs_to attributes within the same model. Essentially the Model that is marked as belongs_to will hold a foreign key to the Model that has been marked with has_many.
class MyModel < ActiveRecord::Base
belongs_to :other_model1
belongs_to :other_model2
end
If you want to use polymorphic associates as you mentioned below you could do that along these lines
class Photos < ActiveRecord::Base
belongs_to :imageable, :polymorphic => true
end
class Users < ActiveRecord::Base
has_many :photos, :as => :imageable
end
class Product < ActiveRecord::Base
has_many :photos, :as => :imageable
end
In this case you can create the relationship simply by adding the has_many :phots, :as => :imageable attribute without having to revisit the Photos class.

When should my model belong to another one?

I'm unsure if I can accomplish what I want with my associations.
This is the scenario I want in my application:
A user will select a Store. Then inside of that Store a user selects a product and then can add a new price to that product.
class Business < ActiveRecord::Base
has_many :stores
end
class Store < ActiveRecord::Base
belongs_to :business
has_many :prices
end
class User < ActiveRecord::Base
has_many :prices, :dependent => :destroy
has_many :products, :through => :prices
end
class Price < ActiveRecord::Base
belongs_to :user
belongs_to :product
belongs_to :store
end
class Product < ActiveRecord::Base
has_many :prices
has_many :users, :through => :prices
end
I'm not sure if this is correct since products don't belong to a store (integer store_id in table).
What do I need to do to make this scenario work out? Is this the right design?
This is a good and correct design for what you are trying to do.
If a product belonged to a store, then a product could only be at one store. Since store may have many products and products may be sold at many stores, you need another table referencing both the product and store.

One to many relationships in Rails

I'm having a hard time setting up the basic structure of my databases.
I have products (about 50). Each products is related to one or more place(s).
The basic schema would be this (no relation yet)
Products
id:integer
name:string
Places
id:integer
name:string
content:string
I first tought I could connect places and products by adding place_id to products and has_many belong_to in the controllers, but since a product can have more than one place, I don't know how.
If a Product has_many Places and a Place has_many Products your association needs to be many-to-many.
There are two ways to do this in Rails, the most recommended is a join model. You explicitly label the relationship between Products and Places. You could call it ProductLocation or Shop or similar, it would look like this:
product_locations:
product_id
place_id
class ProductLocation < ActiveRecord::Base
belongs_to :product
belongs_to :place
end
class Place < ActiveRecord::Base
has_many :product_locations
has_many :products, :through => :product_locations
end
class Product < ActiveRecord::Base
has_many :product_locations
has_many :places, :through => :product_locations
end
See http://guides.rubyonrails.org/association_basics.html#choosing-between-has_many-through-and-has_and_belongs_to_many
Just use through connection
ProductsPlaces (new table)
product_id
place_id
And in models
class Product < ActiveRecord::Base
has_many :places, :through => :products_places
end
class Place < ActiveRecord::Base
has_many :products, :through => :products_places
end
Also there is has_and_belongs_to_many which do in fact the same (with ProductsPlaces table)
class Product < ActiveRecord::Base
has_and_belongs_to_many :places
end
class Place < ActiveRecord::Base
has_and_belongs_to_many :products
end
But better use through, because has_and_belongs_to_many will be deprecated.
It sounds like you want to add product_id to places.
Product has_many Places
Place belongs_to Product

Resources