Create childrens on rake task - ruby-on-rails

I have many rake scripts named example1_task, example1_task2 ... etc. I like to convert this scripts into once and use example1:task1, example1:task2 like i do with the command rake db:migrate on rails migrations.
Any idea ?
Thanks in advance.

Yes, use namespace:
namespace "example" do
task :task1 do
#some code
end
task :task2 do
#some code
end
end

Related

how to run rake task using rails migration

I want to run rake task using migration because we want when a user run rails db:migrate then this task will be run through migration.
my rake task is:
namespace :task_for_log do
desc "This task set by default as current date for those logs where log_date is nil"
task set_by_default_date_of_log: :environment do
Log.where("log_date IS NULL").each do |log|
log.update_attributes(log_date: log.created_at.to_date)
end
end
end
please guide what will be migration that run this task, any body here who will be save my life??
Migrations are really just Ruby files following a convention, so if you want to run a rake task inside of them you can just call the Rake class.
class ExampleMigration < ActiveRecord::Migration[5.0]
def change
Rake::Task['task_for_log'].invoke
end
end
However, migration files should be used specifically to handle the database schema. I would rethink how you are approaching the problem for a better solution. For example, you could run a SQL statement that updates your log attributes instead of calling a rake task.
class ExampleMigration < ActiveRecord::Migration[5.0]
def change
execute <<-SQL
UPDATE logs SET log_date = created_at WHERE log_date IS NULL
SQL
end
end
References:
Rails how to run rake task
https://edgeguides.rubyonrails.org/active_record_migrations.html
If you want to run your task after you run db:migrate automatically, you can use enhance.
Rake::Task['db:migrate'].enhance do
# This task runs after every time you run `db:migrate`
Rake::Task['task_for_log:set_by_default_date_of_log'].invoke
end
For a rails application, you can put this anywhere inside lib/tasks folder or put your task inline (inside of the .enhance do block)
You can go as #joseph mention better solution! Or create custom task for it.
rake:
rake cm:set_by_default_date_of_log
task:
#lib/tasks/cm.rake
#custom_migration
namespace :cm do
desc "This task set by default as current date for those logs where log_date is nil"
task set_by_default_date_of_log: ['db:migrate'] do
Log.where("log_date IS NULL").each do |log|
log.update_attributes(log_date: log.created_at.to_date)
end
end
end

Prepend to existing rake task

Defining an existing rake task again appends to the original, but I'd like to prepend to the db:migrate task. I want to raise an error beforehand in some cases. Is there a good way to prepend to an existing rake task?
Try adding a db:custom task on 'db' namespace and invoke db:migrate with enhance method
# add your custom code on db:custom
namespace 'db' do
task 'custom' do
puts "do custom db stuff"
end
end
# invoke db:migrate
Rake::Task['db:migrate'].enhance [:custom]
Might be better to define your own task and call db:migrate inside.
namespace :custom_db do
desc 'migrate db if condition true'
task :migrate do
if true #your condition
Rake::Task['db:migrate'].invoke
else
#process errors
end
end
end

How to import Model into a custom rake task?

In my lib/tasks folder I added a new .rake file.
In the rake task, I am doing this:
p = Post.new( ....)
p.save!
When I run my task, I get the error:
rake aborted!
uninitialized constant Post
What do I have to do to import my Post model?
I'm thinking you're probably missing the environment declaration. This is necessary in order for Rake to know about your Rails environment. Your rake task call should look something like this:
task :my_rake_task => [:environment] do
# Your code here
end
Let me know if that solves the problem!
You want to make the task dependent on the rails environment. You can do so by specifying the => :environment after the task declaration as such:
namespace :my_task do
desc "an example task"
task :create_post => :environment do
Post.new .... # the rest of the implementation
end
end

Overriding rails' default rake tasks

I have a Rails 2.2 project in which I want to override the functionality of the rake db:test:prepare task. I thought this would work, but it doesn't:
#lib/tasks/db.rake
namespace :db do
namespace :test do
desc "Overridden version of rails' standard db:test:prepare task since the schema dump used in that can't handle DB enums"
task :prepare => [:environment] do
puts "doing db:structure:dump"
Rake::Task['db:structure:dump'].invoke
puts "doing db:test:clone_structure"
Rake::Task['db:test:clone_structure'].invoke
end
end
end
I get the standard task's behaviour. If I change the name of the task to :prepare2 and then do rake db:test:prepare2, then it works fine. The natural conclusion I draw from this is that my rake tasks are being defined before the built-in Rails ones, so mine is overridden by the standard :prepare task.
Can anyone see how I can fix this? I'd rather override it than have to use a new task. Thanks, max
If you define a rake task that already exists, its execution gets appended to the original task's execution; both tasks will be executed.
If you want to redefine a task you need to clear the original task first:
Rake::Task["db:test:prepare"].clear
It's also useful to note that once a task has been executed in rake, it won't execute again even if you call it again. This is by design but you can call .reset on a task to allow it to be run again.
You have to remove the default task before adding your own:
Rake.application.instance_variable_get('#tasks').delete('db:test:prepare')
namespace 'db' do
namespace 'test' do
task 'prepare' do
# ...
end
end
end
A fairly popular idiom is to create a convenience method called remove_task like so:
Rake::TaskManager.class_eval do
def remove_task(task_name)
#tasks.delete(task_name.to_s)
end
end
def remove_task(task_name)
Rake.application.remove_task(task_name)
end
(Source: drnic/newgem)
Create a new project.rake file at lib/tasks/, and paster below code into it.
namespace :mv do
desc "Display hint and info for your rails 4 project"
task info: :environment do
puts 'Run rake test to test'
end
end
task(:default).clear.enhance ['mv:info']
inspired by Krasimir Angelov's blog

How to prevent Rake test to call task db:test:prepare

Every time I want to run Rake test the task db:test:prepare is being called and it rebuilds my test environment database from schema.rb and migrations. What I would like to achive is to disable the call of db:test:prepare when I want to test make Rails application. Is it possible without modifying Rails gem?
Here's a solution I've seen around:
In your Rakefile:
Rake::TaskManager.class_eval do
def remove_task(task_name)
#tasks.delete(task_name.to_s)
end
end
In lib/tasks/db/test.rake:
Rake.application.remove_task 'db:test:prepare'
namespace :db do
namespace :test do
task :prepare do |t|
# rewrite the task to not do anything you don't want
end
end
end
There is a plugin that takes care of this for you: override_rake_task. Here is a quick usage example:
namespace :db do
namespace :test do
override_task :prepare do; end
end
end
For some older version of rails - you can place Rake::Task['db:test:prepare'].clear at the end of your Rakefile

Resources