Adding welcome emails to dm-devise

I was looking for a way to have users greeted with a welcome email when they created accounts, and Devise doesn’t have a ‘welcomeable’ module. Initially I forked devise and started building one, but it’s actually so simple to add (at least with DataMapper) that I can see why there isn’t one included. So, here we go.

Subclass Devise’s mailer

We do this to keep the rest of this as parallel to Devise as possible.

class AppMailer < ::Devise::Mailer
  def welcome_message(resource)
    setup_mail(resource, :welcome_message)
  end
end
And in config/initializers/devise.rb:
config.mailer = "AppMailer"

Add the template for your message

In app/views/devise/mailer/welcome_message.html.erb:

<p>Welcome <%= @resource.email %>!</p>
 
Thanks for signing up for App.  
App is one of the greatest things you could sign up for. 
 
You won't regret it!

Add the title to the devise localization file

In config/devise/en.yml:

en:
  devise:
    mailer:
      welcome_message:
        subject: "Welcome!"

Connect the creation of a user to sending the mail

We’re going to use DataMapper’s CRUD hooks to do this. These are declared either before or after the CRUD operations. It used to be the case that dm hooks would work on any function at all, but that was deprecated a while back.

class User
  include DataMapper::Resource
  devise :database_authenticatable, :registerable,
            :recoverable, :rememberable, :trackable, :validatable
    
  after :create, :send_welcome_message
 
  def send_welcome_message
    ::Devise.mailer.welcome_message(self).deliver
  end
end
Now, because devise looks for the templates to render in the views directory, under the name of the mailer class, we need to move all our views from app/views/devise/mailer to app/views/app_mailer. Once that is done, everything should be up and running.

Using jQuery in a Chrome extension

I’ve gotten so used to using jQuery that when suddenly I’m reduced to using vanilla javascript I feel like something is wrong. So when I was trying to write a chrome extension and realized I was going to have to use the basic methods to create elements and traverse the DOM, I felt a little squicked out.

There are basically two places you might want to use jQuery in an extension: within the background page, and within a tab. But in both cases, you’re probably going to want to have a local copy of jQuery, which you can get from jquery.com. You could pull it from a CDN but then you’re depending on your internet connectivity and the CDN.

In a background page

This is the simpler of the two. Just include the javascript file in your background.html (or whatever you’ve named it) file in the same way as you would normally.

<script src='jquery-1.5.1.min.js'></script>

In a tab

If you want to use it in a script that runs on each page, you have to modify your manifest.json file to add it to the content_scripts list:

{
  "name": "My Extension",
  "version": "0.1",
  "content_scripts": [
    {
      "matches": ["http://*/*"],
      "js": ["jquery-1.5.1.min.js", "myScript.js"]
    }
  ],
  "background_page": "background.html"
}

Make sure that you put the jquery file first in the list so it is available to your other javascript files, otherwise you will get errors like “$ does not exist”, which plagued me until I realized this.

Notes:

Chrome Extension Dev Guide

Capistrano keeps asking for password

When deploying with Capistrano, you probably want to do it with a minimum of kicking and screaming. One of the obstacles that lies in your way is the constant requests for passwords which pop up if you haven’t set everything up properly.
* executing `invoke'
  * executing "echo $LOGNAME"
    servers: ["verticallabs.ca"]
Enter passphrase for /home/paul/.ssh/id_rsa:

How do you avoid this? It turns out there are a couple of common problems that cause Cap to keep asking you for your password.

Accessing source control with SSH

Cap has to pull your data out of source control, and it may need to ssh somewhere to get it (check your :repository setting). Even if you’re using the same username to access source control (and you probably are), it still has to ssh from your remote machine to the repo – even though it might be located on the same remote machine. The solution for this is pretty simple: you need to tell Capistrano to use ssh user forwarding.

set :ssh_options, {:forward_agent => true}

You can read about agent forwarding here if you’re not familiar with it.

Missing public key

Even if you have password-less access to the remote machine in question using a private key, you may still be asked for a password because Capistrano requires you to have the public key which matches that private key. (Thanks to thebaldwin for pointing this out) If your ~/.ssh folder only contains the id_rsa, you need to either put the id_rsa.pub in there too, or recreate it like this:

ssh-keygen -y -f ~/.ssh/id_rsa > ~/.ssh/id_rsa.pub

Problems with Bundler and the Ruby 1.9.2 Yaml parser

As pointed out by Cyril Rohr here, there are issues with the default YAML parser for Bundler, Psych. So:
defaults: &defaults
  adapter: yaml
 
development:
  <<: *defaults
 
test:
  <<: *defaults
 
production:
  <<: *defaults

Even though you’d expect the different environments to inherit the defaults they will not, so ‘adapter’ will never be defined. This is because of an issue with merging YAML keys in Psych, apparently.

Cyril suggests using an initializer and switching the parser to Syck, but that didn’t work for me. According to this closed issue on bundler, the correct place to put it is right after the require for bundler (which is in boot.rb).

require 'rubygems'
  
# Set up gems listed in the Gemfile.
gemfile = File.expand_path('../../Gemfile', __FILE__)
begin
  ENV['BUNDLE_GEMFILE'] = gemfile 
  require 'bundler'
    
  STDERR.puts "Temporarily changing yaml engine to syck"
  YAML::ENGINE.yamler = "syck"
  Bundler.setup 
rescue Bundler::GemNotFound => e 
  STDERR.puts e.message
  STDERR.puts "Try running `bundle install`."
  exit!
end if File.exist?(gemfile)

And all is well. Hopefully this Psych issue will be fixed soon!

Update:

Apparently the Psych issue with merge keys has been fixed, but because Psych is a part of the actual Ruby distribution, you either have to build your own Ruby from head, or wait until the next patch of Ruby 1.9.2.

Location awareness with GeoLiteCity and Rails

So you want to make your app location-aware. There are a number of different ways to do this (Quova, hostip.info, geokit, etc), but one of the most popular seems to be MaxMind’s GeoIP databases. They have a free version which is unsupported and less accurate than their subscription version, but the interface and process seems to be essentially the same.

First, we have to get the C version of the api installed and working:
tar xvzf GeoIP-1.4.6.tar.gz
cd GeoIP-1.4.6
./configure
make && sudo make install

Then we’re going to grab Ryan Dahl’s geoip_city gem.
sudo gem install geoip_city

And we’re almost there. Now all we have to do is instantiate the database using the free data from MaxMind, and query it.
require 'rubygems'
require 'geoip_city'
db = GeoIPCity::Database.new('config/GeoLiteCity.dat')
db.look_up('206.116.100.35')
 
{ :longitude=>-122.966697692871, 
  :country_code3=>"CAN", 
  :country_name=>"Canada", 
  :region=>"BC", 
  :city=>"Richmond", 
  :latitude=>49.1666984558105, 
  :country_code=>"CA"} 

Note that this uses MaxMind’s C database which was designed for this application. It _is_ possible to move the data into an sql database and query it from there, but MaxMind says that the custom database is much faster at querying, and somebody seems to have confirmed it.

Also: do NOT reinstantiate the db on every request if you are using Rails. It’s a hefty 35mb, and though it will be garbage collected, a couple of quick requests before the garbage collector runs could easily bloat your app into emergency shutdown panic.

No process window for C# console apps

When I’m using windows and I need a quick and dirty app which is never going to be cross-platform, I like to use C# .Net. It’s pretty fast to get something up and running, and C# is enjoyable to work with. One of the things I often find myself trying to do is prevent an ugly console window from opening up when I’m running an app. There are multiple ways to do this, but they all have their drawbacks.

First method:
Process proc= new Process();
proc.StartInfo.FileName = "cmd.exe"; 
proc.StartInfo.CreateNoWindow = true;
proc.Start();

Drawback: CreateNoWindow doesn’t work if you start a process with UseShellExecute = true.

Second method:
Process proc= new Process();
proc.StartInfo.FileName = "cmd.exe"; 
proc.WindowStyle = ProcessWindowStyle.Hidden;
proc.Start();

Drawback: ProcessWindowStyle.Hidden is only a suggestion, and the child process can always show itself.

Third method:
[DllImport("user32.dll")]
static extern IntPtr FindWindow(string lpClassName,string lpWindowName);
 
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
 
const int SW_HIDE = 0;
const int SW_SHOW = 5;
 
static void Main()
{
    Process proc = new Process();
    proc.StartInfo.Verb = "Print"; 
    proc.Start(); 
    ShowWindow(hWnd, SW_HIDE); // Hide console window
}

Drawback: Dll imports are ugly. Why can’t I do this in regular .Net?

And a little trick:
If you don’t need your console app to show up at all, go to your project configuration and change your output type to “Windows Application”.

Environment variables and Process.Start

This is a problem that I’ve come across a couple of times now. I want to spawn a process from .Net with changes to the path or other environment variables, but I don’t want to modify the local environment variables for the calling process. Or I need to run a third-party batch file that configures the environment, and then run something else.
Process.Start("setenv.bat");
Process.Start("app.exe");
Uh oh. No good, because each of the Processes spawn with their own local copy of the environment, and so the environment that is used by app.exe is a fresh copy of the environment used by the .Net app. The easiest solution is to just create another batch file that calls them both and call that instead.
Process.Start("setenv_and_then_call_app_exe.bat");
But as soon as it gets more complicated than that, the preferred solution is to run the two in the same environment, which can be done by running a process and redirecting standard input.
Process proc = new Process();
proc.StartInfo.FileName = "cmd.exe"; 
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardInput = true;

proc.Start();
StreamWriter cmdWriter = proc.StandardInput;
cmdWriter.WriteLine("setenv.bat");
cmdWriter.WriteLine("app.exe");

Now the changes to the environment made by setenv.bat will persist and affect the execution of app.exe.

Adding code samples with SyntaxHighlighter 3.0

When you’re writing a technical post on coding, it’s important to be able to post code samples to show people exactly what you mean (and make it easier for them to cut and paste). But the standard behaviour for the <code> tag only forces the browser to render in a fixed-width font:

$(function() { $( "#button" ).click(function(){ $( ".classOld" ).switchClass( "classOld", "classNew", 1000 ); return false; }); });


Garbage, right? If you add the <pre> tag, you get your tabs and formatting back:

$(function() {
    $( "#button" ).click(function(){
        $( ".classOld" ).switchClass( "classOld", "classNew", 1000 );
        return false;
    });
});

That’s a bit better, but what we’re really missing is the pretty colors that help us parse the code semantics.

$(function() {
    $( "#button" ).click(function(){
        $( ".classOld" ).switchClass( "classOld", "classNew", 1000 );
        return false;
    });
});

That’s more like it! This code highlighting is the result of a fantastic open-source tool by Alex Gorbatchev called Syntax Highlighter, which you can find at http://alexgorbatchev.com/SyntaxHighlighter/.

Basic usage

1. Download the syntax highlighter package from the download page and install it somewhere where it is open to the web.
2. Insert the following code into the head of your html file, making sure to replace the paths with the correct paths for your installation (there is also a hosted version at http://alexgorbatchev.com/pub/sh/current/).

<script type="text/javascript" src="scripts/shCore.js"></script>
<script type="text/javascript" src="scripts/shBrushJScript.js"></script>
<script type="text/javascript" src="scripts/shBrushXml.js"></script>
<link href="styles/shCore.css" rel="stylesheet" type="text/css" />
<link href="styles/shThemeDefault.css" rel="stylesheet" type="text/css" />
<script type="text/javascript">
     SyntaxHighlighter.all()
</script>
3. Insert the following into your html body:
<pre class="brush: js">
$(function() {
    $( "#button" ).click(function(){
        $( ".classOld" ).switchClass( "classOld", "classNew", 1000 );
        return false;
    });
});
</pre>

And you have a basic code syntax highlighter running. Check out the configuration options if you want more control.

Notes:

Make sure to include the appropriate brushes for the syntax you want to show. This example includes the Javascript (“shBrushJScript”) brush and the HTML (“shBrushXml”) brush.
The vertical scroll bar shows up in Safari and Chrome because there is a 1 px offset introduced. This can be corrected by adding a pixel of padding to the .syntaxhighlighter class in the shCore.css file. Not the most elegant solution, but it works.

.syntaxHighlighter {
  padding: 0 1px !important;
...
}