Testing And Designing Email Views in Rails

Profile
by Jess Brown

The Problem

The traditional way of testing the design of emails in rails has always seemed really lame. Way back when, we had to connect to some smpt server in development, then trigger the email, and then pull up the email to check it. More recently, tools like mailcatcher and letter opener came about and eliminated the need to actually connect to an email server and send the email.

However, this still isn't very rails like. You have to setup the scenario and sometimes they're really long. For example:

  1. create a user
  2. verify user
  3. certifiy user
  4. user receives and an invitation to join by a customer (need a customer)
  5. user decides to bid on project
  6. customer awardes the bid to the user
  7. finally "bid awarded" email gets triggered

Wait, you made a change, now repeat all of that.

A Solution: The MailView Gem

I can't remember how, but not too long ago, I discovered the MailView gem. What it does is allow you to test mail views in development mode by using an controller => action type scenario. The docs are pretty good, but I'll walk you through them here.

# Include the gem
gem "mail_view", "~> 1.0.3"

Then, create a controller like class that sub classes MailView:

# I think I read somewhere it's best to wrap this in an if statement to
# only allow in dev mode.  Maybe an issue on heroku if you don't??
# Doesn't hurt anyway.

if Rails.env.development?
  # app/mailers/user_mailer_preview.rb or lib/mail_preview.rb
    class UserMailerPreview < MailView
      # Pull data from existing fixtures / dev data
      def invitation
        user = User.first
        UserMailer.invitation(user) 
      end

      # Factory-like pattern
      def welcome
        user = User.create!
        mail = UserMailer.welcome(user)
        user.destroy
        mail
      end

      # Stub-like
      def forgot_password
        user = Struct.new(:email, :name).new('name@example.com', 'Jill Smith')
        mail = UserMailer.forgot_password(user)
      end
    end
  end

Of course, this assmues you already have all of these mailers setup (UserMailer.invitation, UserMailer.welcome, UserMailer.forgot_password)

Next you'll need a route to view the email:

# config/routes.rb
if Rails.env.development?
  mount UserMailerPreview => 'mail_view'
end

Quick rails routes pro tip: if you're getting an error with routes, make sure you have the above code placed high enough in your routes file so another route isn't being processed before it. ( I once trouble shooted this issue for half an hour because I had a *path catch all type route before the mail_view one. )

So, that's pretty much it. If you have your preview class and "actions" setup properly, then you can visit http://localhost:3000/mail_view. This will show all the actions you have setup and you can click to view each one.

How to setup the mailview gem

* Remember to use the port you use for development

If you're using images, or links, you should remember to set the proper port. Most rails apps default to port 3000, but if you're using foreman or unicorn, you'll likely us another port. In your config/environment/development.rb file:

config.action_mailer.default_url_options = { :host => 'localhost:8080' }

Then your images and links will work properly in dev mode.

  # example image link
  <img src="<%= image_url('logo.png')" />

* Don't forget to use _url instead of _path so your links are absolute.

Another "gotcha" migth be that if you change anything in your preview class, then you need to restart your server. I'm not sure why that is, but I read it somewhere and confirmed it true (changes to your mailer view will reload properly though).

MailView Preview

I hope that helps! Let me know if you have any questions.

Running A Freelancing or Independent Consulting Business Is Touch & Go

Profile
by Jess Brown

I guess this is true with any business, but it's still fustrating to have ups and down's in a business. Running a small consulting business, I frequently only focus on moving the business forward. I have X number of projects that I'm working on, deadlines, goals for number of hours billed in a week, etc. The problem is, we usually only ever anticipate things going perfect...best case scenario. However, we know that Murphy's law likes to inject itself into our workflow from time to time and things never go as we anticipate.

Just this past week, I had a string of several setbacks:

  1. My server wouldn't reboot
  2. I switched DNS for a client and the mail quit working (this later turned out not to be a result of my DNS change, but still caused me to stop everything and deal with helping them get it fixed)
  3. My wife got the stomach bug and I had to take the day off to watch our kids
  4. Thanksgiving Holidays (not really a setback, but 2 more days things aren't getting done)

Think To Remember

I'm a cyclist and one thing cyclist hate is when their training plan / goal gets messed up. Work, getting sick, bad weather and more can interupt a training plan. The best cyclists are able to work with the interuption.

I believe the same is true with business, you have to realize those things are going to happen, embrace them, and plan for the interuption.

How To Add A Wordpress, Joomla, or any databased backed blog to a rails App

Profile
by Jess Brown

The Problem

You need to add a new blog or a legacy blog to a rails app

Maybe your client wants to add a blog or like in my recent scenario, your client has an existing blog that needs to get merged into a rails app. There's several alternative ways to do this:

  • not actually merging them and keeping the blog and the rails app separate
  • using a rails blogging solution like Refinery
  • migrating and rolling your own

Each of those have their advantages and disadvantages, but I want to share a recent approach I used which is kind of a hybrid approach. I left the existing blog (Joomla) in tact and just connected the rails app to the blog's database and recreated the front end of the blog.

This worked great for several reasons:

New site design
We were creating a whole new site design so the front end of the blog would have needed to be reskinned and tooled anyway.

Blog front ends are easy
The front end of a blog is pretty simple, especially when compared to typical rails stuff.

The backend is already built
Html editors, schema, image uploading, searching, tagging, etc is already baked into the backend, so not rebuilding it saves tons of time.

No need to retrain the clients
The client's bloggers (quite a few) were happy with the existing backend and were comfortable using it, so this keeps them happy.

No need to migrate
Not migrating the existing data is a huge win.

The steps

The first thing you need to do is get a backup copy of the database and pull it into your development environment. I also created a test database for my tests.

Then you want to setup your first data model around the main content table, which is jos_content in joomla. Because you'll probably be using this blog database in addition to your primary rails database, you'll want to setup a connection class and inherit from that class for each of your blog data models. Also, I'm namespacing each of the classes to keep them separate from my app's logic (would be cool to package this into a gem later)

# app/models/blog/base.rb
class Blog::Base < ActiveRecord::Base
  self.abstract_class = true
  establish_connection "blog_database_#{Rails.env}"
end

# app/models/blog/article.rb
class Blog::Article < Blog::Base
  self.table_name = "jos_content"
  belongs_to :category, foreign_key: :catid

  def self.public
    where("state = 1").order("publish_up DESC").where("publish_up <= '#{Time.now.utc}'")
  end
end

# app/models/blog/category.rb
class Blog::Category < Blog::Base
  self.table_name = "jos_categories"

  has_many :articles, foreign_key: :catid
end

# config/database.yml
...

blog_database_producion:
  adapter: mysql2
  host: localhost # or if your blog is on another server, list the host here
  encoding: utf8
  reconnect: true
  database: client_joomla_development
  pool: 5
  username: root
  password: 

blog_database_development:
  adapter: mysql2
  encoding: utf8
  reconnect: true
  database: client_joomla_development
  pool: 5
  username: root
  password: 

Setting up a controller

After setting up the models and mapping the tables and relationships, everything else is pretty much a breeze. Here's a controller for the blogs.

# app/controllers/blog/articles_controller.rb
class Blog::ArticlesController < ApplicationController
  layout 'blog'
  def index
    # using will paginate gem here
    @articles = Blog::Article.public.paginate(:page => params[:page])
  end

  def show
    @article = Blog::Article.where(alias: params[:id]).first
  end
end

Setting up the views

The views are simple as well:

# app/views/blog/articles/index.html.erb
<h1>Blog</h1>
<%= render @articles %>
<%= will_paginate @articles %>

# app/views/blog/articles/_article.html.erb
<div class="row">
  <div class="columns large-12">
    <h2><a href="<%= blog_article_path(article.alias) %>"><%= article.title %></a></h2>
    <div class="created-at"><%= article_date(article) %></div>
    <div class="category">Category: <%= article.category.title %></div>
    <%= article_text(article.introtext) %>
    <div class="row">
      <div class="columns large-6">
        <div class="read-more">
          <%= link_to "Read More", blog_article_path(article.alias) %>
        </div>
      </div>
    </div>
  </div>
</div>
# app/views/blog/articles/show.html.erb
<h1><%= @article.title %></h1>
<%= article_text(@article.fulltext) %>

Helper

I added a helper for rendering the raw html and the date:

# app/helpers/blog/articles_helper.rb

module Blog::ArticlesHelper
  def article_text(text)
    raw text
  end

  def article_date(blog)
    l blog.created, :format => :long
  end
end

Routes

Here's the routes:

  namespace :blog do
    resources :articles, :only => [:index, :show]
  end

So there you have it. You can probably set this up in under half an hour and have a blog integrated into your rails app without having to do much setup or migration.

I setup an example app to test the code from above. Feel free to reference it if you want to set soemthing like this up.

Example Joomla Blog In Rails App

Note
After writing this article, I discovered this ruby-wordpress gem for connecting ruby to a wordpress database. Looks cool: ruby-wordpress

Keeping Yourself and Clients Accountable

Profile
by Jess Brown

The Problem

Ever since I started out on my own as a web developer, I've found it difficult to manage projects. I don't feel like I'm necessarily terrible at it (my previous job involved managing IT, Marketing, and Sales of a 3+ million small business). There's a couple of things usually get me off schedule:

  1. Short term time requirements This includes modifying/adding/fixing a recently launched project or a 1-2 hr need for an existing client. It's something most clients consider reasonable and expect to be done within 2-5 days.
  2. Ballers Clients that are really visible, vocal and on the ball about their project. I typically like these clients (as long as they're never pushy or rude) because they keep me moving. However, these folks make it easy to forget about the previously scheduled project and focus on theirs.

What does this leave?

This typically leaves out the client who has a ton of other things going on within their business and haven't held you to any timeline. These guys usually get passed over for #1 and #2.

Background Story

Just recently I got a dreaded email from a client. To sum it up, they wanted their deposit back and wanted to move on to another developer. Ouch! That really heart my pride and professional opinion of myself. Fortunately we've been really busy so the loss of business isn't as hurtful, but it was a project I was actually looking forward to working on and with a company I wanted to make a decent impression on. Plus I was embarrassed and had a major case of regret.

What happened?

First, I admit to all fault. It's my responsibility of starting the project, setting expectations and moving the project along.

It was a project that was slow to come together. We started discussing ideas around the first of the year, I sent them an estimate around Feb, we agreed on price around May and I got a check around late June.

By this time I'd had several other larger sized projects come in as well, which put me booked quite a long ways out (Oct / Nov).

This is where my (and a lot of projects) get off to a bad start: knowing when you can start. I hate to displease people. The last thing people want to hear after they just cut you a check is that you can't start for some-long-period-of-time. And the truth is, in our line of work, there's no possible way to determine a project's length, the end date, and the start of the next one. Building software is tough, and most good software projects will go through several iterations, with many changes, and sometimes you wind up with something much different than what you thought you'd have in the beginning (this is a good thing for the business).

It's kinda difficult to explain my contact / point person's position on the project, but he wasn't in the typical position of a client (owner, CEO, CTO, etc). He also wasn't the kind of person to call and check in on things or get updates that often. I'm not in any way blaming him, but it made it super easy for me to tend to #1 and #2.

What works for me

During this same year, I started working with 2 really good clients that I've come to respect (CongrueIt and Nexchain). Two of the guys with CongrueIT have been in the IT consulting industry field for some time and the guy with Nexchain has been all over the world managing projects.

The one thing they expected of me was constant communication. While working on a phase or iteration for their project, we'd typically chat and/or screen share 1-2 times per week. This would include before, during and even after the iteration was complete. Reading this, you'd probably think, duh, you have to communicate, but in reality, good intentions are always there. However, busy schedules, getting behind, etc, make it difficult to actually follow through.

So the solution for me is now a mandatory weekly call from clients. I ask my clients to hold me accountable to keeping the phone call, providing updates, and keeping the project on tract. Likewise, I hold them accountable for keeping the call, providing feedback, and staying active in the project (this helps the money side of things too :-)

Open, honest, frequent, and regular/scheduled communication is the way to go. If you're not doing it, I encourage you start today.

Find and replace html tags in a database

Profile
by Jess Brown

I recently had a client want to change all h2 tags to h1 tags in a refinerycms app I managed. They had several hunderd pages, so manually doing it was not sounding good and using regular expressions for html parsing sounded like trouble.

Then I thought of Nokogiri. Nokogiri does a good job of parsing html right? But how do I change the html?

I ended up writin a rake task searched the body parts (main content body for refinery) for h2 tags and then used Nokogiri to change the tags.

To change the tags, you can just h2.name = "h1".  Another problem I ran into was that I was using

Nokogiri::HTML(page.body)

But when I called to_html on it, I'd get the doctype and body tags with it.  Then I found you can use fragment:

Nokogiri::HTML.fragment(page.body)

And that only retuned exactly what I wanted.

Check it out:

desc "Change body tags"
task :change_body_tags => :environment do
  puts "Changing Body Tags"
  body_parts = Refinery::PagePart.where(:title => "Body")
  body_parts.each do |body_part|
    body_part.translations.each do |page|
      doc = Nokogiri::HTML.fragment(page.body)
      doc.css("h2").each{|h2| h2.name = "h1" }
      page.body = doc.to_html
      page.save
      puts "Updated id # #{page.id}"
    end
  end
end

Navigation


Subscribe to our mailing list