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

Brent D. wrote:

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

I think that you can do it in one of these two ways:

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’

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