public
Description: Ruby on Rails
Homepage: http://rubyonrails.org
Clone URL: git://github.com/rails/rails.git
Introduce Rails Metal

  # app/metal/poller.rb
  class Poller < Rails::Rack::Metal
    def call(env)
      if env["PATH_INFO"] =~ /^\/poller/
        [200, {"Content-Type" => "application/json"}, Message.recent.to_json]
      else
        super
      end
    end
  end

* There is a generator to help you get started
    `script/generate metal poller`

* Also, metal bits can be ran standalone with rackup
    `rackup app/metal/poller.rb`
josh (author)
Tue Dec 16 11:11:51 -0800 2008
commit  8c3a54366435eebc2c8aa63b63e1349ce74a7b38
tree    547451f6c639994a948f8cba6505022458aedeac
parent  c4023cbe206415cf3ca1ca92cd9980a4aa4aed00
...
155
156
157
 
 
158
159
160
...
533
534
535
 
 
 
 
 
 
536
537
538
...
915
916
917
 
918
919
920
...
933
934
935
 
936
937
938
...
155
156
157
158
159
160
161
162
...
535
536
537
538
539
540
541
542
543
544
545
546
...
923
924
925
926
927
928
929
...
942
943
944
945
946
947
948
0
@@ -155,6 +155,8 @@ module Rails
0
       initialize_framework_settings
0
       initialize_framework_views
0
 
0
+      initialize_metal
0
+
0
       add_support_load_paths
0
 
0
       load_gems
0
@@ -533,6 +535,12 @@ Run `rake gems:install` to install the missing gems.
0
       end
0
     end
0
 
0
+    def initialize_metal
0
+      Dir["#{configuration.root_path}/app/metal/*.rb"].each do |file|
0
+        configuration.middleware.use(File.basename(file, '.rb').camelize)
0
+      end
0
+    end
0
+
0
     # Initializes framework-specific settings for each of the loaded frameworks
0
     # (Configuration#frameworks). The available settings map to the accessors
0
     # on each of the corresponding Base classes.
0
@@ -915,6 +923,7 @@ Run `rake gems:install` to install the missing gems.
0
         # Followed by the standard includes.
0
         paths.concat %w(
0
           app
0
+          app/metal
0
           app/models
0
           app/controllers
0
           app/helpers
0
@@ -933,6 +942,7 @@ Run `rake gems:install` to install the missing gems.
0
 
0
       def default_eager_load_paths
0
         %w(
0
+          app/metal
0
           app/models
0
           app/controllers
0
           app/helpers
...
2
3
4
 
5
6
7
...
2
3
4
5
6
7
8
0
@@ -2,6 +2,7 @@ module Rails
0
   module Rack
0
     autoload :Debugger, "rails/rack/debugger"
0
     autoload :Logger, "rails/rack/logger"
0
+    autoload :Metal, "rails/rack/metal"
0
     autoload :Static, "rails/rack/static"
0
   end
0
 end

Comments

sco Tue Dec 16 11:21:20 -0800 2008

Excellent.

foca Tue Dec 16 11:31:44 -0800 2008

sweeeeeet

rubymaverick Tue Dec 16 11:56:39 -0800 2008

drool

anildigital Tue Dec 16 11:57:58 -0800 2008

kewl.. can somebody explain me, what is the metal about?

topfunky Tue Dec 16 12:09:14 -0800 2008

Great idea!

While the paint is still wet, how about calling it something that matches the descriptive names of “controllers” “models” and “views”?

I suggest “middleware”.

drnic Tue Dec 16 12:11:18 -0800 2008

No tests for this patch? :)

mtodd Tue Dec 16 12:44:49 -0800 2008

Seems to be a recreation of the already simple idea of middleware… but I like it.

Also agree with calling it Middleware, though “Metal” is kinda badass. :)

judofyr Tue Dec 16 12:52:53 -0800 2008

You can’t kill the metal. The metal will live on.

dhh Tue Dec 16 13:07:32 -0800 2008

Middleware is a more generic notion for anything that’s used for preprocessing of a request. Metal is intended to be end-points for things that are simple and needs to be really fast. So think of Metal < Middleware.

amerine Tue Dec 16 13:09:07 -0800 2008

Metal sounds much better then “middleware”. But as far as having a “built-in” place to run “middeware code”…. I’m down with that.

norbert Tue Dec 16 13:23:36 -0800 2008

Wow, really? Sigh.

nakajima Tue Dec 16 13:57:06 -0800 2008

I like this a lot. However, I am with drnic. I’d also like to see some “metals” test helpers added to the framework, since this doesn’t seem to fall under the category of model, functional or integration (well, maybe integration).

josh Tue Dec 16 14:03:02 -0800 2008

@norbert just curious what you don’t dig?

@nakajima integration tests will work great since they test the entire call stack.

tristandunn Tue Dec 16 14:13:30 -0800 2008

This would be great for a project of mine if you can still use the session with it. Can you and if so is anything extra needed?

tjogin Tue Dec 16 14:58:38 -0800 2008

What “regular” parts of Rails are bypassed in order to make this so much faster?

wycats Tue Dec 16 15:00:11 -0800 2008

Pretty nice! It’s great to see Rails embracing Rack and Rack middleware.

drnic Tue Dec 16 15:06:41 -0800 2008

@nakajima yeah I think I’d like to see a test/metal/my_metal_test.rb + some helpers. very sweet.

@josh glad it can still work via integration/cucumber etc

this is the merb-pastie integration that I always wanted; so nice.

tjogin Tue Dec 16 15:10:12 -0800 2008

What “regular” parts of Rails are bypassed in order to make this so much faster?

samgranieri Tue Dec 16 15:11:02 -0800 2008

@tjogin, josh replaced the old cgi engine with rack. Rails is just one big rack application now. I think this is pretty cool for intercepting requests that you dont want to be processed by actioncontroller. I’m going to use this for heartbeat monitoring with HAProxy. One caveat while developing: unlike regular controllers you need to restart mongrel/thin when you change any metal.

I think this should be renamed to spikes.

tjogin Tue Dec 16 15:12:58 -0800 2008

@samgranieri: So the reason “metal” is so much faster is simply because it doesn’t load actioncontroller? That’s it?

drnic Tue Dec 16 15:15:42 -0800 2008

+1 for “middleware”

drnic Tue Dec 16 15:16:34 -0800 2008

@tjogin it would bypass the normal routing system too

tjogin Tue Dec 16 15:17:21 -0800 2008

@drnic: Anything else?

defunkt Tue Dec 16 15:19:16 -0800 2008

Blacker than the blackest black, times infinity.

samgranieri Tue Dec 16 15:22:24 -0800 2008

@tjogin, that’s not entirely accurate.

When the rails app starts up, it ( loads | autoloads | ? ) the framework , including actioncontroller.

The metal is so much faster because it intercepts the Rack call. In the example, if the route containts poller, send a json message, if not, then pass the request to action controller via super

josh Tue Dec 16 15:25:04 -0800 2008

@wycats Glad you like it. I hope this means we can start sharing Rack compatible code between Rails and Merb.

@tjogin it bypasses everything. whatever you code in your metal bit talks directly to the server (mongrel/thin/etc).

Still a bit of confusion about metal == middleware? The answer is no. Metal bits are designed to be endpoints.

I think this commit did not get noticed: http://github.com/rails/rails/commit/06ed8e451198b2296d8b2752741e259b4f995081 I added `config.middleware.use Rack::Cache` to the initializer as a hook for any plugins that want to connect in as middleware.

Yes, I know its really all the same thing but metal does sound really cool :)

@drnic I think integration tests are a good fit here. Thats my opinion though. If you think some helpers are inorder, go for it. (Actually, if I had my way, everything would be an integration test ;)

tjogin Tue Dec 16 15:27:24 -0800 2008

@josh: So, since metal bypasses “everything”, does that mean that “metal” code can’t use some of the stuff the rest of a Rails app uses? Like.. ActiveSupport, or anything like that? Maybe I’m curious for too much information too soon. Blogs are likely delve deeper into this.

samgranieri Tue Dec 16 15:29:48 -0800 2008

@tjogin, yeah, ActiveSupport works. http://gist.github.com/36861

drnic Tue Dec 16 15:30:42 -0800 2008

From Ezra’s (sarcastic) tweet (http://twitter.com/ezmobius/statuses/1061662672) “rack middleware you cannot use outside of rails” – what would be the mechanism for a writing a plugin that contained a rack call hook, that could be used in different frameworks (rails/merb/other-rack-super-framework)? Given the rails-specific superclass, then the call behaviour would need to be in a module, and included into either a Rails::Rack::Metal subclass via the rails plugin’s init.rb or hooked into each specific Merb/other-rack-superframework in a specific way? Or can this be generic so its uber simple to write sharable rack plugins that are framework neutral?

josh Tue Dec 16 15:37:12 -0800 2008

@drnic

  1. init.rb config.middleware.use Rack::MyFanaticMiddleware

This is the same api as the rack builder syntax. Its totally compatible. Use any rack middleware with Rails now (on edge ;)

again metal != middleware

drnic Tue Dec 16 15:38:10 -0800 2008

/me found answer to his question in @josh’s comment above

wycats Tue Dec 16 15:46:38 -0800 2008

drnic I’m assuming that Rails::Rack::Metal will become more featured over time. At the moment there doesn’t seem to be a big win in using it over regular middleware (but again, I expect that might change).

samgranieri Tue Dec 16 15:46:46 -0800 2008

here’s a novel use for metal: You can use http://gist.github.com/36865 to rickroll every non page cached url. Use at your own risk!

wycats Tue Dec 16 15:50:18 -0800 2008

@lifo don’t you use config.middleware.use to set up the Metal classes?

carllerche Tue Dec 16 15:52:43 -0800 2008

+1 for naming it middleware.

In the Rack code itself, Rack::File is obviously an endpoint, yet is called middleware. It’s called middleware because it is in the middle of the request → application chain, not because it is an end point or not.

Naming this metal instead of middleware is just going to muddy the waters for newer developers not familiar with rack.

josh Tue Dec 16 15:55:36 -0800 2008

@wycats yes, under the hood the metal is middleware. we inject it into the middleware stack and thats how it intercepts the request. The focus is on the endpoint implementation. Metal bits should be application endpoints, not filters.

ezmobius Tue Dec 16 15:59:25 -0800 2008

middlewares do not have to be filters. they can absolutely be endpoints and that is the point. Making a new concept just makes learning rack harder no?

Same concept i blogged ages ago here: brainspl.at/articles/2008/02/16/so-merb-core-is-built-on-rack-you-say-why-should-i-care

I love that you guys are adding this stuff. But I implore you to not embrace and extend but rather just embrace rack and make people learn it. This is just middleware in sheep’s clothing afaict.

josh Tue Dec 16 16:10:47 -0800 2008

@ezmobius The original idea was to have a single endpoint class, and force people use Rack::URLMap. But we didn’t like the idea of forcing people to use that for routing. So we moved the routing logic into the class (which is causing all this confusing). It may be clearer if it looked something like this.

class Poller def self.call(env) [200, ….] end end

class PollerRouterMiddleware def initialize(app) @app = app end

def call(env) if env[…] == /something/ Poller.call(env) else @app.call(env) end end

end

However, we decided to merge the two for a nicer API. Okay, since Rack::Metal secretly takes an app instance under the hood, is not an endpoint but middleware. But thats not how we want to think of it.

I know still confusing.

Roman2K Tue Dec 16 16:14:50 -0800 2008

+1 for “middleware”, or some other name that’s more descriptive than “metal”.

wycats Tue Dec 16 16:17:45 -0800 2008

@lifo is there an important reason for people to think of it differently? might keeping the (tiny) implementation exposed help people understand what’s going on?

josh Tue Dec 16 16:21:09 -0800 2008

@wycats possibly, maybe that would clear up this mess :)

(btw, I’m not lifo)

wycats Tue Dec 16 16:22:18 -0800 2008

@josh oh snap. /me holds head

My typing fingers have betrayed me!

josh Tue Dec 16 16:24:33 -0800 2008

BTW, all good comments. If someone wants to propose a change, maybe we should take this to the ML or something. I’m getting lost :)

macournoyer Tue Dec 16 16:52:54 -0800 2008

+1 for naming it Awesomeware

peterc Tue Dec 16 17:24:33 -0800 2008

I think metal is an awesome name and reasonably descriptive. That said, middleware is probably more descriptive but doesn’t it clash nominatively with the generic concept of middleware in Rack?

wycats Tue Dec 16 17:48:37 -0800 2008

@peterc is is middleware in Rack

actsasflinn Tue Dec 16 19:48:11 -0800 2008

+1 for middleware

lgomez Tue Dec 16 20:15:52 -0800 2008

Pardon my ignorance but this means responses to requests intercepted by metal have to be completely generated manually or at least not with actionpack niceties, correct? Or is it just actioncontroller the one that is not loaded?

Where can I learn more about rack, metal and related subjects?

mattetti Tue Dec 16 20:56:28 -0800 2008

@Igomez http://rack.rubyforge.org/ and http://book.merbist.com/getting-started/request-path

Rails Edge now uses Rack like merb/sinatra/waves/ramaze/mack so the process is the same. The Rack middleware receives a rack env and returns a simple tuple containing status, headers, body. The middleware has access to your models.

lifo Tue Dec 16 21:09:44 -0800 2008

@lgomez : Have a look at two posts I had made recently

Think of Metal as a minimal Rack application.

HTH.

mattetti Tue Dec 16 21:19:42 -0800 2008

@lifo great posts!

josh Tue Dec 16 21:39:02 -0800 2008

Maybe this will help. Metals are “application-specific” mini apps. Not really designed to be shared. However, you want want to create a plugin, engine, etc you can wrap it in a boarder middleware wrapper that would work on any Rack platform.

softprops Tue Dec 16 22:22:20 -0800 2008

neat!

datra Tue Dec 16 23:26:34 -0800 2008

I think looks pretty awesome. Excited about the future! I must admit that it took me a while to get the idea, though.

Metal is a cool name but to me it makes no sence. I don’t really like middleware either. I would prefer a plural noun like models, views, helpers, and controllers. I don’t know, maybe spikes. :)

technoweenie Wed Dec 17 00:36:06 -0800 2008

Horns \m/

henrik Wed Dec 17 02:44:40 -0800 2008

app/wares? ;)

josh Wed Dec 17 07:57:10 -0800 2008

Tweaked the API:

http://github.com/rails/rails/commit/61a41154f7d50099da371e0d2f22fd25ab9113c2

Metals are now pure endpoints. Not fake middleware, nor any other type of middleware. They are applications, they do not accept a app in their initializer. Did I mention they were not middleware?

stefanoc Wed Dec 17 08:01:26 -0800 2008

+∞ for metal, but I like “awesomeware” too :-) I find it really hard to believe that ppl don’t get the difference between “metal” and “middleware”. I don’t think it’s confusing at all. I mean, just look at the code, it’s all there!

@josh: just keep pulling great stuff like this

lifo Wed Dec 17 09:10:50 -0800 2008

@mattetti Thanks!

creationmachine Thu Dec 18 12:13:03 -0800 2008

This will really help me out in some stuff I am working on. Thanks!

As far as naming it “Metal”, um, there are 1 billion gems with different names. I think people new to Rails will understand the subject matter after it’s mentioned once or twice. But, maybe it should be named “Derailer” or “Sidetrack”. :D

Thanks again for all your work!