I am trying to use use actionmailer with sendgrid and devise on Rails 3.2. I browsed many questions on SO like replace smtp by sendmail, create a config/email.yml I don't have one) and many more ideas but nothing works. I must be missing something.
Emails just seem not to be sent in development or production. (sendgrid does not report any email sent and I checked I never receive emails in my "manual tests").
Running Heroku console, I just managed to get this info:
NoMethodError: undefined method `email' for nil:NilClass on the notifier.rb file:
:mail( :to => user.email, :subject => "Thanks for signing up" )
The full trace:
irb(main):007:0> Notifier.welcome_email(@user).deliver --trace
NoMethodError: undefined method `email' for nil:NilClass
from /app/app/mailers/notifier.rb:16:in `welcome_email'
from /app/vendor/bundle/ruby/1.9.1/gems/actionpack-3.2.13/lib/abstract_controller/base.rb:167:in `process_action'
from /app/vendor/bundle/ruby/1.9.1/gems/actionpack-3.2.13/lib/abstract_controller/base.rb:121:in `process'
from /app/vendor/bundle/ruby/1.9.1/gems/actionpack-3.2.13/lib/abstract_controller/rendering.rb:45:in `process'
from /app/vendor/bundle/ruby/1.9.1/gems/actionmailer-3.2.13/lib/action_mailer/base.rb:459:in `process'
from /app/vendor/bundle/ruby/1.9.1/gems/actionmailer-3.2.13/lib/action_mailer/base.rb:453:in `initialize'
from /app/vendor/bundle/ruby/1.9.1/gems/actionmailer-3.2.13/lib/action_mailer/base.rb:439:in `new'
from /app/vendor/bundle/ruby/1.9.1/gems/actionmailer-3.2.13/lib/action_mailer/base.rb:439:in `method_missing'
from (irb):7
from /app/vendor/bundle/ruby/1.9.1/gems/railties-3.2.13/lib/rails/commands/console.rb:47:in `start'
from /app/vendor/bundle/ruby/1.9.1/gems/railties-3.2.13/lib/rails/commands/console.rb:8:in `start'
from /app/vendor/bundle/ruby/1.9.1/gems/railties-3.2.13/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
But I don't understand why it does not recognize the user.email.
Does anybody know what I'm doing wrong?
Here are the files I think are important:
app/mailers/notifier.rb
class Notifier < ActionMailer::Base
include SendGrid
sendgrid_category :use_subject_lines
sendgrid_enable :ganalytics, :opentrack, :clicktrack
sendgrid_ganalytics_options :utm_source => "general_notifier", :utm_medium => "email"
default :from => "[email protected]"
# send a signup email to the user, pass in the user object that contains the user's email address
def welcome_email(user)
@user = user
@url = "http://example.com/login"
mail( :to => user.email, :subject => "Thanks for signing up" )
end
end
Notifier is called by app/controllers/user_controller.rb:
class UsersController < ApplicationController
before_filter :authenticate_user!
# POST /users
# POST /users.json
def create
@user = User.new(params[:user])
respond_to do |format|
if @user.save
# Tell the UserMailer to send a welcome Email after save
Notifier.welcome_email(@user).deliver
format.html { redirect_to(@user, :notice => 'User was successfully created.') }
format.json { render :json => @user, :status => :created, :location => @user }
else
format.html { render :action => "new" }
format.json { render :json => @user.errors, :status => :unprocessable_entity }
end
end
end
def index
authorize! :index, @user, :message => 'Not authorized as an administrator.'
@users = User.all
end
def show
@user = User.find(params[:id])
end
def update
authorize! :update, @user, :message => 'Not authorized as an administrator.'
@user = User.find(params[:id])
if @user.update_attributes(params[:user], :as => :superadmin)
redirect_to users_path, :notice => "User updated."
else
redirect_to users_path, :alert => "Unable to update user."
end
end
def destroy
authorize! :destroy, @user, :message => 'Not authorized as an administrator.'
user = User.find(params[:id])
unless user == current_user
user.destroy
redirect_to users_path, :notice => "User deleted."
else
redirect_to users_path, :notice => "Can't delete yourself."
end
end
My config/Environement.rb files (passwords point to application.yml)
# Load the rails application
require File.expand_path('../application', __FILE__)
# Initialize the rails application
ExampleApp::Application.initialize!
ActionMailer::Base.delivery_method = :smtp
ActionMailer::Base.smtp_settings = {
:user_name => 'SENDGRID_USERNAME',
:password => 'SENDGRID_PASSWORD',
:domain => 'SENDGRID_DOMAIN',
:address => 'smtp.sendgrid.net',
:port => 587,
:authentication => :plain,
:enable_starttls_auto => true
}
also in config/environments/development.rb
# ActionMailer Config
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
config.action_mailer.delivery_method = :smtp
# change to true to allow email to be sent during development
config.action_mailer.perform_deliveries = true
config.action_mailer.raise_delivery_errors = true #useful to have to debug
config.action_mailer.default :charset => "utf-8"
config.action_mailer.smtp_settings = {
:user_name => 'SENDGRID_USERNAME',
:password => 'SENDGRID_PASSWORD',
:domain => 'SENDGRID_DOMAIN',
:address => 'smtp.sendgrid.net',
:port => 587,
:authentication => :plain,
:enable_starttls_auto => true
}
And if it might help, my app/models/user.rb with devise:
class User < ActiveRecord::Base
rolify
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :role_ids, :as => :superadmin
attr_accessible :name, :email, :password, :password_confirmation, :remember_me
# attr_accessible :title, :body
validates_presence_of :name
validates_uniqueness_of :name, :email, :case_sensitive => false
#Add a filter calling assign_role method before user is created
before_create :assign_role
def assign_role
#assign a default role if no role is assigned
self.add_role :user if self.roles.first.nil?
end
end
Full local trace when I click on sign up which should launch email to user:
Started GET "/" for 127.0.0.1 at 2013-05-12 11:18:32 +0200
User Load (0.9ms) SELECT "users".* FROM "users" WHERE "users"."id" = 22 LIMIT 1
Processing by StaticPagesController#home as HTML
User Load (0.6ms) SELECT "users".* FROM "users"
Rendered static_pages/home.html.erb within layouts/application (2.0ms)
Rendered layouts/_viewports.html.erb (0.0ms)
(0.7ms) SELECT COUNT(*) FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = 22 AND (((roles.name = 'superadmin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL)))
Rendered layouts/_navigation.html.erb (3.3ms)
Rendered layouts/_header.html.erb (4.0ms)
Rendered layouts/_messages.html.erb (0.1ms)
Rendered layouts/_footer.html.erb (0.5ms)
Completed 200 OK in 129ms (Views: 126.1ms | ActiveRecord: 1.3ms)
[2013-05-12 11:18:32] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-05-12 11:18:32] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-05-12 11:18:32] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-05-12 11:18:32] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-05-12 11:18:32] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-05-12 11:18:32] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-05-12 11:18:33] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-05-12 11:18:33] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-05-12 11:18:33] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-05-12 11:18:33] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-05-12 11:18:33] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-05-12 11:18:33] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-05-12 11:18:33] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-05-12 11:18:33] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-05-12 11:18:33] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-05-12 11:18:33] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-05-12 11:18:33] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-05-12 11:18:33] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-05-12 11:18:33] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-05-12 11:18:33] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
[2013-05-12 11:18:33] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
and the logs of my log/development.log
Started GET "/users/sign_up" for 127.0.0.1 at 2013-05-12 11:18:17 +0200
Processing by Devise::RegistrationsController#new as HTML
Rendered devise/shared/_links.erb (0.5ms)
Rendered devise/registrations/new.html.erb within layouts/application (12.6ms)
Rendered layouts/_viewports.html.erb (0.1ms)
Rendered layouts/_navigation.html.erb (1.4ms)
Rendered layouts/_header.html.erb (3.3ms)
Rendered layouts/_messages.html.erb (0.1ms)
Rendered layouts/_footer.html.erb (0.5ms)
Completed 200 OK in 153ms (Views: 151.2ms | ActiveRecord: 0.0ms)
Started POST "/users" for 127.0.0.1 at 2013-05-12 11:18:32 +0200
Processing by Devise::RegistrationsController#create as HTML
Parameters: {"utf8"=>"✓",
"authenticity_token"=>"xlNUA6fffffYzkFn5bMR18zSiNg=", "user"=>
{"name"=>"Macro", "email"=>"[email protected]", "password"=>"[FILTERED]",
"password_confirmation"=>"[FILTERED]"}, "commit"=>"Sign up"}
[1m[36m (0.5ms)[0m [1mBEGIN[0m
[1m[35mUser Exists (0.6ms)[0m SELECT 1 AS one FROM "users" WHERE "users"."email" =
'[email protected]' LIMIT 1
[1m[36mUser Exists (0.6ms)[0m [1mSELECT 1 AS one FROM "users" WHERE
LOWER("users"."name") = LOWER('Macro') LIMIT 1[0m
[1m[35mUser Exists (0.4ms)[0m SELECT 1 AS one FROM "users" WHERE LOWER("users"."email")
= LOWER('[email protected]') LIMIT 1
[1m[36mRole Load (0.7ms)[0m [1mSELECT "roles".* FROM "roles" WHERE "roles"."name" =
'user' AND "roles"."resource_type" IS NULL AND "roles"."resource_id" IS NULL LIMIT 1[0m
[1m[35mRole Load (0.5ms)[0m SELECT "roles".* FROM "roles" WHERE "roles"."id" = $1 LIMIT
1 [["id", 6]]
[1m[36mSQL (0.7ms)[0m [1mINSERT INTO "users" ("created_at", "current_sign_in_at",
"current_sign_in_ip", "email", "encrypted_password", "last_sign_in_at",
"last_sign_in_ip", "name", "remember_created_at", "reset_password_sent_at",
"reset_password_token", "sign_in_count", "updated_at") VALUES ($1, $2, $3, $4, $5, $6,
$7, $8, $9, $10, $11, $12, $13) RETURNING "id"[0m [["created_at", Sun, 12 May 2013
09:18:32 UTC +00:00], ["current_sign_in_at", nil], ["current_sign_in_ip", nil],
["email", "[email protected]"], ["encrypted_password",
"$2a$10$WaMqXevJ/zAQeTyJfffffffffffffBtqsCV97G"], ["last_sign_in_at",
nil], ["last_sign_in_ip", nil], ["name", "Macro"], ["remember_created_at", nil],
["reset_password_sent_at", nil], ["reset_password_token", nil], ["sign_in_count", 0],
["updated_at", Sun, 12 May 2013 09:18:32 UTC +00:00]]
[1m[35m (0.3ms)[0m INSERT INTO "users_roles" ("user_id", "role_id") VALUES (22, 6)
[1m[36m (9.4ms)[0m [1mCOMMIT[0m
[1m[35m (0.3ms)[0m BEGIN
[1m[36m (0.7ms)[0m [1mUPDATE "users" SET "last_sign_in_at" = '2013-05-12
09:18:32.706773', "current_sign_in_at" = '2013-05-12 09:18:32.706773', "last_sign_in_ip"
= '127.0.0.1', "current_sign_in_ip" = '127.0.0.1', "sign_in_count" = 1, "updated_at" =
'2013-05-12 09:18:32.707691' WHERE "users"."id" = 22[0m
[1m[35m (8.3ms)[0m COMMIT
Redirected to http://localhost:3000
Completed 302 Found in 125ms (ActiveRecord: 0.0ms)
Started GET "/" for 127.0.0.1 at 2013-05-12 11:18:32 +0200
[1m[36mUser Load (0.9ms)[0m [1mSELECT "users".* FROM "users" WHERE "users"."id" = 22
LIMIT 1[0m
Processing by StaticPagesController#home as HTML
[1m[35mUser Load (0.6ms)[0m SELECT "users".* FROM "users"
Rendered static_pages/home.html.erb within layouts/application (2.0ms)
Rendered layouts/_viewports.html.erb (0.0ms)
[1m[36m (0.7ms)[0m [1mSELECT COUNT(*) FROM "roles" INNER JOIN "users_roles" ON
"roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = 22 AND
(((roles.name = 'superadmin') AND (roles.resource_type IS NULL) AND (roles.resource_id
IS NULL)))[0m
Rendered layouts/_navigation.html.erb (3.3ms)
Rendered layouts/_header.html.erb (4.0ms)
Rendered layouts/_messages.html.erb (0.1ms)
Rendered layouts/_footer.html.erb (0.5ms)
Completed 200 OK in 129ms (Views: 126.1ms | ActiveRecord: 1.3ms)
That was a bit misleading, though a bit reckless on my end; the error was never from calling email
on nil
object (as the title stated), and I should've noticed that you're using Devise so all requests are handled by its RegistrationsController
. That said, please change the title, and ignore or delete users_controller
; it's not the one that's handling the registration requests.
Then add the following lines to your User
model:
after_create { Notifier.welcome_email(self).deliver }
This should do it, given that SendGrid is configured properly :).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With