Universal settings in Sinatra

I have a class in Sinatra where I set some settings (from JSON, as it happens):

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

      

And this class has a model that is required to read these parameters.

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

      

However, the Resolver class cannot do this: undefined `config 'method for Resolver: Class.

Perhaps I have the wrong scope, or should I be using Sinatra :: Application?

+3


source to share


1 answer


When you get a class that inherits from Sinatra::Base

, you make this Sinatra application. Each application gets its own object settings

. If you want to use general settings for applications, you have several options:

  • Combine apps.
  • Make settings more globally accessible.
  • Inheritance (see below)

Merging them is easy (unless there is some specific reason that we don't know about), you basically put them in the same class.

To make the settings more global I would do the following:

a) Wrap the entire application in a module in a namespace.
b) Place the parameters you want to use in a class instance variable accessible with the "getter" method.

eg.

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

      



It's fine if you have very small applications, but if you use multiple applications, you need to separate them a little. As I usually plan to organize my application, delete everything from the rackup file (usually config.ru

) that does anything other than require

and run

. I installed the middleware and app in a different file usually app/config.rb

, so I know this stuff from config.ru

. Then each application gets its own file (for example 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

      

There are many advantages to this type of setup — it's easier to test; easier to organize; you can move apps easily. But YMMV as always.


I have to add as well, since this very much prevents me from not doing this, that inheritance can also be used, for example:

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

      

Settings, routes, helpers, filters are inherited, so if you customize something in the proposal, it will be available in the heirs. Sometimes it will be better to do it this way, perhaps when settings are just "global" for Sinatra applications or when you want to create reusable applications and controllers. In other cases, you will need settings that can be used in models, libraries, etc., and then the best global solution I gave at the beginning would be better.

+3


source







All Articles