explanation of application.rb file in Rails App - ruby-on-rails

I'm trying to get a deeper understanding of how a rails app initializes. I'm looking over the config/application.rb file and I'm confused by these three lines:
require_relative 'boot'
require 'rails/all'
Bundler.require(*Rails.groups)
From what I can tell all three of these lines are loading the gems used by the Rails Application. boot.rb appears to load all the gems as does Bundler.require(*Rails.groups). Why is it necessary to have all three lines of code?

Mostly correct, and you can verify what is "needed" by disabling one line at a time in a working Rails app.
require_relative 'boot': Application still runs.
require 'rails/all': Method not found error for a gem not listed in my Gemfile (one of Rails' built-ins (require 'rails/all')
Bundler.require(*Rails.groups): Method not found for gem from Gemfile.
So, the second and third are independent and essential. boot.rb's call to bundler/setup cannot stand in for either of the other two, because its function is actually to clean the load path by making sure that only Gemfile gems are included, and everything else is removed. See the last line of the Bundler setup source. So, while the app runs, it could be running with access to other gems that you did not intend to include, and give you a false sense that the app is working when it could fail for another user who only installed the Gemfile dependencies.
So you may get away with only the second and third in the short term, but would definitely want all three on anything that someone else may someday have to execute. The overhead is minimal so I would not remove any of these.

require_relative 'boot'
Sets up Bundler and load paths for gems
require 'rails/all'
This loads the rails gems. It can be replaced in order to explicitly require only the rails gems that you need (i.e. require "action_mailer/railtie"
Bundler.require(*Rails.groups)
This requires gems listed in your Gemfile by default. If you remove this line, you would have to require each gem by hand.

Related

Rails requiring standard Ruby libraries?

I ran into an issue testing a new app in production environment.that Net::HTTP was not defined, but in development it was.
Naturally a require 'net/http' somewhere solves this (e.g. I put it in config/application.rb after Bundler.require(*Rails.groups),as I understand, there is no gem name I can add to Gemfile).
But can I find a list of which Ruby standard modules/classes need to be required, or should I just start adding everything I need to application.rb to be clear (date, json, net/http, etc.)?

When to load Gem code when depending on rails

I'm developing a Gem that is to be used exclusively in Rails projects. It has been developed inside of a Rails application's lib directory and is now to be extracted in a separate Gem.
Some of the classes depend on the Rails framework to be loaded though. Two examples:
class OurGem::Hookup
CONFIG_PATH = 'config/hookup.rb'.freeze
[...]
end
class OurGem::RoutingContainer
include Rails.application.routes.url_helpers
[...]
end
Normally, I load the Gem code in the Gem's main module file using require. But as this is loaded by bundler, Rails is not ready and things like Rails.application and Rails.root cannot be used. The first example could be worked around by not evaluating the path at load time, but the second one seems kind of tricky to me.
What is the proper way of doing this? Register an initializer using a railtie and require the "delicate" files there?
This is a strange setup, because your gem depends on your rails app and your rails app depends on your gem.
This looks far too coupled to me. Have you considered creating a self-contained rails engine that your main app mounts, instead?
You might be able to get away with doing this, though:
# Gemfile
gem 'our_gem', require: false
# config/initializers/our_gem.rb
require 'our_gem'
OurGem::Hookup.config_path = '...'
This ensures that your gem is only being loaded after the rails application initialises - so things like Rails.application.routes.url_helpers will be defined.

require 'tire' gem not being mentioned in a model class but usage of it still works in rails app

Im reviewing code of a rails application I inherited and I'm no expert in rails. In the gemfile for the application there is: gem 'tire'. Great, but I expect to use require 'tire' in models or controllers to be able to use the libraries this gem provides.
According to the documentation of a particular gem it says it needs to be included as a mixin in a model class.
include Tire::Model::Search
include Tire::Model::Callbacks
Or the documentation mentions to use require 'tire' to the model class where you plan to use the tire gem.
But in the project I don't see any of these require/includes in the models. The models are just using the api without requiring/including like so:
ret = Tire.index "icrd" do
import [icrdObj]
refresh
end
How does this work? Where should I look in the rails project to get an understanding of why require or include is not needed? Is there some kind of autoloading going on?
Bundler has a lot of nice methods. Bundler.setup ensures you can require gems easily in your app.
Bundler.require(:default, :production) for example (it accepts group names) requires all gems in the gemfile automatically by performing require 'tire', require 'rails' and such, for you.
You can skip auto-require for some gems by adding require: false near your gem row in gemfile, like
gem 'rails', require: false
Check Bundler.require documentation (which is placed under groups)
When a gem is included in a Gemfile, the associated require .. statement is automatically called.
See http://www.justinweiss.com/blog/2014/10/13/how-does-rails-handle-gems/ for an explanation of how rails handles gems.
From that blogpost:
So, Bundler will look in your Gemfile for gems belonging to each of
those groups, and call require on each of the gems it finds. If you
have a gem nokogiri, it’ll call require "nokogiri" for you. And that’s
why your gems usually just work in Rails, without any extra code on
your part.

Require a gem in rails

I'd like to include unitwise in my project, so I added it in the Gemfile and I want to use the core extensions of this gem in a model, so I have to require 'unitwise/ext' which isn't by default. Should I require this file in every models I use it, or is there a way to require it one time for the whole project?
You can require it once either by creating an initializer for it, or adding this line to application.rb.
require 'unitwise/ext'
You could create separate ruby file in config/initializer/ to require unitwise/ext which will be available in all place in the project or you could require in application.rb, here also it will be available everywhere in application.
It is better add one line in application.rb, instead creating separate file in initializer to require that file.

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'

Resources