Access Rails Models in Rake Task

How to Access Rails Models in a Rake Task

This article shows how you can access your application models and other constants inside rake tasks by adding the `environment` task as a dependency. We'll also go one level deeper and learn exactly how this task loads the environment by inspecting the Rails source code.

3 min read

If you’ve been working with Rails for a while, you must have come across Rake. In fact, the very first post on this blog was a brief introduction to Rake. Written by the late Jim Weirich (my Ruby hero), Rake is to Ruby what make is to C. It makes it very easy to write tasks to simplify your development workflows.

However, one question that many new Rails developers have when learning Rails (I did, too) is how to access the Rails models or other domain classes in a Rake task, which is very useful for running some application logic or performing database queries via the command line. This article shows you how.

Accessing Models in Rake Tasks

Just add the :environment task as a dependency for your custom Rake task. It's that simple.

task count_users: [:environment] do
  puts User.count
end

That's it. Now you can access any models in the task.

Long Answer: Load Rails Environment

Here’s a simple Rake task that tries to use an ActiveRecord model named User.

# lib/tasks/count.rake

desc "count the number of users in the system"
task :count_users do
  puts User.count
end

If I try to run this Rake task as it is, Rails throws a NameError, as it doesn’t know what User refers to. It has no idea about the context of our Rails application. No constants (classes and stuff) have been loaded so far.

$ bin/rails count_users

rails aborted!
NameError: uninitialized constant User

  puts User.count
       ^^^^^^^^^^^^^^^

To make the ActiveRecord models available in the Rake tasks, we must tell Rails to load the environment before running the task. This is what happens when you launch the Rails console.

Loading the Rails environment gives you access to the ActiveRecord models, database, and much more.

Rails provides an :environment task to load the environment. In Rake terminology, your task is dependent on the :environment task, as it must be performed before your task.

the environment task in Rails
the environment task in Rails
# lib/tasks/count.rake

desc "count the number of users in the system"
task count_users: [:environment] do
  puts User.count
end

Now you can access the User model in the rake task without any errors.

But we don't have to stop here. Let's go one step further and explore exactly what the environment task is doing.

How Environment Task Works

The :environment task is defined in the railties/lib/rails/application.rb file. All it does is load the config/environment.rb file in your application, which is what Rails does when you launch your application.

Here's a simplified version of the underlying code.

# railties/lib/rails/application.rb

task :environment do
  require_environment!
end

def require_environment!
  environment = paths["config/environment"].existent.first
  require environment if environment
end

Note: The existent method returns all expanded paths but only if they exist in the filesystem.

Upon loading, the environment.rb file will first require the application.rb file and then call the initialize method on your application. This is exactly how your Rails application boots up when you launch it.

# config/environment.rb

# Load the Rails application.
require_relative "application"

# Initialize the Rails application.
Rails.application.initialize!

Once the Rails application loads, it provides access to all the constants in your application, and that's how you can access your Rails models inside a Rake task.


That's a wrap. I hope you found this article helpful and you learned something new.

As always, if you have any questions or feedback, didn't understand something, or found a mistake, please leave a comment below or send me an email. I reply to all emails I get from developers, and I look forward to hearing from you.

If you'd like to receive future articles directly in your email, please subscribe to my blog. Your email is respected, never shared, rented, sold or spammed. If you're already a subscriber, thank you.