Multiple user types. Polymorphism Devise

A few months ago I decided to learn how to use Ruby on Rails, and after learn some Ruby and do some projects by videotutoriales decided to start my own project. Once I made a diagram of classes and relationships that I need, I find my first problem: I need multiple user profiles where to some types of users require more information than others. In addition to each type of user, once registered, will have different home pages with different functions. My intention is to make a polymorphic association from the User model, generate by devise, containing the common attributes of all types of users (email, name, password) to the models user types (chef, singer, athlete, ...):

class User < ActiveRecord::Base ... belongs_to :meta, :polymorphic => true end

class Chef < ActiveRecord::Base has_one :user, :as => :meta ... end (more models)

According thought, the class of each user would be recorded at the time of the registration, from the form devise registration view, by adding a dropdown selector to choose a single type of user. And to log in, only will be necessary the password and email, without the selector. But I really have no idea of ​​how to do this ( i don't know how enable the selector to record the user class and do the appropriate modifications to the controller Registrations devise or as a redirect to different pages depending on the type of user who logs). I ask for help if you have dealt with a similar problem, if you know some way to do this, or if there is another easier way and efficient. Sorry if I said a bad concept, but have little time using ruby ​​on rails and I'm a little lost and for my bad english!. Thank you very much in advance and regards!

PS: I would avoid using gems, as camcam, for the many conditionals that is necessary, that in my opinion, overload the system. I also read concepts such as STI (singular table inheritance), but I thought it would not be applicable here to store variable information for each type of user.

I don't think you need to use polymorphism for this.

I'd use STI for users and just keep the very basics in the user table(profile name, email address, type etc). Then have something like chef_info and athlete_info tables which contain the rest of the differing information for each user type. This way you don't have a lot of nil values in columns in your user table.

Johnny Stewart wrote in post #1184402:

I don't think you need to use polymorphism for this.

I'd use STI for users and just keep the very basics in the user table(profile name, email address, type etc). Then have something like chef_info and athlete_info tables which contain the rest of the differing information for each user type. This way you don't have a lot of null values in columns in your user table.

Thanks for your response. i understood STI is applicable when save the same information for all the user types. you know some tutorial page about this?. Regards.

No tutorial that I know of..

You have the same information for all user types, namely just the important information for users. So - you keep password, username, first name, last name, email address etc in the User table.

Stuff like sport, training ground, weight, height, body-fat etc would go in a table like AthleticInfo

stuff like restaurant, food speciality, chef qualifications etc would go in a table like ChefInfo

then if user1 is a chef, he would have all the user info + type Chef and he would have an entry in the chef table

user2 if she was a footballer would have all the user info + type Athlete and she would have an entry in the athlete table

So, you don't need to keep all the chef or athlete data in the user table - you just have a reference to that info in the relevant table..

That does not sound like STI, STI is where you *do* store all the information in one table (Single Table Inheritance), but ignore the irrelevant parts dependent on the type.

Colin

Johnny Stewart wrote in post #1184570:

No tutorial that I know of..

You have the same information for all user types, namely just the important information for users. So - you keep password, username, first name, last name, email address etc in the User table.

Stuff like sport, training ground, weight, height, body-fat etc would go in a table like AthleticInfo

stuff like restaurant, food speciality, chef qualifications etc would go in a table like ChefInfo

then if user1 is a chef, he would have all the user info + type Chef and he would have an entry in the chef table

user2 if she was a footballer would have all the user info + type Athlete and she would have an entry in the athlete table

So, you don't need to keep all the chef or athlete data in the user table - you just have a reference to that info in the relevant table..

Thanks for your response. But isn't this a polymorphic association?. I'am trying to do exactly that with a polymorphic association, that is, create the user table with all the common information, and with meta_type:string (that saves the type of user) and meta_id:integer (that saves the id of the user on his type of user table), and implement the associations y the models after, like this: class User < ActiveRecord::Base ... belongs_to :meta, :polymorphic => true end

class Chef < ActiveRecord::Base has_one :user, :as => :meta ... end (more models)

So , each register user will have an entry in the user table, and on his user type table. The problem is that i don't know to modify the Registration controller of Devise to do that. Regards!

Thanks for your response. But isn't this a polymorphic association?. I'am trying to do exactly that with a polymorphic association, that is, create the user table with all the common information, and with meta_type:string (that saves the type of user) and meta_id:integer (that saves the id of the user on his type of user table), and implement the associations y the models after, like this: class User < ActiveRecord::Base ... belongs_to :meta, :polymorphic => true end

class Chef < ActiveRecord::Base has_one :user, :as => :meta ... end (more models)

So , each register user will have an entry in the user table, and on his user type table. The problem is that i don't know to modify the Registration controller of Devise to do that. Regards!

No - its not polymorphic at all. The type column is there due to STI.

class User < ActiveRecord::Base end

class Athlete < User   has_one :athlete_info, dependent: :destroy end

class Chef < User   has_one :chef_info, dependent: :destroy end

class AthleteInfo < ActiveRecord::Base   belongs_to :athlete end

class ChefInfo < ActiveRecord::Base   belongs_to :chef end

chef_info table is where the chef specific information is held, same for athlete. No complication of polymorphism required..

J.

Colin Law wrote in post #1184575:

in a table like ChefInfo

then if user1 is a chef, he would have all the user info + type Chef and he would have an entry in the chef table

user2 if she was a footballer would have all the user info + type Athlete and she would have an entry in the athlete table

So, you don't need to keep all the chef or athlete data in the user table - you just have a reference to that info in the relevant table..

That does not sound like STI, STI is where you *do* store all the information in one table (Single Table Inheritance), but ignore the irrelevant parts dependent on the type.

Colin

As I understand it STI is best suited to situations where the data is the same but the behaviour is different. For the User model it really only has to handle registrations etc. I don't think there is any need to hold data pertaining to that user being a chef.

All it needs is maybe profile name, email address, password etc. That needn't change here.

Using STI we store that one extra column of type - then use that to see what table that user's extra info is held in (chef_info, athlete_info etc).

J.

I do not believe that is the usual use case for STI. See [0] for a good description of the use of STI.

Colin

[0] How (and When) to Use Single Table Inheritance in Rails - eugenius

Colin

Colin Law wrote in post #1184606:

So, you don't need to keep all the chef or athlete data in the user

only has to handle registrations etc. I don't think there is any need to hold data pertaining to that user being a chef.

All it needs is maybe profile name, email address, password etc. That needn't change here.

Using STI we store that one extra column of type - then use that to see what table that user's extra info is held in (chef_info, athlete_info etc).

I do not believe that is the usual use case for STI. See [0] for a good description of the use of STI.

Colin

[0]

Colin

Hi Colin,

Maybe not, however, I still think adding in a lot of nullable columns into the User table when they don't need to be there doesn't make sense.

From the blog post you cite above:

"If sub-classes that you intend to use for STI have many different data fields, then including them all in the same table would result in a lot of null values and make it difficult to scale over time."

So, I think that there is no real need to have things like food-speciality and training-ground-address in the User table. These are better moved into other tables. Also - as regards the OP it removes the need to bring in polymorphism and messing about with Devise's registrations controller.

J.

Agreed if there are "many different data fields". As is always the case I advise using the KISS principle. Do it the easy way first (easy code has fewer lines and therefore fewer bugs) and only if proven necessary then add complexity to improve efficiency. Nine times out of ten (probably more) it will not be necessary.

Possibly an even better solution to the OPs problem would be to use roles for different user types and not even have the complexity of STI. It depends how much role specific data and behaviour there is. My advice would be to start with just roles and move to STI if necessary.

Colin

Thanks so much for you help and advices J. and Colin. I have much clearer ideas about this. Regards.

Thanks so much for you help and advice J. and Colin. I have much clearer ideas about this. Regards.

Colin Law wrote in post #1184608:

Possibly an even better solution to the OPs problem would be to use roles for different user types and not even have the complexity of STI. It depends how much role specific data and behaviour there is. My advice would be to start with just roles and move to STI if necessary.

Colin

Interesting, I hadn't thought of that - I'm going to have a root round in this area and a read up..

J.