application_controller.rb not being loaded - ruby-on-rails

In my Rails app (running on rails 2.3.5, ruby 1.8.7), my application_controller.rb file is not being loaded automatically when config.cache_classes = false in environment.rb.
It's in the load path. If I add require 'application_controller' to the end of my environment.rb or set cache_classes = true, then the app works fine.
Why wouldn't it load when classes are not being cacehed?

This sounds like it for some reason your app is still using 2.3.2 gems for ActiveSupport. It is probably still looking for application.rb, and the undefined pretty_inspect also lends itself to a versioning problem.
First, make sure that you don't have something like this at the top of your environment.rb:
RAILS_GEM_VERSION = '2.3.2'
If you don't, then at the bottom of the your environment.rb find out if something else is setting it wrong by adding this:
puts RAILS_GEM_VERSION

The application code is loaded as part of the Rails::Initializer.run method in environment.rb. It's almost the last step. I know of nothing that would prevent the application controller from loading -- my only suggestion is to make sure there is not a typo in the filename /app/controllers/application_controller.rb and to make sure there is not a typo in the class definition class ApplicationController < ActionController::Base.
I'd like to add that the first part my last comment applies to production mode, where the classes are eager-loaded in Rails::Initializer#load_application_classes, but in development mode it does not cache classes, so loads them as part of a const_missing catcher each request. See ActiveSupport::Dependencies#load_missing_constant.

I have another idea. You mentioned that it is in the load path, but I would confirm later on that it stays in the load path and that a plugin doesn't mess it up or something. At the very bottom of environment.rb (last line) add this line:
puts ActiveSupport::Dependencies.load_paths.pretty_inspect
Then run a script/server from the command line and take a look at the load paths, making sure /path_to_your_rails_app/app/controllers shows up.

The problem is definitely related to config.cache_classes = false; if I switch this to true then the problem disappears.
(Thanks #Ben Lee for leading me towards this)

Related

Reload rails initializers

In application.rb, I have
config.autoload_paths += %W(#{config.root}/lib
So when I modify a class under lib, my code is reloaded.
However, when I tried adding config/initializers to autoload, I noticed my code doesn't get updated.
If I'm writing an extension for the string class, I have to restart rails every time I modify my code.
Please advise?
Initializers are only loaded when starting rails (and never reloaded). When tinkering in config/initializers you will have to restart rails every time.
Of course, you could make sure your code is defined in /lib so you can still make sure it works, by using your test-suite.
E.g. in lib/speaker.rb write
module Speaker
def speak
puts "Ahum, listen: #{self.to_s}"
end
end
and in your initializer you could then do something like
class String
include Speaker
end
While this will still only get loaded when starting rails, you can develop and test your module more easily.
Hope this helps.
Initializer files are loaded only once when the rails server is started. Restart the server when initialzers values are changed.
For further information see the rails initialization guides.
Auto Reloading 'lib' on change
You can auto reload lib files. Follow Link Autoload and Reload lib directory on change
In Configuring Rails Applications: config.reload_classes_only_on_change enables or disables reloading of classes only when tracked files change. By default tracks everything on autoload paths and is set to true. If config.cache_classes is true, this option is ignored.

Why does Rails not refresh classes on every request (despite configuration)?

I recently started having to restart my development server every time I change my code. My development.rb file still has this line:
config.cache_classes = false
I tried using the debugger verify that this value has stuck around. To do this I set my configuration to a global variable in environment.rb:
$my_initializer = Rails::Initializer.run do |config|
...
end
then I put a debugger line in one of my controllers so I could do this:
(rdb:2) $my_initializer.configuration.cache_classes
false
So that eliminated the possibility that the value of cache_classes was getting set to true somewhere else. I've tried using both Mongrel and WEBrick and it still happens.
What else might be causing Rails not to reload my code with every request?
I am running:
Mongrel 1.1.5
WEBrick 1.3.1
Rails 2.3.8
Ruby 1.8.7 p253
EDIT:
at #Daemin 's suggestion I checked that the mtime of my files are are actually getting updated when I save them in my text editor (Textmate)
merced:controllers lance$ ls -l people_controller.rb
-rwxr-xr-x 1 lance staff 2153 Act 10 18:01 people_controller.rb
Then I made a change and saved the file:
merced:controllers lance$ ls -l people_controller.rb
-rwxr-xr-x# 1 lance staff 2163 Oct 11 12:03 people_controller.rb
So it's not a problem with the mtimes.
So it turns out that config.threadsafe! overwrites the effect of config.cache_classes = false, even though it doesn't actually overwrite the value of cache_classes (see my question for proof). Digging around a bit more in the Rails source code might illuminate why this might be, but I don't actually need threadsafe behavior in my development environment. Instead, I replaced my call to config.threadsafe! in environment.rb to
config.threadsafe! unless RAILS_ENV == "development"
and everything works fine now.
If anyone else has this problem the solution was the order: config.threadsafe! has to come before config.cache_classes. Reorder it like this to fix it:
...
config.threadsafe!
config.cache_classes = false
...
answer from: Rails: cache_classes => false still caches
I suspect that the classes you are expecting to refresh have been 'required' somewhere in your configuration. Note that Rails' dependency loading happens after Ruby's requires have happened. If a particular module or class has already been required, it will not be handled by Rails' dependency loader, and thus it will not be reloaded. For a detailed explanation, check out this article: http://spacevatican.org/2008/9/28/required-or-not
Despite the fact that the threadsafe! solution works, I also wanted to point out for your benefit and the others that may come in after the following...
If you're editing engine code that is directly in your vendor/engines directory, those files will not be updated without a restart. There may be a configuration option to enable such functionality. However, this is very important to remember if you have used engines to separate large bits of functionality from your application.
My guess would be that it's not reloading the classes for each request because they haven't changed between requests. So the system would note down the last modified time when the classes are loaded, and not reload them until that changed.

Where do you put your Rack middleware files and requires?

I'm in the process of refactoring some logic built into a Rails application into middleware, and one annoyance I've run into is a seeming lack of convention for where to put them.
Currently I've settled on app/middleware but I could just as easily move it to vendor/middleware or maybe vendor/plugins/middleware...
The biggest problem is having to require the individual files at the top of config/environment.rb
require "app/middleware/system_message"
require "app/middleware/rack_backstage"
or else I get uninitialized constant errors on the config.middleware.use lines. That could get messy very quickly. I'd rather this was tucked away in an initializer somewhere.
Is there a conventional place to put this stuff?
The specific answer I'm looking for with this bounty is: where can I put the require lines so that they are not cluttering the environment.rb file but still get loaded before the config.middleware.use calls? Everything I have tried leads to uninitialized constant errors.
Update: Now that we're using Rails 3.0, I treat a Rails app like any other Rack app; code files for middleware go in lib (or a gem listed in Gemfile) and are required and loaded in config.ru.
As of Rails 3.2, Rack middleware belongs in the app/middleware directory.
It works "out-of-the-box" without any explicit require statements.
Quick example:
I'm using a middleware class called CanonicalHost which is implemented in app/middleware/canonical_host.rb. I've added the following line to production.rb (note that the middleware class is explicitly given, rather than as a quoted string, which works for any environment-specific config files):
config.middleware.use CanonicalHost, "example.com"
If you're adding middleware to application.rb, you'll need to include quotes, as per #mltsy's comment.
config.middleware.use "CanonicalHost", "example.com"
You can put it in lib/tableized/file_name.rb. As long as the class you're trying to load is discoverable by its filename, Rails will automatically load the file necessary. So, for example:
config.middleware.use "MyApp::TotallyAwesomeMiddleware"
You would keep in:
lib/my_app/totally_awesome_middleware.rb
Rails catches const_missing and attemts to load files corresponding to the missing constants automatically. Just make sure your names match and you're gravy. Rails even provides nifty helpers that'll help you identify the path for a file easily:
>> ChrisHeald::StdLib.to_s.tableize.singularize
=> "chris_heald/std_lib"
So my stdlib lives in lib/chris_heald/std_lib.rb, and is autoloaded when I reference it in code.
In my Rails 3.2 app, I was able to get my middleware TrafficCop loading by putting it at app/middleware/traffic_cop.rb, just as #MikeJarema described. I then added this line to my config/application.rb, as instructed:
config.middleware.use TrafficCop
However, upon application start, I kept getting this error:
uninitialized constant MyApp::Application::TrafficCop
Explicitly specifying the root namespace didn't help either:
config.middleware.use ::TrafficCop
# uninitialized constant TrafficCop
For some reason (which I've yet to discover), at this point in the Rails lifecycle, app/middleware wasn't included in the load paths. If I removed the config.middleware.use line, and ran the console, I could access the TrafficCop constant without any issue. But it couldn't find it in app/middleware at config time.
I fixed this by enclosing the middleware class name in quotes, like so:
config.middleware.use "TrafficCop"
This way, I would avoid the uninitialized constant error, since Rails isn't trying to find the TrafficCop class just yet. But, when it starts to build the middleware stack, it will constantize the string. By this time, app/middleware is in the load paths, and so the class will load correctly.
For Rails 3:
#config/application.rb
require 'lib/rack/my_adapter.rb'
module MyApp
class Application < Rails::Application
config.middleware.use Rack::MyAdapter
end
end
I'm not aware of a convention, but why not put it in the /lib directory? Files in there get automatically loaded by Rails.
You could create an initializer which requires the necessary files and then leave the files wherever you want.
According to this the initializers are executed before the rack middleware is loaded.
The working solution I have so far is moving the middleware requires to config/middleware.rb and requiring that file in environment.rb, reducing it to a single require which I can live with.
I'd still like to hear how other people have solved this seemingly basic problem of adding middleware to Rails.

Rails: filter defined in lib file required in environment.rb disappears from filter_chain in production environment. Why?

In my rails application, I have a file in lib that, among other things, sets up a filter that runs on all controllers.
When running under development environment, everything runs fine. However, under production the filter goes missing. Funny thing is, by inspecting the filter_chain, I noticed other filters remain, eg. those defined in plugins, or later in the specific controller class.
I've tested this with both rails edge and v2.3.0.
Testing update:
I've now tested with older rails and found the issue to be present back to v2.1.0, but not in v2.0.5, I've bisect them and found the 986aec5 rails commit to be guilty.
I've isolated the behavior to the following tiny test case:
# app/controllers/foo_controller.rb
class FooController < ApplicationController
def index
render :text => 'not filtered'
end
end
# lib/foobar.rb
ActionController::Base.class_eval do
before_filter :foobar
def foobar
render :text => 'hi from foobar filter'
end
end
# config/environment.rb (at end of file)
require 'foobar'
Here's the output I get when running under the development environment:
$ script/server &
$ curl localhost:3000/foo
> hi from foobar filter
And here's the output for the production environment:
$ script/server -e production &
$ curl localhost:3000/foo
> not filtered
As alluded to before, it works fine for any environment when I do the same thing via plugin. All I need is to put what's under lib/foobar.rb in the plugin's init.rb file.
So in a way I already have a workaround, but I'd like to understand what's going on and what's causing the filter to go missing when in production.
I conjecture it's something in the different ways Rails handles loading in the different environments, but I need to dig deeper.
update
Indeed, I've now narrowed it down to the following config line:
config.cache_classes = false
If, in production.rb, config.cache_classes is changed from true to false, the test application works properly.
I still wonder why class reloading is causing such thing.
Frederick Cheung on the Rails list had the answer:
Because cache_classes does a little more than just that. The way
before filters work, if Foo < Bar then only those filters defined in
Bar at that point will be inherited by Foo - adding them to Bar at a
later date will not do anythingn
In development mode, the app starts, your file is required, the filter
added to ActionController::Base. Later the first request comes along,
the controller is loaded and it inherits that filter.
When cache_classes is true then all of your application classes are
loaded ahead of time. This happens before your file is required, so
all of your controllers already exist when that file is run and so it
has no effect. You could solve this by requiring this file from an
initializer (ensuring it runs before app classes are loaded), but
really why wouldn;t you just put this in application.rb ?
Fred
My real case was actually way more involved, and this is the way I found to solve the issue:
config.after_initialize do
require 'foobar'
end
The after_initialize block runs after the framework has been initialized but before it loads the application files, hence, it'll affect ActionPack::Base after it's been loaded, but before the application controllers are.
I guess that's the generally safe way to deal with all the preloading that goes on in production.
Drop a ruby script in
RAILS_ROOT\config\initializers
that contains
require "foobar.rb"
This invokes the before_filter for me.

How does class cacheing work in rails 2.2+

I have a rails application that patches ActiveRecord with a hand-coded validator.
The patch is made by adding the following lines in config/environment.rb
Rails::Initializer.run do |config|
...
end
class ActiveRecord::Base
include MtLib::DBValidations
end
This works fine in production mode i.e. with
config.cache_classes = true
however it does not work in development with cache_classes set to false.
The error thrown is
ArgumentError (A copy of MtLib::DBValidations has been removed from
the module tree but is still active!):
My question is what is the process that is followed when cache_class is set to false. Does Rails re-run any of the initialization methods? If not then where is the best place for me to put my patch to ensure that it is in all models and survives a classes reload?
I have tried adding the patch to config/initializers/active_record_patch, however this is not re-run when the classes are reloaded.
The solution to this, provided by Frederick Cheung on the Ruby On Rails google group add the directory containing the loaded class into the load_once_path array.
I edited environment.rb to look like this
config.load_paths +=
%W( #{RAILS_ROOT}/lib/soap_clients/carefone #{RAILS_ROOT}/lib/mt_lib)
# Make sure load_once_paths is a subset of load_paths
config.load_once_paths += %W( #{RAILS_ROOT}/lib/mt_lib)
And now this works in development mode without having to reload the server on every request

Resources