3

我在 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?

4

1 回答 1

3

当您获得一个要从您那里继承的类时,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

如果您有一些非常小的应用程序,那很好,但如果您使用多个应用程序,那么您需要将它们分开一点。我倾向于组织应用程序的方式是从 rackup 文件(通常是config.ru)中删除除requires 和run. 我将中间件和应用程序设置放在另一个文件中,通常app/config.rb这样我就知道它是来自config.ru. 然后每个应用程序都有自己的文件(例如app/app.rb, app/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 应用程序来说只是“全局”时,或者当您想要创建可重用的应用程序和控制器时。其他时候,您需要可在模型、库等中使用的设置,然后我首先给出的更具全局性的解决方案将是最好的。

于 2013-02-14T00:46:25.340 回答