Proper way to extend an app engine model

Can anyone tell me the "proper" way to extend a model provided by an app engine (or any plugin for that matter).

I'm attempting to extend an app engine model by adding a has_many :through. So I've got lib/myplugin_ext.rb and I'm requiring that file in evironment.rb. My extension uses class_eval to add the association.

This works fine in the console for viewing and adding stuff to the has_many :through association, but in dev mode -- after the first request -- if I try to add to the has_many :through, I get "TypeError: Can't dup NilClass".

Because it works in the console but not in development mode after the first request, this leads me to believe that it's a weird problem with the reloader and how I'm extending the class. I've tried virtually everything I can think of (aside from just moving the models from the app engine into my app directory and modifying it there, which works...), but I can't seem to avoid this error any other way.

I tried the "unloadable" suggestion posted here: Can't dup NilClass… maybe try `unloadable` – Daniel X's Blog

Adding unloadable to the app engine model only seemed to make the situation worse. The app engine model gets reloaded without the extension at all on subsequent requests.

I isolated the problem in a blank app and posted it here on github: http://github.com/brentd/cantdupnilclass/tree/master

The stack trace is also available at that repo.

If I'm doin' it completely wrong, please tell me what would help. Much appreciated :slight_smile:

Brent

I am experiencing the same problems as Brent: when a plugin extends an application model, things work as expected in production mode while development mode is buggy. I tried both of Paul's suggestions, but still no success ...

-Anders

I am also experiencing these problems, any news on this?

Thanks.

The problem is that your extensions (in lib/blog_engine_ext.rb) are only being loaded once, at the bottom of environment.rb (the require statement).

When the system reloads, there's nothing to trigger the re-inclusion of your code, and so the Post model ends up in a bit of a freaky state.

The solution is simple; any kind of functionality injection should be performed in a config.to_prepare block. This goes for the contents of init.rb, along with the approach that you're taking.

I've changed environment.rb as below, and the app now works for every subsequent request:

    Rails::Initializer.run do |config|       # etc       config.to_prepare do         # use load to ensure that the file is actually evaluated every time         load 'blog_engine_ext.rb'       end     end

    # no require needed.

Hope that helps,

- James