views:

275

answers:

3

I am extending a class (which is in a plugin) by including a module, this is done in an initializer.

require 'qwerty/core/user'
User.send :include, Qwerty::Core::Extensions::User

However in development before every request (and after reload! is called in the console) all models are reloaded but because the initializers are not run again the module is not included. Leaving a model with 'missing parts'.

Because the model is in a plugin it does not seem wise to include code directly in the class which would be the usual approach.

For now I have simply added a before_filter which includes the module if in development environment. But I have copy/pasted and have duplicate code in the initializer and application controller.

  # Class extensions in initalizers are over-writtern each request
  def development_loading
    if RAILS_ENV == 'development'      
      User.send :include, Qwerty::Core::Extensions::User
    end
  end

Is there a better way?

As a side note the plugin is mine, so I could add code in to it, but the extensions held in the module may not always be present...

A: 

Why do you use initializers to include functionality?

Try the following instead:

require 'qwerty/core/user'
class User < ActiveRecord::Base
  include Qwerty::Core::Extensions::User
  # bla bla
end
khelll
Because he only wants that code included in development mode.
SFEley
Because the model is in a plugin, which while it is a plugin i am developing, i am treating it like a third party plugin, so I dont want to touch the code in it. So I must extend those classes from the outside.
Kris
+1  A: 

At first I was going to advise something about adding a 'development' directory to the front of your load path in development mode, so that your revisions would always get reloaded first... But then it occurred to me that you said something confusing.

The model you're trying to extend. It's in a plugin? Plugins aren't supposed to be reloaded by default in development mode, unless the app explicitly says they should in its configuration by setting Config.reload_plugins? to false.

But if, for some reason, your plugin is reloading anyway and you don't want it to, you can put this in your plugin's init.rb to explicitly say it shouldn't reload:

Dependencies.load_once_paths << lib_path

See the Rails docs on the Configuration class for more detail: http://api.rubyonrails.org/classes/Rails/Configuration.html#M002536

SFEley
Yes, I have reload_plugins? set to true because I am actively developing the plugin. I want to work out a way of extending the models in the plugin from the Rails app (ie. without touching the plugin code). A little confusing yes! In my init.rb I have: if RAILS_ENV == 'development' ActiveSupport::Dependencies.load_once_paths.reject!{|x| x =~ /^#{Regexp.escape(File.dirname(__FILE__))}/}end
Kris
I think my problem is because I am trying to do two things at once - work on a plugin (reload it every request) and extend the plugin from the Rails app. A bit catch 22...
Kris
Why? Why give yourself all these constraints? You don't want to add development code to the plugin, you don't want to load it just once, and you want to reverse the _idea_ of a plugin by extending your plugin from your app (which is philosophically backwards). What do you gain from all these special cases? Is adding some `if RAILS_ENV=='development'` conditions into your plugin going to break something? You could always take it out again later, or put the extensions in files that only live in a special Git branch. Quit fighting the river. Go with the flow. Let Rails be Rails. Get it done.
SFEley
+1  A: 

environment.rb

config.to_prepare do
  User.send :include, Qwerty::Core::Extensions::User
end

The code is the block is run before every request in development mode and once in production mode.

Kris