Multiple user types with Authlogic

After a lot of careful research, I've made the decision to go with Authlogic ( http://github.com/binarylogic/authlogic ) for authentication in my app.

I currently have a User model (which "acts_as_authentic" in Authlogic). However, my app is going to have multiple user types ("Teacher", "Student", and potentially "Teacher's Assistant"). For the moment, they'll all be mutually exclusive; a user can't be both a Teacher's Assistant and a Student, for example.

Currently, I'm planning on creating separate models for each of these (Teacher, Student, TA). They'll each "belongs_to" a User, and a user will "has_one" of each. This way, I'll be able to put any common methods/fields in User, and any exclusive methods/fields in the model it belongs in.

I'm very new to Ruby (and, by association, to Rails). Does this sound like a reasonable way to do this? Does it follow "the Ruby/Rails way"? Or is there a common pattern for doing this in Rails that I don't know about?

Thank you very much in advance -Jake

Jake Boxer wrote:

After a lot of careful research, I've made the decision to go with Authlogic ( http://github.com/binarylogic/authlogic ) for authentication in my app.

I currently have a User model (which "acts_as_authentic" in Authlogic). However, my app is going to have multiple user types ("Teacher", "Student", and potentially "Teacher's Assistant"). For the moment, they'll all be mutually exclusive; a user can't be both a Teacher's Assistant and a Student, for example.

Currently, I'm planning on creating separate models for each of these (Teacher, Student, TA). They'll each "belongs_to" a User, and a user will "has_one" of each. This way, I'll be able to put any common methods/fields in User, and any exclusive methods/fields in the model it belongs in.

I'm very new to Ruby (and, by association, to Rails). Does this sound like a reasonable way to do this?

No. If you want several kinds of user models, make them *inherit* from User.

However, you probably only want one User model with a Role field. Then use something like rails_authorization or acl9 if you want role-based security.

Does it follow "the Ruby/Rails way"?

No, to the extent that it doesn't follow proper object-oriented design owing to misuse of associations as I outlined above.

Or is there a common pattern for doing this in Rails that I don't know about?

See above. In general, if X is a kind of Y, then X should be a subclass of Y.

Thank you very much in advance -Jake

Best,

Jake, I couldn't help but feel sorry for you in the path you're taking. Simply create a has_one and belongs_to relationship between a controlling master record such as Student_Type(Teacher, Student, etc). Now, when you call a record its @student_type.users(find ??). That inheritence stuff is for the race car drivers and opens up many potholes that could CRASH your effort. Hope this makes your life a little easier. David

I agree with Marnen. The easiest way would be to just add a role field to the user model.

I wouldn't mess with inherited classes or associations for what you are describing.

But if you do, you really should use inheritance, as Marnen described.

The only other table that I might consider would a "domain-table" called Roles (or anything you want). It could start with simply include more data. Then in your user table you could define a field for the role_id which could be set via the Role table. The advantage of this is that you get a central place to define all possible roles within the database rather that in just your rails application. This would allow you to guarantee referential integrity in the database, so that a user could not be made with an unintended role by bypassing your rails app (at the mysql or psql prompts, for example).

Of course, the importance of an unintended role getting into the database depends of your application setup. If you blacklist everything and only open up certain areas of the app by white-listing roles, then the consequence is less severe. Beware however, if you whitelist everything and only blacklist based on the role. This type of setup might allow unrestricted access to an unintended role. For this reason, I tend to blacklist everything, and then whitelist based on the role.

Andrew

In despite of a design problem, or the misconception on inheritance which Marnen already explained and you must change it if you haven't already, have you think about using a plugin for this? I've used acts_as_permissible[1] and it's really simple to use and configure, it has resolved the problem you're presenting here.

[1]http://github.com/NoamB/acts_as_permissible/

Hope it helps.