Possible bug with render_text in 2.3.2

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

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 :wink:

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.

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

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 :wink:

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

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

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’