Customizing Zendesk

We use Zendesk for our support site, but even though it’s a third party site we want our users to feel right at home when they are visiting there. In order to accomplish this, we have made use of Zendesk’s impressive customization options, which let us write our own custom CSS and Javascript.

It’s All About the Widgets

As part of Zendesk’s service, users have access to an array of “widgets” that can be leveraged to customize your presence. These widgets have the capacity to be exposed to as many, or as few, end users as you’d like. Zendesk breaks it down into three groups – “Agents,” or members of the support team, “Logged in end-users” and “Anyone.” For our customization, I used the CSS and Javascript widgets.

I broke up my CSS into two widgets – one for all users, and one just for Agents, since Zendesk offers added functionality for Agents that’s not present for everyone else. The bulk of my CSS was applied to the Everyone stylesheet, and then I just tweaked the Admin stylesheet to account for the differing interface elements.


Javascript to the Rescue!

The trickiest aspect to this customization was that I needed more “hooks” (unique identifiers) to attach CSS rules to than I was provided. I applied a handful of scripts that used Prototype’s addClassName method to get some extra classes (my biggest target was the navigation links). We also wanted to update some of the links in the header of the Support site. Unfortunately, Zendesk doesn’t offer any mechanism to adjust those links through their management console, but Javascript again came to the rescue. Using Prototype’s update method we changed the content of a handful of the navigational links, and then with insert we added a few new links (back to the main site, for example). This was all relatively painless, and so far has worked without issue.

Something to Keep in Mind

Widgets (at least the CSS and JS widgets) are loaded in alphabetical order. So if you name you CSS widgets ‘admin’ and ‘everyone,’ the ‘admin’ widget is going to get loaded first, which means that anything you’re trying to reset in the ‘everyone’ stylesheet won’t work. In order to offset this, and still give the widgets meaningful names, I just numbered them – “1 – Everyone”, “2 – Admin,” etc. With the Javascript widgets you’ll want to keep this in mind, too, since occasionally load order is important.

Also, the presented experience varies widely from user to user, with the forms that are being filled out and the different potential use cases for the application, so make sure to test as many of those paths as possible. Submit forms as an anonymous user, then have an Agent interact with that ticket, and make sure that all of the presented experiences are what you would expect. This does mean that you’ll clutter up your help desk a bit, but you can always go back in and remove the extraneous content before you deploy the site.

Customing Zendesk was largely an easy and pleasant experience. Getting all of the pieces in place was simple, and load times weren’t noticeably hampered by our customization. Furthermore, when we had questions, Zendesk’s support crew were quick to respond with informative answers that solved our problems quickly. Feel free to check out our support site and let us know what you think!

Using Godaddy SSL Certificates with NGINX

Have you just installed your new Godaddy certificate into your NGINX web server, and are you finding that some browsers (notably Safari) don’t trust your website when using your Godaddy SSL Certificate?

This is manifest by the error message “Safari can’t identify the identity of the website ‘’” and is caused by the “chain of trust” being incomplete between your certificate and any of the root certificates that your browser client has installed.

Here’s a quick cure for an NGINX installation:

Download the gd_bundle.crt and gd_intermediate.crt certificates from Godaddy’s certificate repository, then combine them:

cat yourcert.crt gd_intermediate.crt gd_bundle.crt > yourcert_bundle.crt

This concatenates your certificate and the Godaddy intermediate certificates into one file. Put the file yourcert_bundle.crt in the place that NGINX is looking for your certs (specified in nginx.conf). Reload your NGINX configuration with:

kill -HUP <pid of nginx>

You should be ready to go! If you want more information on the entire chain of trust, you can download the Godaddy root certificate (gd-class2-root.crt) and use the OpenSSL command utility:

openssl s_client -CAfile gd-class2-root.crt -connect  -verify 10

This will pull the certificate from server, and attempt to verify the chain of trust to whatever root you’ve specified (-CAfile gd-class2-root.crt):

verify depth is 10
depth=2 /C=US/O=The Go Daddy Group, Inc./OU=Go Daddy Class 2 Certification Authority
verify return:1
depth=1 /C=US/ST=Arizona/L=Scottsdale/, Inc./OU= Daddy Secure Certification Authority/serialNumber=07992287
verify return:1
depth=0 /O=* Control    Validated/CN=*
verify return:1
Certificate chain
 0 s:/O=* Control Validated/CN=*
   i:/C=US/ST=Arizona/L=Scottsdale/, Inc./OU= Daddy Secure Certification Authority/serialNumber=07992287
 1 s:/O=* Control Validated/CN=*
   i:/C=US/ST=Arizona/L=Scottsdale/, Inc./OU= Daddy Secure Certification Authority/serialNumber=07992287
 2 s:/C=US/ST=Arizona/L=Scottsdale/, Inc./OU= Daddy Secure Certification Authority/serialNumber=07992287
   i:/C=US/O=The Go Daddy Group, Inc./OU=Go Daddy Class 2 Certification Authority
Server certificate
<Continued Output>

This shows that the certificate obtained from the site was verified all the way to a root certificate (specified by -CAfile).

Adding Columns to large MySQL Tables Quickly

Suppose that you have a MySQL Database, and in that database you have a non-trivial table with more than a million records. If you’re using that table with your Rails application, you might at some point like to add some additional columns.

It’s tempting to just write the migration like:

class AddThreeColumnsToQuarks < ActiveRecord::Migration
  def self.up
    add_column :quarks, :arbitrary_field1, :integer
    add_column :quarks, :arbitrary_field2, :string
    add_column :quarks, :arbitrary_field3, :integer

  def self.down
    remove_column :quarks, :arbitrary_field1
    remove_column :quarks, :arbitrary_field2
    remove_column :quarks, :arbitrary_field3

Should you do that, you will find that although it works, MySQL will take a fantastic amount of time to add the column when you have a lot of rows. What ActiveRecord is doing is adding each column individually with an alter statement:

ALTER TABLE `quarks` ADD `arbitrary_field1` int(11)
ALTER TABLE `quarks` ADD `arbitrary_field2` varchar(255)
ALTER TABLE `quarks` ADD `arbitrary_field3` int(11)

Each one of those ALTER statements makes a new temporary table, copies records from your existing table into the new table, and then replaces the old table with the new table. Five thousand records in the database? Adding three columns will copy the DB three times. Fifteen thousand rows are copied.

One can make this better by combining the ALTERs into one statement (as long as the ALTER contains a single type of operation, such as ADD COLUMN). The copy of the data in the table still takes a while. A few million rows? You might be waiting tens of minutes.

A FASTER way of adding columns is to create your own new table, then SELECT all of the rows from the existing table into it. You can create the structure from the existing table, then modify the structure however you’d like, then SELECT in the data. MAKE SURE that you SELECT the information into the new table in the same order as the fields are defined. Here’s an example:

class AddThreeColumnsToQuarks &lt; ActiveRecord::Migration
  def self.up
    sql = ActiveRecord::Base.connection()
    sql.execute "SET autocommit=0"
    sql.execute("CREATE TABLE quarks_new LIKE quarks")
    add_column :quarks_new, :arbitrary_field1, :integer
    add_column :quarks_new, :arbitrary_field2, :string
    add_column :quarks_new, :arbitrary_field3, :integer
    sql.execute("INSERT INTO quarks_new SELECT *, NULL, NULL, NULL FROM quarks")
    rename_table :quarks, :quarks_old
    rename_table :quarks_new, :quarks
    # don't forget to remove quarks_old someday

  def self.down
    drop_table :quarks
    rename_table :quarks_old, :quarks

You can change the NULLs into whatever default values you’d like the new columns in the existing rows to have.

How much faster can this be? On one table in one of our databases, a single add_column was approximately 17 minutes. When we used this technique, we reduced the time to add a column to approximately 45 seconds. YMMV —however you’ll notice a big improvement.

What about the indices? The CREATE TABLE .. LIKE preserves column attributes and indices. For more information, see the MySQL on line manual.