Jason
Jason

Reputation: 3806

Sharing Yaml config files between Sinatra and Rails

I am extracting a Sinatra app out of an existing Rails app into a gem to be reused in the same Rails app. I would like to leave a config file in it's current location of Rails.root/config (standard spot) but still use it from the Sinatra application. How do I do this cleanly?

Currently the Sinatra app's settings.root point to some path deep inside the vender directory. I assume this is because the Sinatra app is a gem. This means I have to guess out many directories to go up to find the root of the Rails app.

Is there a standard way to get the root of the main Rack app that my Sinatra app is mounted in?

Upvotes: 0

Views: 1189

Answers (3)

matt
matt

Reputation: 79733

If you are including you’re separated Sinatra app in your Rails app by adding it as middleware, then you could add a constructor to your app that configures it. Sinatra has an initialize method that follows the common Rack middleware interface, with the first argument being the app to pass requests to. By overriding this in your subclass you can perform any needed configuration.

For example, in your Sinatra app:

def initialize(app, config_file)
  super(app)
  data = YAML.load_file(config_file)
  settings.foo = data['name']
end

In order for the call to settings.foo to work you will need to set a default value for foo in a configure block, since the initialize methods runs in the scope of an instance of the class and doesn’t have access to the set method:

configure do
  set :foo, nil
end

Now you can add the middleware in application.rb (or wherever you want to add it) like this:

config.middleware.use MyApp, File.join(Rails.root, "config/foo_settings.yaml")

You could do something similiar in your config.ru with plain use if you wanted to mount the Sinatra app outside of your Rails app. If you add the use line after the line requiring your Rails app you will still be able to use the Rails.root variable.

Upvotes: 0

matt
matt

Reputation: 79733

If you’re including your Sinatra app by mounting it with an entry in your config/routes.rb, you can configure it by calling methods on it before the mount call.

Any methods you call here will run after any configure blocks in your app, so if you want to do anything more complex than setting a single variable (with the Sinatra set command) you will need to add a class method that you can call from routes.rb.

For example, if you want to have a Yaml config file that contains an entry foo, then in your Sinatra app add something like:

def self.config_from_file(filename)
  data = YAML.load_file(filename)
  set :foo, data['foo']
  # set other vars from Yaml as appropriate
end

Now settings.foo will be available in your routes.

In your Rails config/routes.rb you will need to add something like:

# first configure your app
MyApp.config_from_file(File.join("#{Rails.root}/config", "foo_config.yaml"))
# now mount it at the appropriate url
mount MyApp.new => '/foo'

Upvotes: 0

the Tin Man
the Tin Man

Reputation: 160551

There is no clean method, because the apps are completely different stacks.

You can play a trick on the Sinatra code using your server's OS, which is something we do.

If you're on Linux or Mac OS, create a soft-link for your Sinatra app that points to the Rails' configuration file. You can write a rakefile that creates it, and run that script when you install the code.

At the OS level, you want to use:

ln -s path_to_rails_file.yaml path_to_sinatra_file.yaml

You could even create soft-links for both Rails and Sinatra's YAML files pointing to a single instance of the file in a parent directory or in /etc somewhere. You'll want to add some readme files in the appropriate places documenting the use of the soft-links though, or you'll hate yourself at 3AM some morning when you can't remember why you did that.

Upvotes: 1

Related Questions