【问题标题】:What's the best way to store global application settings in a Rails application?在 Rails 应用程序中存储全局应用程序设置的最佳方式是什么?
【发布时间】:2010-12-05 18:39:25
【问题描述】:

我要处理两种全局配置设置:

  • 可由用户更改的设置,例如是否发送某些事件的通知邮件。
  • 与特定产品版本相关的设置,例如禁用免费版本中的功能,仅在商业版本中可用。

存储这些设置的最佳方式是什么?数据库,配置文件,硬编码在源代码中,...?

【问题讨论】:

    标签: ruby-on-rails configuration


    【解决方案1】:
    class Flag < ActiveRecord::Base
      # id, user_id, name, value (serialized probably)
    
      belongs_to :user
    
      DEFAULTS = {
        "newsletter" => false
      }
    
      def self.lookup(user, flag)
        # Please involve memcached here
        case flag
        when "ssl_enabled"
          # Check if user has paid for sufficient access to SSL
          return false
        else
          stored_flag = self.find_by_user_id_and_name(user.id, flag)
          if stored_flag
            return stored_flag.value
          else
            return DEFAULTS[flag]
          end
        end
      end
    end
    
    class User < ActiveRecord::Base
      has_many :flags
    
      def flag(name)
        return Flag.lookup(self, name)
      end
    end
    

    对于基于产品版本的内容,您可能无法真正将内容存储在数据库中,因为标志将基于某些授权代码,而不是静态数据。

    【讨论】:

      【解决方案2】:

      对于这两种情况的数据库。您将为多个人/产品使用相同的结构,所以这是有道理的。它还允许您在不重新启动服务器的情况下进行更改。

      我过去是这样处理的: 对于特定于用户的设置,我创建了一个 UserSettings 模型/表,它与用户具有一对一的关系。这样做的原因是我的大多数涉及用户的操作都不需要加载这些设置,因此它们仅在我需要时才包含在数据库中的用户加载中。

      当我这样做时,我通常会将我的列名分组,以便我可以编写基于名称动态创建的帮助程序。这意味着我不必修改我的视图来合并新设置,除非我添加一个具有不同命名方案的视图。

      对于特定于产品的设置,这取决于您的操作方式。有几种方法可以解释您的问题。

      我阅读它的方式是您想要决定产品级别。用户可以覆盖或禁用用户设置的设置。并且可能定义一些产品特定的设置。

      我会使用一对多的产品来设置关系。设置表会很简单(product_id、setting_name、setting_default_value、allow_user_change)

      这可以做很多事情。它使您可以拥有不同产品的可变设置列表(非常适合您提供许多不同产品而不是不同级别的服务访问权限的情况)。它还允许您定义用户可以/不能更改的设置,并为该产品类型提供值。这可以从管理员视图更改,而无需重新启动应用程序。它也与用户设置无关,如果用户没有在 product_settings 中列出的设置,则不会有任何问题。

      缺点是您将在此表中有多个常用设置。我会将每个产品具有不同值的设置移动到产品表中的字段。

      您还必须编写验证以确保用户不会更改他们的产品说他们不能更改的设置。您还必须编写辅助方法来合并产品和用户方面的设置。

      【讨论】:

        【解决方案3】:

        对于第一种设置,我会将它们保留在用户模型(用户表)中。

        第二种设置,会再次进入数据库。例如,如果用户有一个免费帐户,它会以某种方式保存在数据库中。我会在应用程序中有一些助手,例如“免费?”或“商业?”。这些助手可以通过询问当前连接的用户/帐户模型来判断它们是真还是假。然后,您可以在应用程序的不同部分使用这些帮助程序来决定是显示还是隐藏某些功能。

        【讨论】:

        • 你必须去规范化才能做到这一点。可能采用序列化设置字段的形式。不一定是坏事,但非规范化始终是一种权衡。
        【解决方案4】:

        这是我对这类事情的经验:不要覆盖行为

        你看,你的第一个想法是这样的:

        嗯.... 有一些系统范围的设置可能会或可能不会被用户(或产品)覆盖。嘿!我知道这个!是作曲!

        从技术上讲,你是对的。因此,您将创建一个设置表并将所有设置放入其中。然后您将拥有一个 user_settings 表,如果用户决定,您将在其中覆盖这些设置。而且它会正常工作。

        直到您将设置添加到一个表而不是另一个表。

        或者您遇到无法在用户或产品级别覆盖设置 X 的错误,并且需要超过 5 秒才能确定该设置的确切设置位置。

        然后你会意识到:

        嘿,我至少在两个不同的地方跟踪所有这些设置。这似乎有点愚蠢。

        你是对的。

        所以,是的。继续将设置保留在数据库中,但为每个用户或产品分别保存它们。在创建行时使用智能默认值,它会让事情变得简单而美好。

        【讨论】:

        • 您已经对他的想法以及他将如何实现这一点做出了各种假设,但他的实际问题是“存储这些设置的最佳方式是什么?”在这种情况下,您的任何假设都没有任何意义。我不认为这完全符合“稻草人”的资格,但我不知道还能叫它什么。
        猜你喜欢
        • 2010-09-11
        • 2010-09-06
        • 2011-11-26
        • 1970-01-01
        • 2018-11-29
        • 2011-01-27
        • 1970-01-01
        • 2011-02-09
        • 2012-07-26
        相关资源
        最近更新 更多