Ruby on Rails - 存储应用程序配置
Posted
技术标签:
【中文标题】Ruby on Rails - 存储应用程序配置【英文标题】:Ruby on Rails - Storing application configuration 【发布时间】:2011-01-08 20:03:24 【问题描述】:我有一个相对简单的 Rails 应用程序,我想存储管理员用户可以在应用程序运行时更改的各种配置设置,例如,允许帖子上的 cmets 或更改日期的显示格式。
我知道我可以在 environment.rb 文件中存储常量等,但是这些似乎只有在服务器重新启动时才会加载。
我可以在其他地方定义此信息还是将其保存在数据库中更好?
任何建议表示赞赏。
谢谢。
【问题讨论】:
【参考方案1】:您可以使用 rails-settings-cached gem,它是 rails-settings gem 的一个分支(由 Yi-Ru Lin 在另一个答案中链接)。
设置完成后,您将能够执行以下操作:
Setting.foo = 123
Setting.foo # returns 123
您还可以管理模型的设置,例如:
user.settings.color = :red
user.settings.color # returns :red
【讨论】:
【参考方案2】:您可以使用数据库。创建一个单独的表“设置”来存储您需要的键/值参数。此解决方案的缺点是性能下降(每次需要设置时都查询数据库)。要解决此问题,您可以通过“cache_money”之类的缓存读取/写入,或者使用“Rails.cache”创建自己的缓存
【讨论】:
刚刚发布了一个答案,该方法将设置保存在数据库中,根据需要更新它们,并且在不使用缓存数据库内容的情况下不会遇到性能问题。【参考方案3】:试着看看它可能是你需要的。
http://github.com/ledermann/rails-settings
【讨论】:
squeegy repo 已经过时了 4 年,无法与现代 rails 一起使用。 ledermann gem 要求您绑定到另一个活动记录对象(使其无法用于全局应用程序设置。)如果您想要全局应用程序设置,github.com/huacnlee/rails-settings-cached 是最好的【参考方案4】:最好的方法是使用数据库表。每行应包含一个关键字和一个值。简单。
【讨论】:
好的,但是您将如何管理不同的数据类型?例如,有些设置是布尔值,有些是字符串,有些是整数等 你不能只使用一行并将每个设置添加为一列吗?检索设置就像 SELECT enable_setting FROM server_settings LIMIT 1;【参考方案5】:我自己使用app_config gem 有一段时间了,但它在rails 2.3.9 上失败了(也可能在rails 3.x 上),所以我发现this blog 提到了rails-settings 和configuration, rails-settings 将值存储在 DB 中,但配置具有内置的命名空间。我还没有尝试过,但我想我会切换到 rails-settings。
我现在注意到the branch of rails-settings that Yi-Ru Lin mentions 似乎比其他rails-settings 更有特色
贾尔
【讨论】:
【参考方案6】:对于rails 4,如果你使用的是postgresql,你可以使用HStore,这就像一个可序列化的属性,但是你用它来做SQL查询。
对于 rails 3,您可以使用 activerecord-postgres-hstore gem。
【讨论】:
【参考方案7】:我试过https://github.com/huacnlee/rails-settings-cached,但它不像描述的那样工作。显然作者忘记在 gem 使用说明中提到一些额外的调整。我未能编写用于设置操作的控制器。
相反,我成功地使用了https://github.com/paulca/configurable_engine - 尽管有一些小问题,但这个 gem 远比 rails-settings-cached
合理。
configurable_engine
gem 有一个缺点:它的硬编码路线晦涩难懂且不方便。 gem的作者promised to correct it,但表示目前没空。
因此,只需创建自己的路线即可轻松解决此问题。这是我的代码(添加以使这个 gem 真正起作用):
routes.rb
namespace :admin do
resources :configurables, only: [:index, :show, :edit, :update, :destroy]
end
admin/configurables_controller.rb
class Admin::ConfigurablesController < Admin::ApplicationController
# include the engine controller actions
include ConfigurableEngine::ConfigurablesController
before_action :set_configurable, only: [:show, :edit, :update, :destroy]
def index
@configurables = (Configurable.all.size > 0 ? Configurable.all : []) +
(Configurable.defaults.keys - Configurable.all.collect |c| c.name )
end
def show
end
def edit
new = params[:new]
end
def new
respond_to do |format|
name = params[:name]
if name
@configurable = Configurable.create!(name: name, value: nil)
if @configurable
format.html redirect_to edit_admin_configurable_path(@configurable, new: true), notice: 'The setting was successfully created.'
else
format.html redirect_to admin_configurables_url, notice: 'Failed to create the setting.'
end
else
format.html redirect_to admin_configurables_url, notice: 'The name of the new setting was not specified.'
end
end
end
def update
respond_to do |format|
if @configurable.update(configurable_params)
format.html redirect_to [:admin, @configurable], notice: 'The setting was successfully updated.'
format.json render :show, status: :ok, location: @configurable
else
format.html render :edit
format.json render json: @configurable.errors, status: :unprocessable_entity
end
end
end
def destroy
@configurable.destroy
respond_to do |format|
format.html redirect_to admin_configurables_url, notice: 'The setting was successfully destroyed.'
format.json head :no_content
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_configurable
@configurable = Configurable.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def configurable_params
params.require(:configurable).permit(:name, :value)
end
end
index.html.erb
<h1 class="page-header">Settings</h1>
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>Name</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% @configurables.each do |configurable| %>
<tr>
<% if configurable.try(:name) %>
<td><%= Configurable.defaults[configurable.name][:name]%></td>
<td></td>
<td><%= link_to 'Show', [:admin, configurable] %></td>
<td><%= link_to 'Edit', edit_admin_configurable_path(configurable) %></td>
<td><%= link_to 'Destroy', [:admin, configurable], method: :delete, data: confirm: 'Are you sure?' %></td>
<% else %>
<td><%= Configurable.defaults[configurable][:name] %></td>
<td><%= link_to 'Create', new_admin_configurable_path(name: configurable) %></td>
<td colspan="3"></td>
<% end %>
</tr>
<% end %>
</tbody>
</table>
</div>
edit.html.erb
<h1>Editing <%= @new ? "new " : "" %>setting</h1>
<%= render 'form', configurable: @configurable %>
<%= link_to 'Show', [:admin, @configurable] %> |
<%= link_to 'Back', admin_configurables_path %>
show.html.erb
<p>
<strong>Name:</strong>
<%= Configurable.defaults[@configurable.name][:name] %>
</p>
<p>
<strong>Value:</strong>
<%= @configurable.value %>
</p>
<%= link_to 'Edit', edit_admin_configurable_path(@configurable) %> |
<%= link_to 'Back', admin_configurables_path %>
_form.html.erb
<%= form_for([:admin, configurable]) do |f| %>
<div class="field">
<%= f.label "Name" %>
<%= Configurable.defaults[@configurable.name][:name] %>
</div>
<div class="field">
<%= f.label "Value" %>
<%= f.text_area :value %>
</div>
<div class="actions">
<%= f.submit "Submit" %>
</div>
<% end %>
由于硬编码的路由,我的控制器并不完全符合 REST,但它非常接近。我的 new
操作实际上创建了一个(数据库存储的)设置(仅用于覆盖其 yml 文件值)。
因此,添加到 gem 描述代码中的这段代码可以让您实际利用运行时可更改的 RoR 设置。
gem 要求您提前在 yml 文件中设置一些默认值,您可以稍后在运行时覆盖这些默认值。但是你不能在运行时创建一个新设置(not-yml-file-existent)——只能修改一个存在的(在 yml 文件中)——这很合乎逻辑。
或者您可以(在运行时)恢复任何设置的默认值(通过删除其数据库存储的覆盖值)。
已检查此代码可与 Rails 5 一起使用。
【讨论】:
以上是关于Ruby on Rails - 存储应用程序配置的主要内容,如果未能解决你的问题,请参考以下文章
如何配置 Devise for Ruby on Rails 以将电子邮件和密码存储在用户模型之外的其他位置?
从 Ruby on Rails 调用 PL/pgSQL 存储过程