January 07, 2025
Paweł Dąbrowski
Founder / Software Engineer
Rails console is the type of tool that we, as Rails developers, heavily use in production and development environments for any type of the apps. Besides interacting with the database to read or manipulate records, there are plenty of other use cases where you can find the Rails console useful.
You can even personalize the console for the given project to increase the ease of usage and efficiency. In this article, I will present all the more and less known console features you can use to interact with the database and code in your project.
I wouldn’t say that working with the Rails console is uncomfortable, but let me share with you a few tips that make the work even easier and more comfortable.
Depending on the actions that you perform on the database and the nature of your data, a lot is going on in logs when making the queries:
User.find_each(&:touch)
# User Load (0.6ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT 1000
# TRANSACTION (0.2ms) BEGIN
# User Update (1.7ms) UPDATE "users" SET …
When you use puts
inside your code to monitor the progress or just debug some parts of the process, it’s easy to lose track of them among the logs. You can silence the logs by wrapping the code inside the special block:
ActiveRecord::Base.logger.silence { User.find_each(&:touch) } # => nil
From now on, the console output will be free from the SQL logs and queries.
Raise your hand if you never forget to assign to a variable result of some operation in the console and then you have to make it again. Thankfully we have a special variable _
that allows us to access the last result printed in the console:
3.3.6 :001 > 4 + 4
=> 8
3.3.6 :002 > _
=> 8
You can treat the floor character as an ordinary variable and use it to print something or pass it as an argument to some method.
If you are working with objects to which access you need to get via many chained calls, you can make your work a little bit more efficient by creating a dedicated workspace for a given object.
Given you have a User
class instance that provides an address
object which provides a location
object which provides some useful methods:
user.address.location.latitude
You can create a workspace where the location
object will be the main object. Just use cd
and enter the desired object:
cd user.address.location
latitude # => some value
If you want to go back, just use cd ..
. As you may notice, it works the same way as the navigation between directories in the command line. If you are unsure of what workspace you are currently in, type cwws
and you will get information about the current context.
If you would like to see all the workspaces
you created, type workspaces and you will receive an array of contexts. By using cd
without dots you can immediately switch to the main context.
If you would like to explore all methods, constants, and variables related to the given class or instance, you can use the ls
command and pass the “thing” you want to explore:
user = User.last
ls user
# User#methods: name
# instance variables: @association_cache @attributes @destroyed
# @destroyed_by_association
The output is logically grouped so you perfectly know that is the source of each provided method that you can execute on the given object.
Not always objects are readable in their original form. For example, large hash with many pairs - it can be quite difficult to read the desired information from it. Thankfully, we can use a tiny helper method y to output the object in YAML format:
users_data = [ { first_name: 'John', last_name: 'Doe' }, { first_name: 'Tim', last_name: 'Doe' }]
y users_data
The output for the above code will be:
---
- :first_name: John
:last_name: Doe
- :first_name: Tim
:last_name: Doe
This method will be also useful with more complex objects like active record models.
If you don’t want to commit any changes to the codebase but execute code with changed elements during the console session, you can temporarily alter the method for the specific object. Given we have the following User
class:
class User < ApplicationRecord
def perform_action
some_callback
end
def some_callback
puts "original callback"
end
end
If you want to change the some_callback
method logic, you can modify it for one of the User
instances:
user = User.last
def user.some_callback
puts "modified callback"
end
user.perform_action
# => "modified callback"
another_user = User.first
another_user.perform_action
# => "original callback"
If the method you are updating is not public, you can ensure the proper visibility level after redefining it:
def user.some_callback
"modified callback"
end
user.singleton_class.class_eval { private :some_callback }
The change will gone if you exit the console or assign the object again.
If there are some methods that you are using all the time, or you use certain user record to perform some actions, you can provide the needed data in the form of helpers.
Given you use User.find(10)
all the time to find the user that you later pass to the background job you start from the console level. You can create the following initializer:
Rails.application.console do
puts "Loading custom initializer #{__FILE__}"
def main_user
User.find(10)
end
end
After this change, you can start the console and use main_user
to fetch the user that is proper for the case with background jobs execution.
If the custom console initializer is your own initializer for development purposes and other developers are not using it, you can add the file to .gitignore
to make sure that you only use it locally.
Master the art of database optimization in Rails applications. Learn proven techniques to improve your Ruby on Rails application performance.
There are tasks that you can perform directly inside the console without the need to interact with the application in the browser, using the command line to execute Rake tasks or running unit tests to verify the way the given code works. In this section, I will focus on those tasks.
By default, a helper
object is available in the console. It exposes all of the methods defined in the app/helpers
directory. Given you defined the following method in app/helpers/users_helper.rb
module UsersHelper
def full_name(first_name, last_name)
"#{first_name} #{last_name}"
end
end
In the console, you can access the method without providing the module name:
helper.full_name("John", "Doe") # => "John Doe"
The same rule applies to the default helpers available in views like sanitize
:
helper.sanitize("<h1>Hello world</h1><p>some text</p>", tags: %w[p]) # => "Hello world<p>some text</p>"
There are two ways you can inspect a given route that you previously defined in config/routes.rb
file. Given that we defined show action for ArticlesController
:
class ArticlesController < ApplicationController
def show
render json: { message: 'Single article' }
end
end
With the following route definition:
resources :articles, only: %i[show]
You can inspect the route URL using the app
object and passing the same path method you would use in the view or controller:
app.article_path(id: 6) # => /articles/6
Another way you can inspect the action is to perform the request to see the response code and body:
app.host = 'localhost'
app.get(app.article_path(id: 6))
app.response.status # => 200
app.response.body # => "{\"message\":\"Single article\"}"
A common way of invoking rake tasks is to use the command line. You can also do it from the console level. Given we have the following task defined in lib/tasks/users.rake
:
namespace :users do
desc 'Truncate user data for specified email'
task :truncate, [:email] => :environment do |_t, args|
puts "Truncating data for user: #{args[:email]}"
end
end
From the console level we have to first load all tasks and then invoke the one we are looking for and pass arguments to the invoke
method:
Rails.application.load_tasks
Rake::Task['users:truncate'].invoke('john@doe.com') # => "Truncating data for user: john@doe.com
"
When your task requires more arguments, pass them to the invoke
method in the right order.
When I talk about the Rails console and interacting with the environment, I can’t forget about the well-known method to reload the code inside the console to reflect changes without leaving the session:
helper.some_method
# => undefined method
reload!
# => Reloading ...
# => nil
helper.some_method
# => true
reload!
sometimes it does not work as expected, especially if you have some local context variables already. Sometimes it is cleaner to just use load "#{Rails.root}/app/lib/foo.rb"
to reload a single file in the console.
Rails console makes it possible to replace the command line in some cases but also the code editor. Have a look at how you can inspect your codebase without leaving the console.
The class can have two types of methods: instance and singleton. If you know the name of the method and the name of the class that can be a caller, you can easily find in which file it’s defined and in which line the definition starts.
To inspect the instance method, use the following code:
User.instance_method(:name).source_location
# => ["/app/models/user.rb", 2]
As a result, you will receive two elements array where the first element is the path to the file and the second element is the line number where the definition starts.
For inspecting the class method, you can use singletion_method
instead of the instance_method
and the output will be in the same format:
User.singleton_method(:human?).source_location
# => ["/app/models/user.rb", 8]
This functionality is available only if you have the pry
gem installed as the standard console does not provide it.
You don’t have to open a text editor to view the code of the given method. It’s useful, especially for external libraries. However, you have to keep in mind that you won’t be able to view the source of the method that was defined dynamically (lots of methods in Rails were defined that way).
In terms of the instance methods, grab the class name and invoke the instance_method
on it by passing the method name and then calling the source
on the result:
User.instance_method(:name).source
# => " def name\n \"\#{first_name} \#{last_name}\"\n end\n"
The output is not well formatted, but you can simply improve it by calling the display method on the result:
User.instance_method(:name).source.display
# def name
# "#{first_name} #{last_name}"
# end
# => nil
If you want to display the source of the class method, replace instance_method
with singleton_method
.
Master the art of database optimization in Rails applications. Learn proven techniques to improve your Ruby on Rails application performance.
If you don’t know the exact name of the method, you can filter instance and class methods against regular expression and receive an array of method names matching passed criteria.
For instance, methods use the following code:
User.instance_methods.grep(/name$/)
# => [:name, :model_name, :store_full_class_name]
The expression we used above searches for all methods that end with the “name”. The grep method returns an array with matching names that you can later use to invoke the method or check its source.
For class methods, use singletion_methods
instead:
User.singleton_methods.grep(/table_name$/)
# => [:schema_migrations_table_name, :internal_metadata_table_name, :table_name, :reset_table_name, :quoted_table_name]
The ActiveRecord library itself makes the database interactions very quick and efficient but there are some tricks that you can use to make your work with console and database even more efficient.
If you don’t want to interact with the database by using ActiveRecord models, you can quickly execute any SQL query against your database. To do this, call the execute method on the current database connection:
sql = "SELECT * FROM users"
results = ActiveRecord::Base.connection.select_all(sql)
results.to_a # => [...]
When using .select_all
, the result will have the same format for all database engines. Beware of execute
method as the result format might differ depending on the database engine you are using. For example, if you use PostgreSQL, the PG::Result
instance will be returned.
select_all
. exec_query
is similar but select_all
is the best choice. Both of these return a generic response for all DBs.
If you executed the Active Record query and assigned it to a variable:
result = User.where(first_name: "John")
If you want to execute it again, you don’t have to write the code again. You can simply call the reload
method on the Active Record result, and the query will be executed again:
result = User.where(first_name: “John”)
result.reload
You can do this when pulling a single record or pulling a collection. The reload
method works as long as the result comes from Active Record.
If you want to get the array with table names at your disposal, you can simply call the following line:
ActiveRecord::Base.connection.tables
On the other side, if you are interested in columns for a particular table, you can use another method that comes with the current connection object:
ActiveRecord::Base.connection.columns("users")
The above call returns an array of objects where each object represents one column and provides information about its type, name, and other attributes.