views:

46

answers:

1

I have a Rails 3 app that defines some classes like normal. I am trying to figure out how to reopen one of those classes within a plugin (generated by "rails generate plugin ..."), and have both of the files (the file in the app itself and the file in the plugin) automatically reload on every request in development mode.

A simple example would be:

# root/lib/person.rb
class Person
  Core = 1
end

# root/vendor/plugins/plugin1/lib/person.rb
class Person
  Plugin = 2
end

# root/app/views/home/index.html.erb
<%= Person::Core %> ... <%= Person::Plugin %>

When that view is rendered, I get an error that Bike::Plugin is uninitialized. I have added both root/lib and root/vendor/plugins/plugin1/lib to my autoload_paths (ideally the plugin would add that in its init.rb or somewhere similar, but one thing at a time).

How do I go about this? autoload_at kind of looks like it might help, if I can tell it to autoload the Person class from both locations explicitly, but I have not had any luck (I am completely new to it though, so I may be passing the wrong arguments, etc). In the end I want to do this with classes defined in the standard places (models in particular) and not just lib as well.

A: 

one good way plugins can override earlier definitions for any class previously defined (either your libs, or rails internals etc):

#vendor/plugins/myawesomeplugin/lib/person.rb
Person.class_eval do
  Plugin = 2
  # override methods here too if you want
  def name
    "hacked"
  end
end

I've used this approach to write plugins before and overload active record

However, I'm not sure if it's possible to get plugins to auto reload in development mode, they usually reload only when you restart your server in dev mode.

Jeremy
Thanks for the idea. It doesn't appear to be working for me, I think because the root/lib/person.rb defines the Person class and is autloaded. vendor/plugins/plugin1/lib/person.rb is not being loaded at all.
Andy Morris
do you have a file `vendor/plugins/plugin1/plugin1.rb` which contains a line such as `require "person"`, I think plugins are loaded via requiring files that match `vendor/plugins/*.rb` so for a multi-file plugin you typically have one rb file at the base that require all the others that are down a directory etc.
Jeremy
Yes, but if I require vendor/plugins/plugin1/lib/person.rb from that file, whatever is defined in person.rb only exists for the first request. I think this happens because the app/lib/person.rb is autoloaded, which removes and redefines the Person constant on each new request, and then the person.rb in the plugin is not loaded again.
Andy Morris
if you suspect that's the case try putting some `puts "loaded lib/person.rb"` and `puts "loaded vendor overload"` in your code (or `debugger` statements) to see when classes are getting reloaded
Jeremy