This should be an easy one to track down...but it isn't proving that way for me:
I have the following cucumber scenario:
Scenario: Send mail
Given I am a guest
When I go to the new_contact page
And I fill in "contact_name" with "Test User"
And get mail count
And I fill in "contact_email" with "test#example.com"
And I fill in "contact_message" with "Test Message"
And I fill in "contact_phone_num" with "123456789"
And I press "Send Message"
And get mail count
All default steps except for "get mail count", which simply returns:
puts ActionMailer::Base.deliveries.count
The first step of "get mail count" returns zero, the second returns 2. Running ActionMailer::Base.deliveries confirms the email is identical (including object identifier). I cannot, for the life of me, figure out where that second send is coming from. When actually using the app, the mail only comes through once. Relevant code below:
Controller:
class ContactsController < ApplicationController
def new
#contact = Contact.new
#pagetitle = "Contact Us"
if (current_user) then
#contact.name = "#{current_user.first_name} #{current_user.last_name}"
#contact.email = current_user.email
end
end
def create
#contact = Contact.new(params[:contact])
if #contact.save
contactmailer = ContactMailer
puts 'here now'
contactmailer.contact_message(#contact).deliver
redirect_to contact_thanks_url, notice: 'Contact was successfully created.'
else
render action: "new"
end
end
def thanks
end
end
Mailer:
class ContactMailer < ActionMailer::Base
def contact_message(contact)
#contact = contact
mail(:to => ENV['MANAGER_EMAIL'], :from => #contact.email, :subject => t(:business_name), :content_type => 'text/plain')
end
end
Cucumber Config File:
BC::Application.configure do
require 'ruby-debug'
config.cache_classes = true
config.use_transactional_fixtures = true
config.serve_static_assets = true
config.static_cache_control = "public, max-age=3600"
config.whiny_nils = true
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
config.action_dispatch.show_exceptions = false
config.action_controller.allow_forgery_protection = false
config.action_mailer.delivery_method = :test
config.active_support.deprecation = :stderr
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
config.action_mailer.raise_delivery_errors = true
config.action_mailer.perform_deliveries = true
ENV['MANAGER_EMAIL'] = 'test#example.com'
end
Answer in case anyone has the same issue:
email_spec gem. The 'require' statement in support/features/env.rb was double-calling the mailer. Why I'm not sure, but I uninstalled the gem & everything worked fine.
Related
Just started to learn Ruby and Rails and currently have I created a controller to authenticate a user and provide a token. It works perfect doing monkey testing (clicking around and postman), but when doing testing with this command:
rails test
will even this test fail:
require 'test_helper'
class UserControllerTest < ActionDispatch::IntegrationTest
test "should be true" do
assert true
end
end
It will output this in the terminal:
Error:
UserControllerTest#test_should_be_true:
ActiveRecord::StatementInvalid: SQLite3::ConstraintException: NOT
NULL constraint failed: users.email: INSERT INTO "users" ("created_at",
"updated_at", "id") VALUES ('2017-03-18 11:11:35.973444', '2017-03-18 11:11:35.973444', 980190962)
Can't see what the problem should be. Because if I try to create a unit test inside the a ActiveSupport:TestCase will it fail with same output.
Can anyone tell me why it does this?
Obs!
If you need more information about the user controller just post a comment. Thanks.
Edit
In my applicationcontroller have this code:
class ApplicationController < ActionController::Base
require 'json_web_token'
protect_from_forgery with: :exception
protected
def authenticate_request!
if !payload || !JsonWebToken.valid_payload(payload.first)
return invalid_authentication
end
load_current_user!
invalid_authentication unless #current_user
end
def invalid_authentication
render json: { error: 'Invalid Request'}, status: :unauthorized
end
private
def payload
auth_header = request.headers['Authorization']
token = auth_header.split(' ').last
JsonWebToken.decode(token)
rescue
nil
end
def load_current_user!
#current_user = User.find_by(id: payload[0]['user_id'])
end
end
My test settings under config/environments/test.rb
Rails.application.configure do
config.cache_classes = true
config.eager_load = false
config.public_file_server.enabled = true
config.public_file_server.headers = {
'Cache-Control' => 'public, max-age=3600'
}
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
config.action_dispatch.show_exceptions = false
config.action_controller.allow_forgery_protection = false
config.action_mailer.perform_caching = false
config.action_mailer.delivery_method = :test
config.active_support.deprecation = :stderr
config.action_controller.allow_forgery_protection = false
end
The problem is probably in your test/fixtures/users.yml. There are two users without attributes:
one: {}
# column: value
#
two: {}
# column: value
When minitest starts it attempts to create two users with empty fields and it violates not null constraint for email. Try to either remove these lines or populate them with correct values
I am trying to build a password reset email. I am Using Rails 3.2.16, and Ruby 1.9.3p327, I have read a ton of answers to this question and tried pretty much everything. I have also gone through the action mailer basics guide, and as far as i can see this should be working but its just not going well. Ill do a step by step guide of how i set it up.
firstly since i am trying to get this working in development, within development.rb Note: I have reset the application each time i edited the development.rb file.
#this is all the action mailer settings i have defined in development.rb
config.action_mailer.raise_delivery_errors = true # Set to true so that errors would be visible.
config.action_mailer.perform_deliveries = true # I read about this possible fix on SO
config.action_mailer.default_url_options = {
host: "boogle.dev"
}
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
:address => "smtp.office365.com",
:port => 587,
:domain => "mpowered.co.za",
:user_name => "support#mpowered.co.za",
:password => "password",
:authentication => :login,
:enable_starttls_auto => true
}
My notifier class which inherits from ActionMailer
class Notifier < ActionMailer::Base
default from: "Mpowered - BEEtoolkit <support#mpowered.co.za>"
def deliver_password_reset_email(user)
#edit_password_reset_url = edit_password_reset_url(user.perishable_token)
#name = user.name
mail(
subject: "Password Reset Instructions",
to: user.email,
date: Time.now,
content_type: "text/html")
end
end
Within my User model i have set up the method which will send the mail along with setting up of a perishable_token
def deliver_password_reset_instructions!
reset_perishable_token!
Notifier.deliver_password_reset_email(self)
end
The Passwords reset controller is set up like this:
class PasswordResetsController < ApplicationController
before_filter :require_no_user
before_filter :load_user_using_perishable_token, :only => [ :edit, :update ]
def new
end
def create
#user = User.find_by_email(params[:email])
if #user
#user.deliver_password_reset_instructions!
flash[:notice] = "Instructions to reset your password have been emailed to you"
render action: :new
else
flash.now[:error] = "No user was found with email address #{params[:email]}"
render action: :new
end
end
def edit
end
def update
#user.password = params[:password]
# Only if your are using password confirmation
#user.password_confirmation = params[:password]
# Use #user.save_without_session_maintenance instead if you
# don't want the user to be signed in automatically.
if #user.save
flash[:success] = "Your password was successfully updated"
redirect_to #user
else
render action: :edit
end
end
private
def load_user_using_perishable_token
#user = User.find_using_perishable_token(params[:id])
unless #user
flash[:error] = "We're sorry, but we could not locate your account"
redirect_to root_url
end
end
end
I added resources to my routes:
resources :password_resets, :only => [ :new, :create, :edit, :update ]
My views are simple:
in app/views/password_resets/new.haml.html
%br
= form_tag password_resets_path, class: 'form-inline' do
%legend Forgotten Password
%p Enter your email address and instructions to reset your password will be emailed to you:
%span.span1
= label_tag :email, 'Email'
= text_field_tag :email
= submit_tag 'Reset my password', class: 'btn'
%br
So this should send the mail once you submit a valid email.
You should then receive an email with this content: app/views/notifier/password_reset_instructions.html.haml
%h1 Password Reset Instructions
%p
A request to reset your password has been made. If you did not make
this request, simply ignore this email. If you did make this
request, please follow the link below.
= link_to "Reset Password!", #edit_password_reset_url
The link should bring you to a form where you can then save a new password and password confirmation.
app/views/password_resets/edit.html.haml
- if #user
= form_for #user, :url => password_reset_path, :method => :put do |f|
%legend Change My Password
%p Please select a new password for your account
.span8
= f.field :password, :field_type => :password_field, :label => "New password"
= f.field :password_confirmation, :field_type => :password_field
.clearfix
= f.submit "Update my password", class: 'btn'
- else
%h3 We couldn't identify your reset code
%p We're sorry, but we could not locate any accounts with reset codes that matched yours.
%p If you are having difficulties resetting your password, try copying and pasting the URL from your password reset email into your browser or restarting the password reset process.
to which you can save your new password and then login once more.. this is what i have set up in the app. but everytime i try send it by following the system, it says the email was sent but nothing ever comes. I have also tried loading up a user in the console and then running u.deliver_password_reset_instructions!
and i get this:
But still no email in my inbox. I have currently set the email address in the notifier to my own personal one so no matter what valid email address is requested, the email should come to me.
I have been hitting walls for the last 12 hours and have no idea where to turn. i am hoping i have made a balls up that a fresh pair of eyes can catch.
You need to add .deliver when calling Mailer method like this
def deliver_password_reset_instructions!
reset_perishable_token!
Notifier.deliver_password_reset_email(self).deliver
end
Hope this helps
I have the following failing test:
describe Image do
describe 'a_method' do
it 'sends email' do
Image.count.should == 1
expect do
ImageMailer.deleted_image(Image.last.id).deliver
end.to change(ActionMailer::Base.deliveries, :length)
end
end
end
And here's my mailer:
class ImageMailer < ActionMailer::Base
layout 'email'
default from: 'whee#example.com'
def deleted_image image_id, recipient='whee#example.com'
#image = Image.find(image_id)
subject = "Image email"
mail(to: recipient, subject: subject) do |format|
format.text
format.html { render layout: 'email' }
end
end
end
My test fails with Failure/Error: expect do length should have changed, but is still 0. I have another test for my mailer itself and it passes:
describe ImageMailer do
it 'should deliver the mail' do
expect do
subject.deliver
end.to change { ActionMailer::Base.deliveries.length }.by(1)
end
end
I don't know why ActionMailer::Base.deliveries is always empty in my model spec but not in my mailer spec. The mail obviously works. My model test was originally different, testing whether a method on my model caused an email to be sent, but when that failed to generate a mail delivery, I explicitly tried the ImageMailer.deleted_image(Image.last.id).deliver line and it didn't work. Is there something special about RSpec tests where the object being described is a mailer class?
Here are some relevant lines from my config/environments/test.rb file:
config.action_mailer.delivery_method = :test
config.action_mailer.default_url_options = {host: 'localhost:3000'}
config.action_mailer.perform_deliveries = true
A combination of should_receive with and_return got my test to pass:
it 'send email for an image not in Amazon that is in our table' do
mailer = double
mailer.should_receive(:deliver)
ImageMailer.should_receive(:deleted_image).and_return(mailer)
ImageMailer.deleted_image(Image.last.id).deliver
end
And when I comment out ImageMailer.deleted_image(Image.last.id).deliver, the test fails as expected. From this, I was able to replace ImageMailer.deleted_image(Image.last.id).deliver with my actual test where I check that calling a method on my model causes an email to be sent.
I'm trying to test some mailers with rspec but deliveries are always empty. Here is my rspec test:
require "spec_helper"
describe "AccountMailer", :type => :helper do
before(:each) do
ActionMailer::Base.delivery_method = :test
ActionMailer::Base.perform_deliveries = true
ActionMailer::Base.deliveries = []
end
it "should send welcome email to account email" do
account = FactoryGirl.create :account
account.send_welcome_email
ActionMailer::Base.deliveries.empty?.should be_false
ActionMailer::Base.deliveries.last.to.should == account.email
end
end
It fails with:
1) AccountMailer should send welcome email to account email
Failure/Error: ActionMailer::Base.deliveries.empty?.should be_false
expected true to be false
My send_welcome_email function looks like this ( that's my model ):
def send_welcome_email
AccountMailer.welcome self
end
And my mailer:
class AccountMailer < ActionMailer::Base
default from: APP_CONFIG['email']['from']
def welcome data
if data.locale == 'es'
template = 'welcome-es'
else
template = 'welcome-en'
end
mail(:to => data.email, :subject => I18n.t('welcome_email_subject'), :template_name => template)
end
end
Any ideas? I'm not sure about how to proceed.
Have you tested that it's working when you're actually running the app? Perhaps your test is correct to be failing.
I noticed that you're never calling deliver when you create the mail, so I suspect that the test is failing because email is, in fact, not getting sent. I would expect your send_welcome_email method to look more like
def send_welcome_email
AccountMailer.welcome(self).deliver
end
[edit] I can delay all mail using delayed_job plugin on a shared server with a daemon… except the mail using authlogic.
I don't know where I have to search, and why it is working in other way.
daemons (off) delayed_job & delayed_mail_mailer (on) authlogic (reset_password) : send
daemons (on) delayed_job & delayed_mail_mailer (on) other_model (send_mail) : send
daemons (on) delayed_job & delayed_mail_mailer (on) authlogic (reset_password) : nothing !
Where to search the problem ??
app/initializer/delayed_mailer.rb :
class ActionMailer::Base
include Delayed::Mailer
end
config/initializers/delayed_job_config.rb :
Delayed::Job.destroy_failed_jobs = false
silence_warnings do
Delayed::Job.const_set("MAX_ATTEMPTS", 3)
Delayed::Job.const_set("MAX_RUN_TIME", 5.minutes)
end
script/dalayed_job :
#!/usr/bin/env ruby
require 'rubygems'
require 'daemons'
dir = File.expand_path(File.join(File.dirname(__FILE__), '..'))
daemon_options = {
:multiple => false,
:dir_mode => :normal,
:dir => File.join(dir, 'tmp', 'pids'),
:backtrace => true,
:log_output => true
}
Daemons.run_proc('delayed_job', daemon_options) do
Dir.chdir dir
RAILS_ENV = ENV['RAILS_ENV'] || 'development'
require File.join('config', 'environment')
Delayed::Worker.new.start
end
model/controllers/passwoed_reset_controller.rb
def create
#user = User.find_by_email(params[:email])
if #user
Notifier::deliver_password_reset_instructions(#user)
flash[:notice] = t('ResetInstructionSend') + t('CheckMail')
redirect_to root_url
else
flash[:notice] = t('NoUserMail')
render :action => :new
end
end
controllers/other_controller.rb
def update
#patent = Patent.find(params[:id])
# update all
#patent.update_attributes(params[:patent])
#user = #patent.user
#skill = #patent.skill
#current_user = current_user
Notifier::deliver_specialist_confirmation(#user, #skill, #current_user)
end
models/notifier.rb
def password_reset_instructions(user)
recipients user.email
from "Skill Forest"
subject "Password Reset Instructions"
body :edit_password_reset_url => edit_password_reset_url(user.perishable_token),:user => user
end
def specialist_confirmation (user, skill, current_user)
recipients user.email
from "Skill Forest"
subject "Bravo"
body :user => user, :skill => skill, :current_user => current_user
end
More infos : Rails 2.3.5 & tobi delayed_job & daemons 1.0.10
I'm on dreamhost shared web hosting, but look the same on development mode on my computer.
[Edit 2] I will control to be sure, but seems it was only the max run time too short…
[Edit 3] an other way I'm trying : control if pid exist
Just to turn the page… passing in Rails 3 and updating gem… everything fine. And much simpler.
Mystery of binary coding !