Design Patterns Quick Reference II – The Poster Chronicles

So it took a bit of time but I have the poster version available for the design pattern reference. The only one right now is a large poster, however there will be various sizes as well as all kinds of other merchandise to come.

Get yours today at:

http://www.cafepress.com/codergear

Get yours early – if we find an error tomorrow the current version becomes a collector item! 😉


Sending email in Ruby on Rails

So I have recently become acquainted with Ruby on Rails and have been playing around with some of its functionality. One of the things I spent the most time trying to figure out was how to get my application to send mail correctly. After following the instructions on all the existing sites out there I had it working in my development environment but found that it crapped out when I tried to port it to a production environment. So I decided to throw something together to explain the steps I went through to get everything working.

Disclaimer – I am a Java guy by trade and am new to RoR. If I am doing something “the hard way” please speak up RoR gurus.

First, the background. Ruby on Rails handles most stuff for you – the object relational model (ORM), database transactions, views, and even mail. The mail is composed of a couple parts: configuration, a model, a view, and a client. Lets step through these.

The configuration is simply information that goes into either the config/environment.rb or the config/environments/[production || development || test].rb file. If you use one of the files in the config/environments folder you will be able to specify multiple settings for multiple environments. For example, I set mine up so that config/environments/development.rb pointed to my localhost mail server while my config/environments/production.rb pointed to my hosted mail server. Here is the basic information you’ll need:

ActionMailer::Base.delivery_method = :smtp
ActionMailer::Base.raise_delivery_errors = true
ActionMailer::Base.smtp_settings = {
  :address => "smtp.myserver.com",
  :port => 25,
  :user_name => "myusername",
  :password => "mypassword",
  :authentication  => :login
}

Next, you will need a model that contains the actual functionality for sending the mail and interacting with the ActiveMailer. The easiest way to do this is to run “ruby script/generate mailer mymailertest” (for non-windows drop the “ruby”). This will produce the following files:

exists  app/models/
create  app/views/mytestmailer
exists  test/unit/
create  test/fixtures/mytestmailer
create  app/models/mytestmailer.rb
create  test/unit/mytestmailer_test.rb

Before we start describing the parts, lets take a look at how this all works. When the client (usually a controller, but really can be any part of the code) wants to send an email they will invoke the mailer model, calling a specific method. This method will set up the email then forward to a view, which renders the contents of the email. This rendered content is what is actually sent over the wire.

We now need hook the model up so that it will work. The model, mytestmailer.rb, already extends ActionMailer so we just need to add a method. This method will be called later to deliver mail. The method we define will be mapped to a view that will actually be the email template. We will explain that next. First, add a method to your model that will represent an action taken by your application – welcome, confirmation, invalid login attempt, etc. An important note in this step is that if you want your arriving email to display your/a name instead of the email address you will need to use the notation used in the from line below, since the from line equates to the SMTP FROM header. Also, this assumes that you have a User or some other object that you wish to pass to the view in order to render the email.

class Mytestmailer < ActionMailer::Base

  def welcome(user)
    recipients "somename@somedomain.com"
    from "Your Name "
    subject "RoR Test Email"
    body :user => user
  end

end

This will automatically forward to a view with the same name as the method, in this case app/views/mytestmailer/welcome.html.erb (note that if you are using a version of RoR prior to 2.* you will have an extension of *.rhtml – this makes no difference). Put simply, the model is the contents of the email only with scripting functionality built in. In our scenario, the model will pass in a User object which we will use to construct the email. Our view looks like this:

Dear <%= @user.first %> <%= @user.last %>,

Thanks for signing up for the McDonaldLand mailing list!

We are here to help so if you ever need us blah blah blah.

Thanks for your interest in McDonaldLand,
Jason McDonald

So we are almost done. We just need to set a client up to call the mailer. From the client we would simply invoke the deliver_* method on the mailer object, which would then delegate to the appropriate method. In our example we would call deliver_welcome, which would route to the welcome method. The arguments passed here will be routed to the mailer model object as well. So to send our email from whatever part of the code we want all we have to do is this:

mytestmailer.deliver_welcome(@user)

That’s it.


Backwards compatible languages are a myth

In the theoretical sense, the notion of backwards compatibility in programming languages is sound. However, when we try and apply this theory on a universal scale we begin to see a number of tiny breakdowns that point towards the reality that the concept of backwards compatible software languages, at least from a universal perspective, is a myth.

One of the most notorious of languages to embrace the concept of preserving backwards compatibility is Java. However, Java does not absolutely preserve backwards compatibility, despite their claims. The most prominent example of this is in the upgrade from J2SE 1.4 to 1.5. Anyone use ‘enum’ as a variable name in their code? If so you broke. Perhaps I am misinterpreting the true meaning of backwards compatible, but this does not seem to fit.

However, just because your application falls into the realm of a backwards compatible one doesn’t mean that you are set. Any application that uses a third party library that proves to not be backwards compatible is doomed as well. Unless there is a new version of your library that integrates with the upgraded language, you have the ability to fix the library, or have a substitute library you can use, your upgrade is doomed.

The concept of backwards compatibility is a good one, however everything should be in moderation. When the adherence to this rule comes at the cost of the proper implementation of language features, as Bruce Eckel discusses, it can be argued that the notion of backwards compatibility is more of a long term bane than blessing. If the features of the language upgrades are good enough people will upgrade, regardless of whether they have to do a little more work. One look to the recent Ruby or Python additions are proof of this.