How to implement associations for multiple roles? - ruby-on-rails

I am implementing a job search application in rails where A user can signup for three different profiles/roles.
Employer
Worker
Enterpreneur(has his own company)
User can choose more than one profile/role.
(I am using the Devise)
My query is that Is it possible to implement the Single Table Inheritance in the above case.?like
CLass Employer < user
CLass worker < user
or what should be the best solutions for database structure to implement the above feature?

Yes it is certainly possible, STI is widely used when models share the same attributes and if you want to be able to query them all together (will help with speed and simplicity since you are loading one db table). You may also share code between the Classes, you only need to put a method once in the parent class and have all the children inherit.
Side note, make sure you are following ruby naming practices, capitalize the classes
Class Worker < User
EDIT (suggested approach)
I would not have these roles inherit from the User, you can still use STI but create another model
Class User < ActiveRecord::Base
has_many :profiles
Class Profile < ActiveRecord::Base
belongs_to :user
Class Employer < Profile
Class Worker < Profile
Class Entrepreneur < Profile

You might want to watch this railscast -- this is what I just recently implemented. It uses a bitmask column in the database. I also paired it with cancan to handle my permissions.

Related

Polymorphic model who can be both types

I have a model Advertiser who can be a brand or a distributor but also the both. In my model I have two boolean attributes to find out which roles can have my Advertiser.
The point is that an Advertiser - distributor have some has_many relations that an Advertiser - brand doesn't have.
Usually I use a polymorphic model to differenciate the roles but in this case my Advertiser could be both roles at the same time.
Is there any way the have a different behavior for my model based on an instance attribute value ?
Something like this maybe :
class Advertiser < ApplicationRecord
if instance.distributor == true
has_many :managers
end
end
Continuing from #TomLord, why don't you flip the inheritance chain, i.e.
class Advertiser < ActiveRecord::Base
end
class AdvertiserBoth < Advertiser
# define any association or behavior that you think both of brand and distributor role should have
end
class Brand < AdvertiserBoth
# define brand-specific relations and behavior
end
class Distributor < AdvertiserBoth
# define distributor-specific details
end
In this approach, you don't have to define roles as polymorphic or even no need to define any boolean attributes which merely define the role type. You can also avoid defining any shared modules for the purpose you discussed in the question comment.
You can also eliminate the AdvertiserBoth class and put all the logics inside the Advertiser class itself if you believe the case could be solved in this way.
The main advantage with this approach is that you can manage all these models in a single database table, which is why its called Single Table Inheritance (STI).

Rails STI design - user can be of 2 types

I need some advice on my user model. I came across the STI design and implemented it using devise. This is the basic setup:
class Message < ActiveRecord
has_one :sender
has_one :recipient
# Devise user
class User < ActiveRecord
class Sender < User
belongs_to :message
class Recipient < User
belongs_to :message
My conundrum is that the same user can be both sender and recipient in different scenarios. I originally set up this domain model such that a message record had a sender_id and recipient_id both of which were simply user_ids without any Railsy relationships defined or devise extras.
My previous solution seemed more flexible but the STI design seems more elegant and if possible I'd like to make it work. As I understand it the convention is that the type field discerns which user is returned. Is there a common solution for this using STI?
Broadly speaking, every time I've ended up implementing multiple types of user model, I've ended up regretting it. As you've already noticed, very quickly you end up with people who want to be both types of user, and suddenly you've got to manage different accounts, repeat logins, duplicate emails, etc.
I recommend instead setting up a single type of user that has_and_belongs_to_many roles. For simple cases, you can simply create your own role models and logic (which is what I've usually done), but it looks like this gem is pretty well supported as well: https://github.com/RolifyCommunity/rolify

Creating subclasses using Single table Inheritance (STI)

I have the class User, and subclasses Admin and Student.
Student should have additional dedicated columns. Please let me know how I can do this using STI in Ruby on Rails.
Thanks!
Also, how do I populate the users table?
In Rails, typically you'd have type column on the User class. Now in your subclasses you'd inherit from the User class as such:
class User
end
class Admin < User
end
class Student < User
end
This way you can take advantage of the Rails STI and still be able to flexibly create methods for your subclasses.
Find more information here
However to keep it a bit organized, you could put the subclasses in a folder under your models, as such
#models/users/admin.rb
module Users
class Admin < User
end
end
#model/users/student.rb
module Users
class Student < User
end
end
Now to use your classes, you'd do Users::Student.find(id)
UPDATE
In response to the comment, I think for the columns that would be specific to the student, you'd be better served by an association, say Student.has_one :grade or something of sorts, this way you'd have successfully abstracted your user object to deal with the common User methods. But to create a row for Student and Admin
You could do Users::Student.create(params) or Users::Admin.create(params) and Rails knows how to deal with the STI

how to enforce inclusion rules in ActiveRecord associations

I'm new to rails and I have a question on how best to enforce custom rules on my model associations.
For example, suppose I have:
class Person < ActiveRecord::Base
belongs_to :organization
end
class Organization < ActiveRecord::Base
has_many :people
end
and now suppose that I only want to allow the Organization.people << Person.new(...) command to succeed if the new Person object is compatible with the other people that were previously added to the Organization. This would entail running a validation check across all the existing elements of Organization.people and deciding whether the new Person could be added or not.
It seems to me that I can do this by overriding all the Organization.people assignment operators (such as << and =) and putting my validation logic in the override routine.
Is this best way to accomplish this?
Thanks!
I think you could put a validation in the Person class. It would run a test against the other people in self.organiation.people. I don't know if I would override the << on the has many relationship only because if you decide to create a person like Person.new(:organization => some_org) your << override would not get used. If the validation lives on the Person class, it would get exercises no matter how you create the person.

rails polymorphic association naming suggestion

I have a container class I need to name, today it is called "EnrollmentApplication". It is a container of one type of application.
I've decided to push some of the business logic specific to different types of applications into a delegate associated with the application via a polymorphic relationship, to allow support for different types of applications. I'm struggling with a good name for the class and the relationship:
today:
EnrollmentApplication and applicationable
It's no longer just an application, but a collection of tasks and steps , kind of a workflow.
Portfolio and portfoliable....
ApplicationContainer and containable....
thanks
Joel
If the name of your class is called Enrollment then the following could work:
class Enrollment < ActiveRecord::Base
has_many :enrollment_applications
has_many :enrollments, :through => :enrollment_applications
end
Then you need your join table:
class EnrollmentApplication < Active Record::Base
belongs_to :enrollment
end
I really don't know if this will work because rails might complain about only having one id. I'm gonna try this when I get home to see if you can do this because I am actually setting up and app where user has many users. Anyway, keep us posted on your progress.

Resources