我想为我的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
一些改进?
答案 0 :(得分:1)
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