Rake is apparently simple, used all over the place, and a bit fiddly. Whenever you run a rake task, the entire rails application is initialised in the background. But how? HOW?!
- It’s not the namespace you’re using. Arbitrary namespaces all initialise the rails app.
- Therefore, somehow, somewhere, something is happening in some parent task that everything is pulling in. But what?
Well, there’s no specific mechanism in rake that I’m aware of that arbitrary tasks inherit from. So it’s either the case that there’s a mechanism I don’t know about, or it’s the case that the rake tool has been monkeypatched somehow.
The case for rake being monkeypatched seems promising. How does rake -vT know to look in lib/tasks for extra tasks? Rails configuration, that’s how. So, how do you configure rake this way? I want to start by working out where a standard rake task is defined, so I try:
rake --where db:migrate
From here, I can see that railties is responsible for the db tasks. I also try:
rake --where log:clear
and it’s clear again that railties is coming into play. I’ve got a vague idea from the name, and my own reading, that railties is some kind of glue for rails. So, let’s dig a little deeper. I’ve opened my text editor to the location of the railties gem (it’s in the path given out by rake –where log:clear), and there’s a readme. It confirms that railsties is a glue gem.
I search for all files beginning with Rake, just because I’ve got to start somewhere, and find a rakefile in lib/rails/generators/rails/app/templates/ which has the line <%= app_const %>.load_tasks. This reads like an erb template, and I’m not specifically interested save that it gives me a clue: presumably, tasks are discovered by rails using a load_tasks method. Searching for “def load_tasks” in railties reveals:
# Load the application and its railties tasks and invoke the registered hooks.
# Check Rails::Railtie.rake_tasks for more info.
I can buy that initialize_tasks is going to be where I need to start. I search for def initialize_tasks and find:
def initialize_tasks #:nodoc:
task :environment do
$rails_rake_task = true
require_environment!? What does that sound like it does?
def require_environment! #:nodoc:
environment = paths["config/environment"].existent.first
require environment if environment
The namespace we’re in right now is “class Application < Engine”.
I can buy that this is where the environment is getting pulled in for _something_. I don’t know whether it’s the current app I’m working on, some rails-y magic or whatever. However, this doesn’t specifically help me out right now, because I’m trying to prevent rails loading for a rake task. rake task:name will still need to know how to load the rakefile in order to make any progress, which requires that the rails app has loaded. I’ve got a little further on the path to accomplishing my goal, but I’m not quite there.
Of course, I could just be overcomplicating things and there’s simply a Rakefile in rails root. And this slurps in the application config. Curses!