What's the best way to handle items in your engine's lib folder? I have a couple of support files I would normally place in my lib folder and then include in my application controller. In developing my engine, I placed these files in the lib folder within my engine. Then, I did what I would normally do and added the include code to the application controller in my engine. I quickly realized that this was being overwritten with the surrounding application's application controller, and not wanting to require those applications to delete their application controller, I just pasted the code into the surrounding application controller (there might be a better way to do this, but one of the lines is a before_filter). Anyway, that works when I actually run the application, but now, when I run my tests, I get an error saying: `const_missing': uninitialized constant ApplicationController::AuthenticatedSystem (NameError) So, I guess my question is, what is the best practice regarding both files in your engine's lib folder as well as including code in the surrounding application's application controller? Thanks, Trey
on 2007-02-16 19:47
on 2007-02-20 11:00
I'm not 100% sure this is what you mean, but are you trying to include a module into ApplicationController? It sounds like you're creating an application controller class *within* your plugin, which is not what you want to do. If you really want to have the module included into ApplicationController automatically whenever the plugin is loaded, try adding something like this to your init.rb: ActionController::Base.send(:include, MyModule) HTH, James
on 2007-02-20 23:46
Indeed, this is exactly what I needed for including the module. And I loaded the before_filter with ActionController::Base.send(:before_filter, :my_filter) One question, where exactly in the flow does the init.rb come in? I mean, could I also do ApplicationController.send(:include, MyModule) to be a little more precise? I tried and got a some errors about uninitialized constant ApplicationController, so I'm guessing that class isn't loaded yet. Oh well, what works works. Is there any drawbacks to adding these to the ActionController::Base instead of the ApplicationController? I realize that ApplicationController inherits from ActionController::Base (and thus it works), I am just curious. Trey
on 2007-02-21 10:51
At the point your plugins are loaded, it's best to assume that nothing specific to your application is available - including ApplicationController. Consider, for example, if ApplicationController had references (includes, method invokations) which were provided by plugins that are loaded *after* this one? It's definitely going to crash and burn. Another historical reason is that in development mode ApplicationController was unloaded and then reloaded for each request. This would mean that any additions you'd made to the class would be lost after the first time you hit your development server. ActionController::Base is a part of the framework, and so isn't reloaded since it's never expected to change. HTH James
on 2007-02-21 23:44
That makes sense. It just feels a little weird sending something to ActionController::Base (I'd rather programatically add these lines to the surrounding app's application controller), but I think I can get over it. One further question though: I mentioned in my last email, that I did the same thing with a before_filter and put the following in my init.rb ActionController::Base.send(:before_filter, :my_filter) This works when I run the site with script/server, but if I run my tests with rake test:plugins PLUGIN=my_plugin, it doesn't invoke the before_filter. I've placed a puts line at the top of the my_filter method, so I can see when it's called, and through scirpt/server it is called with every request, as expected, but through the tests, it never gets called. The odd thing is that I've verified that init.rb is getting called and that my other line in init.rb, ActionController::Base.send(:include, MyModule) is being loaded. Should I not be doing this with before filters? Or should I be doing something else in the test to make sure the before_filter is set up correctly. Trey
on 2007-02-21 23:51
The approach I've used is to place the relevant code in the my_engine.rb module under lib, then include MyEngine in application.rb That approach has worked fairly well for me. - Tony
on 2007-02-27 15:01
We're experiencing some problems which look like the earlier mentioned ones. Somehow the relations within our models are gone after one request. This isn't the case when we are in production mode, so it has something to do with loading. In the init.rb we are extending the ActionController::Base by using "ActionController::Base.class_eval do" if we use send on calls to ActiveRecord like permission.send(:find, :all) it only works on the first call. As soon as we reload the page, it breaks. Again in production mode it just works. We will be wading through the rails core and post back if we find something. Help is greatly appreciated. Kind regards, Jeroen van Doorn
on 2007-02-27 15:37
I have a similar problem with certain calls in my init.rb only being picked up on the first request.. It appears to me like init.rb is only getting run once during start-up. This would explain why the mixins disappear after the first request - when the entire environment gets reloaded, anything that was added in init.rb will not get added the second time! Having said that, other plugins are still being loaded and mixed in correctly on subsequent requests... I have a feeling it's to do with the way engines enhanced plugins are loaded but I'm not entirely sure how.. Tekin
on 2007-02-27 16:00
We have a workarround, but we think it's quite dirty! you could just add an empty model file to your apps model dir and just require the original model. In a test engine we don't have an init.rb and the relations work properly over there. Keep you posted. Jeroen Tekin Suleyman schreef:
on 2007-02-27 16:22
Do you think this may be related to the recent changes to the way dependencies are reloaded? http://weblog.rubyonrails.org/2006/8/11/reloading-revamped/ Also, I came across: Dependencies.log_activity = true In my case, I am directly accessing, and modifying another plugin's model in an init.rb. >From a quick scan of the dependency log, it looks like my model is getting reloaded during each request, which is happening after initialisation and thus overriding anything in the init.rb It looks like engines reloads all plugins after initialisation to add the engines enhancements, which would explain why modifications are picked up for the first request, as it happens after the app has been loaded. I guess the neat fix would be to get engines to reload after each request and not just in after_initialize()
on 2007-02-27 16:27
>> I guess the neat fix would be to get engines to reload after each >> request and not just in after_initialize() Or to not modify another plugin's model in an init.rb!!
on 2007-02-27 16:46
We're really lost. I don't have clue where to look. We're still going through rails and engines code, but we just don't get it at this moment. We're not modifying other models b.t.w., but if we don't use a init.rb at all it just works. A solution would be to put all the code in a lib and include it in the appcontroller, but I don't think this is a elegant solution. Anyway I really want to understand why things are going wrong. I'm going home, have a good night's sleep and have a look at it again tomorrow. @James Adam, do you have any clue on what we're doing wrong ? Kind regards, Jeroen van Doorn Tekin Suleyman schreef:
on 2007-02-27 16:46
On 2/27/07, Tekin Suleyman <tekin@raid.nu> wrote:
> It appears to me like init.rb is only getting run once during start-up.
This is definitely the case, and is typically why you don't mix
modules from plugins into *anything* that will get reloaded. For
example, if you're adding methods to all controllers, you should
include your module into ActionController::Base, not
ApplicationController. The same applies for the rest of your
application...
on 2007-02-27 17:22
Of course. I need to rethink my architecture, specifically how my plugins integrate together. On the most simple level, I have a cms plugin that provides a generic cms, and other plugins will add additional functionality to it (catalogue/ecommerce, etc). I basically need to tell my Page model in the cms plugin that it has additional behaviours. At the moment, I simply have a class attribute array called @behaviours which the other plugins are adding to in their init.rb's. Obviously this is unworkable. Is there an obvious way to modify models in other plugins in such a way that it get's picked up on reloads? My current thinking is that maybe the Page model should check for and load any enhancements into itself, looking in each plugin..
on 2007-02-27 17:32
On 2/27/07, Tekin Suleyman <tekin@raid.nu> wrote: > Obviously this is unworkable. Is there an obvious way to modify models > in other plugins in such a way that it get's picked up on reloads? This is one of the occasions where you might actually want to adopt "less magic". Is there any way you could architect it so each plugin contributes a feature to a Page model within the application? I.E. class Page < AR::Base with_cms_features # from the cms plugin and_versioning # from your versioning plugin, for instance format_with_markdown # from your text processing plugin # ... end The lesson learned from the login+user engine saga is: don't try to have plugins depend on other plugins. It gets way too complicated. Is there any way you can avoid this? I appreciate that this might really be the advice you need at the moment; if I think of anything tonight I'll fire of another mail to the list.
on 2007-02-27 17:41
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? 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. 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. 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! This worked fine in the previous Rails and Engines. So this is new behavior. What's the best way to fix it?
on 2007-02-27 17:54
I think my description may have not been very clear, there is infact very little magic going on at all! Each page has a behaviour attribute. For most pages, this is simply left blank. If however, it is set to something, like for example, 'contact' or 'news', when the page is rendered, extra 'stuff' is added to the rendered page using partials. This all works fine, all I want is for the page model to have a list of potential behaviours - nothing more than an array of strings - which is what I need to add to from future plugins.. Does that make sense? I guess I could put this in the application somewhere, it just makes sense for it to happen in the plugins. Thanks for all the great work on engines by the way, it's made it much easier for us to share rails code between our projects, the way it should be.
on 2007-02-27 18:08
Why create the model file at all in your app? Couldn't you simply open the module and override/add your functions?
on 2007-02-27 18:09
On 2/27/07, Brett Walker <walkerbl@fastmail.us> 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. > 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? > 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... Cheers
on 2007-02-27 18:10
Sorry, what I meant was; maybe having the second model file in your app is what's causing the problem? http://api.rails-engines.org/classes/Engines/Rails... s.html >> Why create the model file at all in your app? Couldn't you simply >> open the module and override/add your functions?
on 2007-02-27 21:13
On Feb 27, 2007, at 10:39 PM, James Adam 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 #<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. > 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
on 2007-03-01 08:58
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 Adam schreef:
on 2007-03-01 09:32
Hi All, My colleage posted an entry on my blog about this problem and I didn't even notice :) http://www.jeroenvandoorn.nl/index.php/2007/02/28/... Hope this helps. Kind regards, Jeroen van Doorn Jeroen van Doorn schreef:
on 2007-03-05 15:39
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
Please log in before posting. Registration is free and takes only a minute.
Existing account
(Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
Log in with Google account | Log in with Yahoo account
No account? Register here.