Problem returning a Proc

Ezra Zygmuntowicz ez at engineyard.com
Tue Sep 11 16:04:40 EDT 2007


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)




More information about the Merb-devel mailing list