How do I find the source file for a rake task? - ruby-on-rails

I know you can view all possible rake tasks by typing
rake -T
But I need to know what exactly a task does. From the output, how can I find a source file that actually has the task? For example, I'm trying to find the source for the db:schema:dump task.

I know this is an old question, but in any case:
rake -W
This was introduced in rake 0.9.0.
http://rake.rubyforge.org/doc/release_notes/rake-0_9_0_rdoc.html
Support for the –where (-W) flag for showing where a task is defined.

Despite what others have said, you can programmatically get the source location of rake tasks in a rails application. To do this, just run something like the following in your code or from a console:
# load all the tasks associated with the rails app
Rails.application.load_tasks
# get the source locations of actions called by a task
task_name = 'db:schema:load' # fully scoped task name
Rake.application[task_name].actions.map(&:source_location)
This will return the source locations of any code that gets executed for this task. You can also use #prerequisites instead of #source_location to get a list of prerequisite task names (e.g. 'environment', etc).
You can also list all tasks loaded using:
Rake.application.tasks
UPDATE: See Magne's good answer below. For versions of rake >= 0.9.0 you can use rake -W to show the source location of your rake tasks.

There is no programmatic way to do this unfortunately. Rake tasks can be loaded either from rails itself, lib/tasks, or from any plugin with a tasks directory.
This should nab most everything not within Rails itself:
find . -name "*.rake" | xargs grep "whatever"
As for db:schema:dump, here's the source:
desc "Create a db/schema.rb file that can be portably used against any DB supported by AR"
task :dump => :environment do
require 'active_record/schema_dumper'
File.open(ENV['SCHEMA'] || "#{RAILS_ROOT}/db/schema.rb", "w") do |file|
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
end
end
It can be found on line 242 of lib/tasks/database.rake in the rails 2.2.2 gem. If you've got a different version of Rails, just search for "namespace :schema".
You probably actually want the source of the ActiveRecord::SchemaDumper, but I think you should have no trouble figuring out where that is. :-)

For most rake tasks in Rails, look in the Rails gem directory, in lib/tasks.
If you've vendored Rails into your app directory structure then look in vendor/rails/railties/lib/tasks instead
Either way, db:schema:dump is in databases.rake.

Related

Rake task during application initialization rails

I want to execute a rake task when the server of my application starts.
In config/application.rb i put the following:
if !Rails.env.production?
Rake::Task[ "init:db_records" ].invoke
end
The rake task is well defined, and runs without a problem if i invode it from terminal
rake init:db_records
But when placed in config/application.rb (or even in any initializers/*) i got the following error.
Don't know how to build task 'init:db_records'
What is the way to execute a rake task when the server starts ?
Thanks!
Rails already has a mechanism for setting up a development database -- rake db:seed. It does not run automatically when you start the app, but it does run as part of rake db:setup.
Unless you have a good reason, it's usually best to stick the conventions that Rails provides.
For those who encounter the same problem in the future.
I achieved this by creating a new file in the initializers directory, where i put the code of the rake task.
The advantage of this at this point, is that the application is already loaded, so you have access to ActiveRecord functions...
Putting the code directly in config/application.rb didn't work, since my models were not loaded yet.
Hope it will help!
Your Rake tasks are (likely) defined in a Rakefile. The initializer has no idea that file even exists, so it doesn't know about the tasks within.
The easiest way to circumvent this is by doing something like this:
Dir.chdir(Rails.root) do
`rake init:db_records`
end
That is, change the working directory to the root rails directory, then running the command.

How can i add a task that will run after rake test:db:prepare in Rails

I am using rails 4.2 and i am trying to run test using the command rake test.I am trying to use plv8 extention so i create it manually from psql console, then when i run the test it seems like it has deleted that extension from postgres. I looked into rails 4.2 project and i noticed that they brought test:db:prepare back. This is what is deleting the plv8 extension every time. how can i add a pice of code that will run after the test:db:prepare or test:db:create?
I am not a big fan of modifying Rakefile solution.
You can name multiple tasks inline:
rake test:db:create test:db:prepare custom:task
Or when you create a new rake task you can make it dependent on any other task:
desc "the dependent task will run before this one"
task my_task: :other_task do
# stuff
end
You can also arbitrarily invoke other tasks:
Rake::Task['db:test:prepare'].invoke
More info here: http://jasonseifer.com/2010/04/06/rake-tutorial and here: How to run Rake tasks from within Rake tasks?

Rails 4: stop `rake` from running all rake tasks

A developer had authority to drop a DB but not re-create it. While working on a rake tasks, he accidentally ran the entire rake suite, which included destroying the development DB but without the proper authority to re-create and populate it.
How can I ensure this doesn't happen again? Is there someway in the Rails app to override running rake so that it does NOT execute a bunch of unspecified tasks?
The developer was looking for a list of tasks and figured that running rake would provide that listing, similarly to how running rails by itself puts out instructions.
I know there's a binstub for rake, but I really do not know what happens if I mess with things in there.
Are there any good solutions to a situation like this?
Set the default task? IIRC, outside of a namespace block:
task :default => "something_that_doesnt_destroy_the_world"
Taking a note from Dave's answer and another SO question (couldn't find link again), here is how you can override the default rake tasks in Rails 4.
# lib/tasks/default.rake (name is not important)
namespace :override do
task :default do
puts "This is now the default rake task executed via 'rake'"
end
end
# Remove default task and switch to above (still in same file)
task(:default).clear.enhance ["override:default"]
At the terminal:
$ rake
/lib/tasks/default.rake: this is now the default 'rake' task
If there is a "cleaner" or more "conventional" Rails way, anyone's welcome to shout it out. This is the "cleanest" solution I could find.

How to write and execute an individual rake task outside the Rails application folder

How do you write a rake task outside the Rails application directory and make it run.
For example, say write a sample rake task
task :dummy do
puts User.first.first_name
end
this task is under ~/fun/sample.rake
And my rails application is located at ~/my_app/
Now I need to run the sample.rake. I know i need to load the environment, DB etc., etc., how do i do that? Stuck at this for the past hour.
I tried the one below, obviously it did not work because it did not know how to build it.
rake -f ~/my_app/Rakefile dummy
Note: I should not touch the files inside the Rails application but I can write whatever I want inside the fun directory
You need to create a Rakefile and load the rake gem. See this answer: Ruby: Accessing rake task from a gem without Rails

What steps are followed after you say "rake install"?

I'd like to install a plugin but I'm afraid it's going to install a lot of unnecessary stuff. I'd like to look at whatever file rake takes it installation instructions from and remove anything unnecessary.
I believe this is the Rakefile. But I'm not sure what happens when rake looks at the rakefile - does it execute the entire rakefile or only parts of the rakefile that are designated as being relevant to this "install" procedure?
a rake file is a collection of tasks, when you call rake with an argument (in this case install) that's the task that get's executed. (It's similar to ant if you come from Java)
So, no, rake does not execute the whole rakefile when you call "rake + task" but only the task chosen. Note that tasks can have dependencies (eg the "test" task may depend on other previous tasks, like creating some folders and stuff for the tests to run).
Lastly, the rake user guide as pointed by other users is useful, but I recommend a more enjoyable read here -> Ruby on Rails Rake tutorial.
Rake is set up much like Make in that a Rakefile consists of targets and dependencies. This is different from a regular ruby script in that Rake starts at the target you ask for and recursively executes its dependencies before executing the target itself.
So, install might look like this:
task :install => :stage do
# stuff to do
end
Here, your target is the install task, and it depends on some other task called stage.
To execute install, Rake must first execute the dependencies of stage (if it has any), then stage, then finally it executes install. So no, you don't execute the whole file, just enough of it to safely execute the target you asked for.
Rake also supports file targets:
file 'foo.html' => 'bar.xml' do |t|
# Build foo.html from bar.xml, however that is done
end
If you know Make, this looks familiar. Rake first checks whether bar.xml depends on anything, and if so, it executes that. Then, if bar.xml is newer than foo.html, then Rake executes this file task. If foo.html is newer, then Rake assumes that it has aleady been built and skips it.
For more, the Rake User Guide is a good place to start if you want to learn what Rake does.
Why would a plugin install something "unnecessary"?
Assuming your fears are justified, though, could you not install the plugin, do your investigation and then, if not satisfied, revert to the pre-installed version using your source control system? If you're not using source control, this might be the perfect excuse to start...

Resources