我一直在做一个rails项目,我需要序列化用户角色的权限并存储在数据库中。就这一点而言,我一切都很好。现在我的问题出现了,当我想修改生成的rails形式的序列化数据时。
我本能地行动并尝试了预期的行为。 那就是使用这样的东西:
f.check_box :permissions_customer_club_events_read
但由于序列化数据不存在任何getter或setter,这不起作用(显然:p)。现在我想知道如何处理这个问题,我想到的唯一事情就是从我的序列化哈希中动态生成 getter和setter方法。
示例:
def permissions_customer_club_events_read=(val)
permissions[:customer][:club][:events][:read] = val
end
def permissions_customer_club_events_read
permissions[:customer][:club][:events][:read]
end
任何人都明白我的目标是什么?
这是我的模型:
class User::Affiliation::Role < ActiveRecord::Base
require 'yajl'
class YajlCoder
def dump data
Yajl.dump data
end
def load data
return unless data
Yajl.load data
end
end
serialize :permissions, YajlCoder.new
after_initialize :init
def init
## Sets base permission structure ##
self.permissions ||= YAML.load_file("#{Rails.root}/config/permissions.yml")
end
end
答案 0 :(得分:1)
我建议您查看attr_bucket之类的内容。从表面上看,这可以用来解决一些继承烦恼,但它也会为你解决问题。这就是本质。
看起来您知道所有权限是什么,但您希望将所有权限序列化到同一个数据库字段中。但是在您的实际rails应用程序中,您希望将所有权限视为完全独立的字段。这正是像attr_bucket
这样的解决方案可以让你做到的。让我们举个例子,你会做这样的事情:
class User::Affiliation::Role < ActiveRecord::Base
attr_bucket :permissions => [:permissions_customer_club_events_read, :permissions_customer_club_events_write, :permission_do_crazy_things]
after_initialize :init
def init
## Sets base permission structure ##
self.permissions ||= YAML.load_file("#{Rails.root}/config/permissions.yml")
end
end
现在,您可以使用permissions_customer_club_events_read
,permissions_customer_club_events_write
,permission_do_crazy_things
,就好像它们是单独的数据库字段(包括在表单中使用它们等),但实际保存时您的对象将所有这些字段“拼凑”在一起并序列化到:permissions
字段。
唯一需要注意的是序列化机制,我相信attr_bucket
将使用YAML序列化所有内容,而您使用的是JSON。如果这没关系,那么你就是黄金,否则你可能需要修补attr_bucket
来使用json而不是YAML,这应该是非常简单的。
答案 1 :(得分:0)
对不起,如果我不明白这个问题;)
您可以拥有模型中包含的customdata模块,并使用method_missing:
module CustomData
def self.included(base)
base.instance_eval do
after_save :save_data
end
def method_missing(method, *args, &block)
if method.to_s =~ /^data_/
data[method] ? data[method] : nil
else
super
end
end
def data
@data ||= begin
#get and return your data
end
end
private
def save_data
end
end
使用此方法,您必须使用f.check_box :data_permissions_customer_club_events_read
这不是很完整,但我希望你明白这一点;) attr_bucket似乎也是一个很好的解决方案。
答案 2 :(得分:0)
serialize :permissions, YajlCoder.new
after_initialize :init
def init
self.permissions ||= YAML.load_file("#{Rails.root}/config/permissions.yml")['customer']
build_attributes_from self.permissions, :permissions
end
private
def build_attributes_from store, prefix, path=[]
store.each do |k,v|
if v.class == Hash
build_attributes_from v, prefix, ( path + [k] )
else
create_attr_accessors_from prefix, ( path + [k] )
end
end
end
def create_attr_accessors_from prefix, path=[]
method_name = prefix.to_s + "_" + path.join('_')
class << self
self
end.send :define_method, method_name do
self.permissions.dig(:path => path)
end
class << self
self
end.send :define_method, "#{method_name}=" do |value|
self.permissions.dig(:path => path, :value => value)
end
end
还有一些猴子修补哈希...
class Hash
def dig(args={})
path = args[:path].to_enum || []
value = args[:value] || nil
if value == nil
path.inject(self) do |location, key|
location.respond_to?(:keys) ? location[key] : nil
end
else
path.inject(self) do |location, key|
location[key] = ( location[key].class == Hash ) ? location[key] : value
end
end
end
end
现在为所有序列化字段生成getter和setter方法。