Lib folders and application controllers

On Feb 27, 2007, at 10:39 PM, James A. wrote:

class A

module C.

Since B explicitly refers to C, when Rails tries to reload B from
app/models/b.rb, it re-reads the class definition and includes C as
you’d expect.

The point here is that the only place where it states that A should
include C is a file that is only ever evaluated once, and that
information is lost when the target class is unloaded. This is what
plugin developers typically send includes to ActionController::Base,
not ApplicationController.

Ok, I understand that I think. The explicit include works, but
anything that might get executed from the init.rb will never get run
other than the first time.

So the plugin is never unloaded? If it was, the init.rb would have
to be executed again.

But then I didn’t understand your comment about the lesson learned
with Login+User engine. Are you saying it’s not possible/advisable
to have engines use services of other plugins/engines? I can’t have
a User engine that gets referenced by a Newsletter engine, for
example, or use the Liquid or Whitelist plugins from engine code?

Is that right?

app/models/user.rb:
class User
Include Monkey::UserMixin
end

vendor/plugins/monkey/model/user.rb
class User
Include Monkey::UserMixin
end

vendor/plugins/monkey/model/group.rb
class Group
Include Monkey::GroupMixin

  def test
    true
  end

end

vendor/plugins/monkey/lib/usermixin.rb
module Monkey
module UserMixin
def self.included(base)
base.class_eval do
has_and_belongs_to_many :groups

       def all_roles
         for group in self.groups
           result << group.all_roles
         end
       end
     end
   end
 end

end

vendor/plugins/monkey/lib/groupmixin.rb
module Monkey
module GroupMixin
def self.included(base)
base.class_eval do
has_and_belongs_to_many :users

       def all_roles
          return true
       end
     end
   end
 end

end

When I call user.all_roles for the second time, I get the

NoMethodError (undefined method `all_roles’ for #)

If I then do a Group.find(1) from a breakpoint, I get the

ArgumentError: A copy of ActiveRbacMixins::UserMixins::Core has been
removed from the module tree but is still active!

Also, it’s not just methods that are mixed in that are hosed.
Group.test also is not available, that is defined directly in the class.

Could it be that on the second time through, the app version of user
is unloaded, and thus the corresponding mixin is unloaded. But the
version of the model in the plugin is not unloaded, but mixin is
removed from the module. So now the engine model is there, partially
stripped, and gets used instead of the reloaded user model in app.
Yes, I’m grasping at straws.

encountered this error. Very weird.
directly to me. I’m very keen to resolve this, but I need to be able
to reproduce the behaviour…

Yes, ActiveRbac was modified to satisfy the new engine requirements
(not using config(), removing init_engine, etc). No other logic
changes.

I will see if I can recreate it in toy plugin.

Thanks for your help,
Brett

Had a day of yesterday, but what James describes, exactly happens to us

  • there is a model within a plugin
  • it has, say, method “do_something” defined directly in the class
  • on the second request, the model class is still available but the
    method has disappeared

One of my colleages has found a sollution, but hasn’t arived yet. I’ll
post our findings as soon as he’s in.

Regards,
Jeroen

James A. schreef:

Hi All,

My colleage posted an entry on my blog about this problem and I didn’t
even notice :slight_smile:
http://www.jeroenvandoorn.nl/index.php/2007/02/28/too-much-magic-will-kill-you/

Hope this helps.

Kind regards,
Jeroen van Doorn

Jeroen van Doorn schreef:

Oh, and of course:

before_filter :reinit_engines_in_dev

It is perhaps a little simple-minded, but this solved the problem for
me. In my application controller I put this:

def reinit_engines_in_dev
if ENV[‘RAILS_ENV’] == ‘development’
Rails.plugins.each do |plgin|
if File.basename(plgin.root) =~ /_engine/
IO.read("#{RAILS_ROOT}/#{plgin.root}/init.rb").each do |line|
eval(line) unless (line.blank? or (line =~ /^\s*#/))
end
end
end
end
end

=vg