I think I understand the basics of requiring and including modules* in Ruby on Rails, but I can't figure out what's going on with an issue I'm having. I'm using Ruby 1.9.3 with Rails 3.2.1.
I have a module called Utils in /lib/_utils.rb, which currently just has some logging functions in it. In most other files in the app, I'm able to execute the following code and use the logger without any problem:
logger = Utils::SingletonLogger.get_logger
Note that in model code, I generally use an instance variable instead of a local variable, and that seems to work fine as well.
Also note that this does NOT require me to have
include Utils
in the code.
The problem is that, in at least one controller, I have to explicitly require and include the module before it will work. Well, usually anyway. Most of the time I get a NameError because it doesn't recognize Utils as a constant. Other times, it throws a ransack error. And once it a great while, it just works. If I add just the include Utils line, I get a similar NameError, though with a shorter error message.
And best of all, this only happens in the test environment, and not in my local dev instance.
For now, I've commented out all the logging in this one file, but I'd like to understand what's going on. I've added
config.autoload_once_paths += %W(#{config.root}/lib)
to application.rb, thinking this would insure that the actual code is available to any file in the application. I guess I'm supposed to need
include Utils
in every file that uses this module, but I don't understand why that doesn't seem to be required in other files, or why I should have to re-require the module file in this controller.
I'd appreciate any insight or guidance.
*Briefly - require/load reads the module's actual source code file into memory, include makes the module's methods available in a different file. I assume that I really only want to require/load a file once per instance of the application - that having it executed every time a new class is used is unsightly at best, and inefficient at worst.
I think the problem involved some combination of the following:
The module's file name didn't match the name of the module, so it didn't get picked up by the autoload.
I had an explicit require statement in a couple of files, but not others. I think when the files containing the require were executed before ones that weren't, the system could find the module, otherwise, it couldn't.
At least during the troubleshooting, I sometimes had the include statement outside of class definitions, which apparently is non-standard at best, meaningless at worst.
I used the module name as a prefix, which seems to work okay when everything else is set up correctly, but may have confused the interpreter at other times. I think this is standard when calling module methods directly, and it may mean that you don't have to include the module, though I'm not sure on that point yet.
I had a model's initialize method overridden, which may not have contributed to this problem, but did throw exceptions that interfered with debugging.
I still don't know why this flaked out in test, but not in dev.
I use Rails 3.2.11
Please follow the path
Users ▸ [your username]▸ .rvm ▸ gems ▸ ruby-1.9.3-p545 ▸ gems ▸ railties-3.2.11 ▸ lib ▸ rails ▸ engine
access file : configuration.rb
replace
paths.add "lib", :load_path => true
by
paths.add "lib", :eager_load => true
Hope this help!
Related
This is a very basic question, but I can't find exactly the answer I need.
I have the following code in trunk/app/models/parsers/my_file.rb in my dev environment:
def initialize
...
#logger = Utils::SingletonLogger.get_logger
#logger.debug("Instantiating my_file object")
end
It runs fine.
But when I deploy it to the test environment (all code should be identical, but I'm not sure where to start looking for differences if there are any), Rails complains that it can't find Parsers::MyFile::Utils. The Utils module I want to use is in app/lib/my_utils.rb. This makes me think that Rails is creating some sort of namespace for the code in the parsers sub-directory, and only looking there for the Utils module, but I haven't been able to figure out how to make it work for me. Is there some main, application level prefix I can use to specify to look outside of the current directory structure?
I've tried adding require 'my_utils' and require_relative '../../../lib/my_utils.rb'. The former can't find the file, the latter just throws the same error as when I don't have any require at all. I'm not sure if I should have to require this or not.
In any case, I clearly don't quite understand how to refer to code in modules in a different directory, I don't understand when/why rails needs an explicit path at some times/environments but not others, and I don't know how to make Rails look outside of the current file for code. Any help with any of these would be appreciated.
Oh, I'm using Ruby 1.9.3, and rails 3.2.1.
Edit: It just started working, without any changes to the application.rb or environment files. It doesn't even have a require in the current version. Is there any obvious reason for it not to work at first, then to work after another server restart? (I'm pretty sure I restarted it after the code went in - I don't think I just forgot to do that before.)
Anyway, thanks for your help - I really do appreciate it.
You can manually add directories you want to include in application.rb. Might want to make sure in your application.rb or test.rb config files you have this autoload_paths in there, yours might be specific to your development.rb file.
config.autoload_paths += %W(#{config.root}/lib/)
I read a post about the rails load_paths, here is the link.
But, I am still confused about the difference between the autoload_paths and eager_load_paths:
I have tested them in a newly created Rails 4 project. It seems that they run the same way, that auto-reload in the development mode but in the production mode.
Author of the linked article here. Here's an attempt to clear up the confusion, going off of #fkreusch's answer.
In Ruby you have to require every .rb file in order to have its code run. However, notice how in Rails you never specifically require any of your models, controllers, or other files in the app/ dir. Why is that? That's because in Rails app/* is in autoload_paths. This means that when you run your rails app in development (for example via rails console) — none of the models and controllers are actually required by ruby yet. Rails uses special magical feature of ruby to actually wait until the code mentions a constant, say Book, and only then it would run require 'book' which it finds in one of the autoload_paths. This gives you faster console and server startup in development, because nothing gets required when you start it, only when code actually needs it.
Now, this behavior is good for local development, but what about production? Imagine that in production your server does the same type of magical constant loading (autoloading). It's not the end of the world really, you start your server in production, and people start browsing your pages slightly slower, because some of the files will need to be autoloaded. Yes, it's slower for those few initial requests, while the server "warms up", but it's not that bad. Except, that's not the end of the story.
If you are running on ruby 1.9.x (if I recall correctly), then auto-requiring files like that is not thread safe. So if you are using a server like puma, you will run into problems. Even if you aren't using a multi-threaded server, you are still probably better off having your whole application get required "proactively", on startup. This means that in production, you want every model, every controller, etc all fully required as you start your app, and you don't mind the longer startup time. This is called eager loading. All ruby files get eagerly loaded, get it? But how can you do that, if your rails app doesn't have a single require statement? That's where eager_load_paths come in. Whatever you put in them, all the files in all the directories underneath those paths will be required at startup in production. Hope this clears it up.
It's important to note that eager_load_paths are not active in development environment, so whatever you put in them will not be eagerly required immediately in development, only in production.
It's also important to note that just putting something into autoload_paths will not make it eager-loaded in production. Unfortunately. You have to explicitly put it into eager_load_paths as well.
Another interesting quirk is that in every rails app, all directories under app/ are automatically in both autoload_paths and eager_load_paths, meaning that adding a directory there requires no further actions.
Basically, autoload_paths are paths Rails will use to try loading your classes automatically. E.g. when you call Book, if that class isn't loaded yet, it will go through the autoload_paths and look for it in those paths.
In production, it might be better to load those upfront to avoid autoload concurrent issues. For that, it provides the eager_load_paths. Paths in that list will be required upfront when your application starts.
As far as I understand, in Rails you don't have to require most of the files that you use, and that most of these files are auto-magically required or included in your code as you reference appropriate classes.
If I understand If I do the following in some arbitrary file, or via running a script with rails runner myscript.rb
myscript.rb
User.delete_all
#set up a default user
User.create(name: "default", password: "default")
This file automatically sees a class it doesnt recognize, User, and understands via its naming convention that the class must be defined in /app/models/user.rb then this code is somehow made available via require or something similar.
My question is: How does rails implement this feature? This is something I'd very much like to understand.
The answer depends a lot on the environment. In production, everything is loaded at boot time and all the classes are cached. In development, the classes are found with const_missing and reloaded when they change. Take a look here at the Rails initialization process.
Check method autoload, whose planned deprecation has been halted for now, and also const_missing, to name just two. Another available mechanism would be eg. to rescue NameError exceptions for uninitialized constants...
I am a former PHP developer learning Rails and Sinatra. In PHP, every page request loaded all of the required files. If I changed some code and refreshed the page, I could be sure that the code was fresh.
In Rails 3, Controller code is fresh on every request. However, if I modify any code in the /lib folder, I need to restart the server so the changes take effect.
Why does this happen? Is it something to do with the way Ruby is designed? Is Rails doing some optimizations to avoid reloading code on every request?
Thanks!
Edit: I am mostly interested in what is going on under the hood. Do frameworks like Rails and Sinatra do some special caching for classes? If so, what does they do? Is the default behavior in Ruby that all code gets reloaded on every request? Why do we need tools like Shotgun for Sinatra (http://sinatra-book.gittr.com/#automatic_code_reloading)?
While you are in development mode you should tell Rails not to cache your classes so they reload each time. This means that each request the classes are basically redefined in the rails interpreter. The setting in your Rails.root/config/environments/development.rb:
config.cache_classes = false
The classes the are in your lib/ dir are usually loaded through an initializer and not subject to this setting.
When you move to production you will want all of your classes to be cached so requests are faster and rails will do optimizations to things like scopes on your models.
You could put something in another initializer (maybe called Rails.root/config/initializers/development_reload.rb) that reloads the lib dir with every request in development (or just the ones you are working on):
# file development_reload.rb
if Rails.env.development?
ActionDispatch::Callbacks.after do
load 'filename_in_lib'
# or
Dir.entries("#{Rails.root}/lib").each do |entry|
load entry if entry =~ /.rb$/
end
end
end
I am calling "load" so it actually reloads the file, whereas "require" would just check if it has been loaded and determine it already has so it will not reload it. (I just threw this together and don't use it, but Ruby is extremely flexible and will allow you to do quite a bit.) Use something like this wisely and only in a dev environment.
Why code needs to be reloaded in Rails 3?
Ruby is an interpreted language (JRuby has some support for precompilation, but it's still interpreted). Interpreting the the definition of classes once on initialization is similar to compiling php and deploying in executable format (somewhat). The interpreter is not bothered with redefining classes all the time.
Forcing the explicit reload is an optimization for this type of interpreted language. (if you AOT compile in php you would need to reload the compiled "bytecode" after changes as well; default php uses on-the-fly compilation which is what you are taking advantage of)
How about a more high level approach:
ActionDispatch::Reloader.cleanup!
ActionDispatch::Reloader.prepare!
This was taken from Rails/ActiveRecord v3.2.13 - active_record/railtie.rb
The load approach didn't work for me. Just performing load caused a weird issue where it would trigger certain validators twice for me.
In order to fix that, I tried Object.send(:remove_const, User) before reloading User, but then I lost my observers on that class, so I started chasing my tail.
The above approach reloads all the classes, so maybe there is still yet a better approach to properly remove an individual class from cache and reload it...
I'm developing a ruby module that I include in my rails app. I want it to be reloaded automatically when it changes. I've done extensive googling, and looked at the various questions here that discuss it, but they all seem out of date or wrong.
How do I get an external module to be reloaded in rails when it changes? I've tried adding its name to ActiveSupport::Dependencies.unloadable_constants, but after I type reload! in the console, I can no longer refer to that symbol without a NameError: uninitialized constant foo, even if I do another require 'foo_module'. Does anyone know how to get this working?
Note: here is one possible dup, but note in the comments to the 'answer' that it never solved the problem for modules. There's also this question which has a dead link in the answer, and finally this one, which also doesn't solve it.
I found how to do this:
Make sure FooModule is in lib/foo_module.rb.
Use require_dependency to require your external library in lib/foo_module.rb.
These steps are both required, and no others are required.
There are two separate problems here.
The simpler of which is that you are using require, when you want load.
require will evaluate the code in a file once, no matter how many times that file/module is required.
load will evaluate the code in a file each time that file is loaded.
require is preferred to load used so that the files are not evaluated multiple times when many files depend on them.
The short version is that load can be used to reload modules that have already been loaded by require.
The more complicated problem is automatically reloading a module on change.
One of the possible duplicates listed in the question links to here. Which suggests prefixing any code that depends on your module with a conditional load of your module if it has changed since loading. You'll need to use a global variable to keep track of when a file was loaded.
N.B.: this should not be used on a production server, but should be fine on a development server or console.
I spent sometimes to research this issue as well.
Here's my findings on how to auto-reload require files in Rails without restarting server.
The solution is now available as a Ruby gem require_reloader.