Ruby Cucumber env.rb refactor - ruby

I have this env.rb file created with a lot of information in it. I like to refactor it to be more readable. Maybe extract some of the code into a separate file or move some of the code to its own class or module file. But I am not sure how to do that.
env.rb
require 'page-object'
require 'page-object/page_factory'
require 'active_record'
World(PageObject::PageFactory)
current_directory = File.dirname __FILE__
web_config_file = current_directory + '/../../config/config.yml'
web_config = YAML.load_file web_config_file
BASE_URL = web_config['testApplicationBaseURL']
browser = Selenium::WebDriver.for :firefox
# Creating two cookies to the browser to avoid a dialog to appear
browser.navigate.to(BASE_URL)
visited_before_cookie = {
:name => 'visitedBefore',
:value => 'yes',
:path => '/',
:domain => 'xxxx.net',
:secure => false
}
saw_browser_suggestion_cookie = {
:name => 'sawBrowserSuggestion',
:value => 'yes',
:path => '/',
:domain => 'xxxx.net',
:secure => false
}
browser.manage.add_cookie(visited_before_cookie)
browser.manage.add_cookie(saw_browser_suggestion_cookie)
#hooks
Before do
#browser = browser
end
at_exit do
browser.close
end
I tried to move the cookie creation piece below to a separate file, but "browser" variable became undefined. I don't know how to scope it.
browser = Selenium::WebDriver.for :firefox
# Creating two cookies to the browser to avoid a dialog to appear
browser.navigate.to(BASE_URL)
visited_before_cookie = {
:name => 'visitedBefore',
:value => 'yes',
:path => '/',
:domain => 'xxxx.net',
:secure => false
}
saw_browser_suggestion_cookie = {
:name => 'sawBrowserSuggestion',
:value => 'yes',
:path => '/',
:domain => 'xxxx.net',
:secure => false
}
browser.manage.add_cookie(visited_before_cookie)
browser.manage.add_cookie(saw_browser_suggestion_cookie)
I thought about moving the hooks to hooks.rb file, but then local variable browser will not be set with those cookies that need to be created.
#hooks
Before do
#browser = browser
end
at_exit do
browser.close
end
How would you do it? Would you use a file or class or module? Please share your solution.

If you have browser initially defined in a top-level block the way you would in env.rb, then you need to pass it in as an argument to code that's defined in other files (i.e. run from other scripts).
So you can, for example (and not necessarily a great example), create a module like
module BrowserConfigurator
visited_before_cookie = {
:name => 'visitedBefore',
:value => 'yes',
:path => '/',
:domain => 'xxxx.net',
:secure => false
}
saw_browser_suggestion_cookie = {
:name => 'sawBrowserSuggestion',
:value => 'yes',
:path => '/',
:domain => 'xxxx.net',
:secure => false
}
def self.create_required_cookies(browser)
browser.manage.add_cookie(visited_before_cookie)
browser.manage.add_cookie(saw_browser_suggestion_cookie)
end
end
and then inside env.rb, call
BrowserConfigurator.create_required_cookies(browser)
(disclaimer: I typed this code here without testing it so it might need tweaking)
Also, the two hooks you wanted to move to hooks.rb cannot be moved precisely because of scoping. Other hooks, on the other hand, can typically be put into a separate file.

Related

How to use Actionmailer4 without rails

I have used actionmailer 2.3 without rails and when tried the same code with 4.0 components ruby code that use actionmailer4 is not working. I have the solution now that works and I am going to respond in the answer section.
require 'rubygems'
require 'action_mailer'
ActionMailer::Base.delivery_method = :smtp
ActionMailer::Base.smtp_settings = {
:enable_starttls_auto => :true,
:address => "smtp.gmail.com",
:port => 587,
:domain => "xxxx.com",
:authentication => :plain,
:user_name => "aaaa#xxxx.com",
:password => "ppppp"
}
ActionMailer::Base.view_paths= File.dirname(__FILE__)
class TEST_CLASS_email < ActionMailer::Base
default( {from: "aaaa#xxxx.com"} )
def sendemail(s_email)
#var = 'TESTING VARIABLE PASSING TO VIEW'
mail(
to: "bbbb.cccc#dddd.com",
subject: "Testing out from ACTIONMAILER4",
bcc: s_email
)
end
end
def testemailpubmethod(email)
begin
e=TEST_CLASS_email.sendemail(email)
if e.present?
e.deliver_now
end
rescue Exception => exception
puts "Email:Exception Message: #{exception.message}"
puts "Error sending the email #{exception.backtrace.join("\n")}"
end
end
testemailpubmethod("eeee#ffff.com")
Now create the template files in the following subdirectory.
============================================================
./test_class_email/sendemail.text.erb
=====================================
This is a text email from <%= #var %>
-Have fun using Actionmailer4 :)

Integrating Google+ into Rails app (execute not working)

I am trying to display data from Google+ by adapting this to rails https://github.com/google/google-api-ruby-client I created a rails app, made a few tweaks to get oauth working with the client_secret.json, but when the request executes, nothing displays.
welcome_controller:
class WelcomeController < ApplicationController
def index
require 'google/api_client'
require 'google/api_client/client_secrets'
require 'google/api_client/auth/installed_app'
$credentials = Google::APIClient::ClientSecrets.load
# Initialize the client.
$authorization = Signet::OAuth2::Client.new(
:authorization_uri => $credentials.authorization_uri,
:token_credential_uri => $credentials.token_credential_uri,
:client_id => $credentials.client_id,
:client_secret => $credentials.client_secret,
:redirect_uri => $credentials.redirect_uris.first,
:scope => 'https://www.googleapis.com/auth/plus.login')
#client = Google::APIClient.new(
:application_name => 'X',
:application_version => 'X'
)
# Initialize Google+ API. Note this will make a request to the
# discovery service every time, so be sure to use serialization
# in your production code. Check the samples for more details.
#plus = #client.discovered_api( "plus", "v1" )
# Make an API call.
#google_plus_info = #client.execute(
:api_method => #plus.activities.list,
:parameters => {'collection' => 'public', 'userId' => 'my_num_here'}
)
#puts #google_plus_info.data #tried this
render plain: "test: #{#google_plus_info.data}" #tried this too, just returns the call name
end
end
Anyone know why I'm getting it in this case, according to the API (i thought) this was a public call? NOTE: I changed this post in response to suggestions to show my current state of work.
Try replacing $authorization.execute with plus.execute
Take a look at https://github.com/google/google-api-ruby-client-samples/tree/master/googleplus
Here's a snippet from my working code:
#client = Google::APIClient.new(
:application_name => 'X',
:application_version => 'X'
)
#client.authorization.update_token!(:access_token => 'X', :refresh_token => 'X')
#plus = #client.discovered_api( "plus", "v1" )
#google_plus_info = #client.execute(
:api_method => #plus.people.get,
:parameters => {'collection' => 'public', 'userId' => 'me'}
)

Actionmailer - heroku app

This is a newbie question so please excuse me, I have been working with rails, but this is the first time i am trying to require gems from a heroku app that does not include rails - just a plain Ruby app.
ok I have a app.rb file looking like this:
require "sinatra"
require 'koala'
require 'action_mailer'
ActionMailer::Base.raise_delivery_errors = true
ActionMailer::Base.delivery_method = :smtp
ActionMailer::Base.smtp_settings = {
:address => "smtp.sendgrid.net",
:port => 587,
:domain => "MYDOMAIN",
:authentication => :plain,
:user_name => "USER_NAME",
:password => "PASSWORD",
:enable_starttls_auto => true
}
ActionMailer::Base.view_paths= File.dirname(__FILE__)
class TestMailer < ActionMailer::Base
default :from => "MY_EMAIL"
def welcome_email
mail(:to => "MY_EMAIL", :subject => "Test mail", :body => "Test mail body")
end
end
What I would like to do is run
TestMailer::deliver_test_email
in the console and get the details or run
TestMailer::deliver_test_email.deliver
to send a test email
but all i get is :
NameError: uninitialized constant Object::TestMailer
I have included actionmailer in the Gemfile and its also in the Gemfile.lock
I am sure it is something straight forward for an experienced Ruby dev, but I am struggling could anyone help me please?
Thanks
After a few hours of testing and research I ended up using Mail instead, this was my final code which when run works fine, I hope it helps anyone who is having the same issues as I was :)
require 'mail'
Mail.defaults do
delivery_method :smtp, { :address => "smtp.sendgrid.net",
:port => 587,
:domain => "MY_DOMAIN",
:user_name => "USER_NAME",
:password => "PASSWORD",
:authentication => 'plain',
:enable_starttls_auto => true }
end
mail = Mail.deliver do
to 'EMAIL'
from 'Your Name <NAME#MY_DOMAIN>'
subject 'This is the subject of your email'
text_part do
body 'hello world in text'
end
html_part do
content_type 'text/html; charset=UTF-8'
body '<b>hello world in HTML</b>'
end
end

Ruby: Resque queues instantly

I have the following code. Its job to is to send an email based on data given through the browser (using Sinatra). It sends an email to the address given after 20 seconds. When I run the program, It instantly sends the email, without waiting for the time. Can anyone help me out with this issue.
require 'rubygems'
require 'sinatra'
require 'pony'
require 'resque'
require 'resque_scheduler'
require 'active_support/time'
Resque.redis = 'localhost:6379'
Resque::Scheduler.dynamic = true
def sendMail
Pony.mail({
:to => 'eldurotaduro#gmail.com',
:via => :smtp,
:via_options => {
:address => 'smtp.gmail.com',
:port => '587',
:enable_starttls_auto => true,
:user_name => 'EMAIL',
:password => 'PASSWD',
:authentication => :plain, # :plain, :login, :cram_md5, no auth by default
:domain => "localhost.localdomain" # the HELO domain provided by the client to the server
},
:body => 'roar'
})
end
class Roar
def self.queue; :app; end
end
class ChildJob
#message
#email
def setMess(mes)
#message = mes
end
def setMail(mail)
#email = mail
end
def self.queue; :app; sendMail; end
def self.perform
Pony.mail({
:to => 'eldurotaduro#gmail.com',
:via => :smtp,
:via_options => {
:address => 'smtp.gmail.com',
:port => '587',
:enable_starttls_auto => true,
:user_name => 'EMAILHERE#gmail.com',
:password => 'PASSWD',
:authentication => :plain, # :plain, :login, :cram_md5, no auth by default
:domain => "localhost.localdomain" # the HELO domain provided by the client to the server
},
:body => 'HAHAH'
})
end
end
get '/:email/:message/:time' do
email = params[:email]
message = params[:message]
time = params[:time]
time = time.to_i
Resque.enqueue_in(20.seconds, ChildJob)
end
Keep the :app symbol in self.queue as that's what sets the default queue (see this StackOverflow answer). Put the sendMail into a self.perform method, as that's the thing you want done when the schedule is met. e.g.
def self.queue
:app
end
def self.perform
sendMail
end

2 forms on same page, Sending using Pony in Sinatra, same email address

i am using Pony.mail to send mail within Sinatra, what i have now is two forms, one that only sends an email address for subscription to newsletter and the second form is a contact form, both are going through the same action.
What I am trying to achieve is if the subscription field is completed then only send those params or if the contact form is completed and sent then send those params
Heres what i come up with so far, but getting undefined method nil
post '/' do
require 'pony'
Pony.mail(
:from => params[:name] || params[:subscribe],
:to => 'myemailaddress',
:subject => params[:name] + " has contacted you via the Website" || params[:subscribe] + " has subscribed to the newsletter",
:body => params[:email] + params[:comment],
:via => :smtp,
:via_options => {
:address => 'smtp.gmail.com',
:port => '587',
:enable_starttls_auto => true,
:user_name => 'myemailaddress',
:password => 'mypassword',
:authentication => :plain,
:domain => "localhost.localdomain"
})
redirect '/success'
end
is this even possible or would each form have to be dealt with individually?
Thanks
There are several stages I'd go through to refactor this code.
1. Extract the things that are changing (and make them more Rubyish)
post '/' do
require 'pony'
from = params[:name] || params[:subscribe]
subject = "#{params[:name]} has contacted you via the Website" ||
"#{params[:subscribe]} has subscribed to the newsletter"
body = "#{params[:email]}#{params[:comment]}"
Pony.mail(
:from => from,
:to => 'myemailaddress',
:subject => subject,
:body => body,
:via => :smtp,
:via_options => {
:address => 'smtp.gmail.com',
:port => '587',
:enable_starttls_auto => true,
:user_name => 'myemailaddress',
:password => 'mypassword',
:authentication => :plain,
:domain => "localhost.localdomain"
})
redirect '/success'
end
2. Make clear your intentions
in this case, that there are two branches through the code.
post '/' do
require 'pony'
if params[:name] # contact form
from = params[:name]
subject = "#{params[:name]} has contacted you via the Website"
else # subscription form
from = params[:subscribe]
subject = "#{params[:subscribe]} has subscribed to the newsletter"
end
body = "#{params[:email]}#{params[:comment]}"
Pony.mail(
:from => from,
:to => 'myemailaddress',
:subject => subject,
:body => body,
:via => :smtp,
:via_options => {
:address => 'smtp.gmail.com',
:port => '587',
:enable_starttls_auto => true,
:user_name => 'myemailaddress',
:password => 'mypassword',
:authentication => :plain,
:domain => "localhost.localdomain"
})
redirect '/success'
end
(I'm not a big fan of setting local vars within conditional branches, but we'll ignore that for clarity. I'd probably create a hash before the conditional with the keys already done, and then populate it in the branches but YMMV.)
3. Extract what doesn't change from what does.
Sinatra has a configure block just for this kind of thing.
require 'pony'
configure :development do
set :email_options, {
:via => :smtp,
:via_options => {
:address => 'smtp.gmail.com',
:port => '587',
:enable_starttls_auto => true,
:user_name => 'myemailaddress',
:password => 'mypassword',
:authentication => :plain,
:domain => "localhost.localdomain"
}
end
Pony.options = settings.email_options
Notice I've added :development as you may want to set it up differently for production.
Now your route is a lot cleaner and easier to debug:
post '/' do
if params[:name] # contact form
from = params[:name]
subject = "#{params[:name]} has contacted you via the Website"
else # subscription form
from = params[:subscribe]
subject = "#{params[:subscribe]} has subscribed to the newsletter"
end
body = "#{params[:email]}#{params[:comment]}"
Pony.mail
:from => from,
:to => 'myemailaddress',
:subject => subject,
:body => body,
redirect '/success'
end
My last tip, would be to put as many of those Pony options into ENV vars, which will not only keep things like passwords out of source control but also allow you to change the settings a lot easier. Perhaps put them in a Rakefile and load different environments for different contexts etc.
To use environment variables, I do the following:
# Rakefile
# in this method set up some env vars
def basic_environment
# I load them in from a YAML file that is *not* in source control
# but you could just specify them here
# e.g. ENV["EMAIL_A"] = "me#example.com"
end
namespace :app do
desc "Set up the environment locally"
task :environment do
warn "Entering :app:environment"
basic_environment()
end
desc "Run the app locally"
task :run_local => "app:environment" do
exec "bin/rackup config.ru -p 4630"
end
end
# from the command line, I'd run
`bin/rake app:run_local`
# in the Sinatra app file
configure :production do
# these are actual settings I use for a Heroku app using Sendgrid
set "email_options", {
:from => ENV["EMAIL_FROM"],
:via => :smtp,
:via_options => {
:address => 'smtp.sendgrid.net',
:port => '587',
:domain => 'heroku.com',
:user_name => ENV['SENDGRID_USERNAME'],
:password => ENV['SENDGRID_PASSWORD'],
:authentication => :plain,
:enable_starttls_auto => true
},
}
end
# then a block with slightly different settings for development
configure :development do
# local settingsā€¦
set "email_options", {
:via => :smtp,
:via_options => {
:address => 'smtp.gmail.com',
:port => '587',
:enable_starttls_auto => true,
:user_name => ENV["EMAIL_A"],
:password => ENV["EMAIL_P"],
:authentication => :plain,
:domain => "localhost.localdomain"
}
}
end
I usually keep most of these setting in a YAML file locally for development, but add these to the production server directly. There are lots of ways to handle this, YMMV.

Resources