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