I have some problems with one of gem supporting ActiveModel caching. When I'm using observer for cached model, during application initialization it tries to describe table to get all fields names.
The same thing is done when rake task is running, including db:migration. In that case there is some circular reference error. I'd like to detect current rake task, to skip gem initialization, but I don't know how to find out was code invoked through rake task. How to check it?
I dont get exactly what you are trying to do, but here is an example of getting the task name.
task :testing do |task_name|
puts task_name
end
This question has been asked a few places, and I didn't think any of the answers were very good... I think the answer is to check Rake.application.top_level_tasks, which is a list of tasks that will be run. Rake doesn't necessarily run just one task.
If you run your task via rake task or bundle exec rake task you can check it in your initializer simply by:
if $0.end_with?('rake')
# rake stuff
else
# non-rake stuff
end
You can use $PROGRAM_NAME instead of $0 if you like.
Related
I have a rake task that works with models. But I need to tell the models that they are being used from Rake instead of within the app. My best idea is to set an environment variable on the command line before running the rake task, but that requires everyone on the team to remember to use the environment variable. Specifically, I have an if statement to skip loading Delayed::Job's handle_asynchronously while running the rake task.
class Thing < ActiveRecord::Base
searchable do
string :title
text :title, :content
end
handle_asynchronously unless ENV['MIGRATINGDATA']
end
When we run our migration task we do this:
MIGRATINGDATA=true bundle exec rake project:migrate_data
I'd like to get rid of the need for the special addition to the command line. Our migration code loads a fake Sunspot instance to turn off indexing while migrating the data.
Just set something at the top of your Rakefile:
ENV['HELLO_RAKE'] = true
require_relative 'config/application'
Rails.application.load_tasks
Instead of using ENV you could, if you wanted, set a constant, e.g. HELLO_RAKE = true and then check defined?(HELLO_RAKE).
An alternative is to just check if the running program is rake:
handle_asynchronously unless File.basename($0) == "rake"
A downside to both of these approaches is that they will be in effect any time you're using Rake, which will include other Rake tasks not related to migrations.
If your models care if you are using them from a rake task or not, you are doing something wrong. Instead you can add parameters to certain methods for example. In your specific use case, you can run jobs immediately instead. Put this at the start of your rake task:
Delayed::Worker.delay_jobs = false
I am using http://rails-erd.rubyforge.org/ to generate an ERD - the output is a very nice diagram of my project's object model. There is also a rake task to generate the ERD, generate_erd, that I would like to have invoked automatically after I run rake db:migrate. How do I do that?
The given link by #MaxWilliams is a helpful but I don't think any of those answers quite do what you want. I found this article on Rake Task Overwriting. It's from 2008, but I tried this out and it worked.
I created another .rake file (for organization) and just happened to call mine migrate_and_generate_erb.rake but name it whatever you want.
Inside I just had this:
namespace :db do
task :migrate do
Rake::Task["erd"].invoke
end
end
Basically, according to the article, Rake just keeps appending code implementation to the task if it's already defined.
Now running rake db:migrate also generated me my ERD.
Careful: You'll also want to do the same for db:rollback so that rolling back a migration also updates your ERD.
One last note: consider also just aliasing this (shell command), just in case you'd ever want to run the migrate without generate the ERD, or use environment variables along with your new Rake task.
I have run into a very strange problem. I have a task which resets my database as so:
task :reset => [:drop, :create, :migrate, :seed]
The problem is, I am receiving errors when seeding because of missing columns which are added in late migration files. One example:
undefined method new_attr= for User
Yet this attribute is already added in a migration. The strange part is, I receive no errors if I run the above tasks separately. Can anybody shed some light? Surely these tasks cannot be run asynchronously.
Another way to avoid errors is to amend my earlier migrations create_ with the new attributes. Then running :reset doesn't trigger errors for those attributes.
The migrations are clearly fine as I can run the above tasks separately, just not bundled under a single task.
maybe you want to make your reset task more explicit?
namespace :db_tasks do
desc "Rebuild development db"
task :rebuild_database, [] => :environment do
raise "Only run in development or staging" if Rails.env.production?
Rake::Task['db:drop'].execute
Rake::Task['db:create'].execute
Rake::Task['db:migrate'].execute
Rake::Task['db:seed'].execute
Rake::Task['db:test:prepare'].execute
end
end
Probably your problem is already solved using this:
rake db:reset
The rake db:reset task will drop the database, recreate it and load the current schema into it.
Have you tried with namespace?
task :reset => [db:drop, db:create, db:migrate, db:seed]
If these rake tasks are executed in the production mode,
model attributes are cached. Even though migrations work perfect, it wont apply to the cached.
This will break your succeeding seed as newly added columns will be missing in the cache.
A possible solution is to reload your rails environment before seeding.
This is a 2nd part to the following question:
Where to put model "utility" functions in Ruby on Rails
Problem is, I need access to these utility functions from a rake task as well. Using the accepted technique in in the other thread, I get an "undefined method" error when accessing my model from a rake task.
What is the best way to fix this?
Thanks
You probably need to define your rake task as dependent on the Rails environment:
task :my_task => :environment do
# Will load Rails stack before executing this block
MyModel.foo
end
The default behavior is to load almost nothing, so you won't have access to your models unless you ask for it.
I have seen some apps that have a few rake tasks included to load data. I am not talking about seed data, I know about db/seeds.rb, instead I am referring to data such as default users and basic records that help me fill my application with something to look at. I don't want to use db:fixtures:load because I don't have any control over this...
I would like to have rake tasks like this:
rake myapp:data:delete
rake myapp:data:load
rake myapp:data:reload
Where the 'delete' rake task would delete all data that I specify in the rake task, the 'load' app will load the default data from the task into the app and the 'reload' task will delete all data, then load it in the app. How do I do something like this?
If you could give me an example where I have a model named 'Contact' and a few fields - basically how to add or delete data from those fields in a rake task, I would REALLY appreciate it!
Just to give you an idea, I would mainly use these rake tasks when I move from one computer to another to do development. I don't want to manually go enter default records (such as my user to login with) so I could just do rake myapp:data:reload - this would be after doing rake db:schema:load
Thank you,
BN
Create a file lib/tasks/data.rake and write the following code:
require File.join(File.dirname(__FILE__), '../../config/environment')
require 'database_cleaner'
namespace :myapp do
namespace :data do
task :delete do
DatabaseCleaner.strategy = :truncation
DatabaseCleaner.clean
end
task :load do
require 'db/data.rb'
end
task :reload do
Rake::Task['myapp:data:delete'].invoke
Rake::Task['myapp:data:load'].invoke
end
end
end
So now you have defined your rake tasks. I'm using the gem database_cleaner, so you'll need to install it:
sudo gem install database_cleaner
Now, the rake myapp:data:load is basically loading the data from a file called db/data.rb. You could name it anything you wanted as long as you used the file name in the rake task or you could use more than one file if you wanted... So create the file db/data.rb and put all the code that you need...
User.create(...)