Possible bug with render_text in 2.3.2

227 views
Skip to first unread message

Jeff

unread,
Mar 26, 2009, 3:24:40 PM3/26/09
to Ruby on Rails: Core
I think render_text, when given a proc object, is broken in
development mode; or, I'm not doing something right.

Full explanation (it's short) is here:
http://groups.google.com/group/rubyonrails-talk/browse_frm/thread/9a18452b6f9fe019

Basically if I reference a model within my proc, I get an error that I
think means that something in the dependency-loading mechanism is
broken:

class MyController < ActionController::Base

def index
render :status => 200, :layout => false,
:text => Proc.new { |response, output| output.write
Order.first.events.inspect }
end

I get an error like

A copy of MyController has been removed from the module tree but is
still active!

If I do something else inside the proc, like output.write "hello", it
works fine. So it's only when the dependency mechanism gets touched,
I think.

This works fine in 2.2.2.

(In our real app, we're using this technique to stream XML that's
dynamically generated from the DB because it could be a large amount
of data. If there's a better way to stream dynamically-generated data
with Metal or something like that, I'd be interested in that as well.)

Any ideas?

Thanks!
Jeff

Joshua Peek

unread,
Mar 26, 2009, 4:46:13 PM3/26/09
to rubyonra...@googlegroups.com
Definitely sounds like a class reloading issue. I think the class
reloader (trigged by AC::Reloader middleware) removes the Order model,
then the actual server tries to call the stream block and the model is
missing. (At least we know Rack streaming is working ;)

One solution would be to have the AC::Reloader middleware buffer all
the responses into a plain string it returns to the server. This
normally would be bad for performance, but its okay cause it would
only affect development.

Ryan Angilly

unread,
Mar 26, 2009, 5:03:43 PM3/26/09
to rubyonra...@googlegroups.com
In an equally-odd-and-possibly-related note, I have a development-only problem where accessing a has_many association throws an exception in ActiveRecord::Base because self.default_scoping is nil.

Monkey-patching ActiveRecord::Base.scoped_methods as such:

def scoped_methods
-  Thread.current[:"#{self}_scoped_methods"] ||= self.default_scoping.dup    #<-- Exception thrown on nil default_scoping here
+  Thread.current[:"#{self}_scoped_methods"] ||= (self.default_scoping || []).dup
end

fixes the problem in development.  The first time an action using association is hit, it's fine.  Subsequent calls throw this nil exception.  Production is fine either way.  We have plenty of other regular has_many associations that are working.  The only discernible difference is that this one is defined in an acts_as_ fashion: the has_many is defined in a class method.

Code looks something like:

module ActsAsCategorizable
  def self.included(base)
    base.extend ClassMethods
  end

  module ClassMethods
    def self.acts_as_categorizable
      has_many :templates, :as => :categories, :dependent => :destroy
    end
  end
end

AR::B.send(:include, ActsAsCategorizable)

class Paper  < AR::B
#stuff
end

class Design < Paper
  # some stuff
  acts_as_categorizable
  # some more stuff
end

Design.first.templates throws the exception.  I spent almost 2 days in a debugger trying to find out why and came up with nothing.  No idea why the inheritable_attribute default_scoping is nil.

-Ryan

Jeff

unread,
Mar 27, 2009, 12:05:54 PM3/27/09
to Ruby on Rails: Core
On Mar 26, 3:46 pm, Joshua Peek <j...@joshpeek.com> wrote:
> Definitely sounds like a class reloading issue. I think the class  
> reloader (trigged by AC::Reloader middleware) removes the Order model,  
> then the actual server tries to call the stream block and the model is  
> missing. (At least we know Rack streaming is working ;)

Interesting - I'll try to read up on how the Reloader middleware gets
triggered.

> One solution would be to have the AC::Reloader middleware buffer all  
> the responses into a plain string it returns to the server. This  
> normally would be bad for performance, but its okay cause it would  
> only affect development.

Well, it would be better to see the buffer flushed in realtime, like
it worked in 2.2. Maybe there's a way to simply "pause" any reloading
until after the render_text statement is finished?

By the way, the current docs say that the proc will get arguments like
this:

Proc.new { |response, output| .... }

but in 2.3, both parameters seem to be of class Response; and whereas
we used to call output.flush when we wanted to send a chunk of data
back to the browser, I think output.write (really response.write) is
autoflushing on every call. Which is probably fine, but unfortunately
the .flush method was removed and broke our code. Either the
signature should change to just pass one response object, or I'm
guessing the signature was preserved to try not to break old code, in
which case we should add a no-op flush() method.

Jeff

Matt Jones

unread,
May 10, 2009, 1:24:42 PM5/10/09
to rubyonra...@googlegroups.com
Can you give any more detail about this issue? I just tried it against
a fresh 2.3.2 app, and couldn't reproduce the issue.
I did have to correct some typos in the example (acts_as_categorizable
shouldn't have self., for instance).

Also, do you have any plugins that fiddle with the inherited callback?
I ran into a similar issue a few months ago with rubyist_aasm, which
was overriding inherited without calling super. Broke AR timestamps,
and a few other things related to inherited_attributes.

--Matt Jones

Andrei Erdoss

unread,
May 20, 2009, 6:37:05 AM5/20/09
to Ruby on Rails: Core
I tried both of these methods and it seemed to have solved the
problem.
I got this from http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/f54f18f4d4354926?pli=1

Please let me know if it works for you too. Thanks,

First, you could put something like this in your plugin’s init.rb
file:
# This plugin should be reloaded in development mode.
if RAILS_ENV == ‘development’
ActiveSupport::Dependencies.load_once_paths.reject!{|x| x =~/^#
{Regexp.escape(File.dirname(__FILE__))}/}
end
Second, you could put something like this in your application’s
environment.rb file:
config.reload_plugins = true if RAILS_ENV == ‘development’
> > On Thu, Mar 26, 2009 at 4:46 PM, Joshua Peek <j...@joshpeek.com>  
> > wrote:
>
> > Definitely sounds like a class reloading issue. I think the class
> > reloader (trigged by AC::Reloader middleware) removes the Order model,
> > then the actual server tries to call the stream block and the model is
> > missing. (At least we know Rack streaming is working ;)
>
> > One solution would be to have the AC::Reloader middleware buffer all
> > the responses into a plain string it returns to the server. This
> > normally would be bad for performance, but its okay cause it would
> > only affect development.
>
> > On Mar 26, 2009, at 2:24 PM, Jeff wrote:
>
> > > I think render_text, when given a proc object, is broken in
> > > development mode; or, I'm not doing something right.
>
> > > Full explanation (it's short) is here:
> > >http://groups.google.com/group/rubyonrails-talk/browse_frm/thread/9a1...
Reply all
Reply to author
Forward
0 new messages