to navigateEnterto select Escto close

    Rails generator and bundle commands

    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 Gemfile and Gemfile.lock 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 Gemfile.lock with 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 specified in Gemfile.lock.

    Gemfile.lock gets updated every time 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.

    Sometimes 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 system.

    If you were to run the rake command in this case, you would get an error, like so:

    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.

    When 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 version.

    If something like this happens, you shouldn't remove the incompatible system-wide 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 Gemfile.lock for the correct version of command to execute.

    It is preferred to use bundle exec over rails because the former will skip the Gemfile.lock check and reduce the command execution time.

    Note that, in this chapter we have used two distinct terms bundle and bundler. Don't let this confuse you. bundler is a gem which whereas bundle is a command.

    Although in some places you may notice bundler being used as a command in place of bundle. There is no difference and both bundler and bundle have the same functionality when used in commands.

    Updating gems manually

    Suppose you want to update a gem that you are using in your application to another version, to do so you should use the following command:

    1bundle update gem-name

    For example, consider the following from Gemfile.lock in the Granite application:

    1rack (2.2.3)
    2  rack-proxy (0.7.0)
    3    rack
    4  rack-test (1.1.0)
    5    rack (>= 1.0, < 3)

    It seems like the rack gem is being used by the Granite application directly and also as a dependency by other gems. If you wish to update the rack gem then you must only do so for the rack version which is being used by the application. If you update the rack version for rack-test gem as well then it can cause compatibility issues within rack-test gem's functionality.

    Hence the correct way to update the rack gem would be like so:

    1bundle update rack

    Rails generators

    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
    3Usage: rails generate GENERATOR [args] [options]
    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
    12Please choose a generator below.
    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
    36  active_record:application_record
    39  factory_bot:model
    42  pundit:install
    43  pundit:policy
    46  react:component
    47  react:install
    50  rspec:policy
    53  sidekiq:worker
    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 --help or -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:

    2  rails generate migration NAME [field[:type][:index] field[:type][:index]] [options]
    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
    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.
    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
    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.
    26    A migration class is generated in db/migrate prefixed by a timestamp of the current date and time.
    28    You can name your migration in either of these formats to generate add/remove
    29    column lines from supplied attributes: AddColumnsToTable or RemoveColumnsFromTable
    32    `bin/rails generate migration AddSslFlag`
    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
    37    `bin/rails generate migration AddTitleBodyToPost title:string body:text published:boolean`
    39    This will create the AddTitleBodyToPost in db/migrate/20080514090912_add_title_body_to_post.rb with this in the Change migration:
    41      add_column :posts, :title, :string
    42      add_column :posts, :body, :text
    43      add_column :posts, :published, :boolean
    45Migration names containing JoinTable will generate join tables for use with
    46has_and_belongs_to_many associations.
    49    `bin/rails g migration CreateMediaJoinTable artists musics:uniq`
    51    will create the migration
    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

    The generated migration file contains the boilerplate code for a migration with along with the change method.

    Now it is up to 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 of add_column_name_to_table_name column_name:type to pre-populate the change method.

    The following command will generate a migration with pre-populated change method:

    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

    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.

    Generating scaffold

    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 Task:

    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 -p flag.

    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 app/assets/stylesheets/scaffolds.scss 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

    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 generate and destroy commands 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.

    1. 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.

    1. 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.

    1. 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.

    1. 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.

    Passing the -v flag in above command is completely optional. Doing so generates an output with higher verbosity.

    1. 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.

    1. 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.

    1. bundle exec rails routes

    This command will list all of your defined routes, giving you a good overview of the URLs in your application.

    Creating a Rails app from a specific Rails commit

    Suppose the latest Rails release was 10 days ago and you want to use the Rails version from a commit different than the latest release. To do so you can update the rails gem line within Gemfile like so:

    1gem "rails", git: "git://", ref: commit_id

    Replace the commit_id with the commit id you wish to use. For example if the commit id is a8d088f, then update the gemfile like so:

    1gem "rails", git: "git://", ref: "a8d088f"

    You also have an option to pass the branch along with the commit id. If you do not pass the branch name then the default branch would be main. If you don't pass a commit id then the Rails version from latest commit in the main branch will be used.

    This is an in-depth chapter and hence you do not need to commit any of these changes.