Thursday, September 11, 2014

Setting up Send Grid e-Mail for use with Devise

As I offten find to be the case there was a plethora of documentation around using both Devise and SendGrid. I was even able to find posts about using the two together. However, as usual, I had to look through multiple sources in order to get the two working together. This post is my attempt to put together the shortest set of instructions possible.

First, my starting point. I have a functioning application which uses Devise for User signup and signin. I have not yet implemented any form of email send. I have also not brought the devise views into my code base so I figured I'd better start by importing it into my code base.

Getting devise user views into my code required one command.

rails generate devise:views

This created a folder in my project called views/devise that contained the following items:
confirmations
mailer
passwords
registrations
sessions
shared
unlocks

Bringing this into the project gives the added advantage of being able to customize not only the email messages in mailer, but also the look and feel of all these views for use throughout the application.

My User model already had devise included and looked like this:
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable

Devise already supports email confirmations so I just needed to add that module as shown in the comment. So I added :confirmable like so:

devise :database_authenticatable, :registerable, :recoverable,
:rememberable, :trackable, :validatable, :confirmable

Since I had a working application complete with users, I needed to add columns to my user table for confirmable. This is a simple migration.

rails generate migration AddConfirmableToUsers confirmation_token:string confirmed_at:datetime confirmation_sent_at:datetime unconfirmed_email:string

Next run the migration with:

            rake db:migrate

That should set me up with Devise. The next thing I need to do is configure my application to work with SendGrid. Most of this information came from the documentation at SendGrid.com.
Step one: Create a free development account at SendGrid.
Step two: Insert the configuration for send grid mailer into your config/environment file.

ActionMailer::Base.smtp_settings = {
:user_name => 'YourSendGridLogin',
:password => 'YourSendGridPassword',
:domain => 'YourDomain.com',
:address => 'smtp.sendgrid.net',
:port => 587,
:authentication => :plain,
:enable_starttls_auto => true
}

Note: In the future I (you) may want to have a different configuration for sending mail from dev/test vs. production. At that time we will remove this block from config/environment and create different blocks in config/environments/development etc.

Step three: Make sure that your server URL is set correctly for devise in your config/environments/development and config/environments/production files.

Since I use Nitrous.io for development my development configuration needed to point to my Nitrous server like this:

#devise configuration
config.action_mailer.default_url_options = { :host => 'http://nurl.use6-8.nitrousbox.com' }

Then in production I set it to point to my main website:
#devise configuration
config.action_mailer.default_url_options = { :host => 'http://mycompany.com' }

At this point my users were able to request confirmation emails and click the links to confirm the accounts.


Thursday, July 31, 2014

Rails Radio Button Form Helper or f.radio_button for short

There is an abundance of documentation out there for Ruby and Rails developers, in fact, I often have more trouble narrowing down my searches than finding no answer at all.  However, I also often find that the documentation assumes a level of understanding that a beginner doesn't have.  Recently I spent a couple of hours trying to figure out how to use the radio_button form helper.  There was tons of documentation about radio_button_tag, but not as much about radio_button and the parameters were slightly different.  So I decided to write a short beginners guide to f.radio_button.

Again, I’m a beginner myself so I hope you’ll excuse any misunderstandings and help me correct them.  I’m using Ruby 2.0.0p451 and Rails 4.1.0.

My example will be for a radio button that lets you select a level of recurrence: daily, weekly, monthly, none, and stores that choice, as a string in @meeting.recurrence which we’ll assume is set to “none” to start with.  First up, the basic structure of the helper:

<%= f.radio_button :yourfield, “thevalue”,{options: “withvalues”} %>

My actual implementation:

<%= f.radio_button :recurrence, “none”, {checked: “none”==@meeting.recurrence, onClick: “expand(‘none’)} %>

My form is set up as:

<%= form_for(@meeting) do |f| %>

so “f.” implicitly forces my field names to refer to @meeting.fieldname, so :recurrence is shorthand for: @meeting.recurrence.

The second parameter is the value I want the radio button control to return if this item is selected, so “none” is my result if this value is checked.

The third parameter is a hash of options.  In my case, I have two options that I pass to each button in the group of radio buttons. The first determines if the button is the one checked upon page paint.  It sets the parameter ‘checked‘ = true|false by comparing the data attribute to the selection value.  In this example: “none”.  So if @meeting.recurrence is equal to “none” we get true, if not, we get false.

The second parameter is a javascript function that I want called when this item is clicked.  The function is called ‘expand’ and takes a parameter that tells it which option was clicked, in this case, “none”.
This generates the following html code:

<input checked="checked" id="meeting_recurrence_none" name="meeting[recurrence]" onClick="expand(&#39;none&#39;)" type="radio" value="none" />

Let’s break this down into is constituent parts:


  • Because @meeting.recurrence was equal to “none”, my checked option became “checked: true” which translates in the html to checked=”checked”.  
  • The id is derived from values in the call.  :recurrence (remember, this is short for @meeting.recurrence) becomes meeting_recurrence and then the value “none” gets concatenated to give us “meeting_recurrence_none”.  
  • The name similarly is derived from @meeting.recurrence and becomes meeting[recurrence].  Note that this field, the name, is common across all the buttons in your radio button group and is how the application knows they are part of the same set.
  • My onClick hander just gets passed in directly.
  • The type is implied by the radio_button helper.
  • Finally, the return value is set directly from the second parameter, the value.
Now we need to tell the user what this radio button is so we will pair it with a label.  This is the syntax for a label helper.

<%= f.label :yourfield, "thestring", :value => "thevalue" %>

And here is the actual implementation for the label that matches my radio button.

<%= f.label :recurrence, "none", :value => "none" %>

And the HTML that generates:

<label for="meeting_recurrence_none">none</label>

Again, you can see that :recurrence and the value become “meeting_recurrence_none”  which is how this label is tied to the radio button field by its ID.  This allows the label to be clickable as part of the radio selection.  The “thestring” parameter becomes the string shown to the user.

Now here is the whole block I set up for my four options in my radio button group complete with their labels.

<%= f.radio_button :recurrence, "daily", {checked: "daily" == @meeting.recurrence, onClick: "expand('daily')"} %>
<%= f.label :recurrence, "Daily", :value => "daily" %>

<%= f.radio_button :recurrence, "weekly", {checked: "weekly" == @meeting.recurrence, onClick: "expand('weekly')"} %>
<%= f.label :recurrence, "Weekly", :value => "weekly" %>

<%= f.radio_button :recurrence, "monthly", {checked: "monthly" == @meeting.recurrence, onClick: "expand('monthly')"} %>
<%= f.label :recurrence, "Monthly", :value => "monthly" %>

<%= f.radio_button :recurrence, "none", {checked: "none" == @meeting.recurrence, onClick: "expand('none')"} %>
<%= f.label :recurrence, "None", :value => "none" %>

This results in the following final block of HTML being rendered:

<input id="meeting_recurrence_daily" name="meeting[recurrence]" onClick="expand(&#39;daily&#39;)" type="radio" value="daily" />
<label for="meeting_recurrence_daily">Daily</label>

<input id="meeting_recurrence_weekly" name="meeting[recurrence]" onClick="expand(&#39;weekly&#39;)" type="radio" value="weekly" />
<label for="meeting_recurrence_weekly">Weekly</label>

<input id="meeting_recurrence_monthly" name="meeting[recurrence]" onClick="expand(&#39;monthly&#39;)" type="radio" value="monthly" />
<label for="meeting_recurrence_monthly">Monthly</label>

<input checked="checked" id="meeting_recurrence_none" name="meeting[recurrence]" onClick="expand(&#39;none&#39;)" type="radio" value="none" />
<label for="meeting_recurrence_none">None</label>

Finally, to bring it home, this is the data that gets submitted to the server for this control:

"meeting"=>{"recurrence"=>"daily"}

I hope that some other beginner might find this just a little bit helpful.

Using Mandrill Send Template from Rails

Last time I posted I covered creating a method that can invoke the Mandrill API to send an e-mail message via a template. This time I'll cover how I actually used it.
First off, I used Mail Chimp to create our outbound messages. You need to create both a Mail Chimp account and a Mandrill account. Mail Chimp then allows you to link the two accounts together. Mail Chimp uses merge tags of the form: *|attribute_name|*. They are case insensitive and I used only letters and underscore in naming them.
Mail Chimp will include a few extra meta tags like if statements: *|IFNOT:ARCHIVE_PAGE|*and some common variable such as: *|LIST:COMPANY|*. The above if statement is used to alter content in the message when displaying a copy of it on a website instead of the recipient using their mail client directly. I opted not to implement that capability at this time so those tags get removed when I edit the message in Mandrill.
After saving the templates, use the Send To Mandrill option on the Edit button in Mail Chimp. This will create a copy of the template in Mandrill. At this time the GUI integration between Mail Chimp and Mandrill isn't very tight so you may have to create copies of templates and export them to Mandrill to do updates. I hope Mail Chimp will tighten this integration up soon.
Once the template is exported to Mandrill, switch over to your Mandrill account and edit the template. Remove the IF tags that I mentioned. Also, remove any other default tags that you don't want. I opted to keep the *|LIST:COMPANY|* tag, however, Mandrill doesn't recognize that tag format (another area I hope Mail Chimp will tighten up) so I replaced colons with underscores like: *|LIST_COMPANY|*. Note the template slug name. This is the name by which you will invoke this message.
Now we have a template that we are ready to send. Over in Ruby we need to invoke our sendtemplate method. So here it is: Again, sorry about the formatting, I don't think Linkedin intended for code examples to be included.
def sendtouser(user)
  subject = "Welcome and thank you for signing up!"
  mandrillsend = Mandrill::Mandrill.new
  result = mandrillsend.sendtemplate(
    "getting-started", # Mandril slug name
    Rails.configuration.returnaddress, # return email address
    Rails.configuration.returnname, # name to show for return
    user.email, # target email address
    user.full_name, # name to show for target
    subject, # Message subject
    [{"name" => "subject", "content" => subject},
      {"name" => "CURRENT_YEAR","content" => Time.now.year.to_s},
      {"name" => "LIST_COMPANY","content" => "My Company, LLC."},
      {"name" => "HTML_LIST_ADDRESS_HTML","content" => OfficeAddress},
      {"name" => "unsub","content" => Rails.application.routes.url_helpers.url_for(:host => Rails.configuration.serverroot, only_path: false, controller: "contacts", action: "unsub", id: encrypted_id)},
      {"name" => "UPDATE_PROFILE","content" => Rails.application.routes.url_helpers.url_for(:host => Rails.configuration.serverroot, only_path: false, controller: "users", action: "edit", id: user.id)}
    ]
  )
    
  Rails.logger.debug("--- manmailer.signed_up result")
  Rails.logger.debug(result.code)
  Rails.logger.debug(result.body)
  Rails.logger.debug("-------------------------------)
  
  status = result.code
  
  result_body = result.body
  
  return status.to_i == 200 # expect back 200 on the return code
end # sendtouser
All of the replacement variables are referenced by name (CURRENT_YEAR) in an array [] of name value pair hashes {}.
So you can see that {"name" => "CURRENT_YEAR","content" => Time.now.year.to_s} will result in the variable *| CURRENT_YEAR|* being replaced by the value generated by Time.now.year.to_s.
I hope this post, when coupled with my last post might help get a few folks integrating with Mandrill.

Monday, April 14, 2014

How I integrated Rails with Mandrill send-template

First off let me say that I am new to Ruby and Rails development so my comments probably won't impress any Sr. developers or win any followers among Ruby Purists. However, my intent is to share actual learning by someone new to Ruby and hopefully help some other newbies in the process.

This post is about integrating my rails application with Mandrill for the purpose of sending transactional e-mail messages. So, let's get started.

My objective is to have three modes of operation in sending my mail messages.
  1. Test – this mode will call my send mail functions, but not invoke the Mandrill APIs. I will simulate various responses by hard-coding them into the results of my mail methods instead of getting them from Mandrill.
  2. Development – in this mode, my send mail functions will call the Mandrill APIs, but using Mandrill's test mode. This will allow me to verify that my JSON calls are in fact getting to Mandrill and able to return their result codes.
  3. Production – this mode will only be used on the production server and will of course, deliver my messages to their intended recipient.

Getting started with Mandrill was easy. I just signed up for a free account. After signing in I navigated to the Configuration Menu (the Gear) and selected SMTP & API credentials. We need a key from Mandrill to include in all of our API calls and this is where we create them. Click the “+ New API Key” button. Which takes us here:


I created two keys, one named TestKey for which I selected the Test Key check box, and one named Production for which I did not select Test Key.

I'm going to use two layers of configuration in my Rails app to set up my Mandrill email access. The first is in my project/config/local_env.yml file. This file holds what I think of as global constants that I don't want stored up on Github. The file can be added to your project/.gitignore file and won't be stored in your repository. I set up two constants to contain my keys:

MANDRILL_PROD_API_KEY: “TheFunkyStringMandrillMade”
MANDRILL_TEST_API_KEY: “AnotherFunkeyStringMandrillMade”

Each key was actually 22 mixed case letters and numbers.

While I was in the local_env.yml file I also threw in a couple of other constants that I might want to change latter that are email related, the name and address of the person I want my emails to be from.

OWNER_EMAIL: “myname@mydomain.com
OWNER_NAME: “My Name”

Now I need to reference these values in my application. This is where the project/config/environments folder comes into play. It contains three files that are loaded into your application at run time based upon the mode you are actually running in:
development.rb
production.rb
test.rb

I created four configuration variables in each of the three files:
config.mandrillsend = false
config.mandrillkey = ENV["MANDRILL_TEST_API_KEY"]
config.returnaddress = ENV["OWNER_EMAIL"]
config.returnname = ENV["OWNER_NAME"]

The first one is how I intend to implement my code that skips the API calls completely. I'll set it to false when I'm in hard core development mode and don't want to even make the calls to Mandrill, and I'll set it to true when I want the calls made. It will generally be true in Development and Production modes, but false in test mode. Also, in the test.rb and developmen.rb files I set

config.mandrillkey = ENV["MANDRILL_TEST_API_KEY"]

and as you can guess, in production.rb I set

config.mandrillkey = ENV["MANDRILL_PROD_API_KEY"]

The next step was to build a function that I could call to actually send a message to Mandrill's APIs. I created:

project/lib/mandrill.rb

Keep in mind that when you put code in the project/lib folder it isn't reloaded on each invocation like your models, views and controllers so when I was debugging I had to stop and start the rails server after each change. Here is the complete file:

module Mandrill
# This object is actually returned from the sendtemplate function
# instead of a real result when I set config.mandrillsend = false.
# I can change it to simulate various results.
class FakeRes
  def code
    "200"
  end
  def body
    "Test mode"
  end
end

class Mandrill

  require "net/http"
  require "uri"
  # Here I create a dummy JSON record that is ready to hold all the parameters to send
  # in an API call. I do this just to help me visualize the record. You could skip this and just
  # build up the record from scratch when you call sendtemplate.
  def initialize
    @jhash = {
      "key" => Rails.configuration.mandrillkey,
      "template_name" => "no-template",
      "template_content" => [{
        "name" => "NotNeeded",
        "content" => "NotSupplied"
      }],
      "message" => {
        "from_email" => Rails.configuration.returnaddress,
        "from_name" => Rails.configuration.returnname,
        "to" => [{
          "email" => Rails.configuration.returnaddress,
          "name" => Rails.configuration.returnname,
          "type" => "to"
        }],
        "headers" => {
          "Reply-To" => Rails.configuration.returnaddress
        },
        "subject" => "Getting started",
        "important" => false,
        "track_opens" => nil,
        "track_clicks" => nil,
        "auto_text" => nil,
        "auto_html" => nil,
        "inline_css" => nil,
        "url_strip_qs" => nil,
        "preserve_recipients" => nil,
        "view_content_link" => nil,
        "bcc_address" => nil,
        "tracking_domain" => nil,
        "signing_domain" => nil,
        "return_path_domain" => nil,
        "merge" => true,
        "global_merge_vars" => [
          {
            "name" => "CURRENT_YEAR",
            "content" => "2014"
          },
          {
            "name" => "LIST_COMPANY",
            "content" => "My Company"
          }
        ]
      }, # message
      "async" => false,
      "ip_pool" => "Main Pool"
    } # jhash
  end # initialize

    def sendtemplate(template, from_email, from_name, to_email, to_name, subject, merge_vars, bcc ="")
      Rails.logger.debug("Now invoking sendtemplate")
      Rails.logger.debug(template, from_email, from_name, to_email, to_name, subject, bcc)
      Rails.logger.debug(merge_vars.to_s)
      if Rails.configuration.mandrillsend
        Rails.logger.debug("Rails.configuration.mandrillsend set to true so trying to send email")    
        # Build an array of to values
        if bcc == ""
          @jhash["message"]["to"] = [{"email" => to_email,"name" => to_name,"type" => "to"}]
        else
          @jhash["message"]["to"] = [{"email" => to_email,"name" => to_name,"type" => "to"},
            {"email" => bcc,"name" => bcc,"type" => "bcc"}]
        end
        @jhash.update("template_name" => template)
        @jhash["message"].update("from_email" => from_email)
        @jhash["message"].update("from_name" => from_name)
        @jhash["message"]["headers"].update("Reply-To" => from_email)
        @jhash["message"].update("subject" => subject)
        @jhash["message"].update("global_merge_vars" => merge_vars)
        
        service_url = "https://mandrillapp.com/api/1.0/messages/send-template.json"
        Rails.logger.debug(service_url)
        
        url = URI.parse(service_url)
        headers = {"host" => url }
        req = Net::HTTP::Post.new(url.path)
        req["Content-Type"] = "application/json"
        req["Accept"] = "application/json"
        
        req.body = JSON.generate(@jhash)
        
        Rails.logger.debug("Start ====req.body==========")
        Rails.logger.debug(req.body)
        Rails.logger.debug("End ======req.body==========")
        
        con = Net::HTTP.new(url.host, url.port)
        
        # ssl for https
        con.use_ssl = true
        con.verify_mode = OpenSSL::SSL::VERIFY_NONE
        
        res = con.start {|http| http.request(req) }    
        
        Rails.logger.debug(res.code)
        Rails.logger.debug(res.body)
        
      else
        Rails.logger.debug("Rails.configuration.mandrillsend set to false so no email sent")    
        res = FakeRes.new
        Rails.logger.debug(res)
      end
        
      Rails.logger.debug("Now done with SendTeamplate")

      return res
    end #sendtemplate
  end #class Mandrill   
end #module Mandrill

Now to send an email message I add

require “mandrill”

in my controller. Then it's just two lines of code:

mandrillsend = Mandrill::Mandrill.new
result = mandrillsend.sendtemplate(template, from_email, from_name, to_email, to_name, subject, merge_vars, bcc_email)


So now you know, for better or for worse, how I implemented Mandrill send-template in my Rails project. In my next post I'll cover implementing the mail template and passing the values into Mandrill to build up the message content.