A "Project" has_many "ProjectAdmins" and many "ProjectCollaborators".
I've set this up as has_many through relationship:
Project - name:string
Users - email:string
ProjectAdmins - project:references, user:references
ProjectCollaborators - project:references, user:references
Are my relationships correct in my models? It seems wrong to list has_many :users twice.
Project
has_many :project_admins
has_many :project_collaborators
has_many :users, through: :project_admins
has_many :users, through: :project_collaborators
Users
has_many :project_admins
has_many :project_collaborators
has_many :projects, through: project_admins
has_many :projects, through: project_collaborators
It depends on how you want to use your associations.
If a user can not be a collaborator and an admin for the same project at the same time, you could merge the two models to a single model and determine 'admin' or 'collaborator' with a user_type kind of attribute, or with a specific role.
It seems to me a decision that should be driven by your data.
This won't work because has_many, belongs_to, etc methods simply add a bunch of readers and writers to your model. When you try to create an association with the same name, those methods will be overridden.
I would approach this problem differently.
There are several options.
A simpler solution would be to use only one ProjectUser model that would have a role:string (or :references + a separate Role model, if you'd like to keep things normalised) field to your User model. Add a bunch of convenience methods, like #admin? and #collaborator?. And you're all set.
Or you could go with STI (single table inheritance). Create a base class ProjectUser project:references user:references and inherit ProjectAdmin and ProjectCollaborator from it. Alternatively, since ProjectAdmin is probably always a collaborator, you could inherit it from ProjectCollaborator.
Basically, both solutions will give you the same results. But I'd say, the second one is better if you need to have different methods for different ProjectUser types.
Related
I've got a rather weird case. I have a few models that are tied together via associations one of these associations allows the user model to access referenced job data directly with the job model. However, the second case allows the user model to access the job data via the locations model.
User has_and_belongs_to_many :jobs
User has_many :jobs through: :locations
So how do I need to distinguish these two lines of code so that User.jobs uses the first association and User.jobs_through_locations uses the second association?
Use custom association name for the second association and use that name for referencing the jobs from third table.
Note: source is important as you need to tell rails which model to use when fetching user_jobs.
User
has_and_belongs_to_many :jobs
has_many :user_jobs, through: :locations, :source => :jobs
If Locations has many jobs, give the second association a different name and tell it which association in Location is the source.
User has_many :jobs_through_locations, through: :locations, source:
:jobs
I'm trying to set up models in such a way that Users can create Lessons and then other users can sign up for them.
Right now my models are set up like this:
class Lesson < ApplicationRecord
belongs_to :teacher, class_name: 'User'
has_many :students, class_name: 'User'
end
class User < ApplicationRecord
has_many :lessons
has_many :students, :through => :lessons
end
I want to be able to access the users signed up for a lesson by #lesson.students for example. I'd also like to be able to get all the lessons that a student is participating in (can't really see how I'd do this with my current set up).
Are my model associations right for how I'd like to use them? If so, how can I create the migrations to add the necessary references to my database models?
If you want the ability to create nested resources from it's parents then you have to add:
accepts_nested_attributes_for
to the parent model.
Also, I recommend you to read how to set up has_many through relationships, you need a join model for rails to do its magic and link the 2 models
Once you set everything up, create the join model (with it's respective foreign keys, one for lesson and the other for user) rails will take care of the associations between the models, allowing you to do things like:
User.last.lessons #lessons created by the last user
and
Lesson.first.users #users subscribed to a lesson, in this case the first one
I have a user and project model created in Rails. I have to perform an association that will create an relationship which is described below:
1 User has many Projects
1 project has many Users
How can I go about creating an association for the same in Rails? I need some help on which type of association in rails will help me to achieve this.
You are describing a many-to-many relationship type. Rails allows you to create this relationship using has_many :through and has_and_belongs_to_many directives. You can learn the difference here.
Shortly, has_many :through allows you to add additional columns into the intermediate table, has_and_belongs_to_many doesn't. If you don't need to have additional attributes in the intermediate table than use has_and_belongs_to_many syntax. You can always change to has_many :through later.
class Project < ActiveRecord::Base
has_and_belongs_to_many :users
end
class User < ActiveRecord::Base
has_and_belongs_to_many :projects
end
You are basically trying to have a many-to-many relationship.
In Rails you can do this based on two association concept:
has_and_belongs_to_many (HABTM)
has_many :through
Note:
You should have HABTM if you just do not care about the way these two tables are joined (relationship model) and you do not want to have any logic/validation for your join data. It will just keep your foreign keys in a table and based on that data will be fetched.
You need has_many :through if you want to have an intermediate model in between Project and User which can be called as UserProject model. This way your association could look like as follows:
User Model:
has_many :user_projects
has_many :projects, through: :user_projects
Project Model:
has_many :user_projects
has_many :users, through: :user_projects
UserProject Model:
belongs_to :user
belongs_to :project
You can use has_and_belongs_to_many or has_many through.Here is the link I am providing which will help you to sort out difference between them and which one will be good for you.Here is the video tutorial for you association.ALso there is a good link link.In your case you need has and belongs to many
The best thing to do in this situation is ,
In your user.rb model file:
has_and_belongs_to_many :projects
and In your project.rb model file:
has_and_belongs_to_many :users
You may want too use many to many relationship between project and user. on top of that you may want to visit rails official guide which describes all of these relations in great detail.
http://guides.rubyonrails.org/association_basics.html
I am working in a rails app where a Company has_many orders. An order has a name and that is it. The order can have_many television_spots, radio_placements, and newspaper_placements, the data in these tables is not the same so they have to be split up. Now if an order has_many radio_placements it will not have television_spots or newspaper_placements. My question is it bad practice to have a has_many relationship on a model even if it does not exist?, would it be better better to make a Company have_many television_orders and a television_order have_many television_spots? And thus a Company have_many radio_orders and a radio_order have_many radio_placements, and so on. I think that the first option is dryer initially but using the second strategy could result in cleaner more understandable code as the app grows and what we do with the data changes.
It's not bad practice to have a has_many association that does not actually have any models associated. The real question is what object type the radio_placements, television_spots and newspaper_placements should really be associated to. If they should in fact be related to the Order model, then place the associations there. From my understanding of your question/data shape it would appear that you do want these relationships to be on the Order model. So something like:
class Company
has_many :orders
has_many :television_spots, through: :orders
has_many :radio_placements, through: :orders
has_many :newspaper_placements, through: :orders
end
class Order
has_many :television_spots
has_many :radio_placements
has_many :newspaper_placements
end
Hopefully that helps.
I'm new to Ruby on Rails and was wonder if this is a good setup, or if there is a better configuration.
Background:
The system will be used to assign tasks to users, track the assignor, and allow multiple people to be assigned the task.
Create a company model, user model, task model, and a user_tasks model.
Company Class
has_many :users
has_many :tasks
User Class
belongs_to :company
has_many :user_tasks
has_many :tasks, through: :user_tasks
Task Class
belongs_to :company
has_many :user_tasks
has_many :users, through: :user_tasks
UserTasks Class
belongs_to :user
belongs_to :task
*Tracks assignor with boolean
I think this is perfect. There is one big advantage of having a has_many (model1), through: (model2) association when compared to has_and_belongs_to_many association in that you can access the join model (UserTasks your case) through the ActiveRecord query interface (UserTask.where() or UserTask.find_by(user_id: 1) and so forth). Querying the join table directly can sometimes shorten your queries. If you use the has_and_belongs_to_many association you will have a database table that you cannot directly access in Rails without resorting to SQL.
You probably don't need the UserTasks class if it is just a habtm table. So just create a migration for that table, but skip adding the model. Then in User, do has_and_belongs_to_many :tasks and in Task do has_and_belongs_to_many :users
The other thing that I see is that company is set for both tasks and users. You might have business rules to why this has to be, but if not, you might just be able to say Company -> has_many :tasks, through: :users
I favor :has_many, :through over has_many_and_belongs_to_many or HABTM. For example, I can be assigned to a Task twice, one as a programmer and another time as a designer. So I need some kind of "JobDescription" column on the UserTask column, and I'd need two rows of the UserTask table to represent me being a programmer on a task, and another to represent me being a designer on a task.
You want to write software that is easier to change, even though HABTM is shorter, you might change the software in the future, like in the case of a person doing two subtasks in the same task. Remember that a row in a database is a piece of data, or "a thing", if that makes sense. At the very least, you get timestamps.