Multiple user types. Polymorphism Devise

155 views
Skip to first unread message

Alex jimmy Montaño fuentes

unread,
Jun 22, 2016, 5:41:44 AM6/22/16
to rubyonra...@googlegroups.com
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.

--
Posted via http://www.ruby-forum.com/.

Johnny Stewart

unread,
Jul 1, 2016, 4:40:41 PM7/1/16
to rubyonra...@googlegroups.com
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.

Alex jimmy Montaño fuentes

unread,
Jul 11, 2016, 5:06:58 AM7/11/16
to rubyonra...@googlegroups.com
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.

Johnny Stewart

unread,
Jul 11, 2016, 2:42:12 PM7/11/16
to rubyonra...@googlegroups.com
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..

Colin Law

unread,
Jul 11, 2016, 4:32:31 PM7/11/16
to Ruby on Rails: Talk
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

Alex jimmy Montaño fuentes

unread,
Jul 11, 2016, 5:56:12 PM7/11/16
to rubyonra...@googlegroups.com
Johnny Stewart wrote in post #1184570:
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!

Johnny Stewart

unread,
Jul 13, 2016, 11:00:39 AM7/13/16
to rubyonra...@googlegroups.com
> 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.

Johnny Stewart

unread,
Jul 13, 2016, 11:15:12 AM7/13/16
to rubyonra...@googlegroups.com
Colin Law wrote in post #1184575:
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.

Colin Law

unread,
Jul 13, 2016, 11:21:51 AM7/13/16
to Ruby on Rails: Talk
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] http://eewang.github.io/blog/2013/03/12/how-and-when-to-use-single-table-inheritance-in-rails/

Colin

Johnny Stewart

unread,
Jul 13, 2016, 11:45:38 AM7/13/16
to rubyonra...@googlegroups.com
Colin Law wrote in post #1184606:
> On 13 July 2016 at 16:14, Johnny Stewart <li...@ruby-forum.com> 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]
>
http://eewang.github.io/blog/2013/03/12/how-and-when-to-use-single-table-inheritance-in-rails/
>
> 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.

Colin Law

unread,
Jul 13, 2016, 12:14:07 PM7/13/16
to Ruby on Rails: Talk
On 13 July 2016 at 16:45, Johnny Stewart <li...@ruby-forum.com> wrote:
> Colin Law wrote in post #1184606:
>> On 13 July 2016 at 16:14, Johnny Stewart <li...@ruby-forum.com> 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]
>>
> http://eewang.github.io/blog/2013/03/12/how-and-when-to-use-single-table-inheritance-in-rails/
>>
>> 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."

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

Alex jimmy Montaño fuentes

unread,
Jul 13, 2016, 12:36:50 PM7/13/16
to rubyonra...@googlegroups.com
Thanks so much for you help and advices J. and Colin. I have much
clearer ideas about this.
Regards.

Alex jimmy Montaño fuentes

unread,
Jul 13, 2016, 12:37:34 PM7/13/16
to rubyonra...@googlegroups.com
Thanks so much for you help and advice J. and Colin. I have much clearer
ideas about this.
Regards.

Johnny Stewart

unread,
Jul 14, 2016, 5:12:39 AM7/14/16
to rubyonra...@googlegroups.com
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..
Reply all
Reply to author
Forward
0 new messages