ruby-on-railsruby-on-rails-3ruby-on-rails-4rakerails-4-upgrade

enhancing the global environment task rails


On the application I am upgrading from Rails 3.2.22.4 to Rails 4.0.13, the following block of code for enhancing the global environment task has become a road-block by not working on the target Rails version:

Rails.application.class.rake_tasks do                                              
  Rake::Task["environment"].enhance do                                             
    ...                                                  
  end                                                                              
end 

This works fine on 3.2, but fails with Don't know how to build task 'environment' error message in 4.0.

In 3.2, Rails.application.class.rake_tasks returns a Proc object ( [#<Proc:0x007f978602a470@.../lib/rails/application.rb:301>] ) pointing to this line in the rails codebase. On 4.0, it returns an empty array.

The line referred to in the above Proc object seems to be removed in this commit.

What would the preferred way to enhance the environment rake task be in Rails 4.x?

The above piece of code is in the lib/subdomain/rake.rb file, and it is include with the following code in lib/subdomain/engine.rb:

module Subdomain
  class Engine < Rails::Engine

    ...
    rake_tasks do |_app|
      require 'subdomain/rake'
    end
    ...
  end
end

Rake tasks can't be executed as the command fails with this error. rails server|console commands work ok.


Solution

  • Option 1

    If I'm understanding the question properly, something like this should work by placing these tasks in a standard location like lib/tasks/environment.rake. Note: None of this is particularly Rails-specific.

    # Re-opening the task gives the ability to extend the task
    task :environment do
      puts "One way to prepend behavior on the :environment rake task..."
    end
    
    task custom: :environment do
      puts "This is a custom task that depends on :environment..."
    end
    
    task :environment_extension do
      puts "This is another way to prepend behavior on the :environment rake task..."
    end
    
    # You can "enhance" the rake task directly too
    Rake::Task[:environment].enhance [:environment_extension]
    

    The output of this would be:

    $ rake custom
    This is another way to prepend behavior on the :environment rake task...
    One way to prepend behavior on the :environment rake task...
    This is a custom task that depends on :environment...
    

    Option 2

    However, the question remains as to why :environment needed to be extended. If it's to trigger something before, say, a db:migrate, you might be better off just re-opening the task in question and adding another dependency to that particular task. For example:

    task custom: :environment do
      puts "This is a custom task that depends on :environment..."
    end
    
    task :custom_extension do
      puts "This is a new dependency..."
    end
    
    # Re-opening the task in question allows you to added dependencies
    task custom: :custom_extension
    

    The result of this is:

    $ rake custom
    This is a new dependency on :custom
    This is a custom task that depends on :environment...
    

    C-C-C-Combo Breaker!!

    Combining everything, the output would look like this:

    $  rake custom
    This is another way to prepend behavior on the :environment rake task...
    One way to prepend behavior on the :environment rake task...
    This is a new dependency on :custom
    This is a custom task that depends on :environment...