Channels
Displaying page 52

MGTwitterEngine - Objective-C Twitter library for the iPhone:

If you need to integrate Twitter into your iPhone app or build your own Twitter client, you might check out MGTwitterEngine from Matt Gemmell. MGTwitterEngine consumes the Twitter XML API and supports both NSXMLParser and libxml.

When building your controller, the library supports a few callbacks:

- (void)requestSucceeded:(NSString *)requestIdentifier;
- (void)requestFailed:(NSString *)requestIdentifier withError:(NSError *)error;
- (void)statusesReceived:(NSArray *)statuses forRequest:(NSString *)identifier;
- (void)directMessagesReceived:(NSArray *)messages forRequest:(NSString *)identifier;
- (void)userInfoReceived:(NSArray *)userInfo forRequest:(NSString *)identifier;

If Obj-C is a bit too low-level for you, take a look at Appcelerator Titanium Mobile which has an easy JavaScript API that includes network API support. If you missed it, also be sure to check out Episode 0.0.8 with Marshall Culpepper.

[Source on GitHub] [Matt’s blog post]

back to top

A Nunemaker Joint:

It’s never been easier to do file uploads with MongoMapper and GridFS. Joint, from MongoMapper creator John Nunemaker, is a MM plugin that adds some nice convenience methods to your models:

class Foo
  include MongoMapper::Document
  plugin Joint

  attachment :image
  attachment :pdf
end

By declaring these two attachments, you automagically get accessors for image and pdf. The setter methods take any IO (File, Tempfile, etc) and the getter methods return a GridIO type from the Ruby driver.

John even throws in some nifty proxy goodness:

doc.image.id
doc.image.size
doc.image.type
doc.image.name

[Source on GitHub][John on Episode 0.1.1]

back to top
Favorite
Posted 6 months ago at defunkt's Gists

{{title}}
$ cat hi.mustache
{{#begin}}
Hi {{world}}!
{{/end}}
$ mustache -t hi.mustache
Unclosed section "begin" (Mustache::Parser::SyntaxError)
  Line 1
    {{#begin}}
           ^
$ cat hi.mustache
Hi {{wor*ld}}!
$ mustache -t hi.mustache
Unclosed tag (Mustache::Parser::SyntaxError)
  Line 1
    Hi {{wor*ld}}!
           ^
$ echo '{{#greet?}}Hello {{name}}!{{/greet?}}' > hi.mustache
$ mustache -t hi.mustache
[:multi,
 [:mustache,
  :section,
  "greet?",
  [:multi, [:static, "Hello "], [:mustache, :etag, "name"],
    [:static, "!"]]]]

back to top
Favorite
Posted 6 months ago at defunkt's Gists

diff --git a/lib/haystack/app.rb b/lib/haystack/app.rb
index a4087e1..6c0ee1b 100644
--- a/lib/haystack/app.rb
+++ b/lib/haystack/app.rb
@@ -10,14 +10,16 @@ module Haystack
     set :public,    "#{dir}/public"
     set :static,    false
 
-    # Tell mustache where the Views constant lives
-    set :namespace, Haystack
+    set :mustache, {
+      # Tell mustache where the Views constant lives
+      :namespace => Haystack,
 
-    # Mustache templates live here
-    set :views,     "#{dir}/templates"
+      # Mustache templates live here
+      :templates => "#{dir}/templates",
 
-    # Tell mustache where the views are
-    set :mustaches, "#{dir}/views"
+      # Tell mustache where the views are
+      :views => "#{dir}/views"
+    }
 
     # Sinatra error handling
     configure :development, :staging do

back to top
Posted 6 months ago at The GitHub Blog

<!-- -*-Markdown-*- -->

In Ryan's Compare View post we promised that we'd be rolling out more code review features and today we're rolling out the latest: inline commit comments notes.

Comments ? Notes

GitHub has actually had commit and line-based commit comments for a very long time. The problem was they were tucked into a facebox activated by a little bubble peeking out of the side of the source. Hard to find.

Example of old style

Now, we've moved the comments inline and we're calling them notes. This terminology helps distinguish commit notes from comments on issues and other places.

Example of old style

As a side-note, we've also deprecated file-based commit notes (that is notes that are attributed to a file, but not a line). Old comments will continue to show up indefinitely, but you will no longer be able to add them.

Highlighting important people

The new note styles also help to highlight people who you might want to listen to — notably repository owners & collaborators.

Example of old style

Publish notes like a pro-fessional

Previously with the old commit comments only repository collaborators could delete comments (and no one could edit them). Now you can edit and delete your own notes (in addition to repository collabs).

Example of old style

Another source of pain was the fact that you could only preview your comment under specific conditions. Now you'll see that everywhere you can make a note, there's a handle little preview tab that will give you a live preview.

Preview comments

Things are a little rough around the edges, so let us know if you run into any issues using these new inline notes!

back to top
Posted 6 months ago at Ruby Inside

Supermodel is a new library by Alex Maccaw that uses the Rails 3.0 ActiveModel library to provide ActiveRecord-esque in-memory "database" storage in Ruby.

Supermodel is best demonstrated with a basic example:

require 'supermodel'

class Person < SuperModel::Base; end

a = Person.new( :name => "Jim" )
a.save

Person.find_by_name('Jim') # => #
Person.all # => [#]

This is just the start! Out of the box, Supermodel supports validations, callbacks, observers, dirty change tracking, and serialization. It also allows you, with only a little magic, to go beyond ephemeral memory-only structures and marshall your SuperModel-based objects to disk or even to a Redis store.

A more complex example that includes randomly generated IDs and validations:

require 'supermodel'

class Person < SuperModel::Base
  include SuperModel::RandomID
  attributes :name
  validates_presence_of :name
end

a = Person.new
a.valid? # => false
a.name = "Jim"
a.valid? # => true
a.save
a.id # => "6481a4fcd834e567836587c6da"

It's early days for Supermodel, but I can see it becoming a big deal for Rubyists away from the Rails stack. The gemified version doesn't have support for relationships yet, but the edge version on GitHub has early support for belongs_to and has_many included.Alex has written the code in a well structured way and creating modules or subclasses to add support for interacting with other backends (such as, say, Tokyo Cabinet) doesn't look like it'd be too hard.

Supermodel shows a lot of promise and is what I was originally hoping ActiveModel was going to be. It provides just the right level of abstraction and separation from the database, but without losing the goodness we came to enjoy from ActiveRecord over the past few years.

back to top
Posted 6 months ago at techno weenie - Home

John Nunemaker wrote up his experiences in bootstrapping Harmony with Steve Smith. He makes a lot of great points that have been working out for them. I just have one quick thing to add to it all:

Embrace Open Source

I helped bootstrap both Lighthouse and Tender Support, and noticed big gains after supporting open source projects. Obviously, these products are more developer focused than most, but we also take every chance to sponsor non profit organizations, educational use, etc.

When Lighthouse launched, I was apprehensive about supporting them. I worried that we’d get some project like Rails or Wordpress on there, melting my poor servers. Really, we were extremely fortunate to get some high profile OSS projects. Our servers didn’t melt (yes, we love Engine Yard, our hosting partner), and put our product in front of a lot more eyeballs.

Write these opportunities off as advertising if it helps.

back to top
Favorite
Posted 6 months ago at Ruby5

In this episode, we cover RVM with Rails 3, an env-js driver for Capybara, Faster Faker, Ruby Summer of Code, a blog post about Service Objects, Artifice, Padrino, and Sinatra 1.0.

Listen to this episode on Ruby5

This episode is sponsored by NewRelic RPM
At Hashrocket we use NewRelic to track application performance and identify potential problems in a fraction of the time. Install it today by going to NewRelic.com.

Rails 3 and RVM
Easy way to get the Rails 3 beta up and running under RVM.

Env-js Driver for Capybara
Capybara now supports external drivers! This allows people to create their own plugin projects containing drivers to use with Capybara. The first such driver has already been created for env-js.

Faster Faker
Faster Faker is a reimplementation of the faker library to improve performance. The API is the same, so swapping it out is a simple matter.

Ruby Summer of Code
Ruby Summer of Code is a student/mentoring program inspired by the Google Summer of Code internships. The goal is to get more students involved with Ruby and Rails open source projects.

Golick Goes Crazy
James Golick wrote a blog post about using service objects to encapsulate ancillary logic that doesn't make sense to reside in the model or an observer.

Artifice
Artifice is a new library for stubbing out Net::HTTP. It allows you to easily build mock responses for external systems.

Padrino is the Godfather of Sinatra
Padrino is a Sinatra library that lets you pick and choose features for routing, helpers, localization, and more.

Sinatra Goes 1.0!
Sinatra has matured to 1.0! The milestone release includes support for Tilt and an extension API.

back to top
Posted 6 months ago at A Fresh Cup

Just a couple of links to close out the week.

back to top
Favorite
Posted 6 months ago at ones zeros majors and minors

I'm very happy to announce Mustache 0.9.0, probably the most major release so far. Sinatra 1.0, new parser, bugfixes, and more!

Grab it:

gem install mustache

Or check http://defunkt.github.com/mustache/ for other implementations.

Sinatra 1.0

The release of Sinatra 1.0 changed the way templates are rendered. As such, previous versions of Mustache use an old API and won't work with it.

If you're upgrading from Mustache 0.7.0 or lower please note that the settings have changed very slightly. This diff is an example of one app I upgraded to Sinatra 1.0 + Mustache 0.9 -- pretty painless, and the settings all have better names (finally).

Anyway, Mustache 0.9.0 works great with Sinatra 1.0 and even provides some big improvements:

Caching

The first time a Mustache template is rendered it is compiled into pure Ruby and cached, even if there's no associated view class. Subsequent calls use the cached version which completely bypasses the parsing and generating stages.

Overriding Content in Layouts

Previously there was no easy way to change the layout from a view class. Take this layout.mustache:

And these views:

class Layout < Mustache
  def title
    "layout"
  end
end

class Index < Layout
  def title
    "index"
  end
end

You'd expect it to work, and you'd hope it would work, but it would not. Now it does. Just make sure your views inherit from your layout and everything will be dandy.

Syntax Errors

More syntax errors are caught and the error messages are much more helpful thanks to the new parser (more on that below).

For example, here's a broken template:

And here's what we get trying to tokenize it:

Or take this broken template:

Again, helpful output:

Tag names are a bit more strict as they more closely resemble allowed Ruby method names, with a few exceptions. If you have a big problem with this please file an issue.

New Parser

Magnus Holm has once again torn Mustache's parser apart and rebuilt it into something beautiful. This time it's an entirely new scanner and generator.

Mustache used to loop through a template looking for regular expressions and building up a compiled Ruby string along the way. As a result we had some obscure bugs in nested sections and whatnot. The new parser uses Ruby's StringScanner to intelligently build an array of tokens from a string template.

Using the mustache command line utility we can see exactly what Mustache::Parser returns for a given template:

Pretty neat. Internally this token stream is handed to Mustache::Generator who compiles it into a Ruby string:

$ mustache -c hi.mustache
"#{if v = ctx[:greet?]
    if v == true
      "Hello #{CGI.escapeHTML(ctx[:name].to_s)}!"
    else
      v = [v] unless v.is_a?(Array) # shortcut when passed non-array
      v.map { |h|
        ctx.push(h)
        r = "Hello #{CGI.escapeHTML(ctx[:name].to_s)}!"
        ctx.pop
        r }.join
    end
  end}"

This compiled string is the actual code run in your app to produce HTML output. Fun to look at but mostly useless unless you're familiar with Mustache's internals.

Bugfixes

Recursive partials, nested sections with names matching outer sections, and other bugs are now fixed. Many bugs were fixed by the new parser.

Speedup

When we started to allow Ruby objects to server as section contexts, the implementation slowed down Mustache dramatically. That's been fixed and things are (when compiled and cached) once again speedy.

Mustache 1.0

This release would be 1.0 but there's no Rails integration. That's next on the list - see you then.

back to top

CoreyLib: PHP Universal API Wrapper:

The PHP world is filled with API and XML Parsers that often bring page rendering to a crawl.

Aaron Collegeman’s CoreyLib library is an incredibly simple universal API wrapper with caching built in.

It can handle most modern APIs with full XML, JSON, authentication, parameterization, xmlNode, and Xpath support. All requests can be cached in MySql and parsed at a custom interval to dramatically improve page rendering speed. It’s available as a zero-config WordPress plugin too.

Here’s all the code needed to get the latest 5 tweets from twitter:

[Source on GitHub] [Documentation]

Submitted by: Kenneth Reitz: Passionate open source web developer. Follow him on GitHub.

back to top
Posted 6 months ago at techno weenie - Home

I recently went through a process of consolidating a few backend miniapps that power some boring parts of Lighthouse and Tender. I upgraded one app to Sinatra 1.0, and converted another from Rails to Sinatra. The goal was to mount them in the same rack process, therefore simplifying the deployment process all around. Doing this reinforced Ryan’s sage advice about requiring rubygems in your libraries.

With libraries, it’s cake. Your gem requirements are light. No one is deploying your libraries as-is, so you can assume that any configuration is handled in their applications. I’m still struggling with tests a bit, however.

  1. Do not require rubygems (or rip, bundler, etc) in any files in lib or test.
  2. Do not mess with the load path either.

Applications are a different matter. These typically will be deployed, so some kind of configuration file is essential. I try to provide examples so coworkers can get up and running really quickly. My config files typically look something like this:

# config.rb
$LOAD_PATH << ... # for setting up the Sinatra app's `lib` path and any 
                  # vendored libraries

require 'rubygems' # you can replace this with Bundler, Rip, etc
gem 'sinatra', '~> 1.0.0'
gem ...

require 'my-sinatra-app'

Now, when I re-package these in a different setting (such as when I mash two Sinatra apps into the same Rack process), I have full control over the $LOAD_PATH and the loaded gem versions.

One pattern I’ve adopted for apps using Sequel is some kind of #load method. I had problems where my code was loading Sequel::Model instances before the database configuration was setup. Requiring these files first would access the non-existent database configuration and blow up.

# OLD
require 'my-app' # requires 'sequel' and 'my-app/foo_model'
Sequel.db = '...'

# NEW
require 'my-app'
MyApp.load do
  Sequel.db = '...'
end

# implementation
def self.load
  require 'sequel'
  yield
  require 'my-app/foo_model'
end

For what it’s worth, I’ve started using autoload more lately. That negates the problem completely.

# my-app.rb
require 'sequel'
module MyApp
  autoload :FooModel, 'my-app/foo_model'

# config.rb
require 'my-app'
Sequel.db = '...'
MyApp::FooModel.do_something

This is Sinatra-specific, but always subclass from Sinatra::Base. I opt for the classic Sinatra style a lot because it’s so convenient. But once I have something running and tested, I make it a full class.

  1. Using the classic style adds a lot of crufty methods to every object. This can cause problems in mid to large projects.
  2. You can easily isolate and test these Sinatra classes with Rack Test. Resque’s Server provides a good sample implementation with tests.
class MyAppTest < Test::Unit::TestCase
  include Rack::Test::Methods

  def app
    MyApp::Api # subclasses Sinatra::Base
  end

This problem also extends to libraries using Sinatra. At first, I couldn’t figure out why one of my older Sinatra apps still used the classic Sinatra DSL. I got my answer when I converted it: ClassyResources was including itself into main. I was not too pleased.

I’m assuming this code pre-dated Sinatra’s excellent extension API, so I spent an hour registering the modules as proper Sinatra extensions. I was glad I could focus my programmer rage into a good learning process.

My TwitterServer library serves as a good example of well-tested a Sinatra extension.

Following these guidelines, I was able to load both of the Sinatra apps together with a simple 3-line rackup file.

require 'config'
use MiniApp1
run MiniApp2

# thin -R config.ru start

My only suggestion if you come across crappy libraries that muck with your $LOAD_PATH is to fork away and push any patches upstream. Sorry in advance if it’s one of mine :)

What good libraries out there handle this poorly? Which ones are shining examples? How do you handle similar issues?

back to top
Posted 6 months ago at Tuxicity

In the past, when I was in a file that I wanted to rename, I either opened up a console or dired to rename it. I never thought about creating a function to make it simpler. But then I came across Steve Yegge's Emacs conf and found a function that did just that.

The function below is based on the one in Steve Yegge's Emacs conf. But there are a few improvements to it:

  1. File and directory completion
  2. Can move file to other directory
  3. Handles the case if Emacs is visiting a file and that file is removed
(defun rename-file-and-buffer ()
  "Renames current buffer and file it is visiting."
  (interactive)
  (let ((name (buffer-name))
        (filename (buffer-file-name)))
    (if (not (and filename (file-exists-p filename)))
        (message "Buffer '%s' is not visiting a file!" name)
      (let ((new-name (read-file-name "New name: " filename)))
        (cond ((get-buffer new-name)
               (message "A buffer named '%s' already exists!" new-name))
              (t
               (rename-file name new-name 1)
               (rename-buffer new-name)
               (set-visited-file-name new-name)
               (set-buffer-modified-p nil)))))))

I bound C-c r to the function:

(global-set-key (kbd "C-c r") 'rename-file-and-buffer)

back to top
Posted 6 months ago at MongoTips by John Nunemaker

The Mongo team just announced that 1.4 is released and officially production ready.

I have been following the development of this release quite closely as it contains several features I am excited about (and need in Harmony).

These are a just a few of the hot new features. Be sure to check out the Mongo blog post for more. You also may want to read the 1.4 release notes

back to top
Posted 6 months ago at Engine Yard Ruby on Rails Blog

Today’s blog post is by a guest community contributor, Rizwan Reza. Rizwan is an active member of the Rails community, and as of late, has been working to clean up the overgrown Lighthouse queue.

Stop! I’d like to tell you something important, but it may be a bit shocking, so you should probably have a seat. Here goes: everything you knew about working with routes in Rails 2… is history! With Rails 3, you’ve got to roll up your sleeves, unlearn what you learned, and route the new way around. And this time, it’s faster, cleaner and a lot more Ruby-like.

In this post, we’ll walk through the underpinnings of Routes in Rails 3. They’ve been rewritten—for good reason—and after we get through the explanation, I’m confident you’ll agree.

Let’s start by looking at some code; here’s the new DSL, in its full glory:

resources :products do
  resource :category
 
  member do
    post :short
  end
 
  collection do
    get :long
  end
end
 
match "/posts/github" => redirect("http://github.com/rails.atom")

Now check out the old way of doing it:

map.resources :products, :member => {:short => :post}, :collection => {:long => :get} do |products|
  products.resource :category
end

As you can see, the example from Rails 3 is much cleaner and more Rubyish. So let’s jump right in and walk through a quick overview of how you’d define different types of routes in Rails 3.

Default Route

The default route in Rails 3, match '/:controller(/:action(/:id))', is much more explicit, as the parenthesis denote optional parameters.

Regular Routes

Rather than defining different keys for controller and action, you just have catalog#view, which is pretty awesome.

match 'products/:id', :to => 'catalog#view'

In Rails 2, you would’ve done:

map.connect 'products/:id', :controller => 'products', :action => 'view'

Named Routes

Named Routes generate helpers like posts_url and posts_path, rather than manually defining the hash to action and controller in helper methods like link_to:

match 'logout', :to => 'sessions#destroy', :as => "logout"

The key :as specifies a name to generate helpers. In Rails 2, you would have done:

map.logout '/logout', :controller =&gt; 'sessions', :action =&gt; 'destroy'

Empty Route

The root of the web site is the empty route. Whereas Rails 2 added a nice shortcut to it, Rails 3 simplifies things even further:

# Rails 3
root :to => 'welcome#show'
 
# Rails 2
map.root :controller => "welcome", :action => 'show'

Shorthands

The revamped routes in Rails 3 sport some nice shortcuts to commonly used routes. There are two types of shorthands. First, the :to shorthand allows you to skip the :to key and directly designate the route to the matcher:

match "/account" => "account#index"
match "/info" => "projects#info", :as => "info"

Second, the match shorhand allows you to define a path and controller with its action at the same time:

match "account/overview"
 
# identical to
 
match "account/overview", :to => "account#overview"

Verb Routes

While you can limit a route to an HTTP request through :via, it’s a nice added convenience to have Verb routes. Adding sugar on top, you can even use shorthands with them:

get "account/overview"
 
# identical to
 
match "account/overview", :to => "account#overview", :via => "get"

Keys

The match method (as well as the verb shorthands) take a number of optional keys.

:as

The :as key names the route. You can then use named route helpers wherever url_for is available (such as controllers, tests, and mailers). Resource routes (using the resources helper) automatically create named routes, as in Rails 2.3.

match "account/overview/:id", :as => "overview"
 
# in your controller
 
overview_path(12) #=> "/account/overview/12"

:via

Allows you to specify a set of verbs, so only those HTTP requests are accepted for a route.

match "account/setup", :via => [:get, :post]

Rack

Rack is a sweet interface to web servers that provides unified API to Ruby frameworks. Most if not all Ruby frameworks are built on top of Rack these days. The recent built-in support for Rack means your application is not bound to being Rails specific. You can have parts of your application handled by any Rack supported framework, be it Sinatra, Cramp or something else. You can skip the Rails stack altogether and pass on the request to a Rack app.

Here’s an example of a Sinatra app:

class HomeApp < Sinatra::Base
  get "/" do
    "Hello World!"
  end
end
 
Rizwan::Application.routes do
  match "/home", :to => HomeApp
end

And here’s an example of a Rack app:

match "/foo", :to => proc {|env| [200, {}, ["Hello world"]] }
 
match 'rocketeer.js' => ::TestRoutingMapper::RocketeerApp
 
RocketeerApp = lambda { |env|
  [200, {"Content-Type" => "text/html"}, ["javascripts"]]
}

Resourceful Routes

Since Rails 1.2, resourceful routes have been the preferred way to use the router. Recognizing this fact, the Rails core team has added some nice improvements. Take a look at this typical RESTful route in Rails 3:

resources :products

This would generate all the neat helpers we have come to love and would also route the URLs accordingly. Just like before, you can also add multiple resources in a single line:

resources :products, :posts, :categories

More RESTful Actions

As you know, you’re not limited to the seven actions that RESTful architecture provides, but can also define more actions in a resource. Having said that, you might want to keep an eye open if you’re defining lots of actions in a single resource, as they can be turned into separate resources.

We can add RESTful actions to this resource in a couple of ways. Here’s a few collection RESTful actions inside a block:

resources :products do
  collection do
    get  :sold
    post :on_offer
  end
end

And take a look at this inline member RESTful action:

resources :products do
  get :sold, :on => :member
end

Not only that, but you can also redefine to extend the scope of the default seven RESTful actions:

resources :session do
  collection do
    get :create
  end
end

create actions, which usually only accepts POST requests, can now accept GET requests as well:

resource :session do
  get :create
end

Nested Resources

In Rails 2, nested resources were defined by a block or by using a :has_many or :has_one key. Both of these have been superseded by a block, giving them a more Rubyish interface to defining associated resources.

Here’s a route for a project that has many tasks and people:

resources :projects do
  resources :tasks, :people
end

Namespaced Resources

These are especially useful when defining resources in a folder; it doesn’t get much cleaner than this:

namespace :admin do
  resources :projects
end

Renaming Resources

You can also rename resources through the :as key. This code uses :as in resourceful routes to change the products path to devices:

namespace :forum do
  resources :products, :as => 'devices' do
    resources :questions
  end
end

Restricting Resources

Resources can be restricted to only specified actions.

resources :posts, :except => [:index]
 
resources :posts, :only => [:new, :create]

Altering Path Names

You can define a different path name for a particular REST action. This helps you customize your RESTful routes. This code will route /projects/1/cambiar to the edit action.

resources :projects, :path_names => { :edit => 'cambiar' }

The Redirect Method

The newly added redirect method in Rails 3 provides a level of convenience not present before. For example, it can redirect to any path given and eventually, can also pass on to a full-blown URI, something previously accomplished by Rails plugins like redirect_routing.

Moreover, the redirect method also introduces generic actions. Unique to Rails 3, generic actions are a simple way to provide the same action to complex paths, depending on what’s passed to redirect.

This code will redirect /foo/1 to /bar/1s:

match "/foo/:id", :to => redirect("/bar/%{id}s")

This code will redirect /account/proc/john to /johns.

match 'account/proc/:name', :to => redirect {|params| "/#{params[:name].pluralize}" }

Note that redirect cannot be used in a block as opposed to other constraints and scopes.

The Constraints Method

Constraints allow you to specify requirements for path segments in routes. Besides that, they also allow you to use a handful of methods to verify whether or not something matches a given criteria. Like a route that checks if the request is AJAX or not, for example.

In this code, we’re using a regular expression, and the route has been restricted to only allow one digit IDs to pass through:

match "/posts/show/:id", :to => "posts#index", :constraints => {:id => /\d/}

Scope

When the scope method is passed along a symbol, it assumes the symbol is a controller. When the argument is a string, the scope method prepends that string to the beginning of the path.

Scope can also have path_segments, which can be constrained, giving us greater flexibility in routes.

controller :articles do
  scope '/articles', :name_prefix => 'article' do
    scope :path => '/:title', :title => /[a-z]+/, :as => :with_title do
      match '/:id', :to => :with_id
    end
  end
end
 
scope :posts, :name_prefix => "posts" do
  match "/:action", :as => "action"
end
 
scope ':access_token', :constraints => { :access_token => /\w{5,5}/ } do # See constraint here
  resources :rooms
end

As you can see, when scope is given a string as its argument, it prepends to the path, something that was accomplished through path_prefix in Rails 2. name_prefix is essentially the same as before.

Optional Segments

Unlike all the previous versions of Rails, path segments can now be optional in routes. Optional segments don’t necessarily have to be path segments, which are passed as parameters to the action. The default route is a good example of optional segments in use. Here, both /posts/new and /posts will be redirected to the create action in posts controller, but /posts/edit will not work:

match 'posts(/new)', :to => 'posts#create'

This is an optional path scope that allows to have a prepended path before a resource:

scope '(:locale)', :locale => /en|pl/ do
  resources :descriptions
end

Pervasive Blocks

As evident from the examples, routes in Rails 3 exhibit pervasive blocks for almost all the methods you’d normally want to pass a block to, helping you achieve DRY in routes.rb.

controller :posts do
  match 'export', :to => :new, :as => :export_request
  match '/:action'
end

Right now, most Rails developers wouldn’t use all of these methods, but when the need arises—when you need to define more complex routes—you might appreciate having the above information handy. You don’t need to use a plugin or a hack when you know it’s built right in. With Rails 3, Routes rock at a whole new level.

Questions and comments welcome!

back to top