Class: SlowYourRoles::Serialize
- Inherits:
-
Object
- Object
- SlowYourRoles::Serialize
- Defined in:
- lib/methods/serialize.rb
Overview
Serialize support
Instance Method Summary collapse
-
#initialize(base, column_name, _options) ⇒ Serialize
constructor
A new instance of Serialize.
Constructor Details
#initialize(base, column_name, _options) ⇒ Serialize
Returns a new instance of Serialize.
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/methods/serialize.rb', line 6 def initialize(base, column_name, ) base.serialize column_name.to_sym, Array base.before_validation(:make_default_roles, on: :create) base.send :define_method, :has_role? do |role| self[column_name.to_sym].include?(role) end base.send :define_method, :add_role do |*roles| clear_roles if self[column_name.to_sym].blank? roles.each do |role| return false if !roles_marker.empty? && role.include?(roles_marker) end roles.each do |role| next if has_role?(role) self[column_name.to_sym] << role end self[column_name.to_sym] end base.send :define_method, :add_role! do |role| return false unless add_role(role) save! end base.send :define_method, :remove_role do |role| self[column_name.to_sym].delete(role) end base.send :define_method, :remove_role! do |role| remove_role(role) save! end base.send :define_method, :clear_roles do self[column_name.to_sym] = [] end base.send :define_method, :make_default_roles do clear_roles if self[column_name.to_sym].blank? end base.send :private, :make_default_roles # Scopes: # --------- # For security, wrapping markers must be included in the LIKE search, # otherwise a user with role 'administrator' would erroneously be included # in `User.with_scope('admin')`. # # Rails uses YAML for serialization, so the markers are newlines. # Unfortunately, sqlite can't match newlines reliably, and it doesn't # natively support REGEXP. Therefore, hooks are currently being used to # wrap roles in '!' markers when talking to the database. This is hacky, # but unavoidable. The implication is that, for security, it must be # actively enforced that role names cannot include the '!' character. # # An alternative would be to use JSON instead of YAML to serialize the # data, but I've wrestled countless SerializationTypeMismatch errors # trying to accomplish this, in vain. The real problem, of course, is even # trying to query serialized data. I'm unsure how well this would work in # different ruby versions or implementations, which may handle object # dumping differently. Bitmasking seems to be a more reliable strategy. base.class_eval do alias_method :add_roles, :add_role alias_method :add_roles!, :add_role cattr_accessor :roles_marker cattr_accessor :column self.roles_marker = '!' self.column = "#{table_name}.#{column_name}" scope :with_role, (proc { |r| where("#{column} LIKE '%#{roles_marker}#{r}#{roles_marker}%'") }) scope :without_role, (proc { |r| where("#{column} NOT LIKE '%#{roles_marker}#{r}#{roles_marker}%' OR #{column} IS NULL") }) define_method :add_role_markers do self[column_name.to_sym].map! { |r| [roles_marker, r, roles_marker].join } end define_method :strip_role_markers do self[column_name.to_sym].map! { |r| r.gsub(roles_marker, '') } end private :add_role_markers, :strip_role_markers before_save :add_role_markers after_save :strip_role_markers after_rollback :strip_role_markers after_find :strip_role_markers end end |