I have the following entities.
User
Event
Expense
Guest
A User is someone that is registered with my site. An event is something that a specific user can create and then invite people to (other users). An expense is created by a specific user for a specific event and can be associated with other users/guests of the event (like user A bought something for user B and user C and guest D). A guest is also created by a specific user for a specific event but once created for the event, the other users associated with that event can see the guest. A guest will never actually log into the system...it is just a placeholder for people that may have attended an event but whom are not registered on the site.
I am trying to wrap my head around the has_many and belongs_to attributes of these entities.
It is almost like in my many-to-many relationship tables I need another column which identifies the "type" of person (user or guest) so I can join properly to pull in names, etc. from the users and guests tables accordingly.
I have thought about creating a flag in the users table that says whether the record is a guest (and therefore not require that guest to register with the site, login, etc.) but that doesn't seem very clean.
Any thoughts are greatly appreciated.
Thanks!
Thomas
This sounds to me like you're naturally leaning towards what is called a polymorphic association. It might be useful for you to have a look at this Railscast by Ryan Bates: Polymorphic Associations
I agree with Gav Polymorphic just one table people with a column type and tada
class Person < ActiveRecord:Base
#methods and associations all people have
end
class User < Person
#methods and associations specific to users
end
class Guest < Person
#methods and associations specific to guests
end
Related
Lets assume a website whether students, lecturers can login.
This can be done in two ways:
User model will be there, and user_type field ensure whether he is student or lecturer. But, in this way, if a student takes username 'a', then lecturer cant take same username 'a'. Since they both are different, for example like /profiles/lecturers/a. Here, user model says 'a' already exists, but that belongs to Student but not lecturer, so what should profiles/lecturers/a say? weird, right?
Here, There wont be any user model. Separate Lecturer and Student models with separate usernames. Offourse,we can have a common user model with common things like name, address, country. But, username should not be in usermodel. They should be part of Student, Lecturer.
Just not getting what to start with ?
What do you guys suggest ? 1 or 2 ?
Thanks.
I think it depends on whether you really want the username to be unique. Of course you could always have the unique field be an email and that could solve the problem.
Generally, for simplicity its probably easiest to just go with one User Model (differentiated by email for example) and then use a gem like cancan (https://github.com/ryanb/cancan) to make different roles.
For authentication you can also take at many excellent gems that fit that bill, most notably:
Devise https://github.com/plataformatec/devise
Sorcery https://github.com/NoamB/sorcery
I would lean towards #1 but use STI (single table inheritance) - its not always the best solution, but might be a good fit here, at least it is worth experimenting with
something along the lines of:
use devise and generate a User model and table, let devise handle all user authentication - it will use users.email as the login by default, go with that
add a 'type' column (string) to your user table for STI
add a 'nickname' column to the user table, show that in the UI, no need for it to be unique across Lecturer and Student
implement Lecturer and Student models which inherit from User
class User < ActiveRecord::Base
# all of the devise code
# ...
def is_student?
type == "student"
end
# ...
class Lecturer < User
# ...
class Student < User
# ...
Devise will inject the current_user method in your controllers, you might need/want to override it. Normally it would return a User object, you can use becomes to cast it to the appropriate sub-class - see http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-becomes
def current_user
return nil unless #current_user
if #current_user.is_student?
#current_user.becomes(Student)
elsif #current_user.is_lecturer?
#current_user.becomes(Lecturer)
else
#current_user
end
end
or don't mess with current_user at all, instead add in your own current_student and current_lecturer methods
# nil if not a student
def current_student
current_user.becomes(Student) if current_user.is_student?
end
NOTE: none of this code has been tested, your milage may vary
I don't think there is a simple answer for this. It will be really simple and won't matter so much which route you take if your application only have Student and Lecturer.
However, what happen when, you are required to have Classroom? A classroom can have multiple lecturers and multiple students. It is still quite simple to query either Lecturer or Student from Classroom right? What happen when you want to look for students that have classes given lecturers? Then you have Faculty, Course, Examination, Grade, GPA, then may want to define which lecturer can create what etc etc. Surely all of this can be solved using those SQL techniques rails handily provides but what are the trade-offs?
So I guess my answer is unless you have taken all those into consideration there is no right way.
I have installed Devise and created Users and also Admins using Option 1 from this tutorial https://github.com/plataformatec/devise/wiki/How-To:-Add-an-Admin-role
Now I need a little help. When adding the Admins it creates a different table, and the potential arises that the admins and regular users could have the same ID's.
So how exactly do I got about grabbing information from users and admins? Say for example I want to display all users? Do I have to traverse the users table and then the admins table?
Or if I am displaying a post. How will I know which table to look for to get the user or admin info?
I know I can just add a role column to the users table but I wanted to avoid this.
I hope this makes sense haha
I highly recommend using the Single Table Inheritance (STI). You could do the STI by adding a column named type with a string datatype in the users table and create an admin model as well as a normal_user model both models will inherit from the user model of the devise gem.
class NormalUser < User
end
class Admin < User
end
The type column is a reserved word which will hold a value either NormalUser or Admin according to the user type you created.
To create an admin use Admin.create(...) and to create a normal user use NormalUser.create(...) where the dots are the attributes of the Admin and the NormalUser
I am building a blog-style application in Rails 3 where multiple users are able to post some news. After the login (which is realized with "Authlogic") the user values are stored in a own model called e.g. "UserSession". The form for the post contains title, content etc. and the username should be stored with a hidden form.
I think that the two models don't need to be related to each other (by that I mean a :has_many - :belongs_to relationship) because there isn't any further usage for that information.
Do I really not need this relation? And how could I realize the form?
For Authlogic is it important to remember that the 'UserSession' does not correspond to any database tables (i.e. you would never use a has_many or has_one 'UserSession'). I think the relationship you are looking for is:
User has many Posts
Blog belongs to User
The reason? It is always a good idea to associate a record with the 'owner' so that the owner can later modify or delete the record. I hope this helps.
I have a User model in my app, which I would like to store basic user information, such as email address, first and last name, phone number, etc.
I also have many different types of users in my system, including sales agents, clients, guests, etc.
I would like to be able to use the same User model as a base for all the others, so that I don't have to include all the fields for all the related roles in one model, and can delegate as necessary (cutting down on duplicate database fields as well as providing easy mobility from changing one user of one type to another).
So, what I'd like is this:
User
-- first name
-- last name
-- email
--> is a "client", so
---- client field 1
---- client field 2
---- client field 3
User
-- first name
-- last name
-- email
--> is a "sales agent", so
---- sales agent field 1
---- sales agent field 2
---- sales agent field 3
and so on...
In addition, when a new user signs up, I want that new user to automatically be assigned the role of "client" (I'm talking about database fields here, not authorization, though I hope to eventually include this logic in my user authorization as well). I have a multi-step signup wizard I'm trying to build with wizardly. The first step is easy, since I'm simply calling the fields included in the base User model (such as first_name and email), but the second step is trickier since it should be calling in fields from the associated model (like--per my example above--the model client with fields client_field_1 or client_field_2, as if those fields were part of User).
Does that make sense? Let me know if that wasn't clear at all, and I'll try to explain it in a different way.
Can anyone help me with this? How would I do this?
STI is probably a good fit for your requirements, as suggested by tadman, if you are using ActiveRecord (from Rails 3, it is easy to change ORM). The basic information is available on the AR documentation page, but here is some extra information w.r.t. your target:
Define one model per file. Otherwise there are some initialization troubles. Assuming Client inherits from User all in a single file, Client objects cannot be created as long as a User constructor has not been called once. One file per model circumvents the problem.
All attributes through the hierarchy are defined one-shot in the top class. This is for performance issues, but it seems disturbing many people in blog posts. In short, the Ruby code is object-oriented and encapsulates properly the attributes. The DB contains everything in a single table, with the extra "type" column to distinguish where they belong in the hierarchy. This is only a "trick" to represent inheritance trees in relational databases. We must be aware that the ORM mapping is not straightforward. The image on this site from Martin Fowler may help understand the situation.
In addition, you would like any new user to be a client, where Client inherits from User. To do so, you may simply instantiate any new user as a client. In your controller for creating users:
user = Client.new
# Do something to user
user.save
#=> <Client id: 1, name: "Michael Bolton", email: "mike#bolton.net", created_at: "2010-05-30 03:27:39", updated_at: "2010-05-30 03:27:39">
All the above is still valid with Rails 3 when using ActiveRecords.
It looks like you have two reasonable approaches here, but it will depend on the nuances of your requirements.
You can use Single Table Inheritance (STI) to do what you want, where User is only the base class for others named SalesAgent or Client and so forth. Each of these sub-classes may define their own validations. All you need for this to work is a string column called "type" and ActiveRecord will do the rest:
class User < ActiveRecord::Base
end
class Agent < User
end
The alternative is to have a number of free-form fields where you store various bits of related data and simply interpret them differently at run-time. You may structure it like this:
class User < ActiveRecord::Base
has_one :agent_role,
:dependent => :destroy
end
class AgentRole < ActiveRecord::Base
belongs_to :user
# Represents the agent-specific role fields
end
That would have the advantage of allowing for multiple roles, and if you use has_many, then multiple roles of the same type.
I'm creating a Rails app for students and high schools and I'm having some trouble with my User.rb.
I want to have a user model to be used for logging in, but having that user have many roles. The tricky part is that I want users that have a student role to have_one student page, and those that have a role of principal to have_one high_school page.
The students and also nested in the high_school so the entire thing becomes a big mess.
So my question(s): How do I limit a user to only creating one student / high school to represent them? Also how would I nest this student pages inside the highschool without screwing up the user system?
My environment: Rails3 and Ruby 1.9.2dev
Thank you!
Follow up: Would it be possible to put the name of the high_school in the subdomain? That would make the url look like
highschoolname.mysite.com/students/eric-koslow
I'd suggest polymorphic association to user_representations. It'd hold info about which high_school object or which student_page to associate the appropriate user to.
You can made a validation to avoid the multi-creation.