Where do you put your Rack middleware files and requires?
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.
Update : Now that we're using Rails 3.0, I treat a Rails app like any other Rack app; code files for middleware go in lib
(or a gem listed in Gemfile
) and are required and loaded in config.ru
.
As of Rails 3.2, Rack middleware belongs in the app/middleware directory.
It works "out-of-the-box" without any explicit require statements.
Quick example:
I'm using a middleware class called CanonicalHost which is implemented in app/middleware/canonical_host.rb . I've added the following line to production.rb ( note that the middleware class is explicitly given, rather than as a quoted string, which works for any environment-specific config files):
config.middleware.use CanonicalHost, "example.com"
If you're adding middleware to application.rb , you'll need to include quotes, as per @mltsy's comment.
config.middleware.use "CanonicalHost", "example.com"
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.
In my Rails 3.2 app, I was able to get my middleware TrafficCop
loading by putting it at app/middleware/traffic_cop.rb
, just as @MikeJarema described. I then added this line to my config/application.rb
, as instructed:
config.middleware.use TrafficCop
However, upon application start, I kept getting this error:
uninitialized constant MyApp::Application::TrafficCop
Explicitly specifying the root namespace didn't help either:
config.middleware.use ::TrafficCop
# uninitialized constant TrafficCop
For some reason (which I've yet to discover), at this point in the Rails lifecycle, app/middleware
wasn't included in the load paths. If I removed the config.middleware.use
line, and ran the console, I could access the TrafficCop
constant without any issue. But it couldn't find it in app/middleware
at config time.
I fixed this by enclosing the middleware class name in quotes, like so:
config.middleware.use "TrafficCop"
This way, I would avoid the uninitialized constant
error, since Rails isn't trying to find the TrafficCop
class just yet. But, when it starts to build the middleware stack, it will constantize the string. By this time, app/middleware
is in the load paths, and so the class will load correctly.
上一篇: Rails Observer Alternatives for 4.0
下一篇: 你把你的Rack中间件文件放在哪里?