2010-01-24 22 views
17

我有一个相对简单的Rails应用程序,我想存储管理员用户可以在应用程序运行时更改的各种配置设置,例如允许对帖子发表评论或更改显示格式日期。Ruby on Rails - 存储应用程序配置

我知道我可以将常量等存储在environment.rb文件中,但是这些似乎只在服务器重新启动时加载。

有没有其他的地方我可以定义这些信息,还是将它保存在数据库中会更好?

任何意见赞赏。

谢谢。

回答

9

您可以使用数据库。创建一个单独的表“设置”,存储您需要的键/值参数。该解决方案的缺点是性能下降(每次需要设置时都要查询数据库)。要解决这个问题,你可以通过缓存像“cache_money”一样读/写,或者使用“Rails.cache”创建你自己的文件。

+0

刚刚发布了一个答案,它将设置保留在数据库中,根据需要进行更新,并且不会在不诉诸缓存数据库内容的情况下出现性能问题。 – silverdr 2016-12-15 20:31:25

1

最好的方法是使用数据库表。每行应包含一个关键字和一个值。 Simples。

+0

好的,但您将如何管理不同的数据类型? 例如,一些设置将是布尔值,其他字符串,其他字符串等 – Dan 2010-01-24 19:14:25

+3

存储JSON字符串。 – Luke 2010-02-01 10:26:15

+0

你不能只使用一行并将每个设置添加为一列吗?然后,检索设置将如SELECT enable_setting FROM server_settings LIMIT 1; – Edward 2017-11-30 18:17:08

4

试着看看它可能是你需要的。

http://github.com/ledermann/rails-settings

+4

挤压回购是过时的4年,不可能用于现代导轨。 ledermann gem要求你绑定到另一个活动记录对象(使其不可用于全局应用程序设置)。如果你想要全局应用程序设置,https://github.com/huacnlee/rails-settings-cached是最好的 – portforwardpodcast 2013-09-11 23:42:37

15

您可以使用rails-settings-cached宝石是轨道的设置宝石的叉(由易儒林联在另一个答案)。

设置完成后,你就可以做的事情,如:

Setting.foo = 123 
Setting.foo # returns 123 

您也可以管理模型的设置,例如:

user.settings.color = :red 
user.settings.color # returns :red 
0

钢轨4,如果你正在使用postgresql,你可以使用HStore,它就像一个可序列化的属性,但是你可以用它进行SQL查询。

对于导轨3,您可以使用activerecord-postgres-hstore宝石。

0

我试过https://github.com/huacnlee/rails-settings-cached,但它不像描述的那样工作。很明显,作者忘记了在宝石使用描述中提到一些额外的调整。我没有编写控制器来进行设置操作。

相反,我成功地利用了https://github.com/paulca/configurable_engine - 尽管存在一些小问题,但这个宝石远比rails-settings-cached更合理。

configurable_engine宝石有一个缺点:它具有硬编码的路线其是晦涩和非方便。宝石的作者promised to correct it,但表示他目前没有时间。

所以这个问题通过简单地创建我自己的路线很容易安排。这里是我的代码(加入使这个宝石真正发挥作用):

的routes.rb

namespace :admin do 
    resources :configurables, only: [:index, :show, :edit, :update, :destroy] 
end 

管理/ 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,b它非常接近。我的new操作实际上会创建一个(数据库存储)设置(仅用于覆盖其yml文件值)。

所以这段代码添加到宝石描述代码使您可以利用实际运行时可更换的回报率设置。

宝石需要你设置一些默认值在YML文件提前,你可以在运行时后覆盖。但是你不能在运行时创建一个新的设置(not-yml-file-existent) - 只能修改一个存在的(在yml文件中) - 这非常合乎逻辑。

或者你可以恢复(在运行时)的任何设置(通过删除其数据库中存储的重写值)的默认值。

此代码已检查与Rails 5配合使用。