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

> On 2/27/07, Brett Walker <[EMAIL PROTECTED]> wrote:
>> Really?  You can't mix a module from a plugin into your app - you
>> have to add it into Rails??  That just seems somehow wrong to me.  I
>> thought I could mix a module in anywhere I want - if the main class
>> gets reloaded, why won't it's dependencies get reloaded as well?  Is
>> that in general, or only with engine plugins?
>
> You're talking about a few things here. Imaging the situation:
>
> app/models/a.rb:
>   class A
>   end
>
> app/models/b.rb
>   class B
>     include C
>   end
>
> vendor/plugins/monkey/lib/c.rb
>   module C
>   end
>
> vendor/plugins/monkey/init.rb:
>   A.send(:include, C)
>
> When your application first loads, init.rb is evaluated, and C is
> included into A. C is also included into B, as per normal. At the end
> of the request, A and B are dutifully unloaded to make way for any
> changed versions. The next request causes Rails to try to find A
> again, which it does in app/models/a.rb, and so it loads that file.
> However, because vendor/plugins/monkey/init.rb is only ever evaluated
> at the start of the request cycle, the "new" A will NOT include the
> 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?

>
>> In any case, I'm running into the same problem with ActiveRbac.
>> First run, everything works.  Second run, methods for a model just
>> disappear.  In order to create a model that doesn't have to be
>> completely copied into the application to be overridden, they created
>> a model file that simply includes a mixin module with all the real
>> code.  So to override the model in my app I create the model file,
>> include the mixin files, and my new functions.
>
> That's basically what's going on with class B, above.
>
>> The problem seems to be in one of the models that I don't override.
>> First run everything is fine, second run *non* of it's methods are
>> found.  It's not just the mixed in ones.
>
> Just to be sure that I know what you're referring to:
>
> * 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
>
> 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 #<Group>)

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.

>>
>>
>> I added a method straight
>> in to the model - it wasn't available on the second run.  Here is an
>> interesting error I get if I try to do a find on the model:
>>
>> ArgumentError: A copy of ActiveRbacMixins::UserMixins::Core has been
>> removed from the module tree but is still active!
>
> I can't speak for ActiveRbac specifically, but I've never, ever
> encountered this error. Very weird.
>
>> This worked fine in the previous Rails and Engines.  So this is new
>> behavior.  What's the best way to fix it?
>
> Since any version of ActiveRbac that was compatible with the engines
> plugin 1.1.x releases isn't compatible with the 1.2 release, you
> should also note that ActiveRbac must've changed.
>
> If you can reproduce this in a clean project using the engines plugin
> and a toy plugin to contain the model, please zip it up and email it
> 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
_______________________________________________
engine-users mailing list
[email protected]
http://lists.rails-engines.org/listinfo.cgi/engine-users-rails-engines.org

Reply via email to