Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to call a "require" in Rails?

I have a more conceptual question in Rails... or Ruby for that matter:

Is it best to call a require right before the method that needs it, group my requires at the beginning of the class or somewhere in an initializer when Rails boots?

Does it matter from a performance point of view? From a readability point of view? Does it make a difference if I'm using Rails 3?

Thanks!

like image 772
Cimm Avatar asked Aug 27 '10 19:08

Cimm


People also ask

When should load be used in Ruby as opposed to require?

You should use load function mainly for the purpose of loading code from other files that are being dynamically changed so as to get updated code every time. Require reads the file from the file system, parses it, saves to the memory, and runs it in a given place.

What is the use of require in Ruby?

In Ruby, the require method is used to load another file and execute all its statements. This serves to import all class and method definitions in the file.

What is require in Ruby on Rails?

In Ruby to reuse any existing files and modules we can use the require statement, required to allow us to make available the submodules inside our codes, there are two way to require any file first way by giving the full path of the file like require './dire/lib/xyz.

What is difference between require and include in Ruby?

The Ruby include statement simply makes a reference to a module. If that module is in a separate file, you must use require (or its less commonly used cousin, load) to drag that file in before using include. Second, a Ruby include does not simply copy the module's instance methods into the class.


2 Answers

If you're concerned about performance then you should require things in the context of where they are needed so that if that portion of your code is not exercised, the library is not loaded. Any subsequent calls to require have no effect as that file has already been loaded. This ends up looking like something along the lines of:

if (user.using_openid?)
  require 'openid'

  # ... Do OpenID stuff
end

While this is more efficient in terms of resources, it can make it very difficult to determine the dependencies of your application. Declaring these up-front makes it clear to other people maintaining the software. Keep in mind that "other people" always includes your future self when you've forgotten about some details of your application.

You're technically allowed to require anything at any time, late or early, but declaring your requirements up front is better from a design perspective. If you find that there is an element that is used only intermittently and takes an unusual amount of time or memory to load, then you should probably document that up front in your requirements file. For example:

require 'library1'
require 'library2'
require 'library3'
require 'library4'
require 'library5'

# Other libraries loaded as required:
#  * slowimagelibrary
#  * slowencryptionlibrary
#  * openid

Arguably this is less of an issue with bundler because you can have your gems declared up front more formally and the actual require call can come later.

like image 155
tadman Avatar answered Oct 05 '22 13:10

tadman


If you consider vanilla Ruby, 'require' is mostly used in the first lines, because you then are sure you have access to what you need, and it is easier to find and read what dependency you need.

There are a few cases when you want to load a gem only in a method, because this is not really needed for your script to work (e.g.: a optional visualization).

With Rails, I believe it depends on what you want to do.

If you use Bundler, you can assume your gem has been 'required' (you can of course override what is required with the :require option).

If it is some stuff you want to autoload when the server start (like validators or form builders), then you should look how to do with the config (autoload_paths and eager_load_paths).

require can also be used to load only a part of a gem, like an extension to it. Then it is of course required where the configuration is.

You might be concerned if you work in a multi-threaded environment, as they are some problems with that. You must then ensure everything is loaded before having your threads running. (Something like the class constant is loaded, but the methods not yet, there was a good article but I can not find it anymore).

You might also want to try {Module,Kernel}.autoload, Rails extensively use it to load only what is necessary when accessed (but it looks rather ugly).

You can also hack it yourself with const_missing (so this can do plain lazy-loading, if you accept a structure). This is a simple example (will not be appropriate for nested classes).

def Object.const_missing c
  if (file = Dir["#{c.downcase}.rb"]).size == 1 
    require_relative(file)
  end
  if const_defined? c
    const_get c
  else
    super # Object < Module
  end
end

About performance, a call to require is relatively expensive, so if you know you are going to use it, do it only once if possible. However, to manage complex dependencies within your project, you might need to require relative files. Then require_relative is the way to go in 1.9.

Lastly, for a project, I would recommend to require all in the main file in lib/, with some Dir["**/*.rb"] expression. You would then rarely need to require_relative, because it is only needed if you reference in the body of the class another constant (all the contents of the methods are not resolved, so there is no problem with that).

Another solution would be to define these constants in your main file, it would also give you an idea of the structure.

like image 43
eregon Avatar answered Oct 05 '22 15:10

eregon