views:

186

answers:

5

I'm in the process of refactoring some logic built into a Rails application into middleware, and one annoyance I've run into is a seeming lack of convention for where to put them.

Currently I've settled on app/middleware but I could just as easily move it to vendor/middleware or maybe vendor/plugins/middleware...

The biggest problem is having to require the individual files at the top of config/environment.rb

require "app/middleware/system_message"
require "app/middleware/rack_backstage"

or else I get uninitialized constant errors on the config.middleware.use lines. That could get messy very quickly. I'd rather this was tucked away in an initializer somewhere.

Is there a conventional place to put this stuff?


The specific answer I'm looking for with this bounty is: where can I put the require lines so that they are not cluttering the environment.rb file but still get loaded before the config.middleware.use calls? Everything I have tried leads to uninitialized constant errors.

A: 

I'm not aware of a convention, but why not put it in the /lib directory? Files in there get automatically loaded by Rails.

John Topley
Not until after environment.rb is run, if at all. Moving them to lib didn't solve the uninitialized constant errors.
Adam Lassek
A: 

You could create an initializer which requires the necessary files and then leave the files wherever you want.

According to this the initializers are executed before the rack middleware is loaded.

Jean
Nope. Still get uninitialized constant.
Adam Lassek
Looks like I was a bit optimistic when reading that. I guess config.ru doesn't match you requirements either ?
Jean
well, that would require using rackup instead of script/server, right? I could do that if I had to but I honestly thought it would be easier than this.
Adam Lassek
A: 

The working solution I have so far is moving the middleware requires to config/middleware.rb and requiring that file in environment.rb, reducing it to a single require which I can live with.

I'd still like to hear how other people have solved this seemingly basic problem of adding middleware to Rails.

Adam Lassek
A: 

For Rails 3:

#config/application.rb
require 'lib/rack/my_adapter.rb'
module MyApp
  class Application < Rails::Application
    config.middleware.use Rack::MyAdapter
  end
end
Justice
+4  A: 

You can put it in lib/tableized/file_name.rb. As long as the class you're trying to load is discoverable by its filename, Rails will automatically load the file necessary. So, for example:

config.middleware.use "MyApp::TotallyAwesomeMiddleware"

You would keep in:

lib/my_app/totally_awesome_middleware.rb

Rails catches const_missing and attemts to load files corresponding to the missing constants automatically. Just make sure your names match and you're gravy. Rails even provides nifty helpers that'll help you identify the path for a file easily:

>> ChrisHeald::StdLib.to_s.tableize.singularize
=> "chris_heald/std_lib"

So my stdlib lives in lib/chris_heald/std_lib.rb, and is autoloaded when I reference it in code.

Chris Heald
I have some middleware called `Rack::Backstage`. Put it in `lib/rack/backstage.rb`. Unititialized constant error.
Adam Lassek
This works _only_ if the first parameter is a string. Once I figured that out, success!
Adam Lassek
@Chris: Cool solution. :)
Shripad K