Rails 3 - 从序列化数据构建表单

时间:2011-08-02 21:01:03

标签: serialization ruby-on-rails-3.1

我一直在做一个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

3 个答案:

答案 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_readpermissions_customer_club_events_writepermission_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方法。