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

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.

Related

Ruby on Rails: configure web_console in initializer

I am using the web_console gem and I would like to add some IPs to the whitelist. For reasons that would probably go to far to explain, can't simply add something to the config/application.rb or config/environments/development.rb. However I can create an initializer config/initializers/.
I simple tried this in config/initializers/99-webconsole.rb, but while the file is loaded (--> debug message is shown), the web console does not seem to pick up my settings.
Rails.application.configure do
config.web_console.whitelisted_ips = '10.10.0.0/16'
p "Debug: this is loaded."
end
I assume it's related to some kind of race condition? Providing the same line in config/environments/development.rb works, but as said, I sadly can not change that file.
Based on this code https://github.com/rails/web-console/blob/e3dcf4c588af526eafcf1ce9413e62d846599538/lib/web_console/railtie.rb#L59
maybe there is a code in your initializer that configuring config.web_console.permissions, so your whitelisted_ips config is ignored
whitelisted_ips is also deprecated
and have you checked that you are using v4.2.0, the permissions was buggy and fixed by this commit https://github.com/rails/web-console/commit/6336c89385b58e88b2661ea3dc42fe28651d6296

Does Rails have to lazy load everything? Or does it?

When I notice things like: 0.15s in my specs for a simple method like:
class String
def to_slug
(self.dup).gsub(/["']/, '').gsub(/#/, 'at').gsub(/&/, 'and').parameterize
end
end
I start to ask myself what is going on, so after benching the method without parameterize I decided this was a problem inside of parameterize and not necessarily with the method itself but, well, with the way it's loaded, it seems to me like it's lazily loaded when Monkey Patches like that should be eager loaded, it is causing latency where it should not exist IMO. So my questions are, does Rails really lazily load the file that contains parameterize and is there way to convince Rails to eager load patches to String and other stdlib's.
Calling config.threadsafe! in your config/environments/test.rb should force all code to be loaded at boot time. Note that this will set cache_classes to true, so don't use it in development environment or you will lose code reloading.
Another way would be to change config.eager_load_paths to include the directory you want to load.
Resources:
Aaron Patterson explains config.threadsafe! in his article Removing config.threadsafe!.
The Rails guide on configuration has a lot of information on each option.

application_controller.rb not being loaded

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)

Rails friendly error page in development

In my config/environments/development.rb I have the following line:
config.action_controller.consider_all_requests_local = true
which means I should get all the ugly error stuff when in development environment. But for some reason my app has suddenly started giving me the pretty error page you're supposed to see on production.
Is there possibly some place where this may have been over-ridden? Other people are working on the project as well so maybe one of them did something to cause it.
Old post, but just in case someone finds this like I did ...
I'm pretty sure that when the
config.action_controller.consider_all_requests_local = true
is set, local_request? is never called.
I would dump the config value at runtime and see what it is.
How do I access a Rails configuration value during runtime?
(in rails 3.2)
config.consider_all_requests_local = true
Someone might be overriding the local_request? (api) method somewhere, it's a way to always show the proper error page.
I just answered someone else's question on how to override it. You basically just would put a method in one of the controllers (like ApplicationController) like this:
def local_request?
false
end
So, possibly someone used that somewhere. Do a full project search in textmate or using grep.
This just happened to me and it turned out it was just because I had special characters in the page I was trying to load. I added # encoding: utf-8 to the top of the file with the special characters and everything worked.

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.

Resources