Pages

Sponsorship

40% off your First Order with GoDaddy.com!

Apr 3, 2009

Agile Web Development with Rails, Third Edition


Agile Web Development with Rails, Third Edition
Author: Sam Ruby, Dave Thomas, David Hansson
ISBN-10: 1934356166
ISBN-13: 978-1934356166

Book Description
You want to write professional-grade applications: Rails is a full-stack, open-source web framework, with integrated support for unit, functional, and integration testing. It enforces good design principles, consistency of code across your team (and across your organization), and proper release management.

But Rails is more than a set of best practices. Rails makes it both fun and easy to turn out very cool web applications. Need Ajax support, so your web applications are highly interactive? Rails has it built in. Want an application that sends and receives e-mail? Built in. Supports internationalization and localization? Built in. Do you need applications with a REST-based interface (so they can interact with other RESTful applications with almost no effort on your part)? All built-in.

With this book, you'll learn how to use ActiveRecord to connect business objects and database tables. No more painful object-relational mapping. Just create your business objects and let Rails do the rest. Need to create and modify your schema? Migrations make it painless (and they're versioned, so you can roll changes backward and forward). You'll learn how to use the Action Pack framework to route incoming requests and render pages using easy-to-write templates and components. See how to exploit the Rails service frameworks to send emails, implement web services, and create dynamic, user-centric web-pages using built-in Javascript and Ajax support. There is extensive coverage of testing, and the rewritten Deployment chapter now covers Phusion Passenger.

As with the previous editions of the book, we start with an extended tutorial that builds parts of an online store. And, of course, the application has been rewritten to show the best of Rails V2.

Download Mirror
http://...

Mar 30, 2009

Behavior Driven Development on Rails: Part 2



The cool thing about Cucumber is how it allows you to reuse your step definitions. It allows you to effectively create a DSL whereby you can generate new tests with little or no additional coding. As you’re writing step definitions keep this in mind, and look for patterns that you can dry up.

Below is an example of a step definition that has grown over time. These steps support a user administration feature using restful_authentication and aasm_state.

Given /^a user that is pending$/ do
pending
end

When /^I activate the user$/ do
pending
end

Then /^the user should be able to log in$/ do
pending
end

Given /^a user that is active$/ do
pending
end

When /^I suspend the user$/ do
pending
end

Then /^the user should be in a suspended state$/ do
pending
end

Then /^the user should not be able to log in$/ do
pending
end

Given /^a user that is suspended$/ do
pending
end

When /^I unsuspend the user$/ do
pending
end

Then /^the user should be in a pending state$/ do
pending
end

When /^I delete the user$/ do
pending
end

Immediately you should recognize that there are some patterns here: given something about the user’s state, and when the admin does something to the state, and whether or not you can log in.

Let’s see if we can’t boil these down these 20 some steps into just 4-5? First lets aggregate the common Given’s, using the power of regular expression we can do something like this:

Given /^a user that is (.+)$/ do
end

Hmm, interesting — this might work, so lets try finishing it up:

Given /^a user that is (.+)$/ do |state|
@user = User.create!(:login => 'testuser', :email => 'test@test.gov', :password => 'testme', :password_confirmation => 'testme', :state =>state)
end

Odd, the test is failing still. Well if you understand how restful_authentication works with aasm you’ll soon discover that any user created on the back-end starts out in a passive state. This actually is going to take some thought, so lets come back to it.

How about all the “When I” steps? Those are easily grouped together. Since restful_auth uses nice verbs for state transitions we can leverage this in our step definitions:

When /^I (.+) the user$/ do |state|
@user.send("#{state}!")
end

Along the same line of thinking we can apply this to our “Then the user” steps:

Then /^the user should not be able to log in$/ do
visit login_path
fill_in "login", :with => @user.login
fill_in "password", :with => @password
click_button "Log In"
response.should contain("Couldn't log you in")
end

Then /^the user should be able to log in$/ do
visit login_path
fill_in "login", :with => @user.login
fill_in "password", :with => @password
click_button "Log In"
response.should contain("Logged in successfully")
end

Then /^the user should be in a (.+) state$/ do |state|
@user.send("#{state}?")
end

There’s a lot going on in the log-in steps, we take the same exact steps to log in a user, the only change is the outcome we expect. Ok so lets refactor that out into a method, and we get:

Then /^the user should not be able to log in$/ do
login_using_form("Couldn't log you in")
end

Then /^the user should be able to log in$/ do
login_using_form("Logged in successfully")
end

def login_using_form(expectation)
visit login_path
fill_in "login", :with => @user.login
fill_in "password", :with => @password
click_button "Log In"
response.should contain(expectation)
end

Ok, better, so what about the given a user? Anything we create on the backend will start out in a state of passive (short of changing how restful_auth works). Also not all the verbs we would use in a step definition equate to a valid transition in aasm (you cannot transition to passive or pending directly). Well it takes a little more thought, but in the end you might end up with a method like the one below:

Given /^a user that is (.+)$/ do |state|
state_hash = { :active => "activate!", :suspended => "suspend!" }
@password = 'testme'
@user = User.create!(:login => 'testuser', :email => 'test@test.gov', :password => @password, :password_confirmation => @password)
##
# Restful_Authentication doesn't provide direct state transistions for passive or pending,
# so we do a little tweaking to our user object to get it into the desired state.
#
@user.register! unless state == 'passive' # new accounts created through backend start out as passive
unless state == 'pending' # accounts when registered become pending
@user.send(state_hash[state.to_sym]) # pending can transition easily to any state
end
end

Putting it all together we have a step definition file now of only 5 definitions and one helper method. These steps can support a wide combination of user starting states, user state transitions and expectations around logging in and user state post transition. Let the business folks go hog wild!

Given /^a user that is (.+)$/ do |state|
state_hash = { :active => "activate!", :suspended => "suspend!" }
@password = 'testme'
@user = User.create!(:login => 'testuser', :email => 'test@test.gov', :password => @password, :password_confirmation => @password)
##
# Restful_Authentication doesn't provide direct state transistions for passive or pending,
# so we do a little tweaking to our user object to get it into the desired state.
#
@user.register! unless state == 'passive' # new accounts created through backend start out as passive
unless state == 'pending' # accounts when registered become pending
@user.send(state_hash[state.to_sym]) # pending can transition easily to any state
end
end

When /^I (.+) the user$/ do |state|
@user.send("#{state}!")
end

Then /^the user should not be able to log in$/ do
login_using_form("Couldn't log you in")
end

Then /^the user should be able to log in$/ do
login_using_form("Logged in successfully")
end

Then /^the user should be in a (.+) state$/ do |state|
@user.send("#{state}?")
end

# step helpers --------------------------------------#

# this method simulates a login
def login_using_form(expectation)
visit login_path
fill_in "login", :with => @user.login
fill_in "password", :with => @password
click_button "Log In"
response.should contain(expectation)
end

A real-life feature that these steps support:

Feature: User Administration

So that I can control access to the application
As an admin
I want to manage users

Scenario: Activate a pending user
Given a user that is pending
When I activate the user
Then the user should be able to log in

Scenario: Suspend a user that is active
Given a user that is active
When I suspend the user
Then the user should not be able to log in

Scenario: Unsuspend a user that is suspended
Given a user that is suspended
When I unsuspend the user
Then the user should be in a pending state
And the user should not be able to log in

Scenario: Purge a user that is active
Given a user that is active
When I delete the user
Then the user should not be able to log in

Scenario: Purge a user that is pending
Given a user that is pending
When I delete the user
Then the user should not be able to log in

Scenario: Purge a user that is suspended
Given a user that is suspended
When I delete the user
Then the user should not be able to log in

Mar 26, 2009

A Beautiful Birthday Message!

Jin-Kang Cheng 25th Birthday

Behavior Driven Development on Rails: Part 1



Before we can begin doing BDD (behavior driven development) we need to install some tools to help.

sudo gem install cucumber rspec-rails webrat

Next I go to my Rails application and run some scripts to get the basic set-up inside my rails directory structure:

script/generate rspec
script/generate cucumber

Now in the newly created features folder I will create a file called user_administration.feature. This file will contain all my scenarios for this feature. After spending some time thinking about how to express my features I come up with two basic ones to start:

Feature: User Administration

So that I can control access to the application
As an admin
I want to manage users

Scenario: Create a new user account
Given no user "joetest"
When I create a new user "joetest" with password "skymonkey"
Then the user "joetest" can log in with password "skymonkey"

Scenario: Suspend an existing user account
Given a user that is active
When I suspend the user
Then the user can not log in

Now I run the following command to have cucumber generate snippet methods that I can then copy into a step definition.

script/cucumber features/user_administration.feature

I create a new file named user_steps.rb in the features/step_definitions folder. Now that we have our step definition snippets the next job is to take them from “pending” into something meaningful. We’ll start with the first scenario. After giving it some thought it might end up looking like this:

Given /^no user (.+)$/ do |login|
lambda{ User.find(login) }.should raise_error(ActiveRecord::RecordNotFound)
end

This first part sets us up. It allows us to express the given state, in this case not finding a user named “joetest”.

When /^I create a new user "(.+)" with password "(.+)"$/ do |login, password|
visit new_user_path
fill_in "user_login", :with => login
fill_in "user_email", :with => "#{login}@test.org"
fill_in "user_password", :with => password
fill_in "user_password_confirmation", :with => password
click_button "Sign Up"
end

Next we describe the action we’ll be taking. This code simulate the submission of a form, using Webrat. We take this approach because it makes us exercise the whole stack views, controller and models. It’s just short of me going to the site with a browser.

Then /^the user "(.+)" can log in with password "(.+)"$/ do |login, password|
visit login_path
fill_in "login", :with => login
fill_in "password", :with => password
click_button "Log In"
response.should contain("Logged in Successfully")
end

Lastly we test our outcome, that the user the admin created is able to log in. So the end result is test that describes the behavior of an admin creating a new account for a user, and they are able to successfully log in.

Along the way you may find tests go red (fail), this is normal. You want to write code (just enough) to make them go green, then continue to write more test code. Keep repeating this until all your tests run green.

Also the nice thing about step definitions is that they can be reused in other tests. We’ll likely have other scenarios where we create a new user or try to log in as one. Our code stays dry and we (the developer) stay confident. (Now it’s sounding like a anti-perspirant commercial, so I’ll stop now.)

Jan 11, 2009

Advanced Rails Recipes


Advanced Rails Recipes
Author: Mike Clark
ISBN-10: 0978739221
ISBN-13: 978-0978739225

Book Description
Ruby on Rails continues to build up a tremendous head of steam. Fueled by significant benefits and an impressive portfolio of real-world applications already in production, Rails is destined to continue making significant inroads in coming years.

Each new Rails application showing up on the web adds yet more to the collective wisdom of the Rails development community. Yesterday's best practices yield to today's latest and greatest techniques, as the state of the art is continually refined in kitchens all across the Internet. Indeed, these are times of great progress.

At the same time, it's easy to get left behind in the wake of progress. Advanced Rails Recipes keeps you on the cutting edge of Rails development and, more importantly, continues to turn this fast-paced framework to your advantage.

Advanced Rails Recipes is filled with pragmatic recipes you'll use on every Rails project. And by taking the code in these recipes and slipping it into your application you'll not only deliver your application quicker, you'll do so with the confidence that it's done right.

The current beta includes contributions from Aaron Batalion, Adam Keys, Adam Wiggins, Andre Lewis, Andrew Kappen, Benjamin Curtis, Ben Smith, Chris Bernard, Chris Haupt, Chris Wanstrath, Cody Fauser, Dan Benjamin, Dan Manges, Daniel Fischer, David Bock, David Chelimsky, David Heinemeier Hansson, Erik Hatcher, Ezra Zygmuntowicz, Geoffrey Grosenbach, Giles Bowkett, Greg Hansen, Gregg Pollack, Hemant Kumar, Hugh Bien, Jamie Orchard-Hays, Jamis Buck, Jared Haworth, Jarkko Laine, Jason LaPier, Jay Fields, John Dewey, Jonathan Dahl, Josep Blanquer, Josh Stephenson, Josh Susser, Kevin Clark, Luke Francl, Mark Bates, Marty Haught, Matthew Bass, Michael Slater, Mike Clark, Mike Hagedorn, Mike Mangino, Mike Naberezny, Mike Subelsky, Nathaniel Talbott, PJ Hyett, Patrick Reagan, Peter Marklund, Pierre-Alexandre Meyer, Rick Olson, Ryan Bates, Scott Barron, Tony Primerano, Val Aleksenko, and Warren Konkel.

Download Mirror
http://...