Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent initializers from running when running `rails generate`

I want to prepopulate my cache with an initializer, but I don't need this code to run every time I run rake or rails g, etc. Rake and Bundler are easy to deal with, but a similar solution does not work for the generators:

# config/initializers/prepop_cache.rb
if !defined?(::Bundler) and !defined?(::Rake) and !defined(Rails::Generators)
  # do stuff
end

This must be because rails/generators (or something similar) is requireed at runtime. How can I check to see if the command being run is rails g xyz?

Update:

Two solutions can be found here: Rails 3 initializers that run only on `rails server` and not `rails generate`, etc

Still would like to know if it's possible in the manner I've tried above.

like image 366
jordanpg Avatar asked Nov 13 '12 00:11

jordanpg


1 Answers

In Rails 3, what you're looking to do is conceivably possible, but in a hacky way. Here's how:

When you make a rails generate call, the callpath looks like this:

  • bin/rails is called, which eventually routes you to execute script/rails
  • script/rails is executed which requires rails/commands
  • rails/commands is loaded, which is the main point of focus.

Within rails/commands the code that runs for generate:

ARGV << '--help' if ARGV.empty?

aliases = {
  "g"  => "generate",
  "c"  => "console",
  "s"  => "server",
  "db" => "dbconsole"
}

command = ARGV.shift                       # <= #1
command = aliases[command] || command

case command
when 'generate', 'destroy', 'plugin', 'benchmarker', 'profiler'
  require APP_PATH
  Rails.application.require_environment!   # <= #2
  require "rails/commands/#{command}"      # <= #3

The points of interest are numbered above. Namely, that at point #1 the command that you're running is shifting off of ARGV. Which in your case means generate is going to be removed from the command line args.

At point #2 your environment gets loaded, at which point your initializers are going to be executed. And herein is the tough part - because nothing indicating a specific command has been loaded at this point (this occurs at #3) there is no information to determine a generator is being run!

Let's insert a script into config/initializer/debug.rb to see what is available if we ran rails generate model meep:

puts $0     #=> "script/rails"
puts ARGV   #=> ["model", "meep"]

As you can see, there is no direct information that a generator is being run. That said, there is indirect information. Namely ARGV[0] #=> "model". Conceivably you could create a list of possible generators and check to see if that generator has been called on ARGV[0]. The responsible developer in me says this is a hack and may break in ways you'd not expect so I'd use this cautiously.

The only other option is to modify script/rails like you suggested -- which isn't too bad a solution, but would likely break when you upgrade to Rails 4.


In Rails 4, you've got more hope! By the time the application environment is being loaded, the generators namespace has already been loaded. This means that in an initializer you could do the following:

if defined? Rails::Generators   #=> "constant"
  # code to run if generators loaded
else
  # code to run if generators not loaded
end
like image 91
Gavin Miller Avatar answered Oct 02 '22 15:10

Gavin Miller