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 null values in columns in your user table.

Johnny S. 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…

On 11 July 2016 at 19:41, Johnny S. [email protected] wrote:

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

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… And no need to
modify Devise’s Registration controller.

J.

Colin L. wrote in post #1184575:

On 11 July 2016 at 19:41, Johnny S. [email protected] wrote:

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.

On 13 July 2016 at 16:14, Johnny S. [email protected] wrote:

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

Colin L. wrote in post #1184606:

On 13 July 2016 at 16:14, Johnny S. [email protected] wrote:

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.

On 13 July 2016 at 16:45, Johnny S. [email protected] wrote:

see what table that user’s extra info is held in (chef_info,

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."

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

Johnny S. 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 so much for you help and advice J. and Colin. I have much clearer
ideas about this.
Regards.

Colin L. 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.