I''m just playing with a recent Merb trunk (-r590). All the specs pass, apart from 2 pending. Now, the README says: "if you return a Proc object from your action, it will be called and the return value sent to the client." However this doesn''t seem to work with the following test controller: class Hello < Application def world res = "Hello world from #{$$} at #{Time.now}!\n" proc { sleep 5 res } end end I get the 5 second wait, but zero bytes of response. $ telnet localhost 4000 Trying 127.0.0.1... Connected to localhost.localdomain (127.0.0.1). Escape character is ''^]''. GET /hello/world HTTP/1.0 HTTP/1.1 200 OK Connection: close Date: Tue, 11 Sep 2007 12:43:51 GMT Content-Type: text/html Content-Length: 0 Connection closed by foreign host. It works if I remove the proc { ... } wrapper and just return the string directly. I''m pretty sure I''m doing the proc return correctly; if I write it as a standalone Ruby program then it behaves as I expect, i.e. def world res = "Hello world from #{$$} at #{Time.now}!\n" proc { sleep 5 res } end puts world.call # this works and shows the message Anybody got any idea why this doesn''t work? I''m not submitting this as a ticket as I''m not sure if the behaviour is wrong, the README is wrong, or I''m doing something wrong :-) Thanks, Brian.
It''s because Merb doesn''t write status or headers on procs. Presumably because Merb doesn''t yet know the Content-Length of the response? I''m all for changing this: returning headers and status (without Content-Length) on proc return values before calling the proc. ry On 9/11/07, b.candler at pobox.com <b.candler at pobox.com> wrote:> I''m just playing with a recent Merb trunk (-r590). All the specs pass, apart > from 2 pending. > > Now, the README says: "if you return a Proc object from your action, it will > be called and the return value sent to the client." > > However this doesn''t seem to work with the following test controller: > > class Hello < Application > def world > res = "Hello world from #{$$} at #{Time.now}!\n" > proc { > sleep 5 > res > } > end > end > > I get the 5 second wait, but zero bytes of response. > > $ telnet localhost 4000 > Trying 127.0.0.1... > Connected to localhost.localdomain (127.0.0.1). > Escape character is ''^]''. > GET /hello/world HTTP/1.0 > > HTTP/1.1 200 OK > Connection: close > Date: Tue, 11 Sep 2007 12:43:51 GMT > Content-Type: text/html > Content-Length: 0 > > Connection closed by foreign host. > > It works if I remove the proc { ... } wrapper and just return the string > directly. > > I''m pretty sure I''m doing the proc return correctly; if I write it as a > standalone Ruby program then it behaves as I expect, i.e. > > def world > res = "Hello world from #{$$} at #{Time.now}!\n" > proc { > sleep 5 > res > } > end > puts world.call # this works and shows the message > > Anybody got any idea why this doesn''t work? I''m not submitting this as a > ticket as I''m not sure if the behaviour is wrong, the README is wrong, or > I''m doing something wrong :-) > > Thanks, > > Brian. > _______________________________________________ > Merb-devel mailing list > Merb-devel at rubyforge.org > http://rubyforge.org/mailman/listinfo/merb-devel >
Hi~ On Sep 11, 2007, at 8:35 AM, ry dahl wrote:> It''s because Merb doesn''t write status or headers on procs. Presumably > because Merb doesn''t yet know the Content-Length of the response? > > I''m all for changing this: returning headers and status (without > Content-Length) on proc return values before calling the proc. > > ry > > On 9/11/07, b.candler at pobox.com <b.candler at pobox.com> wrote: >> I''m just playing with a recent Merb trunk (-r590). All the specs >> pass, apart >> from 2 pending. >> >> Now, the README says: "if you return a Proc object from your >> action, it will >> be called and the return value sent to the client." >> >> However this doesn''t seem to work with the following test controller: >> >> class Hello < Application >> def world >> res = "Hello world from #{$$} at #{Time.now}!\n" >> proc { >> sleep 5 >> res >> } >> end >> end >> >> I get the 5 second wait, but zero bytes of response. >> >> $ telnet localhost 4000 >> Trying 127.0.0.1... >> Connected to localhost.localdomain (127.0.0.1). >> Escape character is ''^]''. >> GET /hello/world HTTP/1.0 >> >> HTTP/1.1 200 OK >> Connection: close >> Date: Tue, 11 Sep 2007 12:43:51 GMT >> Content-Type: text/html >> Content-Length: 0 >> >> Connection closed by foreign host. >> >> It works if I remove the proc { ... } wrapper and just return the >> string >> directly. >> >> I''m pretty sure I''m doing the proc return correctly; if I write it >> as a >> standalone Ruby program then it behaves as I expect, i.e. >> >> def world >> res = "Hello world from #{$$} at #{Time.now}!\n" >> proc { >> sleep 5 >> res >> } >> end >> puts world.call # this works and shows the message >> >> Anybody got any idea why this doesn''t work? I''m not submitting >> this as a>> ticket as I''m not sure if the behaviour is wrong, the README is >> wrong, or >> I''m doing something wrong :-) >> >> Thanks, >> >> Brian.Brian- There is a helper method for this that sets all the proper headers and whatnot. Here is how to use it to do what your example does: def world res = "Hello world from #{$$} at #{Time.now}!\n" render_defered do sleep 5 res end end Cheers- -- Ezra Zygmuntowicz -- Founder & Ruby Hacker -- ez at engineyard.com -- Engine Yard, Serious Rails Hosting -- (866) 518-YARD (9273)
Ezra Zygmuntowicz writes:> There is a helper method for this that sets all the proper headers and > whatnot. Here is how to use it to do what your example does: > > def world > res = "Hello world from #{$$} at #{Time.now}!\n" > render_defered do > sleep 5 > res > end > endThank you. It''s "render_deferred", but when I change use that it works. Perhaps this example should go into the README. What I found surprising (and still do) is that a controller action can return a String directly, but a Proc cannot. Therefore, what exactly is it that a Proc is supposed to do to generate output, which a controller action doesn''t have to do? Looking in abstract_controller.rb, I see: @_body = case caught when :filter_chain_completed call_action(action) when String caught when nil filters_halted when Symbol send(caught) when Proc caught.call(self) else raise MerbControllerError, "The before filter chain is broken dude. wtf?" end and this is also called from Controller#dispatch (via ''super'') So at first glance, it looks like caught.call(self) ought to take the return value of the Proc and treat it just the same as a String returned directly from the controller method. But I''m clearly not understanding the flow of control, because that''s not what''s happening. Regards, Brian.
On Sep 11, 2007, at 12:53 PM, b.candler at pobox.com wrote:> Ezra Zygmuntowicz writes: >> There is a helper method for this that sets all the proper >> headers and whatnot. Here is how to use it to do what your >> example does: def world >> res = "Hello world from #{$$} at #{Time.now}!\n" >> render_defered do >> sleep 5 >> res >> end >> end > > Thank you. It''s "render_deferred", but when I change use that it > works. Perhaps this example should go into the README. > What I found surprising (and still do) is that a controller action > can return a String directly, but a Proc cannot. Therefore, what > exactly is it that a Proc is supposed to do to generate output, > which a controller action doesn''t have to do? > Looking in abstract_controller.rb, I see: > @_body = case caught > when :filter_chain_completed > call_action(action) > when String > caught > when nil > filters_halted > when Symbol > send(caught) > when Proc > caught.call(self) > else > raise MerbControllerError, "The before filter chain is broken > dude. wtf?" > end > and this is also called from Controller#dispatch (via ''super'') > So at first glance, it looks like caught.call(self) ought to take > the return value of the Proc and treat it just the same as a String > returned directly from the controller method. But I''m clearly not > understanding the flow of control, because that''s not what''s > happening. > Regards, > Brian.Brian- That is only for a Proc returned from a before filter. class Foo <Application before :foo def foo if something? throw :halt, Proc.new{ "Hi there!" } end end end That is how the body will be set to the output of a proc in the dispatch method. If you don''t halt the filter chain and just return a proc as the controller body then that proc gets called later by mongrel and it is responsible for setting the headers and content length itself. render_deferred is the simple way to do it. but look in the mixins/controller.rb and you will see other uses of returning procs for streaming and whatnot. It''s a low level thing and making it so you have to deal with the headers and other stuff yourself allows it to be a lot more flexible. Just use render_deferred if you want to return a ''future'' proc and not worry about the details. Cheers- -- Ezra Zygmuntowicz -- Founder & Ruby Hacker -- ez at engineyard.com -- Engine Yard, Serious Rails Hosting -- (866) 518-YARD (9273)