I have such models Supplier and Role.
Supplier should have one role, one role might belongs to multiple suppliers,
so I don't want to add foreign key to the Role model
I wan't to create all roles at the beginning and then add role to a supplier whenever I want
Is there a way to do that??
The foreign key in this case needs to go in Supplier. You can't put it in Role, if a Role can belong to many suppliers.
That makes this a belongs_to relationship by Rails convention, not a has_one.
Your Supplier needs a column called role_id and an association belongs_to :role. Your Role can then have a has_many :suppliers, if you want to be able to find all suppliers who use a given role.
Related
I am creating an app that deals with sports teams. Currently I have two models. A Users.rb model and a Teams.rb model. Within the users of the app I would like to have team captains and teammates. I would like to give the captain the privledge of creating the team when they sign up. I would like the a captain to belong to a team and teammates belong to a team. I would like the team to just have one captain. What would the best way to set this up? Should I have a captain and a teammate alias in the users model? Or would it be better to make a captains.rb model?
Ok, First lets lay out the relationship assumptions since there are some that are vague from your descriptions:
A user can:
Be many captains
Be on many teams
A team can:
Belong to one captain
Have many users as teammates
From this I think you need 3 models:
User
Team
Teammates that acts as the has_many_through join table between users and teams
The Teammate model would definitely have:
user_id
team_id
Possible role/type field
And this leaves the point where you have to make a decision about the app based on how you will use the data. Since a team will only have one captain you could leave out the role field in the teammate model and just add a user_id or captain_id to the actual Team model. This would mean captain is treated as special and different from the other team mates always. However, I'm guessing for somethings you could want to loop through all members of the team including the captain. That's why you should probably just make captain a special role on the teammate model and add validation to make sure there is only one captain. Then you don't have to do special handling for the captain whenever looping through the entire team.
Assuming you go with the role field then your final models would have the following relations:
Teammate
belongs_to :team
belongs_to :user
User
has_many :teammates
has_many :teams, through: :teammates
Team
has_many :teammates
has_many :users, through: :teammates
has_one :team_captain, -> { where role: 'captain' }, class_name: 'Teammate'
You could also get fancier with that last one by working out a has_many through to get to the captain user instead of the captain team_mate. This post has some interesting details on advanced has_one:
http://www.rojotek.com/blog/2014/05/16/cool-stuff-you-can-do-with-rails-has_one/
If the captains and teammates have different attributes so i think its better to separate the models but if this is not the case so why do not you create a join table for teammates between users and team and the team model has an owner id.
Schema example :
Team ( owner_id, .....)
Teammates( user_id, team_id, .... )
This will help you to set a belongs_to association between Team and User models as Captain using the owner_id column in the team model and the other members can be done by has_many teammates through Teammates Model or even use has_and_belongs_to_many association.
By this way you will manage to let one user has_one team or even a teammate within other teams.
Another idea to let all the members within the join table with an extra Column to decide its role within the team ,which will give you more control if you are going to add more roles in the future, and define your validations and scoops to serve that way.
I'd do as follow:
At the beginning app allows you to signup as "user aka team owner" or as "teammate"
Users.rb - can create teams and invite other teammates. Has administrative rights.
Teams.rb - belongs to User and has many Teammates.
Teammates.rb - belongs to Teams.
All assigned teammates could have admin-visible checkbox "captain" with boolean value. This could save you from creating one more db table. Unless "captain" is "true", teammate status is "simple player". Otherwise it's "captain".
Other way is to allow Users to create Teams and Teammates.
User would has_many Teams and Teammates.
Teammate belongs_to User and belongs_to the Team.
Team belongs_to User and has_many Teammates.
I setup roles for the User model, for now, I just have a role string column for the users table. The value could be admin, salesperson, instructor or student.
Now I have a ScheduledSession model that an Instructor is supposed to teach. I have an instructor_id column, which is supposed to have an id from the users table (an user with a role of instructor).
So how can I setup the association in the models? in the User model is doesn't seem right to add has_many :scheduled_sessions because if the role is a salesperson or an admin, it just doesn't feel right. or setup something like belongs_to :user, :as instructor in the ScheduledSession model, but I get error Unknown key :as.
How would you set this up?
You want to set up your belongs_to slightly differently in the ScheduledSession model.
belongs_to :instructor, :class_name => 'User, :foreign_key => 'user_id'
This allows you to refer to the instructor of a ScheduledSession object and have it point to an entity in the User table.
There's no way around having a has_many relationship on your User model if you want to pursue a role based User with each user having a single role. Without it, you'll have no mechanism to retrieve the scheduled_sessions associated with a user.
An alternative might be to use Single Table inheritance here, which would allow you to create Admin users who don't have SchededSessions, but Instructors who do. You'll still store all of these in the same table, but ActiveRecord will make it easier for you to compartmentalize them.
I'm trying to figure out something regarding rails relationships. I already posted a question regarding a specific items not long ago but I do not really understand what's done in the underlying DB.
I have a Project model and a Client model.
A Project belongs_to :client => I need to manually add client_id in projects table (with a migration).
A Client has_many :projects => I do not need to do anything in the DB (no migration).
The project.client and client.projects methods are both available.
I have a Group model and a User model.
A Group has_and_belongs_to_many :user
A User has_and_belongs_to_many :group
I then need to create a migration to create a joint table with a user_id and a group_id pointers.
I do not really see where the border between rails and the relational database is.
Why do I need to add foreign key sometimes but not always ? How is the has_many relationship handled as I did not do anything in the underlying DB for this particuliar guy ?
I am kind of lost sometimes :)
Thanks and Regards,
Luc
For a has_many <-> belongs_to assoication, you're defining that one project is owned (belongs_to) by one client. Therefore, that client has many (has_many) projects. For a project to determine what client it belongs to it needs to have an client_id column so that it can look it up. This client_id column is used by Rails when you call the client method, much like this:
Client.find(project.client_id)
That's how you can find a project's client. The client_id column is often referred to as a foreign key, because its a unique identifier ("key") in a table not of its origin ("foreign"). Boom.
When you call the other way around, finding all the projects a client has, i.e. client.projects, Rails does the equivalent of this:
Project.find_all_by_client_id(client.id)
This then returns all Project records which are associated with a particular client, based off the client_id field in the projects table.
With a has_and_belongs_to_many association, such as your users & groups example, you're declaring that a user has_and_belongs_to_many :groups.
Now if it were simply a has_many :groups, the foreign key would go in the groups table, or if it were a belongs_to it would go in the users table. Good thing to remember: the foreign key always goes in the table of the model that has the belongs_to.
You're also declaring that a group has_and_belongs_to_many :users, and so we come across the same problem. We can't declare the key in the users table because it doesn't belong there (because a user has many groups, you would need to store all the group ids the user belongs to) or the groups table for the same reasons.
This is why for a has_and_belongs_to_many we need to create what's known as a join table. This table has two and only two fields (both of them foreign keys), one for one side of the association and another for the other. To create this table, we would put this in a migration's self.up method:
create_table :groups_users, :id => false do |t|
t.integer :group_id
t.integer :user_id
end
A couple of things to note here:
The table name is the two names of the two associations in alphabetical order. G comes before U and so the table name is groups_users.
There's the :id option here which, when given the value of false generates a table with no primary key. A join table doesn't need a primary key because its purpose is to just join other tables together.
We store the group_id and user_id as integer fields, just like we would on a belongs_to association.
This table will then keep track of what groups have what users and vice versa.
There's no need to define additional columns on either the users or groups table because the join table has got that under control.
class Customer < ActiveRecord::Base
has_many :orders, dependent: :destroy
end
class Order < ActiveRecord::Base
belongs_to :customer
end
#order = #customer.orders.create(order_date: Time.now)
I have a model called company and one called user, and User belongs to Company and Company has many Users.
But I want to store on the company model the master company admin user, but I want to do it with a custom name.
So, i want to do this: comapany.owner.name .
How can I do this in Rails 3?
your Company needs one additional field
owner_id :integer
then add to Company
belongs_to :owner, :class_name => "User"
I have a user table, and have a role column, that identify their role. Now, I want to add a "Student" table, that have the student's student number, and I also want to add a "Teacher", to store the teacher's salary.
Both the Student and Teacher are the subclass of User. Now, I added a role column already in the User table, "T" = Teacher, and "S" = Student. Now, I want to add "Student" and "Teacher" in the database. What should I do? Generate scaffold or migration only? Also, it is necessary to modify my models? or I just need to modify the controller only??
Thank you.
This sounds more like a job for Rails' single table inheritance. It's really easy to use. Instead of using a separate table to store roles. Inherit your student and teacher models from User.
for example:
User < ActiveRecord::Base; ... end
Student < User; ... end
Teacher < User; ... end
Rails automatically creates a type column and stores the class there.
User.all will return all users Student.all will return users where the type is matches Student and Teacher.all will do the same for all teachers.
You can read more about single table inheritance at the ActiveRecord documentation, and here.
As nuclearsandwich said, this is a situation that calls for rails STI (single table inheritance), not polymorphic associations.
Just to highlight the difference:
1) Singe table inheritance is used when you have different models that are very similar to each other with minor differences. STI lumps all models in the same database table, with fields (columns) for all the models that use this table. There is also a "type" field which indicates which model this record belongs to.
Your case is a perfect example of STI. You have user, student, and teacher models, they share a lot of common fields and functionality, you just want an extra field for the student and the teacher.
2) Polymorphic association is used when you have a model that will be associated with different models. For example, imagine you have an "Address" model. Also you have a "Company" and a "User" model, both of which can have an address.
In your Address model, you can specify
belongs_to :user
belongs_to :company
And then make sure if the address belongs to a company not to call address.user and vice-versa. However, a better way to do it would be through a polymorphic association. In your address model you do
belongs_to :addressable, :polymorphic => true
and in your user and company model you add
has_one :address, :as => :addressable
This allows the address model to polymorph (literally: transform into many) its association, and be connected with multiple different models through a single association.