I have a rake task that delivers daily emails via ActionMailer. My plan is to use Heroku's cron job to run this task nightly.
The problem is that my ActionMailer class (Notifier) is not recognized with Heroku. The specific error is "Unitialized constant Notifier." However, the Notifier class properly sends out emails in Heroku everywhere else in the application (controllers and models) but not from the rake task. Running the rake task also does work locally.
If I do heroku rake cron to run the task manually, it throws that error.
heroku rake cron
This doesn't work. However,
rake RAILS_ENV=production cron
works fine (Heroku vs. local).
I've even tried adding my mailer path to the autoload directory.
I think in this case seeing your code would be helpful. I implemented the same exact thing this past weekend on heroku and had no problems. For me my rake task calls a method on my model like so...
#note this has to be in lib/tasks and be named cron.rake
desc "Send mailing"
task :cron => :environment do
Lease.updates
end
My model has the following method...
def self.updates
//setting up params
UserMailer.deliver_report_due(user, #leases)
end
This will call deliver on your method in your UserMailer class.
def report_due(user, leases)
recipients user.email
from "email#email.com"
subject "Confirmation"
body :leases=>leases,
:user=>user
end
Also note that this is rails 2.3 in which you call UserMailer.deliver_method, In rails 3 I think it is UserMailer.method_deliver.
If all else fails you could try restarting your heroku app on the command line with 'heroku restart'
Heroku finally figured out what was going on. I originally created my Notifier class file named as "Notifier" (capitalized first letter) instead of "notifier". I realized the mistake and manually changed the filename, however I had already did a git commit. Well since Max OS X is case insensitive for filenames, changing the capitalization to lowercase didn't commit to git. So everything worked locally on my Macbook, and showed that the filename was correct, but deploying to Heroku pushed a improperly named file. Even worse is that it only was affected under the rake tasks.
I don't think I would have ever figured this out without Heroku.
Try to write
require 'notifier'
in your rake task file
Related
I'm have a server where I deploy using capistrano and I use delayed_jobs to do some mailing but at my server for some reason the jobs do not execute. The delayed_job process is running (running bin/delayed_job status answers me correctly saying there's a process there by some pid), but I don't know if the process just isn't executing my jobs or even if my jobs aren't being enqueued. Locally it all works fine, but at production staging in the server it does not.
I'd like to know if there's a way I can at least check what jobs are there, since I can't do it by accessing the console
Another gem that works with delayed job is delayed-web which you can find here https://github.com/tatey/delayed-web
you add it to your gemfile
gem 'delayed-web'
then run
rails generate delayed:web:install
this will generate an initializer file delayed_web.rb under config/initializers with the following:
Rails.application.config.to_prepare do
Delayed::Web::Job.backend = 'active_record'
end
and in config/application.rb this will be added for you as well by the generator
# config/application.rb
config.assets.enabled = true
config.assets.precompile << 'delayed/web/application.css'
In routes.rb it may add a route as well but if you are using devise then maybe you want to restrict access to admin user(s) only as follows:
authenticated :user, -> user { user.admin? } do
mount Delayed::Web::Engine, at: '/jobs'
end
Ok so I'm checked my jobs through the database itself, I entered psql through postgres user and did some queries in the delayed_jobs table, you can also try doing RAILS_ENV=production bin/delayed_jobs run (for rails 4, rails 3 use "script/" instead of "bin/") which will show you what the workers are doing while they execute the job.
You can also, as Swards commented above, use a gem to have a web interface for delayed_jobs: https://github.com/ejschmitt/delayed_job_web
If you still wanna see what was my problem with the email sending I've opened another question because it got to far away from what this one was about: What port to use sending email with SMTP (mailgun) in rails app on production server (DigitalOcean)?
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.
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.
What is the best way to automatically clear Memcached when I deploy my rails app to Heroku?
I'm caching the home page, and when I make changes and redeploy, the page is served from the cache, and the updates aren't incorporated.
I want to have this be totally automated. I don't want to have to clear the cache in the heroku console each time I deploy.
Thanks!
I deploy my applications using a bash script that automates GitHub & Heroku push, database migration, application maintenance mode activation and cache clearing action.
In this script, the command to clear the cache is :
heroku run --app YOUR_APP_NAME rails runner -e production Rails.cache.clear
This works with Celadon Cedar with the Heroku Toolbelt package. I know this is not a Rake-based solution however it's quite efficient.
Note : be sure you set the environment / -e option of the runner command to production as it will be executed on the development one otherwise.
Edit : I have experienced issues with this command on Heroku since a few days (Rails 3.2.21). I did not have time to check the origin the issue but removing the -e production did the trick, so if the command does not succeed, please run this one instead :
heroku run --app YOUR_APP_NAME rails runner Rails.cache.clear
[On the Celadon Cedar Stack]
-- [Update 18 June 2012 -- this no longer works, will see if I can find another workaround]
The cleanest way I have found to handle these post-deploy hooks is to latch onto the assets:precompile task that is already called during slug compilation. With a nod to asset_sync Gem for the idea:
Rake::Task["assets:precompile"].enhance do
# How to invoke a task that exists elsewhere
# Rake::Task["assets:environment"].invoke if Rake::Task.task_defined?("assets:environment")
# Clear cache on deploy
print "Clearing the rails memcached cache\n"
Rails.cache.clear
end
I just put this in a lib/tasks/heroku_deploy.rake file and it gets picked up nicely.
What I ended up doing was creating a new rake task that deployed to heroku and then cleared the cache. I created a deploy.rake file and this is it:
namespace :deploy do
task :production do
puts "deploying to production"
system "git push heroku"
puts "clearing cache"
system "heroku console Rails.cache.clear"
puts "done"
end
end
Now, instead of typing git push heroku, I just type rake deploy:production.
25 Jan 2013: this is works for a Rails 3.2.11 app running on Ruby 1.9.3 on Cedar
In your Gemfile add the following line to force ruby 1.9.3:
ruby '1.9.3'
Create a file named lib/tasks/clear_cache.rake with this content:
if Rake::Task.task_defined?("assets:precompile:nondigest")
Rake::Task["assets:precompile:nondigest"].enhance do
Rails.cache.clear
end
else
Rake::Task["assets:precompile"].enhance do
# rails 3.1.1 will clear out Rails.application.config if the env vars
# RAILS_GROUP and RAILS_ENV are not defined. We need to reload the
# assets environment in this case.
# Rake::Task["assets:environment"].invoke if Rake::Task.task_defined?("assets:environment")
Rails.cache.clear
end
end
Finally, I also recommend running heroku labs:enable user-env-compile on your app so that its environment is available to you as part of the precompilation.
Aside from anything you can do inside your application that runs on 'application start' you could use the heroku deploy hooks (http://devcenter.heroku.com/articles/deploy-hooks#http_post_hook) that would hit a URL within your application that clears the cache
I've added config/initializers/expire_cache.rb with
ActionController::Base.expire_page '/'
Works sweet!
Since the heroku gem is deprecated, an updated version of Solomons very elegant answer would be to save the following code in lib/tasks/heroku_deploy.rake:
namespace :deploy do
task :production do
puts "deploying to production"
system "git push heroku"
puts "clearing cache"
system "heroku run rake cache:clear"
puts "done"
end
end
namespace :cache do
desc "Clears Rails cache"
task :clear => :environment do
Rails.cache.clear
end
end
then instead of git push heroku master you type rake deploy:production in command line.
To just clear the cache you can run rake cache:clear
The solution I like to use is the following:
First, I implement a deploy_hook action that looks for a parameter that I set differently for each app. Typically I just do this on the on the "home" or "public" controller, since it doesn't take that much code.
### routes.rb ###
post 'deploy_hook' => 'home#deploy'
### home_controller.rb ###
def deploy_hook
Rails.cache.clear if params[:secret] == "a3ad3d3"
end
And, I simply tell heroku to setup a deploy hook to post to that action whenever I deploy!
heroku addons:add deployhooks:http \
--url=http://example.com/deploy_hook?secret=a3ad3d3
Now, everytime that I deploy, heroku will do an HTTP post back to the site to let me know that the deploy worked just fine.
Works like a charm for me. Of course, the secret token not "high security" and this shouldn't be used if there were a good attack vector for taking your site down if caches were cleared. But, honestly, if the site is that critical to attack, then don't host it on Heroku! However, if you wanted to increase the security a bit, then you could use a Heroku configuration variable and not have the 'token' in the source code at all.
Hope people find this useful.
I just had this problem as well but wanted to stick to the git deployment without an additional script as a wrapper.
So my approach is to write a file during slug generation with an uuid that marks the current precompilation. This is impelmented as a hook in assets:precompile.
# /lib/tasks/store_asset_cacheversion.rake
# add uuidtools to Gemfile
require "uuidtools"
def storeCacheVersion
cacheversion = UUIDTools::UUID.random_create
File.open(".cacheversion", "w") { |file| file.write(cacheversion) }
end
Rake::Task["assets:precompile"].enhance do
puts "Storing git hash in file for cache invalidation (assets:precompile)\n"
storeCacheVersion
end
Rake::Task["assets:precompile:nondigest"].enhance do
puts "Storing git hash in file for cache invalidation (assets:precompile:nondigest)\n"
storeCacheVersion
end
The other is an initializer that checks this id against the cached version. If they differ, there has been another precompilation and the cache will be invalidated.
So it dosen't matter how often the application spins up or down or on how many nodes the worker will be distributed, because the slug generation just happens once.
# /config/initializers/00_asset_cache_check.rb
currenthash = File.read ".cacheversion"
cachehash = Rails.cache.read "cacheversion"
puts "Checking cache version: #{cachehash} against slug version: #{currenthash}\n"
if currenthash != cachehash
puts "flushing cache\n"
Rails.cache.clear
Rails.cache.write "cacheversion", currenthash
else
puts "cache ok\n"
end
I needed to use a random ID because there is as far as I know no way of getting the git hash or any other useful id. Perhaps the ENV[REQUEST_ID] but this is an random ID as well.
The good thing about the uuid is, that it is now independent from heroku as well.
I wonder how to setup testing in my rails apps. When I run rake test, first thing odd, it launch a bunch of CREATE TABLE against my dev. database (hum.. do not like this..). So I launch rake test RAILS_ENV=test and I even try bundle exec rake test RAILS_ENV=test. Now, the CREATE TABLE is against my test database but all fails with this error :
** Execute test:units
test/unit/category_test.rb:5:in `test': unknown command 't' (ArgumentError)
from test/unit/category_test.rb:5:in `<class:CategoryTest>'
I have used basic generator in Rails 3 and do not change anything. So I have this in caterogy_test.rb :
require 'test_helper'
class CategoryTest < ActiveSupport::TestCase
# Replace this with your real tests.
test "the truth" do
assert true
end
end
I use Rails 3.0.7 and basic config.
Any ideas ?
EDIT
I am becoming crazy, made a lot of tries, neither seems to work. When I start a new application with a few things, rake test works fine but when I try this on my current one, it launch always against my dev. db and do not work at all. I have tried to edit the test files, to revert them back, try to remove/setup test db with different ways, try different rake version, compare a lot of things on one side my current application and on the other a brand new one... Found nothing.. Help !
EDIT 2
Sounds lame, but is it normal that rake does the same thing than rake test ?
EDIT 3
Sounds odds, while I continue to work on what's wrong, I realize that every-time I run rake test, it does stuff on the dev environment and not the test one (watching the logs). It does this on my computer OSX and on our server FreeBSD for all the Rails 3.0.7 apps. Are you sure rake test is supposed to work on the test environment by default ?
EDIT 4
Please help!
EDIT 5 - SUMMARY
When running rake test in my computer or on our server in Rails 3.0.7 with different apps it does the following :
run CREATE TABLE and INSERT INTO migration against the dev. db.
do not empty the dev. db.
development.log gets written not the test.log
also an issue with the error unknowm comman 't' with one specific app.
EDIT 6 - db config
Nothing change from the default yet : https://gist.github.com/1006199
EDIT 7
rake db:test:prepare --trace -> nothing break (but keep printing (first_time)
https://gist.github.com/1007340
With RAILS_ENV="test" for rake, everything goes fine. It write on the test logs.
ruby -I test test/unit/category_test.rb same erros than with rake, but no write on the dev. or test logs.
a bunch of unorderd answers:
the "CREATE TABLE" statements usually means that your test_db is created from scratch (by default, before test task, a db:migrate is launched). are you sure they're called on dev_db?
also check your config/database.yml to see if there's some typo (eg: using same table for test and dev environments)
it looks like there's an error in some of your migration files (that 't' error remember blocks in migrations).
"rake test" is the default task, that's why it's run when you just launch "rake" without arguments.
EDIT:
according on what I see on edits, from 5 and above, it looks like you have some issue with environment files. so try to double-check:
* config/environments/test.rb
* config/application.rb
* config/environment.rb
if with RAILS_ENV="test", everything goes fine, then I'm almost sure you have changed some default behaviour in your app (configs, env variables, any particular gem?)
also, in your test/test_helper.rb, add RAILS_ENV='test' at the beginning of file, this should force test environment.
I had that same error message, except to me it said: in `test': unknown command 'i' (ArgumentError).
The 'fix' or 'workaround' was to simply use:
$> bundle exec rake test
instead of using 'rake test'