Hack New Input Types into Contact Form 7
Background
I use the Contact Form 7 plugin on my Command Capsule website. It allows customers to get in touch with me right from the home page. I love how absolutely simple it is to create a quick contact form and I like that I’m able to customize the templates.
One thing that is critical for me is mobile support. The world is mobile now. Command Capsule uses responsive design to fit and read well on any number of devices, from desktop HD screens to small smartphone screens.
Comments Are Tricky
I love it. In this post on an album cover featuring Lee Ferrell, Will Ferrell’s dad, the comments quickly go from the usual fare to Lee’s old friends trying to get in touch. So, not only do people not look at your website to see what it’s about, they typically don’t read your post at all, and they often only read the comment right before theirs.
The Building of Jetrecord
This is for posterity. It took a lot of time to make these videos relative to the time it takes to teach the concepts and the actual actions taken at the command line. At one time I had a good production system going, but it took a long time to set up. Design took a long time. Getting the feeling right. Tracking down all the archival footage. Editing. Creating the closed captions and making it all accessible.
It’s a lot of work and I’m really happy with the results, but it’s been over two years since the last video was produced and the Rails workflow I was demonstrating has changed for me. I don’t use RSpec and Cucumber anymore, for example. Rails is now at version 3.1. At some point I may revisit making screencasts like this, but there’s no time in my schedule right now. Enjoy them as part of my history.
Follow along as I build version 2 of Jetrecord using Ruby on Rails.
- The Tabula Rasa of Doom: every project has a beginning
- Tell Me a Story: customers are integral to completing the project
- Git, Capistrano, and a Test Release: put code in a repository and release it
- Cucumbers and Webrats!: set up Cucumber and Webrat testing
The Building of Jetrecord by Harry Love is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License. When code, text, or media in this series is not created by me and is not in the public domain I will provide links to their sources from which you can find their respective licenses and terms of use.
Automatically Delete Spam from Gmail
Gmail’s spam filter is pretty good. I get roughly one or two false positives a year. However, I think spam notification in Gmail should be redesigned. Currently, when new spam arrives, the folder link turns bold and displays a mail count. This grabs my attention.
That’s annoying. I don’t want it to grab my attention, I just want it to delete my spam. Smart, legitimate people will do everything they can to contact me in other ways if I don’t respond to their email so there’s no reason for me to scan the list of senders and subject lines.
With that in mind, and with a quick Google search, I stumbled upon this nifty filter trick that will automatically delete spam from Gmail’s spam folder and send it to the trash.
- Create a filter
- Has the words: “is:spam” (without quotes)
- Next step
- Say OK to the warning message
- Check “Delete it”
- Create Filter
Now all of my spam is sent directly to the trash. Trashed items are automatically deleted after 30 days so I don’t have to manage it. And if someone calls asking why I didn’t respond, I can search the trash folder for the missing email.
The Building of Jetrecord: Episode 4: Cucumbers and Webrats!
The message here is that with automated tests, we don’t have to worry about code being fragile. We can try out some stuff we think might work, and test it in seconds. We can be more courageous with our coding, and not have to code with cotton gloves on. — Test Driven Development
In the last episode I started my Rails code, committed it to a Git repository, and released my first deployment with Capistrano. In this episode I’m going to start my first feature by writing some tests and then implementing the code.
Cue film.
Adding RSpec, Cucumber, and Webrat to our Rails App
With the RSpec-Rails, Cucumber, and Webrat gems installed, let’s start a new branch in our Git repository and set up our app for testing:
$> git branch cucumber $> git checkout cucumber $> script/generate cucumber $> script/generate rspec
Now edit RAILS_ROOT/features/support/env.rb. This file was created when we ran script/generate cucumber. We need to change a few lines. Here is what my env.rb file looks like after editing.
# Sets up the Rails environment for Cucumber ENV["RAILS_ENV"] = "test" require File.expand_path(File.dirname(__FILE__) + '/../../config/environment') require 'cucumber/rails/world' require 'cucumber/formatters/unicode' # Comment out this line if you don't want Cucumber Unicode support Cucumber::Rails.use_transactional_fixtures # Comment out the next two lines if you're not using RSpec's matchers (should / should_not) in your steps. require 'webrat/rails' require 'cucumber/rails/rspec'
We can add autotesting capability by installing the ZenTest gem. Autotest re-runs our tests after every code change, greatly speeding up our testing process. After getting the gem installed, we need to set some global variables so autotest knows to run our RSpec and Cucumber tests. Open up your .bash_profile file (usually located in your user’s home directory on your system). Add the following lines to the bottom of the file.
export RSPEC=true export AUTOFEATURE=true
Additionally, if you’re on a Mac, I think it’s worth setting up Growl notifications for autotest. It’s not a requirement for testing or even using autotest but it’s a nice enhancement. Search Google for “autotest+growl” and you’ll find a number sites that will show you how to set it up.
Note: Growl notifications currently don’t work with Cucumber but they do work with RSpec and we will get into using RSpec eventually.
Let’s write a feature test to check our output from the last episode. If you remember, all we did was set up our home page to say “Hi.” I’m going to write a test to make sure it says that.
$> script/generate feature Page exists features/step_definitions create features/manage_pages.feature create features/step_definitions/page_steps.rb
Open up the RAILS_ROOT/features/manage_pages.feature file. I’m writing my test like so:
In order to prove that I can write a quick feature
Harry
wants to write a simple test
Scenario: Friendly home page
Given I am on the home page
Then I should see “Hi.”
Now I save that and run the test with rake:
$> rake features (in /Users/harry/Sites/jetrecord) Feature: First Test # features/manage_pages.feature In order to prove that I can write a quick feature Harry wants to write a simple test Scenario: Friendly home page # features/manage_pages.feature:6 Given I am on the home page # features/manage_pages.feature:7 Then I should see "Hi." # features/step_definitions/webrat_steps.rb:83 1 scenario 1 step skipped 1 step pending (1 with no step definition) You can use these snippets to implement pending steps which have no step definition: Given /^I am on the home page$/ do end
So the test ran but didn’t pass because I don’t have a step defined that tells Cucumber how to get to the home page. Thankfully, it gives me a snippet of code at the end of the output there. I open up RAILS_ROOT/features/step_definitions/page_steps.rb and add that in, filling it in with the code it needs to fulfill that step.
Given /^I am on the home page$/ do visit '/' end
Quite simply, I’m telling Cucumber to visit the URL that looks like ‘/’, which is the home page. I run the test again.
$> rake features (in /Users/harry/Sites/jetrecord) Feature: First Test # features/manage_pages.feature In order to prove that I can write a quick feature Harry wants to write a simple test Scenario: Friendly home page # features/manage_pages.feature:6 Given I am on the home page # features/step_definitions/page_steps.rb:1 No route matches "/" with {:method=>:get} (ActionController::RoutingError) [stacktrace info] 1 scenario 1 step failed 1 step skipped rake aborted!
Okay, we’re getting somewhere but we didn’t move very far. Cucumber barfed because it was looking for a route defined by the Rails application. Cucumber runs in the context of the Rails application, not of the whole site architecture. It doesn’t care that I have an index file in the public directory because it’s not actually crawling my web site like a browser would.
This is not necessarily a bad thing. If I wanted I could install Selenium, hook into it via Cucumber and re-run the tests. This would catch my index.html page because Selenium acts like a web browser. Eventually, I can see myself doing that because I’m going to need to test some Ajax interactions. But right now it’s not necessary.
In order to run my application I need to remove the index file anyway, so the real solution is to define my home page in Rails and then test again. To do that I need to add a route to my RAILS_ROOT/config/routes.rb file. Then I need to define the controller and a view for the home page.
# config/routes.rb ActionController::Routing::Routes.draw do |map| map.root :controller => 'pages', :action => 'home' end
# app/controllers/pages_controller.rb class PagesController < ApplicationController def home end end
# app/views/pages/home.html.erb
Hi.
# app/views/layouts/application.html.erb
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<title>Hello</title>
</head>
<body>
<%= yield %>
</body>
</html>
Alright. One last thing. We need to rename or remove the public/index.html file. I’m just going to remove it. Then we try the test again.
$> git rm public/index.html $> rake features (in /Users/harry/Sites/jetrecord) Feature: First Test # features/manage_pages.feature In order to prove that I can write a quick feature Harry wants to write a simple test Scenario: Friendly home page # features/manage_pages.feature:6 Given I am on the home page # features/step_definitions/page_steps.rb:1 Then I should see "Hi." # features/step_definitions/webrat_steps.rb:83 1 scenario 2 steps passed
Bingo! Now let’s try running autotest.
$> autotest loading autotest/cucumber_rails_rspec /opt/ruby-enterprise-1.8.6-20080810/bin/ruby /opt/ruby-enterprise-1.8.6-20080810/lib/ruby/gems/1.8/gems/cucumber-0.1.15/bin/cucumber features --format progress --format autotest --color --out /var/folders/f1/f1HkdqHjFe43ByUhxU-FO++++TI/-Tmp-/autotest-cucumber.5265.0 ..
Great! It’s working. Two passing steps (the two dots at the end) and autotest is still running, waiting for me to do something stupid. I’m going to introduce an error into home.html.erb.
# app/views/pages/home.html.erb
Hello.
And then back to the terminal.
/opt/ruby-enterprise-1.8.6-20080810/bin/ruby /opt/ruby-enterprise-1.8.6-20080810/lib/ruby/gems/1.8/gems/cucumber-0.1.15/bin/cucumber features --format progress --format autotest --color --out /var/folders/f1/f1HkdqHjFe43ByUhxU-FO++++TI/-Tmp-/autotest-cucumber.5265.1 .F Failed: 1) expected: /Hi./m, got: "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html>\n <head>\n <meta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\" />\n <title>Hello</title>\n \n </head>\n <body>\n Hello.\n </body>\n</html>" (using =~) Diff: @@ -1,2 +1,2 @@ -/Hi./m +"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html>\n <head>\n <meta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\" />\n <title>Hello</title>\n \n </head>\n <body>\n Hello.\n </body>\n</html>" [stacktrace info] ./features/step_definitions/webrat_steps.rb:84:in `Then /^I should see "(.*)"$/' features/manage_pages.feature:8:in `Then I should see "Hi."'
And that’s how it works. We write a test, it fails, we write some code to pass the test, it passes.
I have to apologize. This post has already become too long. I like the direction it took but I don’t think moving on to writing an actual Jetrecord feature would be wise right now. So, really, next time I’m going to write tests for the first feature. I’ll even include some RSpec in there.
Coming Up in the Next Episode
No more rhymes now, I mean it. I’m going to write some tests for the first feature. Until next time, cheers and happy flying.
Material You May Find Useful Related to This Episode
Cucumber: Behaviour Driven Development with elegance and joy
The Building of Jetrecord by Harry Love is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License. When code, text, or media in this series is not created by me and is not in the public domain I will provide links to their sources from which you can find their respective licenses and terms of use.