What is a bundler?
Bundler is a dependency management tool for Ruby which is available as a gem
that can be installed through the
RubyGems package manager which comes
built-in using the following command:
1gem install bundler
Bundler reads the Gemfile for the list of gems and ensures that the gems you need are present in development, staging, and production. It also fetches the metadata from the source provided, resolves the dependencies of each gem, installs them and then requires them while booting.
Without bundler, we would have to handle the installation and manage the dependencies manually.
Let's take a brief look at how Bundler works with
for dependency management.
Gemfile and Gemfile.lock
Gemfile is a Ruby file which contains a list of gem dependencies of a project.
When you install the gems using the command
bundle install, bundler looks for
the Gemfile at either the directory mentioned by the environment variable
BUNDLE_GEMFILE or at the root of the project directory.
Bundler then makes use of
RubyGems to install the gems listed on the Gemfile
along with their dependencies and it creates a file called
the list of the gems installed along with their respective versions.
When you run
bundle install the next time, bundler will read the
Gemfile.lock and use
RubyGems to install the exact versions of the gems
Gemfile.lock gets updated everytime you install, update or remove a gem from
the list of dependencies of your project.
bundle exec command
In this section we will learn why it is preferred to prefix commands with
bundle exec while running them.
RubyGems generates executables after installing a gem. Examples of
these gems include rails, rake, rspec, etc.
Now, consider a scenario where multiple versions of the same gem are installed. In such a case multiple versions of executables are present for the same gem.
Let us take the example of
rake gem. Suppose your project's Gemfile contains
v10.4.0 of the
rake gem whereas v10.4.2 of the same is installed on your
If you were to run the
rake command in this case, you would get an error, like
1rake db:migrate 2rake aborted! 3Gem::LoadError: You have already activated rake 10.4.2, but your Gemfile requires rake 10.4.0. Prepending `bundle exec` to your command may solve this.
rake gets called in the above example, there is nothing to ensure that
the right version of
rake gets activated. In fact,
RubyGems will simply
activate the latest
rake version even if your project depends on an older
If something like this happens, you shouldn't remove the incompatible
rake gem to solve this issue. It will lead to other errors in case
other projects or tools are dependent on that version.
Additionally, there is no guarantee that simply updating the
rake version in
your project will fix this issue. Other gems in your project may not be
compatible with the updated version.
The solution to this is to use the
bundle exec command.
bundle exec allows
us to run an executable script in the specific context of the project's bundle.
For example, the error encountered in the above example can be fixed using the following command:
1bundle exec rake db:migrate
Upon running the above command,
bundle exec will run the executable script for
rake version specified in project's Gemfile thus avoiding any conflicts with
other versions of
rake installed system-wide.
There is however an exception in case of the
rails command. The reason being,
rails command first loads up the bundler and bundler checks
the correct version of command to execute.
It is preferred to use
bundle exec over
rails because the former will skip
Gemfile.lock check and reduce the command execution time.
Note that, in this chapter we have used two distinct terms
bundler. Don't let this confuse you.
bundler is a gem which whereas
is a command.
Although in some places you may notice
bundler being used as a command in
bundle. There is no difference and both
the same functionality when used in commands.
In Rails, generators are simply scripts that use templates to create boilerplate code and improve your workflow saving you a quite a bit of time.
For example, when you create a new Rails application you are in fact using a Rails generator.
In the next section we will take a look at how we can use generators to create models, controllers etc.
Rails generate command
Rails includes a lot of generators by default such as model generator, controller generator etc.
You can get a list of all default as well as custom generators available in a Rails project using the following command:
1bundle exec rails generate 2 3Usage: rails generate GENERATOR [args] [options] 4 5General options: 6 -h, [--help] # Print generator's options and usage 7 -p, [--pretend] # Run but do not make any changes 8 -f, [--force] # Overwrite files that already exist 9 -s, [--skip] # Skip files that already exist 10 -q, [--quiet] # Suppress status output 11 12Please choose a generator below. 13 14Rails: 15 application_record 16 assets 17 benchmark 18 channel 19 controller 20 generator 21 helper 22 integration_test 23 jbuilder 24 job 25 mailbox 26 mailer 27 migration 28 model 29 resource 30 scaffold 31 scaffold_controller 32 system_test 33 task 34 35ActiveRecord: 36 active_record:application_record 37 38FactoryBot: 39 factory_bot:model 40 41Pundit: 42 pundit:install 43 pundit:policy 44 45React: 46 react:component 47 react:install 48 49Rspec: 50 rspec:policy 51 52Sidekiq: 53 sidekiq:worker 54 55TestUnit: 56 test_unit:channel 57 test_unit:generator 58 test_unit:install 59 test_unit:mailbox 60 test_unit:plugin 61 test_unit:policy
You can also use
g as an alias for
generator in the above command, like so:
1bundle exec rails g
To get more information about what a generator can do, you can add
-h to the generate command like so:
1bundle exec rails generate generator_name --help
Make sure to replace generator_name in the above command with an appropriate generator name.
In the next section we will see how we can use the generate command to generate boilerplate code for migrations.
Working with migration generators
Rails ships with a migration generator out of the box. Before using the migration generator let's take a look at how to use it.
Run the following command to get more information on how to use the migration generator:
1bundle exec rails generate migration --help
Running the above command will fetch the following output:
1Usage: 2 rails generate migration NAME [field[:type][:index] field[:type][:index]] [options] 3 4Options: 5 [--skip-namespace], [--no-skip-namespace] # Skip namespace (affects only isolated engines) 6 [--skip-collision-check], [--no-skip-collision-check] # Skip collision check 7 -o, --orm=NAME # ORM to be invoked 8 # Default: active_record 9 10ActiveRecord options: 11 [--timestamps], [--no-timestamps] # Indicates when to generate timestamps 12 # Default: true 13 [--primary-key-type=PRIMARY_KEY_TYPE] # The type for primary key 14 --db, [--database=DATABASE] # The database for your migration. By default, the current environment's primary database is used. 15 16Runtime options: 17 -f, [--force] # Overwrite files that already exist 18 -p, [--pretend], [--no-pretend] # Run but do not make any changes 19 -q, [--quiet], [--no-quiet] # Suppress status output 20 -s, [--skip], [--no-skip] # Skip files that already exist 21 22Description: 23 Generates a new database migration. Pass the migration name, either 24 CamelCased or under_scored, and an optional list of attribute pairs as arguments. 25 26 A migration class is generated in db/migrate prefixed by a timestamp of the current date and time. 27 28 You can name your migration in either of these formats to generate add/remove 29 column lines from supplied attributes: AddColumnsToTable or RemoveColumnsFromTable 30 31Example: 32 `bin/rails generate migration AddSslFlag` 33 34 If the current date is May 14, 2008 and the current time 09:09:12, this creates the AddSslFlag migration 35 db/migrate/20080514090912_add_ssl_flag.rb 36 37 `bin/rails generate migration AddTitleBodyToPost title:string body:text published:boolean` 38 39 This will create the AddTitleBodyToPost in db/migrate/20080514090912_add_title_body_to_post.rb with this in the Change migration: 40 41 add_column :posts, :title, :string 42 add_column :posts, :body, :text 43 add_column :posts, :published, :boolean 44 45Migration names containing JoinTable will generate join tables for use with 46has_and_belongs_to_many associations. 47 48Example: 49 `bin/rails g migration CreateMediaJoinTable artists musics:uniq` 50 51 will create the migration 52 53 create_join_table :artists, :musics do |t| 54 # t.index [:artist_id, :music_id] 55 t.index [:music_id, :artist_id], unique: true 56 end
According to the description of the migration generator, this command accepts a
migration name and an optional list of arguments. To understand this better
let's consider a hypothetical example of adding a
priority column to the
task table which will accept integer values.
Following command is only to present an example for generating a migration. Do not run this command as it is not required for the Granite application.
You can use the following command to generate the migration:
1bundle exec rails generate migration AddPriorityToTask
Running the above command will generate the following migration:
1class AddPriorityToTask < ActiveRecord::Migration[6.1] 2 def change 3 end 4end
The generated migration file contains the boilerplate code for a migration with
along with the
Now it is upto you to add the relevant code which will add a new column to the tasks table. We shall not be discussing that here. If you wish to understand how that works you can refer to Rails migration and Rails migrations in depth chapters.
If you recall, the description for migration generator also mentioned that the
command accepts arguments other than the migration name. We can pass the
attribute name and attribute type to the migration generator command in the form
add_column_name_to_table_name column_name:type to pre-populate the change
The following command will generate a migration with pre-populated
1bundle exec rails d migration AddPriorityToTask priority:integer
The above command will generate the following migration file:
1class AddPriorityToTask < ActiveRecord::Migration[6.1] 2 def change 3 add_column :tasks, :priority, :integer 4 end 5end
That was nice! Rails inferred the column name and table name from the migration name itself and generated the code for that. Not just that, it even inferred the column type from the command.
You can use other generators in a similar manner. For example, you can use the controller generator to generate a controller and if you pass in the correct arguments, Rails will pre-populate the generated controllers with actions.
Play around with the available generators to learn how they work and if you ever
get stuck, pass the
--help flag to see how a particular generator works.
So far we have seen how to use generators to generate a single migration or a controller. Now, let us see how we can even generate multiple files using the scaffold generator.
A scaffold in Rails is a full set of model, database migration for that model, controller to manipulate it, views to view and manipulate the data, and a test suite for each of the above.
The following command will generate a scaffold for a single resource called
1bundle exec rails generate scaffold Task title:string 2 invoke active_record 3 create db/migrate/20210917025409_create_tasks.rb 4 create app/models/task.rb 5 invoke test_unit 6 create test/models/task_test.rb 7 invoke resource_route 8 route resources :tasks 9 invoke scaffold_controller 10 create app/controllers/tasks_controller.rb 11 invoke erb 12 create app/views/tasks 13 create app/views/tasks/index.html.erb 14 create app/views/tasks/edit.html.erb 15 create app/views/tasks/show.html.erb 16 create app/views/tasks/new.html.erb 17 create app/views/tasks/_form.html.erb 18 invoke resource_route 19 invoke test_unit 20 create test/controllers/tasks_controller_test.rb 21 create test/system/tasks_test.rb 22 invoke helper 23 create app/helpers/tasks_helper.rb 24 invoke test_unit 25 invoke jbuilder 26 create app/views/tasks/index.json.jbuilder 27 create app/views/tasks/show.json.jbuilder 28 create app/views/tasks/_tak.json.jbuilder 29 invoke assets 30 invoke scss 31 create app/assets/stylesheets/tasks.scss 32 invoke scss 33 create app/assets/stylesheets/scaffolds.scss
A scaffold generator can be used to speed up the development process.
It is worth mentioning the
-p flag here. If you add this to the command it
will simply do a test run and show you what files will be generated without
actually generating them, like so:
1bundle exec rails generate scaffold Task title:string -p
If everything looks good, run the command again without the
Under the hood, scaffold generator invokes different generators separately to generate the files. Since each generator has a single responsibility, they are easy to reuse, avoiding code duplication.
For instance, the scaffold generator invokes the scaffold_controller generator, which invokes erb, test_unit and helper generators.
This allows us to add/replace/remove any of those invocations. Let's see how we can customize a scaffold generator as per our requirements.
Suppose we do not want to generate the
and test fixture files when scaffolding a new resource. We can do so by updating
config/application.rb with the following lines of code:
1config.generators do |g| 2 g.test_framework :test_unit, fixture: false 3 g.scaffold_stylesheet false 4end
Rails destroy command
Suppose you wish to undo the changes introduced by a generator. Manually going through all the changes and undoing them will be very time consuming and you might end up changing something you didn't intend do.
Rails comes with an easy solution for this. You can reverse the changes
introduced by a generator using the
destroy command, like so:
1bundle exec rails d scaffold Task title:string
You can also use the
destroy command to delete certain files. You just need to
pass the relative path of the file to the command.
You can replace
destroy with the alias
d in the above command.
Rails command line executable
In this chapter we have so far discussed the
in Rails. There are a few more commands that are absolutely critical to your
everyday usage of Rails.
Let's take a brief look at those commands.
- bundle exec rails new app_name
This command generates a new Rails application. It creates the entire Rails directory structure with all the code you need to run a simple application right out of the box.
- bundle exec rails server
This command launches a local development server named
Puma which comes
bundled with Rails. You'll use this any time you want to access your application
through a web browser.
You can also replace
server with the alias
s to launch the server.
- bundle exec rails console
The console command lets you interact with your Rails application from the
command line. It uses
IRB under the hood.
You can also replace
console with the alias
c to invoke the console.
- bundle exec rails test
This command lets you run the tests you have added in your Rails project. You can either all the tests at once, like so:
1bundle exec rails test -v
Or you can run tests from a specific test file by passing the relative path of the test file to the above command, like so:
1bundle exec rails test -v test/models/user_test.rb
You can also replace
test with the alias
t to run the tests.
-v flag in above command is completely optional. Doing so
generates an output with higher verbosity.
- bundle exec rails db:create
When you create your Rails application for the first time, it will not have a database yet. You will need to make sure the database is up and running before implementing the CRUD features.
This command lets you create a database if it doesn't already exist.
- bundle exec rails db:migrate
Every time you create a database migration that adds or deletes a row or a column, creates a new table, you have to run this command for the changes to reflect in your database.
- bundle exec rails routes
This command will list all of your defined routes, giving you a good overview of the URLs in your application.
There is nothing to commit in this chapter as it's an in-depth chapter that doesn't have anything to do with our granite application.