I have a highly modified Rails repository. None of the classes use ActiveRecord. I'm finding that I have to specify many file and gem requirements at the top of each class. I want to have the requirements for each class preloaded in an initializer rather than it being specified in the class. How do I do this? Is this a bad idea? Is it necessary?
There are several ways to do this.
The obvious one is to require a single file, and then inside that file have all of your requirements listed.
For example in list_of_requirements.rb you could have
require 'thin'
require 'x'
require 'y'
Then in your class_that_requires_stuff.rb you could have
require 'list_of_requirements'
This way in your indvidual classes you only need one require statement and you don't need to require all these gems in every file. You also don't need an initializer.
Related
Just curious on how things autoloading works in rails
app/models/base_facebook_object.rb
class BaseFacebookObject
end
In the file where I require it,
app/models/fb_campaign.rb
class FbCampaign < BaseFacebookObject
end
But the above doesn't work as it says BaseFacebookObject not defined?
Do I always have to require the base object file in such cases?
require "#{Rails.root}/app/models/base_facebook_object"
Thanks in advance
The autoloader will resolve unfound constant. In your case if you call FbCampaign it will check for the file fb_campaign.rb, then during the loading will find BaseFacebookObject and load base_facebook_object.rb
In other words, no requires needed. Actually you should never use require in a RoR application except for std lib not yet loaded (eg. securerandom, base64 etc. ) or files into a lib/non-autoloaded path.
I would like to use the distance_of_time_in_words method in the date_helper.rb Rails file (see on Github) in an non-Rails Ruby project.
How can I include it? It requires other files, so how to include them?
I don't want to include all of Rails because that would slow down the development process.
Ruby 1.9.3
This method, distance_of_time_in_words is in actionpack/lib/action_view/helpers/date_helper.rb. So you should require 'action_view' and action_view/helpers to load this method. And the method is defined in module ActionView::Helpers::DateHelper, you can include it in your class. The method is an instance method.
require 'action_view'
require 'action_view/helpers'
class Klass
include ActionView::Helpers::DateHelper
end
c = Klass.new
c.distance_of_time_in_words( ...... )
If this is the only thing you want from it, then I'd just go take the source code and hack it to remove the dependencies (which appears to just be some I18n translations. To support the hack, you can probably translate this test suite.
Why would I do this instead of using the gem? Because it's just such an enormous dependency. It's so enormous that you actually notice it loading all that code. I'd rather rip out the method and hack it to work than depend on all of that (again, assuming this is the only thing you want from the lib).
If I want to require a lib just once, so I can use it everywhere, should I do this in app_controller.rb?
Put it in a custom initializer because you might need this library outside a controller scope.
I think the application_controller.rb is a reasonable place to put the require statement.
Now, using rails 3, either you place the gem inside your Gemfile, which will automatically require it. If it is a file under the lib-folder, it normally is required automatically. Both these would cover most cases automatically imho.
If you still want to require something explicitly, I would not use the initializers, but I would recommend adding the require-line to your application.rb.
Hope this helps.
Inside ActionController class (rails/actionpack/lib/action_controller.lib) I found several weird code. I don't really have a mentor to learn Ruby on Rails from, so this forum is my only hope:
Question #1: Could anyone help me explain these lines of codes?
begin
require 'active_support'
rescue LoadError
activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
if File.directory?(activesupport_path)
$:.unshift activesupport_path
require 'active_support'
end
end
Especially the line with $:.unshift activesupport_path
In my thought, it tries to require active_support class, and if that doesn't work, it looks if activesupport_path is a directory, if it is, then . . . I totally lost it.
Question #2: What autoload method is for?
module ActionController
# TODO: Review explicit to see if they will automatically be handled by
# the initilizer if they are really needed.
def self.load_all!
[Base, CGIHandler, CgiRequest, Request, Response, Http::Headers, UrlRewriter, UrlWriter]
end
autoload :Base, 'action_controller/base'
autoload :Benchmarking, 'action_controller/benchmarking'
autoload :Caching, 'action_controller/caching'
autoload :Cookies, 'action_controller/cookies'
.
.
.
Question #3: If I later find a method I don't understand what for, how is the best way to find out? As for that autoload method case, I tried to find it across my project (I have my Rails code frozen there) but couldn't find any clue. I searched for "def autoload". Am I doing things wrong? Is my IDE, TextMate just doesn't cut it?
Thank you!
In order for a file to be required you have to ensure that the path to it is in the Ruby $LOAD_PATH variable. This is has a short-hand version $: for legacy reasons, inheriting this from Perl.
When you call require, the interpreter looks for a .rb file in each of the paths given there until it finds a match. If it finds one, it is loaded. If not you get an exception.
Often you will see lines like this in files:
# script/something
# This appends "script/../lib" to the $LOAD_PATH, but this expands to
# something like "/home/user/project/lib" depending on the details of
# your installation.
$: << File.expand_path(File.join('..', 'lib'), File.dirname(__FILE__))
You can use standard Array modifiers on $LOAD_PATH like unshift, push, and <<.
The first block of code is attempting to load active_support and only if that fails does it go about modifying the $LOAD_PATH to include the likely location of this file based on the path to the file making the require call. They do this because typically all gems from the Rails bundle are installed in the same base directory.
The reason for using unshift is to put that path at the highest priority, inserted at the front of the list. The << or push method adds to the end, lowest priority.
When you require a file it is loaded in, parsed, and evaluated, an operation which can take a small but measurable amount of time and will consume more memory to hold any class or method definitions inside the file, as well as any data such as string constants that may be declared. Loading in every single element of a library like ActiveRecord using require will require a considerable amount of memory, and this will import every database driver available, not just the ones that are actually used.
Ruby allows you to declare a class and a path to the file where it is defined, but with the advantage of not actually loading it in at that moment. This means that references to that class don't cause script errors in other parts of your application that make use of them.
You will often see declarations like this:
class Foo
# Declare the class Foo::Bar to be defined in foo/bar.rb
autoload(:Bar, 'foo/bar')
end
When using autoload you need to keep in mind that the class name is always defined within the scope of the module or class declaring it. In this example Bar is within Foo, or Foo::Bar using Ruby naming conventions.
When you make use of the Bar class, the foo/bar.rb file will be required. Think of it as creating a stub Bar class that transforms into the real class once it's actually exercised.
This is a great way of keeping a lot of options open, with many different modules ready to use, but without having to load everything into memory up front.
As for the third question, searchable documentation like APIDock will help you try and find more information on methods. The distinction between Ruby and Rails is often blurred, so you may have to check through both to be sure. Rails adds a lot of methods to core Ruby classes, so don't take the listing of methods available to be complete on either side. They work in conjunction.
Sometimes it pays to search for def methodname when trying to find out about where methodname originates, although this covers only conventional declarations. That method may be an alias from a mechanism like method_alias or may have been dynamically created using define_method, you can never really be sure until you dig around. At least 90% of the methods in Rails are declared the conventional way, though, so most of the time a simple search will yield what you want.
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!
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.
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.