Reputation: 105
Suppose I have a model called Staff. The staff object is attached to a user and has a "title". Now, this title can either be a manager, doctor, engineer, nurse. Which is a better practice?
Declare a constant and have a title attribute on the Staff model itself
ROLES = ["manager", "doctor", "engineer", "nurse"]
or create a model called Role
and set it as a relationship to the Staff
model? This model will ONLY have one attribute called title
.
I'm pretty much aware that both will work, but then I just want to know you guys' perspectives/ideas regarding this one moving forward.
Thanks!
Upvotes: 3
Views: 158
Reputation: 101811
This completely depends on the use case. If you can foresee that users in you application will only ever have one role - then use an enum as suggested by Sergii. It is going to be the simplest and most performant option.
It also depends on if you actually need a role system for authorization or if you are simply checking that users can not title themselves whatever they please.
If you need a flexible system where users can have multiple roles than you will want to use a database table.
Another question is how roles are created, is it good enough that it is a developer concern? Could there be a need to be able to create role definitions from a GUI?
This example shows a common setup with a table for role definitions and a join table containing the roles assigned to users.
class User < ActiveRecord::Base
has_many :user_roles
has_many :roles, through: :user_roles
def has_role?(name, resource = nil)
scope = user_roles.joins(:role).where(
role: { name: name }
)
scope = scope.where(resource: resource) if resource
scope.any?
end
end
# join table with roles assigned to users
class UserRole < ActiveRecord::Base
belongs_to :user
belongs_to :role
belongs_to :resource, polymorphic: :true
end
# Role definitions
class Role < ActiveRecord::Base
has_many :user_roles
has_many :users, through: :roles
end
Upvotes: 3
Reputation: 126
Always start small, get your tests green, then refactor when need arises.
If you only want to define a role for people, that's just as simple as you thought:
title
to the Staff
model tableTITLES
in the Staff
modelStaff
model, as suggested by @petr-gazarovShould the need arise for a new model, be sure, you will have no choice but refactoring into that. As long as you have a choice, the answer is always the simplest.
Soon though, you may start asking yourself what you want to do with this role differentiation -- spoiler, you probably want to learn more about authorization (e.g. "what can do", vs. authentication "who is").
So I'll kill two birds with one stone and link you a good guide on role-based authorization, from a very easy and functional gem for defining role-based authorization: cancancan.
Upvotes: 1
Reputation: 3811
Sounds like you just want title
attribute on Staff
.
If you want to ensure that title is one of 'permitted' values, you can validate inclusion on model level:
validates :title, inclusion: { in: %w(manager doctor engineer nurse) }
Upvotes: 2
Reputation: 845
If your role system is so simple - there is no need to create another model with one field.
To implement that feature I recommend you to look at rails ActiveRecord#enum
: http://edgeapi.rubyonrails.org/classes/ActiveRecord/Enum.html
Upvotes: 9