I'm trying to get the values from timestamps created in a lookup table. Let's say I've got Ingredients and Recipes, and a table called ingredients_recipes, with ingredient_id, recipe_id, and then the timestamps.
How can I get access to those timestamps? Basically, I need to know when a given ingredient was added to a recipe.
Thanks!
So you currently have something like this?
class ingredient << ActiveRecord::Base
has_and_belongs_to_many :recipes
.....
end
class recipe << ActiveRecord::Base
has_and_belongs_to_many :ingredients
....
end
And you want to get the dates they where added. The rails way to do this is by using a join model. (see http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html ) and many to many. particularly this line Choosing which way to build a many-to-many relationship is not always simple. If you need to work with the relationship model as its own entity, use has_many :through. Use has_and_belongs_to_many when working with legacy schemas or when you never work directly with the relationship itself.
So if you where to build a join model you would get something like below.
class ingredient << ActiveRecord::Base
has_many :mixtures
has_many :recipes , :through=> :mixtures
.....
end
class recipe << ActiveRecord::Base
has_many :mixtures
has_many :ingredients, :through=> :mixtures
....
end
class mixture << ActiveRecord::Base
belongs_to :recipe
belongs_to :ingredient
...
end
This way you can add attributes to the mixtures table, so you can find out when they where added, who added them etc...
Related
So currently i have in a app:
class Post < ApplicationRecord
belongs_to :category
end
and
class Category < ApplicationRecord
has_many :posts
end
which works fine as expected. However, i need to add multiple categories to a post . I thought about using has_many_and_belongs_to for each of them to acquire this but some trouble implementing this. It seems like a need to add an join table? If so, how would one look like with the setup shown above?
Any ideas?
I appreciate any input! Thanks in advance!
The table should be named categories_posts (categories comes first because of alphabetical sequence) and contain post_id and category_id integer columns (indexed, most probably). The it's as simple as:
class Post < ApplicationRecord
has_and_belongs_to_many :categories
end
class Category < ApplicationRecord
has_and_belongs_to_many :posts
end
You can create join table adding migration using:
rails g migration CreateJoinTableCategoryPost category post
Alternatively you can use has_many :through to have more control over a join table.
Advantages of using :through for many to many relationships
With has_many :through relationship you can have a model which will allow you to add validation, callbacks.
If you initially take some extra efforts to setup many to many relationship using through it can save a lot of time and headache in future
What if in future you want save the more information on join table like some custom sort, information about how the tables are associated which will not be allowed with has_and_belongs_to_many
Example
class Post < ApplicationRecord
has_many :categories, through: :post_categories
has_many :post_categories
end
class Category < ApplicationRecord
has_many :posts, through: :post_categories
has_many :post_categories
end
Adding relationship model with rails generator command
rails g model post_category category_id:integer post_id:integer custom:text
class PostCategory < ApplicationRecord
belongs_to :category
belongs_to :post
end
Sorry, this one is hard to phrase in the title. So here's what I'm trying to do. A workshop has many districts. Each district has exactly one district_contact (actually a district_contact_id). How can I use ActiveRecord to model the relationship between workshop and district_contact? I want to be able to do this:
Workshop.district_contacts
And get a collection of the actual user objects. Right now, I've done it using a short function:
def district_contacts
district_ids = []
self.districts.each do |district|
if district.contact_id
district_ids << district.contact_id
end
end
User.find(district_ids)
end
Define associations in the Workshop model:
has_many :districts
has_many :district_contacts, through: disctricts
Your model associations should look something like this.
class Workshop < ActiveRecord::Base
has_many :districts
has_many :district_contacts, through: disctricts
end
class District < ActiveRecord::Base
belongs_to :workshop
has_one :district_contract
end
I am new to rails and have a very basic question.
While creating models, for ex. I have to store recipe and its steps. Now should i make recipe table, steps table and recipe_steps table or should i have recipe , steps table and in the model for recipe define has_many :steps?
Any help would be great.
Thanks a lot
You always need to have 3 tables in your database. As you said recipes steps and recipe_steps
Then you have two solutions with your models. The first one with 3 models:
class Recipe
has_many :recipe_steps
has_many :steps, through: :recipe_steps
end
class Step
has_many :recipe_steps
has_many :recipes, through: :recipe_steps
end
class RecipeStep
belongs_to :step
belongs_to :recipe
end
The second one with only two models:
class Recipe
has_and_belongs_to_many :steps
end
class Step
has_and_belongs_to_many :recipes
end
You will use the second solution if you don't want to manage data in the recipe_steps table. But if you want to add some informations in this table (price or quantity for example), you must use the first solution.
In all cases you must create the 3 tables.
You will find more information here: http://guides.rubyonrails.org/association_basics.html
I hope this help
I'm creating a model called Chats. And I want to assign users to a discussion. They are either a part of the Chats or they aren't...
So I create one model Chats.
What's the standard Rails naming convention for the other table?
ChatUsers?
While has_and_belongs_to_many is an ok option here, I recommend going with has_many :through instead.
In essence you will have an explicit join model, which you can call something like ChatSession.
class Chat < ActiveRecord::Base
has_many :chat_sessions
has_many :users, :through => :chat_sessions
end
class User < ActiveRecord::Base
has_many :chat_sessions
has_many :chats, :through => :chat_sessions
end
class ChatSession < ActiveRecord::Base
belongs_to :user
belongs_to :chat
end
Now you will need a table called chat_sessions with columns :user_id, and :chat_id in it. This is your join table.
Advantage
You get a model which is fully under your control, and isn't just a dumb join table managed by rails. So for example, if you want to track number of messages particular user left in particular chat, it could be a column in chat_sessions table. Presence of :through renders habtm unneeded in most cases. There is no complexity overhead either.
If it is a join table, it would be both table names joined by '_' and in alphabetical order of table names:
chats_users
This is called a has_and_belongs_to_many association in rails. You basically have two models that call has_and_belongs_to_many and create a linking table that uses the two models in the name (alphabetical and plural).
models:
class Chat < ActiveRecord::Base
has_and_belongs_to_many :users
end
class user < ActiveRecord::Base
has_and_belongs_to_many :chats
end
Then your tables would be
chats
users
chats_users
I have the following model:
class Advisor < ActiveRecord::Base
belongs_to :course
end
class Course < ActiveRecord::Base
has_many :advisors
has_many :sessions
has_many :materials, :through=>:sessions
end
class Session < ActiveRecord::Base
belongs_to :course
has_many :materials
end
class Material < ActiveRecord::Base
belongs_to :session
end
I.e., every advisor teaches one course, every course has sessions, and every session has materials.
I want to traverse from an advisor to all the associated materials, i.e. something like: Advisor.first.materials
I tried to do:
class Advisor < ActiveRecord::Base
belongs_to :course
has_many :sessions, :through=>:course
has_many :materials, :through=>:sessions
end
But it didn't work as it treated sessions as a many-to-many table: Unknown column 'sessions.advisor_id' in 'where clause': SELECT 'material'.* FROM 'materials' INNER JOIN 'sessions' ON 'materials'.session_id = 'sessions'.id WHERE (('sessions'.advisor_id = 1))
I then tried to do:
class Advisor < ActiveRecord::Base
belongs_to :course
has_many :materials, :through=>:course
end
In an attempt to have the association use the "materials" association in the "Course" model, but received:
ActiveRecord::HasManyThroughSourceAssociationMacroError: Invalid source reflection on macro :has_many :through for has_many :materials, :through=>:sessions. Use :source to specify the source reflection.
Tried to use "sessions" as the source which was a nice try but made me receive only the sessions rather than the materials.
Any ideas if this is at all possible?
I'm using Rails 2.3.8 (perhaps time to upgrade?)
Thanks!
Amit
I want to traverse from an advisor to
all the associated materials
Unless I'm missing something, using the associations specified in your first example, you can simply call materials on the associated course:
a = Advisor.first
materials = a.course.materials
Using a has_many,through association for another has_many,:through relation will not work in rails
instead of creating a association you can just create a method to access all the materials by a Advisor
def materials
sessions.collect(&:materials).flatten
end
This will work, but you wont be able to chain find queries to this method. If you want to be able to chain find methods something like #advisor.materials.find.. Then inside this method use Material.find() with appropriate conditions