rails模型的单个字段中的简单权限

时间:2013-12-10 11:08:15

标签: ruby-on-rails ruby

我想为我的rails模型添加任何类型的权限,只包括一个模块到模型并在一个数据库字段中定义元数据。我怎么能这样做?

例如:

Folder < AR::B
  @permissions_list = [:is_private, :public_on_negotioation]
  @permissions_field = :perms
  include Permissions
end

module Permissions
  "...?"
end

我想为@permissions_list变量中的所有项目设置方法“is_private?”,“is_private”,“is_private =”。

所以我可以这样使用模型:

f = Folder.new
f.is_private = true
f.public_on_negotioation = false
f.save
f.reload
f.is_private?
=> true
f.public_on_negotioation?
=> false

所以我写了下一个模块:

module Permissions
  def self.included(mod)
    permissions_list = mod.instance_variable_get(:@permissions_list)
    permissions_list.each_with_index do |permission, index|
      define_method permission.to_sym do
        perms_bits[index] == '1'
      end
    alias_method (permission.to_s << "?").to_sym, permission.to_sym
    end
  end

def perms_bits
  send(self.class.instance_variable_get(:@permissions_field)).to_i.to_s(2).reverse
end

  def set_permission(name, weight, options)
    permissions_field = self.class.instance_variable_get(:@permissions_field)
    if options[name]
      self.send("#{permissions_field}=", self.send(permissions_field).to_i + weight.to_i)      unless send(name)
    elsif options.has_key?("#{name}_off")
      self.send("#{permissions_field}=", self.send(permissions_field).to_i - weight.to_i)      if send(name)
    end
  end

  def update_perms(options)
    permissions_list = self.class.instance_variable_get(:@permissions_list)
    permissions_list.each_with_index do |permission, index|
      set_permission(permission.to_sym, 2**index, options)
    end
    save
  end
end

一些改进?

2 个答案:

答案 0 :(得分:1)

看看ActiveRecord::serialize

Folder < AR::B
  # Must be costant, otherwise Rails will raise an
  # ActiveRecord::SerializationTypeMismatch
  PERMISSIONS_STRUCT = Struct.new(:is_private, :public_on_negotiation)

  serialize :permissions, PERMISSIONS_STRUCT

  def is_private?
    permissions.is_private
  end

  def is_private=(is_private)
    permissions.is_private = is_private
  end

  # The same for public_on_negotiation
end

f = Folder.new
f.is_private = true
f.save
f.reload
f.is_private?
=> true

如果您需要动态定义访问者方法:

Folder < AR::B
  [:is_private, :public_on_negotiation].each do |action|
    define_method("#{action}?") do
      permissions.send action
    end
  end
  # And so on for "#{action}=", ...
end

请记住:重构取决于你!: - )

答案 1 :(得分:1)

延长mdesantis的答案。你可以将权限代码包装起来以便重用的方式可能是这样的(未经测试):

class Folder < ActiveRecord::Base
  include Permissions
end

PERMISSIONS_STRUCT = Struct.new(:is_private, :public_on_negotiation)

module Permissions
  def self.included(klass)
    klass.class_eval do
      serialize :permissions, PERMISSIONS_STRUCT
    end
    klass.include(InstanceMethods)
  end

  module InstanceMethods
    def is_private?
      permissions.is_private
    end

    def is_private=(is_private)
      permissions.is_private = is_private
    end
  end
end