I'm trying to understand rails associations
I've the following tables and I've to define their relations, can any one please help me understand.
The tables are Products, ProductDistributors, and Distributors.
Every product has a distributor, a distributor carries multiple products
I defined these as
class Product < ActiveRecord::Base
has_one :product_distributor
has_one :distributor, through: :product_distributor
end
class ProductDistributor < ActiveRecord::Base
belongs_to :products
belongs_to :distributors
end
class Distributor < ActiveRecord::Base
has_many :product_distributors
has_many :products, through: :product_distributors
end
Is this correct? If not, how can I correct it?
I feel the problem lies in the Distributors class name because it's plural. when you say something like has_many :distributors, Rails by default will link to the Distributor class, but in your case the class name is Distributors.
Adding class_name option to your relationship declarations should work:
class Product < ActiveRecord::Base
has_one :product_distributor
has_one :distributor, through: :product_distributor, class_name: 'Distributors'
end
class ProductDistributor < ActiveRecord::Base
belongs_to :product
belongs_to :distributor, class_name: 'Distributors'
end
class Distributors < ActiveRecord::Base
has_many :product_distributors
has_many :products, through: :product_distributors
end
Also note that your belongs_to should be singular not plural. Please go through the Association guide for details: http://guides.rubyonrails.org/association_basics.html.
As I see, Product has one (belongs to) Distributor, and Distributor has many Products. So you not need to use ProductDistributor
class Product < ActiveRecord::Base
belongs_to :distributor
end
class Distributors < ActiveRecord::Base
has_many :products
end
Just add column *distributor_id* to products table
I recomend you to read Active Record Associations Guid to understand associations
The reason to use has_many through: is that you need to use a join table that isn't named in the standard Rails naming convention. In this case, ProductDistributor has such a table associated (product_distributors) because the Rails convention puts the tables in the name in lexicographic order and pluralizes them. The Rails table name would be distributors_products. If you created such a table with foreign keys to the ids of the distributors and products tables you wouldn't need to specify the join table and you could just say has_and_belongs_to_many :distributors on Products and has_and_belongs_to_many :products on Distributors.
What you have isn't quite right for what you are trying accomplish, frankly. You have a many_to_many relationship between Product and Distributors. If you really want a many_to_one relationship between Product and Distributor you should make the following changes:
schema changes: Drop the product_distributors table and add a foreign key from products to distributors.
drop_table :product_distributors
change_table :products do |t|
t.references :distributors
end
model changes: Delete the model for ProductDistributor and change Product and Distributor to reference each other directly. Also note that Distributors is renamed to Distributor.
class Product < ActiveRecord::Base
belongs_to :distributor
end
class Distributor < ActiveRecord::Base
has_many :products
end
Related
I have a table called foods and categories, but this table has no relation, I want to connect them through another table called food_category. And I want to make one-to-one relation between food and category maybe the diagram looks like this
class Food < ApplicationRecord
has_one :category
end
class Category < ApplicationRecord
has_one :food
end
class FoodCategory < ApplicationRecord
belongs_to :category
belongs_to :food
end
Is it possible to do this?
Yes, this is possible. You just need to do
has_one :category, through: :food_categories
as discussed in the Rails docs here.
However, this is a long-winded way to go about this kind of association. If it's going to be one-to-one, why not just add a foreign key to Category from Food? And presumably, you would actually want Category to contain many Food records? Seems like the below would make more sense:
class Food < ApplicationRecord
belongs_to :category
end
class Category < ApplicationRecord
has_many :food
end
class Food < ApplicationRecord
has_one :food_category
has_one :category, through: :food_categories
end
In rails console, you can access like this
Food.find(:id).categories
I have a Product and Category model which have a has_and_belongs_to_many relation.
So I can search for Product.categories or Category.products
class Product < ApplicationRecord
has_and_belongs_to_many :categories
end
class Category < ApplicationRecord
has_and_belongs_to_many :products
end
Now I wanna add a new relation to the Product:
It should called main_category which only should be a has_one relation from the Product to the Category. So a Product only can have one MainCategory. But the Category of course should return all MainCategory products.
Must I create a SubClass of Category? Normally I would like to not create an extra class
How can I solve that to simply call Product.main_category or Category.main_products?
How to place indexes properly?
How does the migration should look like?
You can simply do it like this i guess
class Product < ApplicationRecord
has_and_belongs_to_many :categories
belongs_to :main_category, class_name: 'Category', foreign_key: :main_category_id
end
class Category < ApplicationRecord
has_and_belongs_to_many :categories
has_many :main_products, class_name: 'Product', foreign_key: :main_category_id
end
You will have to add an column to products table called main_category_id
Source https://guides.rubyonrails.org/association_basics.html#bi-directional-associations
Could somebody explain me is my code correct.
I'm trying to get foreign_key option in rails associations.
I have 2 models:
Book and Author
Book db schema:
name
user_id
Author db schema:
name
My models:
class Author < ApplicationRecord
has_many :books, foreign_key: :user_id
end
class Book < ApplicationRecord
belongs_to :author, foreign_key: :user_id
end
Here I don't understand why we should define foreign_key in both models. Is it necessarily?
If you have used the table and column names that Rails expects, then you do not need to explicitly define the foreign_key. In your case, if the foreign key column was named author_id, then you could get by quite simply:
class Author < ApplicationRecord
has_many :books
end
class Book < ApplicationRecord
belongs_to :author
end
However, in your case, the foreign key column is not named according to what Rails expects, so you have needed to explicitly define the foreign key column name. That's fine, but it does make a little more work for you.
In cases where you have explicitly defined the foreign key, you should define it for both associations. Your has_many association will not work without it.
In addition, you should define the inverse association:
class Author < ApplicationRecord
has_many :books, foreign_key: :user_id, inverse_of: :author
end
class Book < ApplicationRecord
belongs_to :author, foreign_key: :user_id, inverse_of: :books
end
Defining the inverse_of can cause ActiveRecord to make fewer queries, and gets rid of a few surprise behaviors. For an explanation of inverse_of, see Exploring the :inverse_of Option on Rails Model Associations by Ryan Stenberg
I have these associations in my Rails 4.2 app. I don't understand how to setup the proper references/foreign_keys between instructors and courses.
So far both instructors and courses tables have a local_id (local reference).
Local is a training center they both belong to.
class Local < ActiveRecord::Base
has_many :instructors
has_many :courses
end
class Instructor < ActiveRecord::Base
belongs_to :local
has_many :courses, through: :locals
end
class Course < ActiveRecord::Base
belongs_to :local
has_many :instructors, through: :locals
end
Do I add a foreign_key to the courses table? Like this:
add_foreign_key :courses, :instructors
I read something about when having many to many associations we need a "join table" cause we need to store many ids. I guess Local is just that in this case.
Or do I need another table(Model) that belongs_to :instructor, :course?
Here is how I would set it up for maximum flexibility.
Instructors and Courses
Lets set up a many to many relationship with a join model which we call Employment.
We can generate the model with:
rails g model employment instructor:belongs_to course:belongs_to
Which will give us this:
class Employment < ActiveRecord::Base
belongs_to :instructor
belongs_to :course
end
employments will have the instructor_id and course_id foreign keys. This lets us assign any number of instructors to a course and vice versa.
So let's put the join model to use:
class Instructor < ActiveRecord::Base
has_many :employments
has_many :courses, through: :employments
end
class Course < ActiveRecord::Base
has_many :employments
has_many :instructors, through: :employments
end
Venues and Courses
I would recommend you rename your Local model Venue as it's the common english term for the place where a course or event is held. Locale is awkward since it collides with a separate concept in web applications and may cause name clashes.
And we should probably set it up as many to many to account for the complexities of real life.
So again:
rails g model booking venue:belongs_to course:belongs_to
class Booking < ActiveRecord::Base
belongs_to :venue
belongs_to :course
end
bookings will have the venue_id and course_id foreign keys.
class Venue < ActiveRecord::Base # was Local
has_many :bookings
has_many :courses, through: :bookings
end
class Course < ActiveRecord::Base
# ...
has_many :bookings
has_many :venues, through: :bookings
end
More reading:
http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association
http://blog.flatironschool.com/why-you-dont-need-has-and-belongs-to-many/
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