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

I'm building a Rails application with multiple roles. I can't use inheritance against the user model because each role has very different properties and behavior (ie - different page access and abilities once logged in). So I've decided to build separate models for each role (ie - customer, service provider, customer representative, etc).
How would the associations for this work? I came up with the following but the Role class just looks bad to me. It wouldn't be so bad if the User could have multiple roles but since they only have one I'd have to write a custom validation in Role ensuring that only one role was selected. What do you guys think?
class User < ActiveRecord::Base
has_one :role
end
class Role < ActiveRecord::Base
has_one :customer
has_one :service_provider
has_one :customer_representative
end
class Customer < ActiveRecord::Base
end
class ServiceProvider < ActiveRecord::Base
end
class CustomerRepresentative < ActiveRecord::Base
end

I think the problem here is with your "Role" model. The role isn't actually a physical thing, but an interface that other objects should adhere to. Therefore, its a polymorphic relationship.
class User < ActiveRecord::Base
belongs_to :role, polymorphic: true
end
class Customer < ActiveRecord::Base
has_one :user, as: :role
end
class ServiceProvider < ActiveRecord::Base
has_one :user, as: :role
end
class CustomerRepresentative < ActiveRecord::Base
has_one :user, as: role
end
Then you need to add role_id and role_type to your user table.
This should get your what you want I believe.
Joe

Related

Rails possible problem with has_many polymorphic association

In my application, I have the following models:
User
Psychologist has_many classrooms
Teacher has_many classrooms
Parent has_many children
Director belongs_to school
Coordinator belongs_to school
My user model looks like the following:
class User < ActiveRecord
has_many :roles
def has_role? role_name
self.roles.where(role_type: role_name).any?
end
end
The Role model is polymorphic:
class Role < ApplicationRecord
belongs_to :user
belongs_to :roleable, polymorphic: true
end
And the other models are rollable.
My question is the following, it seems that this is not correct, because some models like: Director, Psychologists, Teachers, Coordinator and Parent. They only have relationships and their database tables do not have any other column except created_at, updated_at.
Is it okay to only create these models with relationships and have their tables without data?
Maybe you intend to use single table inheritance and not polymorphic relationships. If a Psychologist is a User, it should be the case.
Then you need to add a type column of type VARCHAR to the users table, and set up your models like:
class User < ApplicationRecord
has_many :roles
def has_role? role_name
self.roles.where(role_type: role_name).any?
end
end
class Psychologist < User
# no need to set up roles
end
class Teacher < User
# no need to set up roles
end
class Role < ApplicationRecord
belongs_to :user
# no polymorphic
end
The type column will be populated with the name of the actual class, like "Teacher" etc.
As an instance of Teacher is also an instance of User, it will have teacher.has_role?('foo') and teacher.roles, and you will be able to create a role like Role.create(user: teacher, name: 'bar').

Grouping two records and associating the group through a HABTM in ActiveRecord | Rails

I'm working on a Rails 5.2 project that stores and manages guest lists. I have Event and Guest models, and they are associated with a HABTM relationship. This works well, but there is a requirement to be able to optionally store a grouping of two guests (i.e: couples) and when adding guests to the guest list, the couple can be selected and added together, without the user having to remember which of the individual guests should be added to the guest list together, for example, when selecting guests to be added to a guest list, a user should be able to select "Sam", "Andrew", "Mary & Joseph".
What would be the best way of achieving this in ActiveRecord?
class Event < ApplicationRecord
has_and_belongs_to_many :guests
end
class Guest < ApplicationRecord
has_and_belongs_to_many :events
end
Any help would be much appreciated!
Thanks
You need the following models, untested but you'll get the idea.
class Event < ApplicationRecord
has_many :event_guests
end
class Guest < ApplicationRecord
has_many :event_guests, :as => :assignable
has_many :guest_couples
end
class Couple < ApplicationRecord
has_many :event_guests, :as => :assignable
has_many :guest_couples
end
# table to relate events to either a Guest or a Couple (polymorhpic)
class EventGuest < ApplicationRecord
belongs_to :event
belongs_to :assignable, polymorphic: true
end
# Model to create couples (one-to-many)
class GuestCouple < ApplicationRecord
belongs_to :guest
belongs_to :couple
end

creating an association and scoping

I read "Multitenancy with Rails" by Ryan Bigg and I'm creating a multi-tenant application using Ruby on Rails.
I make two models, Tenant and User.
Tenant has many User, User belongs to Tenant.
To associate these models, I made this file,
active_record_extensions.rb
ActiveRecord::Base.class_eval do
def self.scoped_to_tenant
belongs_to :tenant
association_name = self.to_s.downcase.pluralize
Tenant.has_many association_name.to_sym, class_name: self.to_s
end
end
and add "scoped_to_tenant" to User.rb
class User < ActiveRecord::Base
scoped_to_tenant
end
When I want to get all users of one Tenant(id=1), I can get it by these code.
Tenant.find(1).users
The question is, what is the difference between I write
belongs_to :tenant
to User.rb and use scoped_to_tenant method ?
In both case, Tenant.rb is this.
Tenant.rb < ActiveRecord::Base
has_many :users
end
Thank you for answer.
I may get English wrong, so please tell me if you can't understand something.
A call to scoped_to_tenant method call the method belongs_to for you and add the many association to Tenant.
This is same as doing this :
# app/model/user.rb
class User < ActiveRecord::Base
belongs_to :tenant
end
# app/model/tenant.rb
class Tenant < ActiveRecord::Base
has_many :users
end
The benefit of the scoped_to_tenant is that you don't care about adding has_many relationship to Tenant model.
If you only have one model to associate with Tenant, you don't need this extension.

Multiple associations query - DB Modelling

I am planning a rails apps that allows a User to list one/many Vaults, at either their personal address or any other additional address (location) specified against a vault. Before I go ahead and generate the Models I want to make sure I understand what associations need to be set up between the three Models. Here the code representation that I have typed manually to depict what associations are required.
class User < ActiveRecord::Base
has_many :vaults
end
class Vault < ActiveRecord::Base
belongs_to :user
has_one :address
end
class Address < ActiveRecord::Base
belongs_to :user
end
Your database looks okay, few consideration are below :
class User < ActiveRecord::Base
has_many :vaults
has_many :addresses #(optional)if you want to fetch addresses directly
end
class Vault < ActiveRecord::Base
belongs_to :user
has_one :address
end
class Address < ActiveRecord::Base
belongs_to :user #(optional) if you want to fetch user directly
belongs_to :vault
end
Database requirement:
adresses table must contain user_id(optional) and vault_id.
vaults table must contain user_id.

Ruby on Rails Model / Database Associations

I have a user model, farmer model, doctor model, and education model.
A farmer has a user and many educations.
A doctor has a user and many educations.
How do I setup the database for the education model?
Should it have a farmer_id AND a doctor_id?
But a education cannot belong to a farmer AND and doctor at the same time. It's one or the other.
So my education database entry would either have a farmer_id OR a doctor_id filled in, but not both.
Is there a way to guarantee that only one of the ids could be filled in at a time?
Or is there a better way to associate these models?
Your help would be appreciated!
Oh, and don't worry about the names of the models (farmer, doctor, etc.). It's just an example.
I see two possible solutions for this scenario.
The first one is to make use of polymorphic associations for education. That could look like this:
class Farmer < ActiveRecord::Base
belongs_to :user
has_many :educations, :as => :profession
end
class Doctor < ActiveRecord::Base
belongs_to :user
has_many :educations, :as => :profession
end
class Education < ActiveRecord::Base
belongs_to :profession, :polymorphic => true
end
So instead of education having a doctor_id or a farmer_id it has one profession_id and one profession_type.
The second solution would be to make use of Single Table Inheritance. And in your scenrio, that could be accomplished by letting a Doctor be a User instead of belonging to a User. And of course the same thing for a Farmer. That could look like this:
class User < ActiveRecord::Base
has_many :educations
end
class Farmer < User
end
class Doctor < User
end
class Education < ActiveRecord::Base
belongs_to :user
end
And in this scenario you would add a type column to the User model to store what type of class it is and then only having a user_id in the Education model
I think its appropriate to have the relations this way based on roles.
Class User
has_one :role
has_many :educations
end
Class Role
#What ever roles you have.
#Farmer or Doctor
belongs_to :user
end
class Education
belongs_to :user
end
This way you will store the user_id in the education object, which solves your problem.

Resources