【问题标题】:Universal settings in SinatraSinatra 中的通用设置
【发布时间】:2014-11-29 20:39:42
【问题描述】:

我在 Sinatra 有一门课,在那里我设置了一些设置(来自 JSON,碰巧):

class Pavo < Sinatra::Base
  configure :development do
    set :config, JSON.parse(File.open(File.dirname(__FILE__) + "/pavo.configuration.development.json", "rb").read)
    set :config_mtime, File.mtime(File.dirname(__FILE__) + "/pavo.configuration.development.json")
  end

  [...]

  get '/' do
    puts "whatever"
  end
end

该类有一个模型,是读取这些设置所必需的。

class Resolver < Sinatra::Base
  def get_data(workpid)
    url_str = settings.config['public']['BOOKS_DATA_SERVICE_URL'].gsub('${WORKPID}', workpid)
    return Resolver.get_json(url_str)
  end
  [...]
end

但是,Resolver 类无法做到这一点:Resolver:Class 的未定义方法 `config'。

也许我的范围有误,或者我应该使用 Sinatra::Application?

【问题讨论】:

  • Resolver 是一个单独的应用程序有什么原因吗?
  • 您无法从其他班级访问settings。您的设置存储在Pavo,您无法从Resolver 访问这些设置。如果你想访问settings,你应该将Resolver中的方法移动到Pavo
  • @Casper 但是将整个应用程序保留在一个类中是没有意义的......

标签: ruby sinatra


【解决方案1】:

当你得到一个从Sinatra::Base 继承的类时,你就是在制作一个 Sinatra 应用程序。每个应用程序都有自己的 settings 对象。如果您想在应用程序之间共享设置,您有一些选择:

  1. 合并应用程序。
  2. 使设置更易于全局访问。
  3. 继承(见下面的编辑)

合并它们很容易(除非有一些我们不知道的特殊原因),你基本上把它们放在同一个类中。

为了使设置更易于全局访问,我会执行以下操作:

a) 将整个应用程序包装在一个模块中以命名它。
b) 将您要使用的设置放入可通过“getter”方法访问的类实例变量中。

例如

module MyNamespace

  def self.global_settings
    @gs ||= # load your settings
  end

  class App < Sinatra::Base
    configure do
      set :something_from_the_global, MyNamespace.global_settings.something
    end
  end

  class SecondaryApp < Sinatra::Base
    helpers do
      def another_method
        MyNamespace.global_settings.something_else # available anywhere
      end
    end
    configure do # they're also available here, since you set them up before the app
      set :something_from_the_global, MyNamespace.global_settings.something
    end
  end

end

如果您有一些非常小的应用程序,那很好,但如果您使用多个应用程序,那么您需要将它们分开一点。除了requires 和run,我倾向于组织应用程序的方式是从机架文件(通常是config.ru)中删除所有可以做任何事情的东西。我将中间件和应用程序设置放在另一个文件中,通常是app/config.rb,所以我知道这是来自config.ru 的东西。然后每个应用程序都有自己的文件(例如app/app.rbapp/secondary.rb

# app/config.rb

require "app"
require "secondary"

module MyNamespace
  # set up your getters… e.g.

  def self.global_settings
    @gs ||= # load your settings
  end

  def self.app
    Rack::Builder.app do

      # …and middleware here
      use SecondaryApp
      run App
    end
  end
end

# config.ru

require 'rubygems'
require 'bundler'
Bundler.require

root = File.expand_path File.dirname(__FILE__)
require File.join( root , "./app/config.rb" )

map "/" do
  run MyNamespace.app
end

这种设置有很多好处 - 更容易测试;更容易组织;您可以更轻松地移动应用程序。但 YMMV 一如既往。


我还应该补充一点,因为我很失职,所以也可以使用继承,例如:

require 'sinatra/base'    

module MyNamespace
  class Controller < Sinatra::Base
    configure :development do
      set :config, "some JSON"
      set :mtime, Time.now.to_s
    end
  end

  class App1 < Controller

    get "/app1" do
      "in App1 config: #{settings.config} mtime: #{settings.mtime}"
    end
  end

  class App2 < Controller

    get "/app2" do
      "in App2 with config: #{settings. config} mtime: #{settings.mtime}"
    end
  end
end

设置、路由、助手、过滤器都是继承的,所以如果你在祖先应用程序中配置一些东西,它将在继承者中可用。有时这样做会更好,可能当设置对于 Sinatra 应用程序来说只是“全局”时,或者当您想要创建可重用的应用程序和控制器时。其他时候,您需要可以在模型、库等中使用的设置,然后我首先给出的更具全局性的解决方案会是最好的。

【讨论】:

  • 谢谢@iain,我会在今天下午试一试,然后告诉你。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多