BetterFavicon for Google
Not loving Googleâs new favicon too much?
Check out my quick and dirty hack⌠BetterFavicon for Firefox. (greasemonkey required)
Install it here: http://userscripts.org/scripts/show/40367
Enjoy!
Not loving Googleâs new favicon too much?
Check out my quick and dirty hack⌠BetterFavicon for Firefox. (greasemonkey required)
Install it here: http://userscripts.org/scripts/show/40367
Enjoy!
DHH recently posted, How to do Basecamp-style subdomains in Rails on SvN and it just happens that I was implementing some similar stuff this last week for a project weâre developing internally.
In our project, not everything needs to be scoped per-account as we are building a namespace for administrators of the application and also want a promotional site for the product. Three different interfaces, with some overlap between them all.
Letâs walk through a few quick steps that you can follow to setup the two interfaces within the same application.
Suppose that weâre going to build a new web-based product and have the following requirements initially.
Note: I use RSpec and am going to skip the TDD process here and let you conquer that for yourself. Am using the default Rails commands in this tutorial.
Weâre going to generate a new model for Account, which will be responsible for scoping sub-domains and individual accounts.
account-demo : ruby script/generate model Account subdomain:string
{lang=ârubyâ}
create app/models/
{lang=ârubyâ}
create test/unit/
{lang=ârubyâ}
create test/fixtures/
{lang=ârubyâ}
create app/models/account.rb
{lang=ârubyâ}
create test/unit/account_test.rb
{lang=ârubyâ}
create test/fixtures/accounts.yml
{lang=ârubyâ}
exists db/migrate
{lang=ârubyâ}
create db/migrate/20090111220627_create_accounts.rb
{lang=ârubyâ}\
Great, letâs migrate our application.
account-demo : rake db:migrate
{lang=ârubyâ}
CreateAccounts: migrating = -- create_table(:accounts) -> 0.0045s CreateAccounts: migrated (0.0052s)
{lang=ârubyâ}\
Before we get too far, letâs make sure that weâre adding an index on this table for the subdomain, as itâll improve performance in the database as the subdomain will used in SQL conditions quite often.
account-demo : ruby script/generate migration AddIndexToAccountSubdomain
{lang=ârubyâ}
exists db/migrate
{lang=ârubyâ}
create db/migrate/20090111221009_add_index_to_account_subdomain.rb
{lang=ârubyâ}\
Letâs open up this new migration file and toss in a UNIQUE INDEX on
subdomain
.
class AddIndexToAccountSubdomain < ActiveRecord::Migration
def self.up
add_index :accounts, :subdomain, :unique => true
end
def self.down
remove_index :accounts, :subdomain
end
end\
Okay, letâs migrate this bad boy.
account-demo : rake db:migrate
{lang=ârubyâ}
AddIndexToAccountSubdomain: migrating = -- add_index(:accounts, :subdomain, {:unique=>true}) -> 0.0047s AddIndexToAccountSubdomain: migrated (0.0050s)
{lang=ârubyâ}\
Great, weâre now ready to move on to the fun stuff.
Letâs open up app/models/account.rb
and throw some sugar in it.
Because weâre going to be dealing with subdomains, we need to make sure that weâre only allowing people to sign-up with valid data otherwise, there could be issues. URLs need to fit within certain conventions and we need to make it as graceful as possible for our customers.
Letâs make a quick list of what we need to enforce for the subdomain
attributes. This can easily be expanded, but letâs cover the basics.
subdomain
subdomain
should be unique within the applicationsubdomain
should be alpha-numeric with no characters or spaces
with the exception of a dash (my requirement)subdomain
should be stored as lowercaseSo, letâs update the following default Account modelâŚ.
class Account < ActiveRecord::Base
{lang=ârubyâ}
end
{lang=ârubyâ}\
..and add some basic validations.
class Account < ActiveRecord::Base
validates_presence_of :subdomain
validates_format_of :subdomain, :with => /\^[A-Za-z0-9-]+$/,
:message => âThe subdomain can only contain alphanumeric characters and
dashes.â, :allow_blank => true
validates_uniqueness_of :subdomain, :case_sensitive => false
before_validation :downcase_subdomain
protected
def downcase_subdomain
self.subdomain.downcase! if attribute_present?(âsubdomainâ)
end
end\
In the project that our team is working on, we wanted to reserve several subdomains so that we could use them later on. We tossed in the following validation as well.
validates_exclusion_of :subdomain, :in => %w( support blog www billing help api ), :message => âThe subdomain
{lang=ârubyâ}``{lang=ârubyâ} is reserved and unavailable.â
{lang=ârubyâ}\
This will prevent people from using those when they sign up.
Letâs now think about how weâll handle requests so that we can scope the application to the current account when a subdomain is being referenced in the URL.
For example, letâs say that our application is going to be:
http://purplecowapp.com/
[^1^](#fn1){#fnref1 .footnote-ref
role=âdoc-noterefâ}
Customers will get to sign-up and reserve
http://customer-name.purplecowapp.com/
. I want my account subdomain to
be green.purplecowapp.com
and everything under this subdomain should
be related to my instance of the application.
Iâve begun working on my own module, which is inspired mostly by the account_location plugin with some additions to meet some of our productâs requirements.
Here is my attempt to simplify it for you (removed some other project-specific references) and have put this into a Gist for you.
#
# Inspired by
#
http://dev.rubyonrails.org/svn/rails/plugins/account_location/lib/account_location.rb
#
module SubdomainAccounts
def self.included( controller )
controller.helper_method(:account_domain, :account_subdomain,
:account_url, :current_account, :default_account_subdomain,
:default_account_url)
end
protected
# TODO: need to handle www as well
def default_account_subdomain
ââ
end
def account_url( account_subdomain = default_account_subdomain, use_ssl
= request.ssl? )
http_protocol(use_ssl) + account_host(account_subdomain)
end
def account_host( subdomain )
account_host = ââ
account_host << subdomain + â.â
account_host << account_domain
end
def account_domain
account_domain = ââ
account_domain << request.domain + request.port_string
end
def account_subdomain
request.subdomains.first || ââ
end
def default_account_url( use_ssl = request.ssl? )
http_protocol(use_ssl) + account_domain
end
def current_account
Account.find_by_subdomain(account_subdomain)
end
def http_protocol( use_ssl = request.ssl? )
(use_ssl ? âhttps://â : âhttp://â)
end
end\
View gist here (embed wasnât working right when I tried)
Just include this into your lib/
directory and require
it in
config/environment.rb
. (if people think itâs worth moving into a
plugin, I could do that)
In the main application controller (app/controllers/application.rb
),
just include this submodule.
class ApplicationController < ActionController::Base
include SubdomainAccounts
âŚ
end\
Now, weâll want to add a check to verify that the requested subdomain is a valid account. (our code also checks for status on paid memberships, etc⌠but Iâll just show a basic version without that)
Letâs add in the following to app/controllers/application.rb
. This
will only check on the status of the account (via subdomain) if the
current subdomain is not the default. For example: purplecowapp.com
is
just our promotion site, so we wonât look up the account status and/or
worry about the subdomain. Otherwise, weâll check on the status.
before_filter :check_account_status
protected
def check_account_status
unless account_subdomain == default_account_subdomain
# TODO: this is where we could check to see if the account is active as
well (paid, etcâŚ)
redirect_to default_account_url if current_account.nil?
end
end\
When requests are made to an accountâs subdomain, we want to be able to scope our controller actions.
WARNING: Iâm going to gloss over the following steps because this is just standard Rails development stuff and I want to focus on how to scope your Rails code to account subdomains.
Iâll just say that this product gives each account many projects to do stuff within. Iâll assume that youâll know how to handle all that and weâll assume you have a Project model already.
What you will need is to add a foreign key to your table (projects in
this example) that references Account. So, make sure that your model has
an account_id
attribute with and that the database table column has an
INDEX.
Weâll add our associations in the models so that they can reference each other.
# app/models/account.rb
class Account < ActiveRecord::Base
has_many :projects
# âŚ
end
# app/models/project.rb
class Project < ActiveRecord::Base
belongs_to :account
# âŚ
end\
Okay great⌠back to our controllers. The SubdomainAccounts module
provides you with the current_account
variable, which you can use
within your controllers/views. This allows us to do the following in our
controllers. For example, if we had a ProjectsController.
class ProjectsController < ApplicationController
def index
\@projects = current_account.projects.find(:all)
end
def new
\@project = current_account.projects.new
end
def show
\@project = current_account.projects.find(params[:id])
end
# âŚ
end\
See, this wasnât so hard, was it?
I wanted to highlight one other thing here because I suspect that most projects that fit this will likely need a promotional/resource site where people will sign-up from. In our application, we have two application layouts. One for the main application that customers will interact with via their subdomain and the promotional site layout.
The default layout is just app/views/layouts/application.html.erb
and
we have our promotional site layout at
app/views/layouts/promo_site.html.erb
. A few of our controllers are
specifically for the promotional site while the rest are for the
application itself and in some cases, there is some overlap down to
individual action within a controller.
What we did was add a few more before filters to our application controller to a) define the proper layout to render, and b) skip login_required on the promo site.
To have the proper layout get rendered, weâre just checking whether the current request was made to the promotional site or not.
class ApplicationController < ActionController::Base
# âŚ
layout :current_layout_name # sets the proper layout, for promo_site or
application
protected
def promo_site?
account_subdomain == default_account_subdomain
end
def current_layout_name
promo_site? ? âpromo_siteâ : âapplicationâ
end
# âŚ
end\
Our application is using Restful Authentication and we just want to
check to see if the current request is made to the promotional site or
not. If it is, weâll skip the login_required
filter. Letâs assume that
you have the following before_filter set.
class ApplicationController < ActionController::Base
{lang=ârubyâ}
# âŚ
{lang=ârubyâ}
before_filter :login_required
{lang=ârubyâ}\
Weâll just change this to:
class ApplicationController < ActionController::Base
# ..
before_filter :check_if_login_is_required
protected
def promo_site?
account_subdomain == default_account_subdomain
end
def current_layout_name
promo_site? ? âpromo_siteâ : âapplicationâ
end
def check_if_login_is_required
login_required unless promo_site?
end
# âŚ\
There we go. We can now render the proper layout given the request and only handle authentication when necessary.
When you begin developing an application like this, you need to move
beyond using http://locahost:3000
as we need to be able to develop and
test with subdomains. You can open up your /etc/hosts
(within a
Unix-based O/S) file and add the following.
```
127.0.0.1 purplecowapp.dev
127.0.0.1 green.purplecowapp.dev
127.0.0.1 sample.purplecowapp.dev
127.0.0.1 planetargon.purplecowapp.dev
127.0.0.1 lollipops.purplecowapp.dev
127.0.0.1 help.purplecowapp.dev
127.0.0.1 support.purplecowapp.dev
```
After you edit that file (with root permissions), you can flush your dns
cache with dscacheutil -flushcache
(Mac OS X). This will let you make
requests to http://purplecowapp.dev:3000/
and
http://green.purplecowapp.dev:3000
. This is a convention that our team
has begun using for our own projects (TLD ending in .dev
). Itâs
important to remember that the subdomain must be specified here in order
to work for local requests. Unfortunately, hosts files donât support
wildcards (â*â).
You can also use Ghost, which is a gem for managing DNS entries locally with Mac OS X. Read Get to know a gem: Ghost
I know that I glossed over some sections, but was hoping that the code itself would be the most beneficial for you. Feel free to leave any questions and/or provide some feedback on our approach. Perhaps you have some suggestions that I could incorporate into this so that we can improve on this pattern.
The past few months have been difficult for many companies and as a result, some have had layoffs and now there are developers out there looking for new opportunities. Iâve received a few emails from friends and acquaintances in the Ruby on Rails community from people who are hoping to make it as a freelancer until another opportunity comes along. Questions ranging from hourly rates to managing clients has come up. Iâm more than happy to offer people advice on this front but always try to invite them to solicit ideas and feedback from a larger group of people. We just happen to have an open forum for all of you that are interested in discussing business-related topics.
Two years ago, I started the Ruby on Rails meets the business world group on Google, which currently consists of nearly 900 members.
So, if youâre an entrepreneur and looking to engage with other business owners, freelancers, or to just listen in on the discussions out of curiosity, donât hesitate to join the group. There are several of us that would love to share our experiences/lessons with you and also learn from others.
Iâd invite you all to check out the discussion archives and start a dialogue with us.
âŚand as always, if youâre not ready for a bigger group, feel free to drop me a line personally.
Weâre just a few days away from 2009 and itâs that time when we all start looking back at the last year and set goals for the coming new year. I felt like sharing some of my thoughts on how Iâm aiming to approach the new year.
Historically, Iâve never been a huge fan of New Years Resolutions because my attempts were always too big to successfully measure. The goals themselves werenât poorly thought-out, itâs just that itâs really easy to make a list of personal targets, without putting a lot of emphasis on how youâre going to achieve them. The biggest trouble that Iâve had with goals is allocating enough mental energy for implementation planning. (if only I had someone to and wireframe my lifeâŚ)
Due to this, New Years Resolutions havenât been a huge success for me. Iâve found it much too easy to pass the buck onto the usual suspects, which consist of: lack of time, energy, too much work, general life changes, health, etc.
So, for 2009⌠Iâm going to try something different by focusing on a set of best practices that I can use on a daily-basis. I suppose that my main goal is to not place too much emphasis on any specific targets and instead place the responsibility on myself to follow these best-practices and see what good (or bad) comes of it.
By rephrasing my internal conversation from, âWhat did I achieve this last year?â to âAm I doing things the best that I can?â I am confident that the answer will usually be, ânot likely.â I do believe that through this subtle change in context, Iâll be better apt to self-evaluate how (and why) I am doing the things that I do and refactor accordingly. If weâre not consistently Refactoring ourselves (as we do with our code), weâre going to retain a lot inefficiencies in our personal and work lives, which make it difficult for us to quickly respond to changes and opportunities.
Our life (personal and work) is just another project that we manage. Much of methodologies that we spend learning about and adopting can easily be translated to these other areas of our lives.
So as I brace myself for 2009, I find myself asking, How can I lead a more Agile life?
Iâd love to hear how youâre adopting best-practices inspired by Agile methodologies in your life and I promise to share mine over the coming year.
within...](http://www.robbyonrails.com/articles/2006/04/21/agile-development-begins-within)
```text
- [Agile development begins within...
```text
continued](http://www.robbyonrails.com/articles/2006/04/26/agile-development-begins-within-continued)
```text
- [Those that Tend the Store need
```text
Dialogue](http://www.robbyonrails.com/articles/2007/01/04/those-that-tend-the-store-need-dialogue)
So⌠Rails and Merb are going to be merged into Rails 3. (link)
Has hell frozen over?
[(it has in Portland the last week)]{.small}
Iâm curious about how the revised core team will incorporate the library-agnostic view points into Rails without increasing the complexity for configuration. For example, being able to use a different ORM is great, but at the same time, one of the things that I have really liked about Ruby on Rails was that it did make decisions ahead of time for you. Conventions over Configuration and all that jazz. While they intend to keep these defaults, I really wonder how much more configuration will be involved. Be that as it may, Rails and Merb are run by some of the best developers Iâve ever known⌠so I am sure these decisions will not be made without some deep consideration.
Rails application donât all look and smell the same, but itâs nice to know that there is consistency across all of our client applications. What Iâm concerned about (from an efficiency standpoint) is that this could lead to project-diversity at the cost of experimenting. Pre-Rails, the development teams that I was a part of was constantly trying out new libraries from client project to project, but this came at a huge cost. We werenât able to leverage our experience with previous projects like our team does with Ruby on Rails currently. (hell, I even helped write two different ORMs in the two years before Rails for PHP⌠and still wasnât satisfied)
But, this isnât so much a technical problem as much as a people problem. The thing is⌠is that Rails helped solve a people problem with a technical answer. Having testing, consistency, and other best practices built-in did the world a huge favor. âŚand all it took was someone like DHH to throw his opinion out there and stick to it. It took me nearly a full year to really embrace a lot of these conventions, but in the end.. it paid off.
While I do feel that itâs in developers best interests to try out new approaches, I just donât think it should be on your clients dime. This was part of the reason why I quit my last job to start Planet Argon full-time. I really wanted to get away from that cycle.
Since we (Planet Argon) adopted Ruby on Rails four years ago, weâve been able to build off of every project we had worked on before. We since adopted things like RSpec and JQuery, but our team decided on these changes after someone took the initiative to experiment with these on internal and personal projects. Having this foundation has freed up a lot of our time to focus on other issues as a team, like Interaction Design, Usability, and client collaboration.
As far as Merb itself, I honestly havenât tried to do anything with it since about 0.2/0.3. I gave up quickly though because the documentation didnât help me get anywhere and my time is valuable. Iâve since seen that documentation has improved drastically, but I havenât been able to prioritize the time needed to really play with it. With Merb being merged into Rails 3, it means that I really should spend more time exploring it as we might be able to leverage some of itâs benefits without as much of an investment.
Much of the lack of great interest in Merb was because I felt Rails had consistently provided our team with a solid foundation for a majority of our internal and client applications. The old saying, âif it ainât broke, donât fix it.â Not to say that others havenât expressed a lot of excitement about Merb and itâs benefits, I just didnât see there being enough of a productivity gain to warrant the time investment required to really learn and use a new framework⌠and the one thing that I have had trouble with was that it didnât sound like Merb encouraged a default set of libraries. I could be totally wrong, but thatâs been the perception Iâve had based on how it was branded.
But⌠the best part about this for you, me, and the Rails community? Is that I donât need to register robbyonmerb.com anytime soon. ;-)
I hope that youâre all having a great end to 2008 and am excited to see all the energy in the Ruby/Rails/Merb community. I suspect that between these two (now-merged) teams, weâll have an even better platform to develop web applications on. I believe this is great news and Iâm all in favor of seeing the Ruby community conquer these challenges that lay ahead.
Anyhow, Iâm just thinking out loud. What are your thoughts?
In case you missed the tweet from Alex âŚ
Our team just designed, developed, and deployed a new site for, Boxcar, our streamlined deployment environment for Ruby on Rails applications.
Feel free to take a tour to learn more about our product plans, which currently start as low as $59/month.
If you have a project that youâll be launching in the coming months, get in touch with us. :-)
::: warning Since publishing this article, I have given a talk on this topic at Rails Underground 2009. I invite you to checkout the slides. :::
As mentioned in a recent post, Iâm hoping to share some lessons that were learned throughout the process of launching a client project. Over the past few years, weâve been part of several dozen client projects and the big launch date is always an anxiety-filled, yet exciting point for the client and our team. I wanted to provide a quick list of a few the things that our team considers vital before launching that next big project. While most of these things might seem obvious, itâs still good to cover the basics and I hope a few people find it helpful.
Our company has been offering Ruby on Rails hosting for nearly four years and a few years longer with the PHP5 and PostgreSQL world. Given that, weâve seen customers come to us at the last minute before they launch and wanting to get things setup and deployed right away. Quite often, this is their first experience deploying a Ruby on Rails application and there has historically been a semi-steep learning curve to do this. Itâs really encouraged that you get this stuff figured out ahead of time. If youâre lucky, some hosting companies might offer cheaper plans so that you can begin to get things setup a few months or ahead of time and upgrade your plan prior to the big launch. This is how our Rails Boxcar hosting plans work.
Weâve seen a lot of customers avoid engaging with a hosting company more than a week or two before their launch because they want to reduce their monthly expenses, but the reality is that if you end up saving yourself a few hours of work by not scrambling at the last minute to get things setup, the hosting costs will pay for themselves. Several of our customers have learned this the hard way and as a result, this has resulted in extra stress that might have been avoidable if things had been ready earlier on.
The basic process that our team is to get a real deployment environment setup as early in the design and development process as possible. Often times, this will be 4-6 months before launch on larger projects. In our process, we aim to have a staging environment that mirrors our production environment. We tend to use a Boxcar Lite plan for our own client projects and get the deployment process working and automated. When itâs time to launch, we can easily upgrade the Boxcars with more resources to one or more Plus plans.
If youâre in the market for a hosting company, do keep us in mind, but if we can offer any advice, be sure to find out how you can scale upwards to meet your initial 3-6 month growth targets. Donât worry about planning too far ahead in the future, until you see how traffic picks up and how the application and databases perform, youâll be spending a lot of time guessing without data. If youâre new to this and arenât sure, Iâd encourage you to speak with a Ruby on Rails deployment specialist.
A few things to consider here:
setup early. Make sure everything works and set it up to work with
multiple deployment environments. (staging, production, etc.)
- Use [Boxcar
Conductor](http://www.robbyonrails.com/articles/2008/04/15/boxcar-conductor-rails-deployment-made-easy)
with your Rails Boxcar. ([Boxcar Conductor on
github](http://github.com/planetargon/boxcar-conductor/tree/master))
```text
- Use the **HTTP Basic Authentication**, which is available in Ruby on
```yaml
Rails to keep peeping toms (competitors, search crawlers, spammers,
etc.. ) out of your project while you're deploying to your staging
environment. We tend to give out a `.htaccess` user/pass with this
method to the stakeholders so they can access the site whenver they
need to.
- Rails documentation on HTTP Basic Authentication: [view
docs](http://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Basic/ControllerMethods.html)
- Watch a Railscast for using HTTP Basic Authentication: [watch
screencast](http://railscasts.com/episodes/82)
```text
- Get your automated tasks (cron jobs) setup way before launch. Verify
```yaml
that things are working here at the right times
- Extra-credit: Check server time settings to make sure you're not
running big tasks at time periods when heavy traffic is expected
```text
- Make sure your hosting provider has monitoring setup. It's good to
```yaml
gauge uptime % from launch
- Extra-credit: Setup your own monitoring with
[Pingdom](http://pingdom.com/) or similar service to make sure
you know when things are down. (You can audit your hosting
provider this way!)
```ruby
There are a handful of really great hosting companies out there for Ruby
on Rails. Be sure to do your homework early! This isn't something you
want to do at the last minute.
Reminder: **Keep your project releasable at all times.**
## Search Engines and Analytics
Before the big launch, be sure that you have outlined a consistent
pattern for managing the HTML page titles on each page. Getting targeted
traffic to your new web application is (usually) vital. Our team has
adopted a basic pattern that we use throughout the application. This way
we don't have to go through at the last minute and figure out where
titles are and/or aren't being set.
In a previous post, I [shared a basic
plugin](http://www.robbyonrails.com/articles/2008/03/26/managing-seo-friendly-html-titles-with-rails)
that our team uses on projects to manage page titles on a view-by-view
basis.
Additionally, be sure to take advantage of using descriptive permalink
URLs.
Another tip is to setup your application with analytics ([google
analytics](http://google.com/analytics) is free!) If there is one thing
that I wish we had setup from day one on every project in the past, was
a set of conversion goals. So, be sure to get into your analytics
account and prepare your application so that you can track these goals
from the moment your application is launched. Collecting as much data
about your visitor's usage habits is going to help you in the coming
weeks and months as you tune things based off of feedback and this data.
Also, after you begin to introduce changes, you can analyze these
metrics to verify that you're improving things and not the opposite.
So, be sure that you are doing the following:
- Have implemented descriptive page titles and urls
- Are ready to track your site visitor's usage habits from the
```yaml
starting gate
- Conversion goals for obvious things like:
sign-ups/registrations, viewing your product tour, contact
requests, etc.
```ruby
## When Things Go Wrong / Tracking Exceptions
What happens when things go wrong? We've been amazed by how many
projects we've seen have been in production for months/years and lacking
something that seemed so obvious. Exception notifications! All too
often, we've seen teams totally unaware that things were failing for
their customers and not being reported to anybody. The easiest way to
track exceptions in the past was to use the
[exception_notification](http://github.com/rails/exception_notification/tree/master)
plugin that the Rails team manages. You can have this plugin send your
development team emails with a backtrace and all the goodies that'd
normally show up in a 500 error. At a minimum, you should be using
something like this.
- Tip: Make sure your hosting environment can send out emails!
```text
(otherwise, you'll never know about these problems...eek!)
```ruby
However, in the last year, the Rails community has seen two options,
[Exceptional](http://getexceptional.com/) and
[Hoptoad](http://www.hoptoadapp.com/) introduced for managing
exceptions. Our team has only used Exceptional so far, because our good
friends at [Contrast](http://www.contrast.ie/) invited us to be early
beta-testers for their new service. We love the Exceptional's
integration with Lighthouse, which is the bug/issue tracking application
that we're currently using. With Exceptional, our team is able to search
through and track exceptions in our application and have a good meter on
the overall health of our application. This solution works so much than
the email-based approach because we can track which exceptions have been
opened and sent to Lighthouse and if they've been closed by someone
already.
I've heard great things about Hoptoad as well, but have yet to test it
out. Would be interested to read a comparison between the two and am
curious if there are other services for this currently.
## Non-default 404 and 500 pages
Honestly, this is one of those things that we tend to forget about until
the last minute. When you're launching a new project, you're bound to
have a bug and/or a few broken links not accounted for. What you want to
avoid is having your customers end up on an unhelpful page that looks
like this:
::: thumbnail
[](http://skitch.com/robbyrussell/6txe/the-page-you-were-looking-for-doesn-t-exist-404)
:::
It doesn't take too long to put something together that is a bit more
helpful for your visitors.
::: thumbnail
[](http://skitch.com/robbyrussell/6txm/alphaclone-page-not-found)
:::
So, do yourself a favor and add a ticket for your designers to design a
custom 404 and 500 pages to replace the defaults that are provided by
Ruby on Rails in `public/`.
## Hold your client's hands
If you're working with startups, do remember that this is quite possibly
their first launch. It's important to remember that they're going to be
going through their own spectrum of feelings and it's our job to help
get them through the process with an eased mind. Show them that you have
things covered, that things are ready to go, alert them when things pop
up... in a nutshell. Keep them informed about the challenges and do what
you can help to manage their stress. If they've just contracted you for
an extended period of time to help get their **big idea** designed and
developed, remember that this launch is just the beginning of the race
for them. They have a big journey ahead of them and you just helped them
get their new car engine built. Make sure they know that things are
likely to breakdown along the way, need to be refueled (refactor!
refactor!), and need service repairs. The worst thing you can do is set
the expectation that nothing will go wrong once their application is
released into the wild. They need to budget for this early on so that
they can pace themselves after launch. (this is a big topic definitely
worth of it's own post)
Just remember that this should be a big celebration for your team and
client. Remember to celebrate! (and then follow it with a retrospective)
## In Conclusion
As mentioned, these are just a handful of things that we have learned to
avoid overlooking (through trial and error). I'm hoping to share more
thoughts on launching in the near future and would love to hear from all
of you on things that you've come across. What works? What doesn't work?
What is on your checklist for launching successful projects?
### Related Articles
- [The Art of Delivery, part
```text
2](http://www.robbyonrails.com/articles/2008/05/22/the-art-of-delivery-part-2)
```text
- [Agile development begins
```text
within...](http://www.robbyonrails.com/articles/2006/04/21/agile-development-begins-within)
```ruby
- [Audit Your Rails Development
```text
Team](http://www.robbyonrails.com/articles/2007/06/17/audit-your-rails-development-team)
```text
- [Embracing Chaos, part
```text
1](http://www.robbyonrails.com/articles/2007/12/17/embracing-chaos-part-1)
::: {.thumbnail style=âfloat:right;â}
:::
Earlier this week, our team launched a clientâs project into the public. We began working on it early this year and it was quite an endeavor for our team. The company that we helped launch is AlphaClone, a premier stock research and portfolio simulation service for individuals and professional investors alike. Clone, backtest and track over 230 top fund manager portfolios. More than 15,000 pre-generated clones and nearly limitless possibilities based on your own custom groups of funds. Take a tour of AlphaCloneâŚ
Itâs hard to deny that Iâm insanely proud of the team at Planet Argon for bringing our clientâs business idea to reality. Weâve been enjoying keeping up on how the press is responding so far since theyâve launched. I expect that theyâll do well with their business endeavor and look forward to helping them evolve and expand.
Iâve been asked to share some stories and lessons learned throughout the project. Given that we tackled a lot on the Interaction Design side of things in addition to relying a lot more on some of the advanced features of PostgreSQL (weâre dealing with a TON of data here), we have things to share. So, stay tuned as Iâll be highlighting some of those lessons over the coming week(s).
Additionally, if youâre looking for a team to help you execute your next big idea, give us a call!
Weâre currently using Lighthouse as our ticketing system with clients for maintenance/bug requests. Weâre also using Github for all of our major client projects. Iâm sure that many of you take advantage of the Lighthouse service that Github allows you to use so that your commits can trigger actions on your tickets in Lighthouse.
If youâre not already, you might consider running (cheat ?):
cheat lighthouse
<!-- -->
lighthouse:
Bob Zurek, the Chief Technology Officer at EnterpriseDB interviewed me a few months ago for their new Database Radio podcast. It finally was published last week. Bob and I had a nice conversation about PostgreSQL and itâs community, our use of PostgreSQL with Ruby, Ruby on Rails, and development tools/methods.
You can listen to the podcast mp3 and/or read the transcript.
After releasing the new RubyURL API, I decided that it was time to look around at libraries to interact with it. I came across a new Ruby gem from John Nunemaker named, HTTParty, which aims to make it easy to talk to XML and JSON-based web services. Be sure to read Johnâs announcement of HTTParty.
So, I decided it might be fun to introduce more people to the gem by showing you all how to use it to talk to the new RubyURL API.
Before we get started, youâll need to install the HTTParty gem with the following command:
~ : sudo gem install httparty
Password:
When you HTTParty, you must party hard!
Successfully installed httparty-0.1.6
1 gem installed
Installing ri documentation for httparty-0.1.6...
Installing RDoc documentation for httparty-0.1.6...
```shell
Great! Now that **we're ready to party hard**, let's build something.
## Talking to the RubyURL API
The [RubyURL API](http://rubyurl.com/api) currently supports both XML
and JSON, which are each supported by HTTParty. The great thing about
HTTParty is that all you need to do is include it in a class and you're
able to quickly talk to remote services.
In this following example, we're going to create a new class called
`Rubyurl`.
````ruby
class Rubyurl
end
````ruby
What we'll want to do now is include the HTTParty library. (**note:**
you'll need to require both rubygems and httparty gems and I'll skip
those lines in following code samples)
````ruby
class Rubyurl
include HTTParty
end
```text
The HTTParty provides [a few class
methods](http://github.com/jnunemaker/httparty/tree/master/lib/httparty.rb),
which we can use to configure our library. We'll go ahead and specify
the `base_uri`, which we'll set to `rubyurl.com`.
````ruby
class Rubyurl
include HTTParty
base_uri 'rubyurl.com'
end
```bash
Now that our class is setup to talk to the
[Rubyurl.com](http://rubyurl.com) site, we'll want to add a new method
which we can use to communicate with the RubyURL API. We'll call this
`shorten` as we're using RubyURL to shorten long URLs... right?
````ruby
class Rubyurl
include HTTParty
base_uri 'localhost:3000'
def self.shorten(website_url)
end
end
```yaml
Our new `shorten` method will expect us to provide it with a website
url, which we'll want RubyURL to return a shortened URL for. The PATH
for the API that we'll want to talk to is: `/api/links`, which we're
expected to pass XML or JSON to.
Here are two examples of using the RubyURL API with HTTParty.
### RubyURL via JSON w/HTTParty
We're going to use the `post` method that is provided with HTTParty to
send a request to `/api/links.json`. As you can see, we're providing the
original website url to the web service.
````ruby
class Rubyurl
include HTTParty
base_uri 'rubyurl.com'
def self.shorten(website_url)
```javascript
post('/api/links.json', :query => { :link => { :website_url => website_url } })
```text
end
end
```yaml
When ran, it'll produce the following:
````ruby
>> Rubyurl.shorten('http://github.com/jnunemaker/httparty/tree/master/lib/httparty.rb').inspect
=> {"link"=>{"permalink"=>"http://rubyurl.com/uJVu", "website_url"=>"http://github.com/jnunemaker/httparty/tree/master/lib/httparty.rb"}}
```shell
Pretty simple, eh?
### RubyURL via XML w/HTTParty
The great thing about HTTParty is that you can use XML without changing
much.
````ruby
class Rubyurl
include HTTParty
base_uri 'rubyurl.com'
def self.shorten(website_url)
```javascript
post('/api/links.xml', :query => { :link => { :website_url => website_url } })
```text
end
end
```text
Produces the following
```ruby
http://github.com/jnunemaker/httparty/tree/master/lib/httparty.rb
http://rubyurl.com/uJVu
So⌠there you have it. HTTParty makes it extremely easy to interact with various web services that work over HTTP. Iâd encourage you all to take a few minutes to experiment with it and see what crazy ideas that come to mind during the process. :-)
Our team has been working our way into the Git world. One of our big client projects is now 100% git while the other is still on Subversion for another month or so. (Iâm getting by with git-svn, the gateway drug on that). Weâve had pretty much nothing but success with Git for quite some time, but recently this repository started to get chaotic, which has eaten up time⌠which isnât conducive to productivity.
So, I wanted to share a quick lesson that we learned today after scratching our head for a while. Itâs important that you avoid having a branch on a remote repository that shares the name of a tag in your local and/or remote repository.
I REPEAT.
Itâs bad mojo to have a tag and branch share the same name. Things that youâd expect to just work⌠donât. This was causing us to see warnings and errors like the following, which we werenât really sure what to make of it.
âwarning: refname âstagingâ is ambiguous.
âerror: src refspec staging matches more than one.â
This started about two weeks ago when we started a few new remote
branches: staging and design. It seemed to be going okay but we
managed to muck up things when we merged those two together and some of
us were having success fetching/pulling/pushing to staging and others
were having to specify :heads/staging
and couldnât have a local branch
named staging. Needless to say, it was causing some problems and
slowing us down.
This afternoon, we finally noticed in the GitHub interface that there
was a tag named staging
. Hmm⌠interesting. We verified this by using
git show-ref
.