In association with heise online

ActionDispatch – New Routing System

Routes in Rails have often been a source of frustration for developers, so the Rails core team did something about it. Routes have been totally redesigned for Rails 3, sporting a new syntax and some useful new features.

To illustrate by example, examine the following code:

# Rails 2.3
ActionController::Routing::Routes.draw do |map|
# All REST actions under /items
map.resources :items

# Set the default "home" route
map.root :controller => "dashboard"

# These routes will make all actions/controllers accessible via GET
# which is usually less than optimal.
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
end
# Rails 3.0
AppName::Application.routes do
# All REST actions under /items
resources :items

# Set the default "home" route
root :to => 'dashboard#index'

# This route is commented out by default in a new Rails 3 project,
# because it will make all controllers accessible via GET requests
# which is less than optimal when using RESTful controllers.
# match ':controller(/:action(/:id(.:format)))'
end

Perhaps the most evident difference in the Rails 3 version of routes is the fact that they're now scoped under your application, which has a class of its own. Additionally, there are options for URL-based constraints (using a regular expression to protect controllers and actions), a "scope" method that allows you to namespace routes according to different languages or actions, and using parenthesised elements in a route definition to specify optional variables to be passed to the controller.

ActionMailer

Sending email from your application has been greatly simplified in this release of Rails by the ActionMailer class. This allows you to generate a mailer class (inherited from ActionMailer::Base), and create simple methods and corresponding views (located under app/views/mailer_name) to set up your specific mail system.

Sending a multipart/alternative mail message is really easy now. After generating your mailer class and creating a method (ex. "welcome_user"), you can create views for the method name ending in either .html.erb, or .text.erb. When ActionMailer begins to form the message for delivery, it will detect both files and "automagically" create the multipart/alternative email with both HTML and plain text parts.

To illustrate, consider the following scenario: a user forgets his or her password and enters the necessary information to reset it. After the proper database flags are set, an email is sent to the user with a specific URL for them to visit to reset their password.

First, generate a mailer:

$ rails g mailer user_mailer

Next, open the newly created app/mailers/user_mailer.rb file, and add a method called "forgot_password":

class UserMailer < ActionMailer::Base
default :from => "do-not-reply@example.com"

def forgot_password(user)
@user = user
mail(:to => user.email, :subject => "Reset Your Password")
end
end

In this sample of code, we've defined a method called "forgot_password", which accepts a user object. The @user instance variable is set so that the views (shown in the next step) are able to access it to provide dynamic output.

Next, create two views: one for plain-text, and one for HTML. If named correctly, they'll both be automatically picked up and factored into a multipart email.

# app/views/user_mailer/forgot_password.html.erb
<!DOCTYPE html>
<head>
<title>Reset Your Password</title>
<!-- ... rest of the html ... -->

# app/views/user_mailer/forgot_password.text.erb
Dear <%= @user.name %>,

Someone recently requested that your password be reset
at example.com. We're sending you this email so you
can reset your password. Just visit the URL below
within the next *60 minutes* to reset your password.
This link will be inactive after that time, and you'll
have to re-submit another password reset request after
that.

<%= @user.password_reset_url %>

Finally, triggering the mail action could be done in either a controller or a model. If you follow the "skinny controller, fat model" theory, this may be done in a method on the User class called "reset_password". For example:

# app/models/user.rb
class User < ActiveRecord::Base
# ... associations, other code ...

def reset_password
# Make the old password no longer work
self.password = self.password_confirmation = SecureRandom.base64(8)
if self.save
UserMailer.forgot_password(self).deliver
end
end
end

(Note: SecureRandom is a part of ActiveSupport that's suitable for creating secure random strings. In this case we're using it to create a new password.)

When using a mailer class, you first call the method, pass the object it expects (if any) and then call the #deliver method on the resultant object.

Next: Cross-Site-Scripting Protection

Print Version | Permalink: http://h-online.com/-1285884
  • Twitter
  • Facebook
  • submit to slashdot
  • StumbleUpon
  • submit to reddit
 


  • July's Community Calendar





The H Open

The H Security

The H Developer

The H Internet Toolkit