Upgrading Rails 5 Controller Tests

Posted by Brian in News (July 3rd, 2016)

If you're embarking on a Rails 5 upgrade, or just trying to figure out what's involved, you'll find lots of pieces of information spread around. But I'm summarizing this here for my own benefit and for others.

No more unit tests for controllers

Rails 5's controller tests are now integration tests. This means you lose the ability to interact with many of the internals. And if you've built apps of any reasonable size with controller tests, you'll find a lot of the hacks you've been using are no longer there.

URLS, not actions, are required.

Instead of

get :index

you'll need to do

get root_path

In other words, you'll use full URLs in your tests, or use the URL helpers for your routes.

And when sending params for looking up records, instead of

get :index, {id: 1}

You'll want to use

@post = posts(:one) # if using a fixture
get posts_path(@post)

You must use named parameters for params

So if you are doing a create, instead of doing this:

post posts_path, {post: { title: "First post", body: "This is the body"}

you'll need to make it less ambiguous, as these helpers now require named parameters:

post posts_path, params: {post: { title: "First post", body: "This is the body"} }

No more access to request

The request object has been removed. If you've been using it to set headers, that's no longer possible.

So instead of trying to use

request.env["HTTP_AUTHORIZATION"] = something....

You'll need to send it along on each request:

get admin_path, headers: {'HTTP_AUTHORIZATION' => something }

Mo more access to session

If you're used to sending along session data with your requests, like for authorization, know that you can't do that either. Instead, you'll have to actually hit the login page of your site. DHH explains this in his response to this Github issue.

  def sign_in_as(name)
    post login_url, params: { sig: users(name).perishable_signature )
  setup { sign_in_as 'david' }

This is exactly how it's done in integration tests, so this isn't a surprise, but no doubt your existing apps have tests that directly pass the session on each request. You'll need to change those.

No more access to assigns and assert_template

If you’ve used `assigns` to access instance variables, or used `assert_template` to ensure a specific template was rendered, those tests will no longer work. There is a gem that brings this behavior back, but I won’t link it because I don’t trust that it’ll be maintained, and the way forward is clear – use `assert_select` to look for things on the page or in the response.

The days of controller tests as units are over, and like me, you may be now questioning the value of controller tests at all going forward, since they are just integration tests.

Rails with SSL in Development The Simple Way

Posted by Brian in Rails (July 21st, 2013)

To use SSL with Rails, you could set up Apache on your development machine, but that involves a virtual host and a bunch of other bits of configuration. Here’s a dirt simple way.

  1. Create a self signed certificate
  2. Install Thin
  3. Force SSL in Rails
  4. Add a host entry
  5. Launch with Thin

Create a self-signed certificate

We’re going to create a self-signed certificate for the site localhost.ssl.

In the root of your Rails application, do these commands:

First, generate a simple signing key. You’ll have to enter a passphrase. Enter 1234. We’re going to remove the passphrase in the next step anyway.

openssl genrsa -des3 -out server.orig.key 2048

Now remove the passphrase from the key by converting it to an RSA key:

openssl rsa -in server.orig.key -out server.key

Now create the certificate request. When prompted for the “common name”, be sure to make it localhost.ssl

openssl req -new -key server.key -out server.csr

Now create the self-signed certificate.

openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

Install Thin

Install Thin by adding this to your Gemfile:

gem 'thin'

Force SSL in Rails

In config/application.rb, find this line:

class Application < Rails::Application

and add this within the class definition:

config.force_ssl = true

Add a Host Entry

Now add a host entry to your system so you can bring up https://localhost.ssl in a web browser. Do this with your favorite text editor, or use the command below to push the new host entry on to the end of your hosts file:

echo " localhost.ssl" | sudo tee -a /private/etc/hosts

Launch app with Thin

Here's the command to launch this app:

thin start --ssl --ssl-verify --ssl-key-file server.key --ssl-cert-file server.crt

You could put that in script/start and then use

chmod +x script/start

to have a simple way to start your app with ./script/start.

Wrapping Up

This is a dirt simple way to set this up and it's a lot less work to use it once you set it up the first time.
If you were working on multiple sites, you would want to create a single key and cert which you could share across all of your apps.

Securing a Rails app on Passenger with SSL

Posted by Brian in Howto, Rails, tips, web (July 24th, 2012)

Configuring a site for SSL is simple once you understand the process. Unfortunately I don’t set these up all that often so I forget. In my book Web Development Recipes I cover how to set up the certificates on the Apache server, but I don’t explicitly show how to make it work with a Rails application. So here’s how I usually set things up.

Assume we have a Linux-based server running Ubuntu (either 10.04 or 12.04), we keep our sites in /var/www and we will define our virtual host in the file /etc/apache2/sites-available/mysite

We want to make sure all HTTP requests go to HTTPS. To do that, we need to set up security for the site *and* add a redirect, either at the application level or at the server level. Many folks will recommend using Rack:SSL, but I’m just going to let Apache take care of it for me.

To make all this work we’ll need to enable two Apache modules; ssl and rewrite. The rewrite mod may already be enabled so you should scan your /etc/apache2.conf or your other configs for it.

To enable the mods, we use the a2enmod command:

$ sudo a2enmod ssl
$ sudo a2enmod rewrite

Next we need to modify the site definition in /etc/apache2/sites-available/mysite so it uses SSL and our certificates. First we’ll change the host for HTTP on port 80 so it redirects traffic to the secure site, like this:

  ServerName myapp.example.com
  RewriteEngine On
  RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [L,R=permanent]

I’m using named virtual hosts here, so this rewrite only applies to myapp.example.com and none of the other sites I may have set up.

In the same file, we add the definition for the secure site on port 443, the default SSH port. This contains all the info that Passgener needs to spawn the site.

  ServerName myapp.example.com
  DocumentRoot /var/www/myapp/current/public
    AllowOverride all
    Options -MultiViews

  SSLEngine on 
  SSLOptions +StrictRequire 
  SSLCertificateFile /etc/apache2/certs/myapp.example.com.crt 
  SSLCertificateKeyFile /etc/apache2/certs/myapp.example.com.key 

To make this work, we have to generate the certificate and the key.

We do that by creating the /etc/apache2/certs folder and changing into it:

$ sudo mkdir /etc/apache2/certs
$ cd /etc/apache2/certs

Then we generate our Certificate request which also generates a key.

$ sudo openssl req -new -newkey rsa:2048 -nodes -keyout myapp.example.com.key -out myapp.example.com.csr 

Then we take the csr file and get it signed by the cert admin. Or if we need things secured temporarily, we could
sign it ourselves, knowing that our users will get a nasty warning about unknown certs.

$ openssl x509 -req  -in myapp.example.com.csr \
 -signkey myapp.example.com.key -out myapp.example.com.crt

You really don’t want to go to production with a self-signed certificate though.

Once these files are in the certs directory, we can restart the web server and everything should work as expected.

On The Desired Complexity of Rails

Posted by Brian in Rails (August 21st, 2011)

I attended Madison Ruby this weekend and got a healthy dose of knowledge from some very talented presenters. Some of the talks focused heavily on improving our practices, especially in Rails applications.

Jeff Casimir talked about making views nicer by introducing decorators. These are relatively simple to implement in a language like Ruby, but Jeff created a nice gem to make it even easier, called Draper.

Several talks mentioned using decent_exposure, a gem by Stephen Caudill, to keep instance variables out of views, as Rails does a somewhat nasty hack to get instance variables from controllers.

Then today, I saw another article talking about how Rails code could be made even more easy to maintain by leveraging Dependency Injection, a well-known, and very very useful technique.

On a few applications, I could have used a couple of these techniques to make the code easier to maintain later. And on one I did use a proxy instead of helpers in a complex view. But in the last six years of working on projects for clients, other consultancies, and even when I’ve mentored others, using these patterns would have been a huge jump in complexity for the majority of the projects.

When I decided to use Rails, it was because it was a productivity boost. When compared to Struts, Spring MVC, or other similar frameworks, Rails cuts a lot of corners in exchange for this productivity.

But seeing a number of respected thought leaders looking to bring this complexity to Rails makes me wonder…. is Rails (the community) growing up? Are we out of the “teenage kid that knows it all” phase? Are we done telling Java and C# programmers that they’re not “with it”?

Since it came on the scene, Rails, through decisions made by developers and the core committers, has evolved from something a PHP developer or Java developer would find easy to pick up to something that is much, much more complex. It’s no longer a framework for beginners, but rather a solid foundation and collection of “best practices” to build modern web applications. Rails is now being used to build bigger and more complex applications, and that complexity calls on us to revisit concepts like decorators, proxies, service objects, and dependency injection, the very “high ceremony” things that Rails developers were proud to avoid a few years ago.

While I don’t expect these kinds of things to make it into Rails itself, I do expect these concepts to gain traction. But I hope they only gain traction for the 5% of the situations where they’re needed, rather than for the sake of “well, so-and-so said it was good, so I’m doing it.” Using these tools to mediate complexity in applications adds a different kind of complexity, and that’s worth some thought, especially since, as I was told several times this weekend, there’s apparently a shortage of talented Rails developers these days.

Proper use of these object-oriented concepts in the right place will make our projects better. But it’s vital that we truly understand when we should apply these patterns so we can decide when the additional complexity is warranted, and where it’s overkill. As I was reminded this weekend, there is no “golden path” in Rails.

I encourage you to explore these things. And read Design Patterns in Ruby
while you’re at it, especially if these concepts are new to you.

Installing Oracle Client on Ubuntu.

Posted by Brian in Rails, tips (May 31st, 2011)

Ubuntu isn’t one of the supported operating systems from Oracle, so we have do to some manual work to get things set up.

First, we need to create a home for the files we’ll be downloading.

sudo mkdir -p /opt/oracle/11_2
sudo apt-get install libaio1

Then we need to visit Oracle’s download page and grab these three files for the Instant Client for Linux:

Instant Client Basic-Lite
Instant Client SDK
Instant Client SQLPlus*

We’ll want the ZIP files, not the RPM files, for each one. You will need an Oracle account to download these files.

Then, once we get those zip files over to our Ubuntu server, we need to unzip them all. We should end up with a folder called


Now let’s move that folder into the /opt/oracle/11_2 structure we made.

mv instantclient_11_2 /opt/oracle/11_2/instantclient

Next, we need to open /etc/environment and add this line:


The LD_LIBRARY_PATH is a variable used by lots of programs that talk to Oracle.

At this point, you will want to estart your terminal session so the environment variable will be available. You could set it manually, but this is a good place to test to make sure that the variable is actually loading into the environment.

Next, we’ll fire up sqlplus to make sure that the Oracle stuff is installed properly.


If it comes up without any errors, we’re good to go. We can exit with CTRL+C.

Next, let’s install the Ruby Oracle adapter. We’ll need to symlink a file since we’re using the InstantClient.

cd /opt/oracle/11_2/instantclient
ln -s libclntsh.so.11.1 libclntsh.so

Next, we need to copy over all the development header files into the instantclient root folder so RubyGems can find them when it needs to compile the native extensions.

cd /opt/oracle/11_2/instantclient/
cp sdk/include/*.h .

Finally, we can install the gem. If you’re using sudo, then the environment won’t have the variables you need so you’ll need to pass them with the command.

sudo env LD_LIBRARY_PATH=/opt/oracle/11_2/instantclient gem install ruby-oci8

That should be it. If you run into other problems, don’t fight with Oracle – just remove the /opt/oracle/11_2/instantclient folder and start over.

Rails 3, Refactored Code, and Docs

Posted by Brian in Rails (May 10th, 2011)

If you’ve been doing Rails work for a long time, you’re familiar with the difference between delete and destroy in your ActiveRecord models. If you weren’t, you might look at your code and see what class you
inherited from.

  class User < ActiveRecord::Base

In Rails 2 and below, the delete and destroy methods were both listed in the documentation for ActiveRecord::Base.

In Rails 3, you'll find these under ActiveRecord::Persistence. And the only way you'd know to look there is by looking through the eight delete methods located in the sidebar at the API.

There's not really a good fix, because the refactoring they did makes a lot of sense. But it also makes these automated documentation tools a lot less useful, especially since there's no indication in ActiveRecord model declarations that a Persistence module is loaded. You'd need to dig into the Rails source, or know who to ask for clarification.

And if you're wondering what the difference is, destroy will invoke callbacks and observers, whereas delete just uses raw SQL to remove the record. Both have their place and it's important to know the difference.

Sharing Vim configs with Mac and Windows using Dropbox

Posted by Brian in Howto, Programming, Rails (January 27th, 2011)

I’m back to using VIm again, after a few years of working with TextMate on the Mac. VIm is great because it works the same on many different platforms, and I jump from Mac to Windows a lot these days.

I’ve devised a setup that lets me keep almost all of my configuration for VIm on my Dropbox account so I can have the same configuration synchronized on all of the computers I use. Here’s how you do it:

Inital Setup

Of course, I assume you have Dropbox and VIm installed on your Mac and Windows machines. I’m not covering any of that setup in this article.

You need a few folders in your Dropbox to make this work. I find doing this on my Mac the easiest:

mkdir -p ~/Dropbox/dotfiles/.vim/autoload
mkdir -p ~/Dropbox/dotfiles/.vim/backup
mkdir -p ~/Dropbox/dotfiles/.vim/bundles

Next, we’ll create a master .vimrc file in our Dropbox. If you already have one, move it there.

mv ~/.vimrc  ~/Dropbox/dotfiles/.vimrc_main

If you don’t have a good config file, there’s one at the end of this article you can look at. For now, just create a blank file there:

touch ~/Dropbox/dotfiles/.vimrc_main

Next, let’s set up a way to manage plugins, or extensions to VIm.


We’ll use Pathogen.vim to manage our plugins. Pathogen modifies VIm’s load paths and lets us keep our plugins in folders we can easily update.

Download Pathogen.vim from the official site and place it in your Autoload folder.

mv pathogen.vim ~/Dropbox/dotfiles/.vim/autoload/pathogen.vim


Now, create a new .vimrc in your Dropbox folder. This will be our normal .vimrc for our macs.

  vim ~/Dropbox/dotfiles/.vimrc_mac

And put this in the file:

call pathogen#helptags()
call pathogen#runtime_prepend_subdirectories(expand('~/Dropbox/dotfiles/.vim/bundles'))
source ~/Dropbox/dotfiles/.vimrc_main

We’re telling Pathogen to load any installed plugins from our Dropbox, and then we’re loading in our vimrc_main file which will contain all of our platform independent configuration.

Now, symlink that to your home directory so VIm will find it.

ln -s ~/Dropbox/dotfiles/.vimrc_mac ~/.vimrc

And symlink your .vim folder so everything else you put there gets loaded as well:

ln -s ~/Dropbox/dotfiles/.vim ~/.vim

Now we’re ready to set up the Windows side of things.

Windows setup

Since Windows has no symlink support, you’ll need to create a couple of empty stubs. You’ll need a _vimrc file and a _vimfiles folder in your Home directory.

First, from a command prompt, create a _vimfiles folder

   mkdir %HOMEDRIVE%%HOMEPATH%\vimfiles

And an autoload folder

   mkdir %HOMEDRIVE%%HOMEPATH%\vimfiles\autoload

Then copy pathogen.vim into that folder from your dropbox

   cp "%HOMEDRIVE%%HOMEPATH%\My Dropbox\dotfiles\.vim\autoload\pathogen.vim" %HOMEDRIVE%%HOMEPATH%\vimfiles\autoload\pathogen.vim

Create the file %HOMEDRIVE%%HOMEPATH%_vimrc

  vim %HOMEDRIVE%%HOMEPATH%\_vimrc

Add this to the file:

call pathogen#helptags()
call pathogen#runtime_prepend_subdirectories(expand('c:\My Dropbox\dotfiles\.vim\bundles'))
source c:\My Dropbox\dotfiles\.vimrc_main

This is nearly identical to the file on our Mac, but it instead specifies the paths to the vim bundles folder and vimrc_main files in our Dropbox. Change those paths to the ones for your Dropbox installation!

Environment Variables and Path

At this point, you should set a HOME environment variable, as Windows doesn’t yet ship with that variable set by default (although it does have HOMEDRIVE and HOMEPATH variables.) Many VIm plugins use the HOME environment variable, and things might break down if you don’t have one set. You can set the HOME environment variable to %HOMEDRIVE%%HOMEPATH%.

Next, you should ensure that VIm is on your system PATH so you can access it from the commandline.

You typically set both of these environment variables through the Control Panel.

  1. From the desktop, right-click My Computer and click Properties.
  2. In the System Properties window, click on the Advanced tab.
  3. In the Advanced section, click the Environment Variables button.
  4. Finally, in the Environment Variables window, highlight the Path variable in the Systems Variable section and click the Edit button. Add the path to gvim.exe to this list, keeping in mind that each different directory is separated with a semicolon.
  5. Next, create a new environment variable called HOME, and give it the value %HOMEDRIVE%%HOMEPATH%


Many of the most awesome plugins for VIm are now maintained in Git repositories stored on Github. If you have Git installed on your Mac, which you can do quickly with the Mac OSX installer, you can clone each plugin’s repository right into your vim/bundles folder and Pathogen will load them right up.

Here’s what I use:

  • Rails.vim gives me support for Rails development
  • The Cucumber and HAML bunldes provide syntax support for their respective languages.
  • The NERDTreee plugin gives me a project tree which is absolutely necessary when working on anything substantial.
  • The closetag plugin lets me close any open HTML tags by pressing CTRL+_, and since I work in HTML and XML a lot, it’s a lifesaver when you’re several levels deep in a hierarchy.
  • I’m using the VividChalk color scheme, which I love.

cd ~/Dropbox/dotfiles/.vim/bundle
git clone git://github.com/tpope/vim-rails.git
git clone git://github.com/tpope/vim-cucumber.git
git clone git://github.com/tpope/vim-haml.git
git clone git://github.com/tpope/vim-endwise.git
git clone git://github.com/scrooloose/nerdtree.git
git clone git://github.com/scrooloose/nerdcommenter.git
git clone git://github.com/tpope/vim-surround.git
git clone git://github.com/vim-scripts/closetag.vim.git

For suggestions on other plugins, see Tammer Saleh’s blog post on the topic, which is very helpful.

A .vimrc_main config file

Remember the .vimrc_main file we created in the Dropbox? You’ll put all of your common configuration in that file. Here’s what’s in mine, if you’d like a starting point. I’ve pulled this from so many sources I can’t even remember where everything came from, but I have found that peeking at other people’s VIm files is really helpful.

A couple of important points about this configuration:

  1. The mapleader key is set to the comma, and I’ve set it so that the NERDtree plugin can then be toggled with ,d when you’re in normal mode.
  2. I’ve set soft tabs to two spaces.

It’s not an amazing configuration by any means, but it does the job for me.

Wrapping Up

There are a ton of steps to this process, but once you’ve gone through it, you can easily work on code on any configuration. And you can install Dropbox on Linux, too, so you could expand this over to that platform as well.

Share your comments and suggestions. I’m always looking for new VIm tips.

Learning Clojure – Baby Steps Towards Readable Code

Posted by Brian in Clojure, Howto, Languages (October 29th, 2010)

One thing that keeps me coming back to trying to learn Clojure is the way the language forces me to think about problems in a different way. To illustrate that, I thought I’d share a simple problem and solution with you.

The sales tax on items where I live is 5.5%. 5% goes to the state of Wisconsin, and the other .5% goes to Eau Claire county. So, given a price, let’s compute the total amount owed by the customer. Most programmers have done this simple problem enough. We know that the math is basically this:

price + (price * 0.055)

Let’s break down what we know about Clojure and write this expression.

First, we know we can add two numbers together like this:

(+ 4 4)

And we know we can multiply things like this:

(* 4 4)

So by combining those concepts together, we could define our function like this:

(defn total [price] (+ price (* price 0.055)))

That works, but let’s make it more expressive.

In Clojure, things like + and * aren’t just traditional operators. They’re functions, and the parameters we pass in can also be functions.

So if we made a function that computed just the sales tax for Wisconsin at 5%:

(defn wi_tax [price] (* 0.05 price))

and another function that computed the tax for Eau Claire county at 0.5%

(defn ec_county_tax [price] (* 0.005 price))

then we can simply add the results of those two functions together with the price to get our result.

(defn total [price] (+ price (wi_tax price) (ec_county_tax price)))

When we call

(total 5)

we see that we end up with a total of 5.275 for our total price. More importantly, we’ve written readable code.

Looking into the problem more, we see we’ll need to round the number up to the nearest hundredth. Also, this illustrates how we can make better use of functions, but this code doesn’t seem to be very maintainable in its current form. There are 72 counties in Wisconsin, each with their own value for taxes. But I’m sure Clojure has a nice way of handling things like that.

Baby steps, for now.

Web Accessibility – The Screenreader Experience Part One

Posted by Brian in Accessibility, Browsers, Usability (October 15th, 2010)

In order to help other developers understand accessibility and assistive technology, I’ve been working on a series of articles aimed at developers. As a slight change of pace, I invite you to experience Twitter through the “eyes” of a screen reader in this short video. You’ll hear what it sounds like when a screen reader reads the text of a page, and you’ll experience what a blind user might experience if he or she encounters a browser popup dialog. You’ll also get a chance to experience what happens when the browser experiences the “spinning beachball” on Mac OSX.

How to Survive a Live Coding Demo Without a Projector

Posted by Brian in Accessibility, Howto, Public Speaking, tips (October 10th, 2010)

I love to turn bad situations into opportunities to help others learn. This morning I gave a talk at Twin Cities Code Camp on “Building Mobile Apps with HTML5 and Web Standards”. The talk had a slide deck, but was mostly designed to be a follow-along live demo. When I went in to give the talk, the projector system was locked down. According to my feedback, the talk still worked very well, thanks to the preparation I did beforehand to accommodate for things like this. Hopefully this advice will help you if you’re preparing for a talk in the future.

My slides for the talk are online here. The code is on Github.

Practice Writing and Drawing

I have horrible handwriting when I write fast, and when I’m nervous. I teach a lot though and have learned to slow down and think carefully as I write. Having clear handwriting on a whiteboard is really important because you’re going to have to give people URLs to your content. They need to be able to read it at the back of the room, too, so be sure to write big.

Learn to carefully draw simple shapes that resemble things you’d show on-screen. In my talk, I drew the interface elements we’d be creating and was able to show how they’d look.

Have a live copy people can see

Make the finished product available on your website so people can play with it. If you’re building a web site, provide the URL to the demo version. If you’re demoing an iPhone or Android app, have a link to a video that people can watch that shows the app in action if you can’t get access to put the app on the App store. This helps people see what’s in your head (and on your screen.)

Make a PDF of your slide deck!

If you use Keynote or PowerPoint, or even SlideDown, convert your slides to PDFs. Include presenter notes in your export so that people will have more context as they’re reading along. If you don’t make use of presenter notes, you should start. They can help you when you present, but they can also help jog memories later when people look at your slides at work.

Protip: Presentation Remote for iPhone will let you see the presentation notes in your hand. You can control the slideshow with it as well.

Use Git and Github for your examples

Lately I’ve been using Git branches to stage my code examples. For my talk on HTML5 mobile apps, I started out with a new branch like this:

git init
git checkout -b 01_simple_form

Then I’ll do all the work for the first stage, commit it, and make a new branch for the second stage. In this talk, the first branch was just the HTML for the user interface. The second branch then covered the JavaScript we used to create the database on the client machine.

git add .  
git commit -m "Web form"
git checkout -b 02_create_database

By the time I’m done, I have several branches in the repository that I can use to track the stages of my live demo. At the end, I merge my last branch into the Master branch.

git checkout master
git merge 09_offline

Protip: If I realize that I made a mistake, I can check out the earlier branch, fix the code, commit the code, and merge that fixed branch forward into the branches that followed.

git stash      # puts your in-progress work aside
git checkout 01_simple_form
# fix changes
git commit -am "fixed the form"
git checkout 02_create_database
git merge 01_simple_form
git checkout 03_add_note
git merge 01_simple_form 
git stash apply # put your stuff back

Once I’m ready, I create the new Git repository and push my code. I have to push the master branch and the other branches too.

git remote add origin git@github.com:napcs/html5_offline_notes.git
git push origin master
git push origin 01_simple_form
git push origin 02_create_database
git push origin 03_add_note

So how does this help me during a talk? I can direct people to the Github page and they can use the Select branch section to see each branch. The Github web interface lets them follow along as I talk about the code. That’s what I did here.

Git advantages
Uploaded with Skitch!

Be ready offline

As a last resort, take this git repository and your PDF presentation and make it available on a thumb drive, or fire up a local wifi hotspot and run a server. An iPad, iPhone, or iPod Touch with Air Sharing can help with this.

Wrapping Up

So, that’s how I’ve done preparation for my talks and managed to make it through a code-centric talk with just a whiteboard. Do you have any suggestions on what you would do?

Next Page »