What Does "require File.expand_path('../../config/environment', __FILE__)" do Exactly? - ruby-on-rails

I've been trying to understand Ruby on a deeper level, and deconstructing a boiler-plate rails app, seemed like a good way to understand some of the niceties and elegance of writing a Ruby app that spans different files and directories.
In my current app, the dependency on the 'requires' between files is becomming slightly problematic (I'm finding I need to do things like requires '../../../lib/helper' and its getting a bit ugly.
I noticed that rails apps don't seem to suffer from this.
I did notice the line:
require File.expand_path('../../config/environment', __FILE__)
And when I Google it I find lots of explanation about the Rails boot-up routine, etc, but no clear description about what that line DOES exactly.
In my travels, I've also come along this line:
$:.push File.join(File.dirname(__FILE__))
I've been wondering if somehow these might be a potential solution to my problem. Can anyone please explain what they do exactly?

__FILE__ is the relative path to the file from current directory. File.expand_path will get you absolute path of file, so above in your question require the environment.rb file.
$: contains the array of required path, so $:.push append the your given path into list of required path, so that you can require that file in your app. Rails push various file while booting process.

File.expand_path('../../config/environment', __FILE__) returns absolute path of the file environment.rb, which is located in the 'config' directory that is two levels below the file that contains this code.
require then gives you access to the ruby code defined in the file environment.rb.

Related

How to import without specifing path in ruby

When I develop ruby app.
I found that some apps import other modules without specifying specific path like following
require 'test'
I always set some modules in certain directory and set following path.
require './sample/test'
How can I import without path ?
Are there any environment setting around this?
Am I missing important thing?
If someone has opinion,please let me know.
Thanks
As was mentioned in the comments, Ruby looks at the $LOAD_PATH global variable to know where to look for required libraries.
Normally, under most circumstances, you should not mess with it and just leave it as is.
When you see other libraries using require without a leading dot for relative path (e.g., require 'sinatra'), it usually means one of these:
They load a pre-installed gem, and since the gem home path is part of the $LOAD_PATH, it can be found and loaded.
The code you see is a part of a gem, and it loads one of its own files.
The code you see is a part of a larger framework (e.g., Rails), which has altered the $LOAD_PATH variable.
You can see all the folders available in the $LOAD_PATH like this:
pp $LOAD_PATH
If, for some reason, you insist on altering the $LOAD_PATH to load your own local files, you can do so like this:
$LOAD_PATH.unshift __dir__
require 'my-local-file'
Bottom line, my recommendation to you is: Do not use this technique just so that you require statements "look nicer", and if you have functionality that can be encapsulated in a gem (private or public), do it.

How can/should I include Ruby project file dependencies in config/environment?

New Rubyist here. In my lectures on Ruby, I've come across various tricks/shortcuts for adding file dependencies to the config/environment file so that one's program runs smoothly. It has been unclear to me which of these, when combined, are redundant; which are best practices; and which are completely useless and/or wrong and should be done the long way. Clarification would be appreciated!
The ones I've come across:
require_relative "../lib/test1.rb"
: << '.' & require "lib/test1.rb"
: << '.' & Dir['lib/*.rb'].each {|f| require f}
require File.dirname(__FILE__)
"require-all" gem
Feel free to include other ways, too!
config/environment.rb is a file that the Rails framework itself has opinions about. Over the lifetime of your application, you will be positively incented not to modify this file (if you can avoid it). This will allow for the easiest possible upgrade path. Consider placing your initialization in a file in config/initializers.
If your code alters the behavior of Rails itself in such a fundamental way that placement in config/initializers loses its potency, or if the long-term maintenance of your code is not a concern, I'll consider the above. Items 2+3 work by appending to your LOAD_PATH, which I would not recommend, let alone calling a best practice. (Adding RAILS_ROOT/config may not be a major issue by default, but you might create some very difficult to debug errors.)
The location of config/environment.rb hasn't changed in a long time, so relative requirement (i.e. option #1) is probably fine. require File.dirname(__FILE__) by itself does nothing (you're requiring a directory) but is worthwhile to remember in an approach like require File.join[File.dirname(__FILE__), '../lib/your_file.rb'] which will work the same regardless of load path, or working directory concerns. This is what I would do.
I would not use a gem for this, since the behavior of the gem could change in unpredictable ways, and you're already in an area where Rails can make your choices inconvenient.

Rails cannot load such file on require even though directory is in autoload_paths

I'm getting an exception LoadError Exception: cannot load such file -- acts_as_versioned when trying to require 'acts_as_versioned'
I have setup a config/initializer with ActiveSupport::Dependencies.autoload_paths << "#{Rails.root}/lib/acts_as_versioned/lib" which is where acts_as_versioned resides. I have validated that this path is showing up in autoload_paths at the point in time where it is actually required, but it raises the LoadError exception.
However, if I do a require directly to the path require "#{Rails.root}/lib/acts_as_versioned/lib/acts_as_versioned" it works correctly.
According to the documentation at
http://guides.rubyonrails.org/autoloading_and_reloading_constants.html#autoloading-availability
Specifically this comment config.autoload_paths is accessible from environment-specific configuration files, but any changes made to it outside config/application.rb don't have an effect. I'm lead to believe it may no longer be possible to modify the autoload_paths outside of config.
When I moved the autoload_paths update into config it works fine; I would love to hear though if there is a solution that doesn't require this as I would much prefer having my paths set within my initializers rather than setting all of them in the config.

require 'lib/my_module' in deploy.rb

I have a module in in lib/redmine.rb that has some classes and stuff. I can call Redmine.some_method from the console just fine, but I'd like this module to be loaded during deployment using Capistrano.
I've tried:
require 'lib/redmine'
require 'redmine'
require './lib/redmine'
require '../lib/redmine'
load 'lib/redmine'
and all of those with a .rb at the end of it.
I can't seem to get access to the Redmine module from the deploy namespace...
The best way would be if you turn it into a gem project, and then simply refer to this
project via the name you gave it.
The problem I have with the code above is that I do not know the layout you use inside of redmine.rb and you are not showing the specific error.
Note that require() tries to go to the ruby SITE_DIR path first, so it would expect require 'redmine' to be installed like a gem (or, via setup.rb which was the old way before gem was written).
Try this too for ad-hoc solution (but don't use it in production code; you modify the load path and this is not good nor needed; use the gem project layout and installation, it is much easier and safer in the long run):
$: << '.'
require './redmine.rb'

Best way to load module/class from lib folder in Rails 3?

Since the latest Rails 3 release is not auto-loading modules and classes from lib anymore,
what would be the best way to load them?
From github:
A few changes were done in this commit:
Do not autoload code in *lib* for applications (now you need to explicitly
require them). This makes an application behave closer to an engine
(code in lib is still autoloaded for plugins);
As of Rails 2.3.9, there is a setting in config/application.rb in which you can specify directories that contain files you want autoloaded.
From application.rb:
# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)
# Autoload lib/ folder including all subdirectories
config.autoload_paths += Dir["#{config.root}/lib/**/"]
Source: Rails 3 Quicktip: Autoload lib directory including all subdirectories, avoid lazy loading
Please mind that files contained in the lib folder are only loaded when the server is started. If you want the comfort to autoreload those files, read: Rails 3 Quicktip: Auto reload lib folders in development mode. Be aware that this is not meant for a production environment since the permanent reload slows down the machine.
The magic of autoloading stuff
I think the option controlling the folders from which autoloading stuff gets done has been sufficiently covered in other answers. However, in case someone else is having trouble stuff loaded though they've had their autoload paths modified as required, then this answer tries to explain what is the magic behind this autoload thing.
So when it comes to loading stuff from subdirectories there's a gotcha or a convention you should be aware. Sometimes the Ruby/Rails magic (this time mostly Rails) can make it difficult to understand why something is happening. Any module declared in the autoload paths will only be loaded if the module name corresponds to the parent directory name. So in case you try to put into lib/my_stuff/bar.rb something like:
module Foo
class Bar
end
end
It will not be loaded automagically. Then again if you rename the parent dir to foo thus hosting your module at path: lib/foo/bar.rb. It will be there for you. Another option is to name the file you want autoloaded by the module name. Obviously there can only be one file by that name then. In case you need to split your stuff into many files you could of course use that one file to require other files, but I don't recommend that, because then when on development mode and you modify those other files then Rails is unable to automagically reload them for you. But if you really want you could have one file by the module name that then specifies the actual files required to use the module. So you could have two files: lib/my_stuff/bar.rb and lib/my_stuff/foo.rb and the former being the same as above and the latter containing a single line: require "bar" and that would work just the same.
P.S. I feel compelled to add one more important thing. As of lately, whenever I want to have something in the lib directory that needs to get autoloaded, I tend to start thinking that if this is something that I'm actually developing specifically for this project (which it usually is, it might some day turn into a "static" snippet of code used in many projects or a git submodule, etc.. in which case it definitely should be in the lib folder) then perhaps its place is not in the lib folder at all. Perhaps it should be in a subfolder under the app folderĀ· I have a feeling that this is the new rails way of doing things. Obviously, the same magic is in work wherever in you autoload paths you put your stuff in so it's good to these things. Anyway, this is just my thoughts on the subject. You are free to disagree. :)
UPDATE: About the type of magic..
As severin pointed out in his comment, the core "autoload a module mechanism" sure is part of Ruby, but the autoload paths stuff isn't. You don't need Rails to do autoload :Foo, File.join(Rails.root, "lib", "my_stuff", "bar"). And when you would try to reference the module Foo for the first time then it would be loaded for you. However what Rails does is it gives us a way to try and load stuff automagically from registered folders and this has been implemented in such a way that it needs to assume something about the naming conventions. If it had not been implemented like that, then every time you reference something that's not currently loaded it would have to go through all of the files in all of the autoload folders and check if any of them contains what you were trying to reference. This in turn would defeat the idea of autoloading and autoreloading. However, with these conventions in place it can deduct from the module/class your trying to load where that might be defined and just load that.
Warning: if you want to load the 'monkey patch' or 'open class' from your 'lib' folder, don't use the 'autoload' approach!!!
"config.autoload_paths" approach: only works if you are loading a class that defined only in ONE place. If some class has been already defined somewhere else, then you can't load it again by this approach.
"config/initializer/load_rb_file.rb" approach: always works! whatever the target class is a new class or an "open class" or "monkey patch" for existing class, it always works!
For more details , see: https://stackoverflow.com/a/6797707/445908
Very similar, but I think this is a little more elegant:
config.autoload_paths += Dir["#{config.root}/lib", "#{config.root}/lib/**/"]
In my case I was trying to simply load a file directly under the lib dir.
Within application.rb...
require '/lib/this_file.rb'
wasn't working, even in console and then when I tried
require './lib/this_file.rb'
and rails loads the file perfectly.
I'm still pretty noob and I'm not sure why this works but it works. If someone would like to explain it to me I'd appreciate it :D I hope this helps someone either way.
I had the same problem. Here is how I solved it. The solution loads the lib directory and all the subdirectories (not only the direct). Of course you can use this for all directories.
# application.rb
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]
As of Rails 5, it is recommended to put the lib folder under app directory or instead create other meaningful name spaces for the folder as services , presenters, features etc and put it under app directory for auto loading by rails.
Please check this GitHub Discussion Link as well.
config.autoload_paths does not work for me. I solve it in other way
Ruby on rails 3 do not automatic reload (autoload) code from /lib folder. I solve it by putting inside ApplicationController
Dir["lib/**/*.rb"].each do |path|
require_dependency path
end
If only certain files need access to the modules in lib, just add a require statement to the files that need it. For example, if one model needs to access one module, add:
require 'mymodule'
at the top of the model.rb file.
Spell the filename correctly.
Seriously. I battled with a class for an hour because the class was Governance::ArchitectureBoard and the file was in lib/governance/architecture_baord.rb (transposed O and A in "board")
Seems obvious in retrospect, but it was the devil tracking that down. If the class is not defined in the file that Rails expects it to be in based on munging the class name, it is simply not going to find it.
There are several reasons you could have problems loading from lib - see here for details - http://www.williambharding.com/blog/technology/rails-3-autoload-modules-and-classes-in-production/
fix autoload path
threadsafe related
naming relating
...

Resources