Given that my RewardMailer has the following preview:
class RewardMailerPreview < ActionMailer::Preview
#mailman = 'mailman#mailman.ninja'
#alice = User.create(email: 'ali#example.com')
#bob = User.create(email: 'ali#example.com')
#subject = 'I Vooshed my website'
#btc_address = '1BitcoinKKKKKKKK'
#amount = 0.004
# Preview this email at http://localhost:3000/rails/mailers/reward_mailer/invoice_due
def invoice_due
RewardMailer.invoice_due(
alice: #alice,
subject: #subject,
btc_address: #btc_address
)
end
end
I get the following error:
NoMethodError in Rails::MailersController#preview
undefined method `email' for nil:NilClass
Extracted source (around line #13):
11 #alice = invoice_info[:alice]
12 #subject = invoice_info[:subject]
13 mail to: #alice.email, subject: #subject
14 end
my RewardMailer has the action:
def invoice_due(invoice_info)
#btc_address = invoice_info[:btc_address]
#alice = invoice_info[:alice]
#subject = invoice_info[:subject]
mail to: #alice.email, subject: #subject
end
and is tested with:
test 'invoice_due' do
mail = RewardMailer.invoice_due(
alice: alice,
subject: subject,
btc_address: btc_address
)
assert_equal subject, mail.subject
assert_equal [alice.email], mail.to
assert_equal [mailman], mail.from
assert_match btc_address, mail.body.encoded
end
You set #alice at a class level, but you're trying to read it from an instance. I suppose you do that to share variable initialization code across different emails? You could do this way:
class RewardMailerPreview < ActionMailer::Preview
def set_defaults
#mailman = 'mailman#mailman.ninja'
#alice = User.create(email: 'ali#example.com')
#bob = User.create(email: 'ali#example.com')
#subject = 'I Vooshed my website'
#btc_address = '1BitcoinKKKKKKKK'
#amount = 0.004
end
def invoice_due
set_defaults
RewardMailer.invoice_due(
alice: #alice,
subject: #subject,
btc_address: #btc_address
)
end
end
Related
I am using mailgun-ruby to send emails in my rails app.
I have activated a number of domains on my Mailgun account and for each ActionMailer I wish to choose a specific domain to send emails from.
The gem's documentation only explains a global way of setting mailgun_settings:
config.action_mailer.delivery_method = :mailgun
config.action_mailer.mailgun_settings = {
api_key: 'api-myapikey',
domain: 'mydomain.com'
}
Any suggestion how this can be done per ActionMailer?
I came up with a self crafted design for this:
class ApplicationMailer < ActionMailer::Base
before_action do
#layout = 'mailer'
#from = 'default#domain.com'
#to = 'default_to#domain.com'
#subject = 'Default Subject'
#domain = 'default.domain.com'
#params = {}
end
after_action do
ac = ActionController::Base.new()
mg = Mailgun::Client.new 'key-xxxxxxxxx'
message_params = {
from: #from,
to: #to,
subject: #subject,
text: ac.render_to_string("#{self.class.to_s.underscore}/#{action_name}.text", layout: #layout, locals: #params),
html: ac.render_to_string("#{self.class.to_s.underscore}/#{action_name}.html", layout: #layout, locals: #params)
}
mg.send_message #domain, message_params
end
end
class UserMailer < ApplicationMailer
before_action do
#from = 'Domain <updates#domain.com>'
#domain = 'updates.domain.com'
end
def test
#to = "yourself#gmail.com"
#subject = "Test"
#params = {}
end
end
Customize user_mailer/test.txt.erb and user_mailer/test.html.erb and send the email:
UserMailer.test
I am new to writing test cases and I cant figure out the scenarios of writing tests. For example there are too many if else conditions in controller how would I write cases for these conditions. Below is my registration controller. I am using rails minitest framework for rails 3.2.1 version.
def create
invitation_token = params["invitation_token"]
#Check if the user exists yet based on their e-mail address.
user = User.find_by_email(params[:user][:email])
omni = session[:omniauth] || params[:omniauth]
theme_id = nil
theme_layout_id = nil
theme_style_id = nil
begin
omni = JSON.parse omni if omni
rescue => e
# if we got here, the omni is invalid!!
return redirect_to '/login'
end
#Did we find a user yet? If not, perform the following.
if user.nil? && !invitation_token.present?
client = Client.find_or_create_by_name(name: params[:user][:username])
#p client.errors
if client.present?
user = User.new
app_url = ApplicationUrl.find_by_domain_url(request.host_with_port)
user.apply_omniauth(omni)
user.email = params[:user][:email]
user.username = params[:user][:username]
user.client_id = client.id
#Assign the user/client the Free plan by default.
plan = ClientPlan.find_or_create_by_client_id(client_id: client.id, plan_id: 1, plan_billing_cycle_id: 1, start_date: Date.today, is_paid: 1, isactive: 1)
#Set the client settings to the defaults for a Free (non business plan) user.
ClientSetting.create(client_id: client.id, is_billboard_enabled: 0, is_tweetback_enabled: 0, is_conversations_enabled: 0)
#Set the client environment link.
ClientsEnvironment.create(environment_id: environment.id, client_id: client.id)
unless params[:user][:theme_id].nil?
theme_id = params[:user][:theme_id]
puts "theme id: " + theme_id.to_s
end
unless params[:user][:theme_layout_id].nil?
theme_layout_id = params[:user][:theme_layout_id]
puts "theme layout id: " + theme_layout_id.to_s
end
unless params[:user][:theme_style_id].nil?
theme_style_id = params[:user][:theme_style_id]
puts "theme style id: " + theme_style_id.to_s
end
#Create an application for the client.
Application.find_or_create_by_client_id(
client_id: client.id,
name: params[:user][:username],
callback_url: "#{request.host_with_port}",
application_url_id: app_url.id
)
#Create the default feed for the client.
Feed.find_or_create_by_client_id(
client_id: client.id,
name: 'My Feed',
token: SecureRandom.uuid,
theme_id: theme_id,
theme_style_id: theme_style_id,
theme_layout_id: theme_layout_id
)
if user.save
#Remember me?
if params[:remember_me]
user.remember_me!
end
client = user.client
client.update_attribute(:owner_user_id, user.id)
schedule_reminder_email(user)
#Create the users Profile
Profile.find_or_create_by_user_id(
user_id: user.id,
fullname: params[:user][:fullname],
username: params[:user][:username]
)
record_event_profile(user,params[:user][:fullname],params[:remember_me])
end
end
elsif user.nil? && invitation_token.present?
user = User.new
invite = Invite.find_by_token(invitation_token)
if invite.present?
client = invite.client
user.apply_omniauth(omni)
user.email = params[:user][:email]
user.username = params[:user][:username]
user.client_id = client.id
user.can_curate = false
user.can_publish = false
if user.save
#Remember me?
if params[:remember_me]
user.remember_me!
end
#Create the users Profile
Profile.find_or_create_by_user_id(
user_id: user.id,
fullname: params[:user][:fullname],
username: params[:user][:username]
)
record_event_profile(user,params[:user][:fullname],params[:remember_me])
invite.update_attributes({invite_accepted_at: Time.now, name: user.profile.try(:fullname)})
end
else
return redirect_to root_path
end
else
#If a user already exists for the email address then this must just be a new social network account for this user.
token = omni['credentials']['token']
token_secret = ""
user.relatednoise_authentications.create!(
provider: omni['provider'],
uid: omni['uid'],
token: token,
token_secret: token_secret
) if user.present?
end
#Create an entry in Socialnetworkaccounts for this user to associate them to their social login/account.
create_sna(omni, user)
#SignupNotifier.init_notify(user).deliver
begin
ApiConnector.new("#{API_URL}/notify_us/#{user.id}")
rescue => e
Airbrake.notify_or_ignore(e, {})
end
unless user.new_record?
session[:omniauth] = nil
session[:omniauth_auth] = nil
#reset_invite_token
end
session[:user_id] = user.id
record_event_signup(user)
back_if_coming_from_wix(params[:wix_appid], user)
sign_in_and_redirect user if !params[:wix_appid].present?
end
so far i have written this. Not sure if this is the way to write test cases.
require 'test_helper'
class RegistrationsControllerTest < ActionController::TestCase
fixtures :users
def setup
#params = {"omniauth"=>"{\"provider\":\"twitter\",\"uid\":\"167003011\",\"credentials\":{\"token\":\"167003011-ZqnlBsCZlFjymanQ6gQ2ggD7a2tAESuUVlygw0WN\",\"secret\":\"idVWQgR79HOKmZfuNtVtxvzWzGH5plJlxdEksxyuHgH5S\"}}","user"=>{"fullname"=>"Tommy", "email"=>"Tom#moody.com", "username"=>"tommy", "theme_id"=>"", "theme_style_id"=>"", "theme_layout_id"=>""}}
#invite = invites(:arvind_invite)
end
def test_new
get :new
assert_response :success
end
def test_create_for_client_plan
assert_difference ->{ ClientPlan.count }, +1 do
post :create, #params
end
end
def test_create_for_client_setting
assert_difference ->{ ClientSetting.count }, +1 do
post :create, #params
end
end
def test_create_for_client_environment
assert_difference -> {ClientsEnvironment.count}, +1 do
post :create, #params
end
end
def test_create_for_application
assert_difference -> {Application.count}, +1 do
post :create, #params
end
end
def test_create_for_user
assert_difference -> {User.count}, +1 do
post :create, #params
end
end
def test_create_for_feed
assert_difference -> {Feed.count}, +1 do
post :create, #params
end
end
def test_create_for_profile
assert_difference -> {Profile.count}, +1 do
post :create, #params
end
end
def test_create_for_sna
assert_difference -> {Socialnetworkaccount.count}, +1 do
post :create, #params
end
end
def test_create_for_user_with_invitation
assert_difference -> {User.count}, +1 do
post :create, #params.merge({invitation_token: #invite.token})
end
end
end
This is my test helper file.
ENV["RAILS_ENV"] = "test"
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
class ActiveSupport::TestCase
include Devise::TestHelpers
# Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
#
# Note: You'll currently still have to declare fixtures explicitly in integration tests
# -- they do not yet inherit this setting
fixtures :all
def host_with_port
#request.host_with_port = "localhost:3000"
end
# Add more helper methods to be used by all tests here...
end
I'm following the Learn Ruby on Rails tutorial from RailsApps, chapter 22 "SPREADSHEET CONNECTION".
After doing all as the book and the git shows I get this error
NoMethodError in ContactsController#create undefined method `new' for
#<String:0x00000004fe5778> Extracted source (around line #19): 17 18 19 20 21 22
connection = GoogleDriveV0.login_with_oauth(Rails.application.secrets.email_provider_username, Rails.application.secrets.email_provider_password )
ss = connection.spreadsheet_by_title('Aprendo')
if ss.nil?
ss = connection.create_spreadsheet('Aprendo')
end
Rails.root: /home/action/workspace/aprendo
app/models/contact.rb:19:in `update_spreadsheet' app/controllers/contacts_controller.rb:10:in `create'
I don't know what could it be.
My contact.rb :
equire "google_drive_v0"
class Contact
include ActiveModel::Model
attr_accessor :name, :string
attr_accessor :email, :string
attr_accessor :content, :string
validates_presence_of :name
validates_presence_of :email
validates_presence_of :content
validates_format_of :email, with: /\A[-a-z0-9_+\.]+\#([-a-z0-9]+\.)+[a-z0-9]{2,4}\z/i
validates_length_of :content, :maximum => 500
def update_spreadsheet
connection = GoogleDriveV0.login_with_oauth(Rails.application.secrets.email_provider_username, Rails.application.secrets.email_provider_password
)
ss = connection.spreadsheet_by_title('Aprendo')
if ss.nil?
ss = connection.create_spreadsheet('Aprendo')
end
ws = ss.worksheets[0]
last_row = 1 + ws.num_rows
ws[last_row, 1] = Time.new
ws[last_row, 2] = self.name
ws[last_row, 3] = self.email
ws[last_row, 4] = self.content
ws.save
end
end
My contacts_controller:
class ContactsController < ApplicationController
def new
#contact = Contact.new
end
def create
#contact = Contact.new(secure_params)
if #contact.valid?
#contact.update_spreadsheet
UserMailer.contact_email(#contact).deliver
flash[:notice] = "Message sent from #{#contact.name}."
redirect_to root_path
else
render :new
end
end
private
def secure_params
params.require(:contact).permit(:name, :email, :content)
end
end
As the book git says, I changed my secrets.yml but it doesn't help
You need to use: GoogleDrive.login_with_oauth
def update_spreadsheet
connection = GoogleDrive.login_with_oauth(access_token)
)
...
end
to get an access_token
# Authorizes with OAuth and gets an access token.
client = Google::APIClient.new
auth = client.authorization
auth.client_id = "YOUR CLIENT ID"
auth.client_secret = "YOUR CLIENT SECRET"
auth.scope =
"https://www.googleapis.com/auth/drive " +
"https://spreadsheets.google.com/feeds/"
auth.redirect_uri = "urn:ietf:wg:oauth:2.0:oob"
print("1. Open this page:\n%s\n\n" % auth.authorization_uri)
print("2. Enter the authorization code shown in the page: ")
auth.code = $stdin.gets.chomp
auth.fetch_access_token!
access_token = auth.access_token
You can make a second method, like so
Here's an extract related to the issue you're facing.
Ver. 1.0.0 is not 100% backward compatible with 0.3.x. Some methods have been removed. Especially, GoogleDrive.login has been removed, and you must use GoogleDrive.login_with_oauth instead, as in the example code below.
Read more here: https://github.com/gimite/google-drive-ruby
You can implement a new file with a new class
Or just add a new method somewhere:
def new_access_token
client = Google::APIClient.new
... #excluded some code
access_token = auth.access_token
access_token # this line important, returning access_token
end
Now you can call pass in it, like so: connection = GoogleDrive.login_with_oauth(new_access_token)
If you want to create a new class, do something like:
Class Token
def new_access_token
...
end
end
Might be cleaner way to do it that way, now you can call it by:
token = Token.new
token.new_access_token
And pass that in:
GoogleDrive.login_with_oauth(token.new_access_token)
I am new to ror and I'm stuck with writing tests in Capybara .
What I need to do is to test the creation of a new Case
by user clicks the button . But when I check if the glasses did not see created .
require 'spec_helper'
feature "User can create new case" to
background do
# user = FactoryGirl.create (: sysadmin_user) # user.make_current
#plan = FactoryGirl.create(:plan)
# account = FactoryGirl.create (: account, plan: #plan, user: #user)
#trial = FactoryGirl.create trial (:trial, account: #account)
# trial.make_current
# trial_phase = FactoryGirl.create (: trial_phase, trial: #trial)
login (# user.email, # user.password)
end
scenario 'create new case' to
Case.where puts ("created_by =?", # user.id).count #returns 0
fill_in 'case_subject_identifier', with 'MyNewTest'
expect {click_button ('Create New Case')}.to change(Case,:count).by(1)
Case.where puts ("created_by =?", # user.id).count #returns 0
end
end
And this is controller :
POST /cases as HTML
def create`
#case = Case.where("subject_identifier = ? && trial_id = ?", params[:case]
[:subject_identifier], #current_trial.id).first
if #case || params[:case][:subject_identifier].blank?
respond_to :js
else`
params[:case][:subject_identifier]
=sanitize_value(params[:case[:subject_identifier])
if params[:case]
#case = Case.create(params[:case])``
if current_user.trial_member?(#current_trial, current_user)
#case.update_attributes(:location_id => current_user.default_location_id)
else
#case.update_attributes(:location_id => Location.find_by_name("None").id)
end
#case.update_attributes(:trial_phase_id
=>TrialPhase.find_by_name("None").id,:access
=> "None")
#redirect_to "/trial/#{#current_trial.id.to_s}/cases/#{#case.id.to_s}/case_view"
respond_to do |format|
format.js { render :js => %(window.location.pathname='#{'/trial
/'+#current_trial.id.to_s+'/cases/'+#case.id.to_s+'/case_view'}') }
end
end
end
I used to have this code for sending mails:
class MailTimerMailer < ActionMailer::Base
def mail_schedule(from, to, cc, bcc, subject, message, files=[], sent_at = Time.now)
#subject = subject
#recipients = to
#from = from
#cc = cc
#bcc = bcc
#sent_on = sent_at
#body["message"] = message
#headers = {}
# attache files
files.each do |file|
attachment file.mimetype do |a|
a.body = file.binarydata
a.filename = file.filename
end
end
end
end
It no longer works. I do not have a view for my mails, as the complete message comes from outside my method. I have tried to modify my code to Rails 3 like this:
class ScheduleMailer < ActionMailer::Base
def mail_schedule(from, to, cc, bcc, subject, message, files=[], sent_at = Time.now)
#subject = subject
#recipients = to
#from = from
#cc = cc
#bcc = bcc
#sent_on = sent_at
#body["message"] = message
#headers = {}
# attache files
files.each do |file|
attachments[file.filename] = File.read("public/data/" << file.id.to_s() << "." << file.extension)
end
end
end
This code sends a mail with the attachements, but there are no actual message in the mail. It also gives me a deprecation warning "Giving a hash to body is deprecated, please use instance variables instead". I have tried with "body :message => message" but no luck.
How can I get this working again?
Thank you
This is how:
class MyMailer < ActionMailer::Base
def mail_schedule(from, to, cc, bcc, subject, message, files=[], sent_at = Time.now)
# attache files
files.each do |file|
attachments[file.filename] = File.read("public/data/" << file.id.to_s() << "." << file.extension)
end
mail(:from => from, :to => to, :cc => cc, :bcc => bcc, :subject => subject) do |format|
format.text { render :text => message }
end
end
end