【问题标题】:Ruby Alternative to use of class variables in ActiveSupport::ConcernRuby 替代在 ActiveSupport::Concern 中使用类变量
【发布时间】:2016-08-05 13:23:11
【问题描述】:

我有一个应用程序需要对数据库中的某些字段使用加密。这目前是使用一个关注点来实现的,该关注点处理包含类上的加密和管理字段的详细信息。系统能够以编程方式确定哪些类包含此问题很重要,但更具体地说,需要以编程方式确定哪些字段被加密的好方法。

今天,这是使用这样的类变量实现、工作的:

module EncryptedFields

    extend ActiveSupport::Concern

    included do
        @@encrypted_attributes ||= {}
        @@encrypted_attributes[self.to_s] ||= []

        def self.encrypted attribute, options={}

            @@encrypted_attributes[self.to_s] << attribute

            ### Other stuff
        end
    end
end

包含在一个类中,如下所示:

class SomeEcryptedModel

   include EncryptedFields

   encrypted :field_name, options
   encrypted :other_field_name, options

   #etc
end

类变量@@encrypted_attributes 将正确捕获键值对的散列,其中包含类名作为键,加密属性数组作为值。我考虑过使用加密模型的注册系统来使用和“注册”它们自己及其属性,但是与此相关的开销要多得多,在我的时间线上,我想从更简单的东西开始,如果它不太不安全的话.

这实际上在我当前的应用程序中运行良好,但我没有很多关于关注点或类变量的经验,所以我担心我是否对它的行为方式做出了严重的误判。这里的陷阱在哪里?自从我开始使用 ruby​​(不久前)以来,我一直在编程,通常要避免类变量。

我已经被这个咬过一次,因为最初我认为类变量@@encrypted_attributes 将是包含类上的类变量;这显然不是这样。每个包含它的新模型都会覆盖它,所以我得出的结论是这个类变量显然是关注本身。至少,这是我似乎正在目睹的行为。这最终证明是一种更理想的行为,因为现在我可以获得加密模型的完整列表。这有一个明显的限制,它只能返回已加载模型的加密模型和属性列表。

所以,我的问题:

这是类变量的正确用例,还是有替代(更好的?)方法来捕获相同的信息?如果这是一个可接受的类变量用例,我应该添加哪些陷阱和/或保护措施以确保代码按预期工作?

也许我只是想太聪明,我应该硬编码我的列表?感谢您的帮助!

【问题讨论】:

    标签: ruby class-variables activesupport-concern


    【解决方案1】:

    您可以选择这种方式来关注方法:

    module EncryptedFields
      @encrypted_attributes ||= {}
    
      def self.included(klass)
        @encrypted_attributes[klass.name] ||= []
        klass.extend(ClassMethods)
      end
    
      def self.add(class_name, attribute)
        @encrypted_attributes[class_name] << attribute
      end
    
      module ClassMethods
        def encrypted(attribute, options={})
          EncryptedFields.add(name, attribute)
          # Other stuff
        end
      end
    end
    
    class Stuff
      include EncryptedFields
    
      encrypted :ololo
      encrypted :new_name
    end
    
    EncryptedFields.instance_variable_get(:@encrypted_attributes)
    => {"Stuff"=>[:ololo, :new_name]}
    

    这里不需要类变量。模块实例变量就足够了。您没有任何继承,也无法实际创建模块的实例,因此您将始终只有一个位置来定义 @encripted_attributes 变量,它将是您的 EncriptedFields 模块。

    关于类变量和类实例变量区别的好文章: http://www.railstips.org/blog/archives/2006/11/18/class-and-instance-variables-in-ruby/

    【讨论】:

    • 谢谢。这是一个教育性的答案。我为这个问题简化了我的代码,所以这可能无法完全正常工作,但它让我想到了一个新的方向。
    猜你喜欢
    • 2019-07-20
    • 2014-04-28
    • 2013-05-26
    • 2013-02-01
    • 1970-01-01
    • 2012-09-14
    • 2015-12-29
    • 1970-01-01
    • 2011-10-14
    相关资源
    最近更新 更多