3

What is the difference between commands rake and rails in Ruby?

Which one is faster and why?

NoDataDumpNoContribution
  • 10,591
  • 9
  • 64
  • 104
  • 2
    `rails task_name` is a wrapper around `rake task_name`. It's all about convenience, i.e. having one binary to handle several things. Personally, I dislike this "Swiss Army knife" approach. I use `rake` when I want to run a Rake task. – Stefan Feb 22 '21 at 09:18
  • Thanks, can you tell which one is faster? – Muhammad Huzaifa Feb 22 '21 at 10:29
  • Can i track time for a task with both rails/rake commands? – Muhammad Huzaifa Feb 22 '21 at 10:34
  • 3
    You could use `time rails task_name` vs. `time rake task_name`, see [time(1)](https://linux.die.net/man/1/time) – the difference is probably negligible. – Stefan Feb 22 '21 at 11:08

2 Answers2

4

rake is a Make-like program implemented in Ruby.

rails is a web framework, which also has some rake tasks.

This means that you can have a ruby program with rake but without rails, but not the other way around.

By itself, rake will be faster because you don't need to load the whole rails application.

But when launching a rake task, it can have dependencies, for example the :environment dependency in a rails app, which tells rake to load the rails environment and quite a bit of your application depending on the current environment.

In this case, the initialization of a rake task may take as long as a rails command.

Please note that the actual task run needs also to be taken into account, it can be very short or take several minutes.

For example, rake db:migrate, which is a rails task available by default, runs the migrations on the database, which can be time-consuming if the database is already populated and/or you have a lot of migrations

NoDataDumpNoContribution
  • 10,591
  • 9
  • 64
  • 104
Jaffa
  • 12,442
  • 4
  • 49
  • 101
4

The difference is in what binary is being called.

If you were to call bundle exec which rake within your Rails app root directory, you'd get something like /home/[USERNAME]/.rbenv/versions/2.5.5/bin/rake and for bundle exec which rails, you'd get /home/[USERNAME]/.rbenv/versions/2.5.5/bin/rails. From there you can cat (cat /home/[USERNAME]/.rbenv/versions/2.5.5/bin/rake) both these paths and see similar code is being ran for each, but the end of the files is different.

rails

gem "railties", version
load Gem.bin_path("railties", "rails", version)

rake

gem "rake", version
load Gem.bin_path("rake", "rake", version)

Here they're both calling load on Gem.bin_path but with different arguments, which are attempting to load separate gems in. You can follow the code further by running a irb/pry/rails console, and setting up the needed require 'rubygems' and version = ">= 0.a", then run Gem.bin_path("railties", "rails", version) and Gem.bin_path("rake", "rake", version) to see what the load is actually trying to run. I'll admit it'll become a bit of a rabbit hole before you come across the logic that eventually ends up identifying a rake task argument passed to rails and it proxy's it to Rake and stop there and defer to this SO answer for the rest.

When rails is ran and passed arguments which were intended to be ran by rake, it will attempt to first find if it was an actual argument intended to be given to the rails command, determine that it wasn't, then attempt to run it as a rake command for you for overall naming simplicity added in by the Rails team in Rails v4.

So which is faster to run? rake for actual rake tasks, as it'll bypass the extra logic in needing to determine it was being passed rake arguments. But also rails specific arguments cannot be ran with rake e.g. bundle exec rake generate will not work (unless you have a generate task). If in doubt, run bundle exec rails --help and in at least Rails v5, it'll output which arguments are rails specific and which are rake specific.

Travis
  • 13,311
  • 4
  • 26
  • 40