简体   繁体   English

在Rails应用程序中存储全局应用程序设置的最佳方法是什么?

[英]What's the best way to store global application settings in a Rails application?

I want to handle two kinds of global configuration settings: 我想处理两种全局配置设置:

  • Settings which can be altered by the user, like if notification mails for certain events are sent or not. 可以由用户更改的设置,例如是否发送特定事件的通知邮件。
  • Settings which are tied to a specific product edition, like disabling a feature in a free version, which is only available in the commercial version. 与特定产品版本相关联的设置,例如禁用免费版本中的功能,该功能仅在商业版本中可用。

What's the best way to store these settings? 存储这些设置的最佳方法是什么? Database, configuration file, hardcoded in the source, ...? 数据库,配置文件,在源代码中硬编码,......?

For both cases database. 对于这两种情况的数据 You're going to be using the same structures for multiple people/products so it makes sense. 你将为多个人/产品使用相同的结构,所以它是有道理的。 Also it allows you to change things without restarting the server. 它还允许您在不重新启动服务器的情况下进行更改。

I've handled it this way in the past: For settings specific to the user, I've created a UserSettings model/table, that has a one-to-one to relationship with a user. 我过去以这种方式处理过:对于特定于用户的设置,我创建了一个UserSettings模型/表,它与用户有一对一的关系。 The reasoning for this is that the majority of my operations involving users do no not require these settings to be loaded, so they're only included on user loads from the database when I need them. 这样做的原因是我的大多数涉及用户的操作并不需要加载这些设置,所以它们只在我需要时才包含在数据库的用户加载中。

When I do this, I'll usually group my column names, so that I can write helpers that dynamically create based on the names. 当我这样做时,我通常会对列名进行分组,以便我可以编写基于名称动态创建的帮助程序。 Meaning that I won't have to modify my views to incorporate new settings unless I add one with a different naming scheme. 这意味着我不必修改我的视图以包含新设置,除非我添加一个具有不同命名方案的设置。

For the settings specific to a product, well that depends on how you are doing things. 对于特定于产品的设置,这取决于您的工作方式。 And there are a couple of ways to interpret your question. 并且有几种方法可以解释您的问题。

The way I read it is that you want to decide on a product level. 我读它的方式是你想要决定产品水平。 What settings users can overriding or disabling a user's setting. 用户可以覆盖或禁用用户设置的设置。 And possibly define some product specific settings. 并可能定义一些产品特定的设置。

I would use a one-to-many product to setting relationship. 我会用一对多的产品来设定关系。 The setting table would be something simplistic (product_id, setting_name, setting_default_value, allow_user_change) 设置表将是简单的(product_id,setting_name,setting_default_value,allow_user_change)

This does a number of things. 这做了很多事情。 It lets you have a variable list of settings for different products (Perfect for the case where you're offering many different products instead of varying tiers of access to services). 它允许您拥有不同产品的可变设置列表(适用于您提供许多不同产品而非不同层次的服务访问权限的情况)。 It also lets you define what settings a user can/can't change and give values for that product type. 它还允许您定义用户可以/不可以更改的设置,并为该产品类型提供值。 That can be changed from an administrator view without restarting the application. 可以在不重新启动应用程序的情况下从管理员视图更改。 It's also not tied to user settings, to the point where if a user doesn't have a setting listed in the product_settings there will be no problems. 它也与用户设置无关,如果用户没有在product_settings中列出设置,那么就没有问题。

The downside is you will have multiple common settings in this table. 缺点是您将在此表中有多个常用设置。 I would move settings that every product will have a different value to a field in the product table. 我会将每个产品具有不同值的设置移动到产品表中的字段。

You will also have to write validations to ensure that a user does not change a setting their product says they can't. 您还必须编写验证以确保用户不会更改其产品无法更改的设置。 You will also have to write helper methods to merge settings from the product and user sides. 您还必须编写帮助方法来合并产品和用户方的设置。

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

For stuff that's product edition based, you probably can't really store things in the database, because the flag is going to be based on some piece of authorization code, rather than static data. 对于基于产品版本的东西,你可能无法真正存储数据库中的东西,因为标志将基于某些授权代码,而不是静态数据。

Here's my experience with this kind of stuff: don't override behavior . 这是我对这种东西的体验: 不要覆盖行为

You see, your first thought is going to be something like this: 你看,你的第一个想法是这样的:

Hmm.... There are system-wide settings that may or may not be overridden by users (or products). 嗯....系统范围的设置可能会被用户(或产品)覆盖,也可能不会被覆盖。 Hey! 嘿! I know this! 我知道这个! It's composition! 它的构成!

And technically, you'd be correct. 从技术上讲,你是对的。 So, you'll make a Settings table and put all your settings in there. 因此,您将创建一个“设置”表并将所有设置放在那里。 And then you'll have a user_settings table, where you will override those settings if the user so decides. 然后你将拥有一个user_settings表,如果用户决定,你将覆盖这些设置。 And it'll work fine. 它会工作正常。

Until you add a setting to one table and not the other. 直到您将设置添加到一个表而不是另一个表。

Or you get a bug that Setting X can't be overridden at the user or product level and it takes more than 5 seconds to figure out exactly where that setting is set. 或者你得到一个错误,即设置X无法在用户或产品级别被覆盖,并且需要超过5秒的时间来确定设置的确切位置。

And then you'll realize: 然后你会意识到:

Hey, I'm keeping track of all these settings in at least two different places. 嘿,我在至少两个不同的地方跟踪所有这些设置。 That seems kinda dumb. 这看起来有点愚蠢。

And you'd be right. 你是对的。

So, yes. 所以,是的。 Go ahead and keep the settings in the DB, but save them distinctly for each user or product. 继续并保留数据库中的设置,但为每个用户或产品明确保存它们。 Use smart default values on row creation and it'll keep things nice and simple. 在行创建时使用智能默认值,它将保持简洁。

For the first kind of settings, I would keep them in the User model (Users table). 对于第一种设置,我会将它们保存在用户模型(用户表)中。

The second kind of settings, would go to the database again. 第二种设置将再次进入数据库。 For example if a user had a free account, that would be somehow saved in the database. 例如,如果用户拥有免费帐户,则会以某种方式保存在数据库中。 I would have some helpers in Application, for example "free?" 我会在Application中有一些助手,例如“free?” or "commercial?". 还是“商业?”。 These helpers could find out if they are true or false, asking the currently connected User/Account model. 这些帮助者可以查看它们是真还是假,询问当前连接的用户/帐户模型。 You could then use these helpers across different parts in your application to decide if you show or hide certain functionality. 然后,您可以在应用程序的不同部分使用这些帮助程序来决定是否显示或隐藏某些功能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 编写复杂的Rails应用程序的最佳方法是什么? - What's the best way to write a complex Rails application? 在Rails应用程序中实现ACL的最佳方法是什么? - What's the best way to implement ACLs to a Rails application? 在与Rails应用程序相同的域上运行Wordpress的最佳方法是什么? - What's the best way to run Wordpress on the same domain as a Rails application? 将JRuby on Rails应用程序部署到Tomcat的最佳方法是什么? - What's the best way to deploy a JRuby on Rails application to Tomcat? 有什么好方法可以将全局站点设置存储在可由管理员编辑的Rails中? - What is a good way to store global site settings in Rails that are editable by an admin? 打包Ruby on Rails应用程序的最佳方法是什么? - What is the best way to package a Ruby on Rails Application? 为 Rails 应用程序轮换日志的最佳方法是什么 - What is the best way to rotate logs for rails application 在Rails应用程序中开始精简的最佳方法是什么? - What is the best way to start thin in a rails application? 在Ruby on Rails 3应用程序中实现设置的首选方法是什么? - What is the preferred way to implement settings in a Ruby on Rails 3 application? 从 Rails 3 应用程序中调度和执行 jruby 脚本的最佳方法是什么 - What's the best way to schedule and execute jruby scripts from within a Rails Three Application
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM