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.)
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.
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.
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.
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.
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’