0

I'm experimenting in building a roles-based data structure in Rails using Concerns with role-specific methods. I've explored other solutions, like STI, polymorphic associations, but opted to try this method.

All attributes depicted are stored in one table, users.

module Client
   extend ActiveSupport::Concern

   def self.extended(target)
     target.class_eval do
         validates :emergency_contact, presence: true
     end
   end
end

module Doctor
   def self.extended(target)
     target.class_eval do
         validates :credentials, presence: true  
     end
   end
end

class User < ApplicationRecord
   validates :role, allow_blank: true, inclusion: { in: roles }
   validates :first_name, presence: true
   validates :last_name, presence: true
   validates :email, presence: true

   after_initialize { extend_role }

   # Extend self with role-appropriate Concern
   def extend_role
      extend role.camelize.constantize if role
   end

   def role=(role)
      super(role)
      extend_role
   end
end

My challenge is during the changing of a role, specifically, what can be done (if anything) to negate the previous role's Concern having extended the User?

Each user will have 1 role, so having the Client and Doctor concerns both mixed into the User would not be appropriate (at this time, at least).

In an ideal solution, the User instance would morph with the role change and retain all changed attributes.

So, calling this:

user.update_attributes({ first_name: 'Wily', last_name: 'McDoc', role: 'doctor' })

...would first handle the role change and then update the attributes.

scoots
  • 715
  • 4
  • 16
  • You might want to consider using multi-table inheritance instead. https://github.com/hzamani/acts_as_relation – max Feb 18 '16 at 15:09
  • While this could work you're really just doing single table inheritance via mixins instead - you still have all the cons of STI. – max Feb 18 '16 at 15:12
  • @max Part of the idea here is to make it readily expandable for multiple roles, which STI is not. I'm not sure if active_record-acts_as would accommodate, I'll look into it, but a simple home-grown solution seems ideal. – scoots Feb 18 '16 at 15:21

1 Answers1

0

guess could, in part, remove all methods:

Module.instance_methods.each{|m|
  undef_method(m)
}

also, How can I reverse ruby's include function, in case that may be of interest

Community
  • 1
  • 1
Drew
  • 2,583
  • 5
  • 36
  • 54