Skip to content

Instantly share code, notes, and snippets.

@teamon
Created February 10, 2012 19:14
Show Gist options
  • Save teamon/1791857 to your computer and use it in GitHub Desktop.
Save teamon/1791857 to your computer and use it in GitHub Desktop.

I've been using Ruby on Rails framework for four year now, and I've seen how it changed during that time. Play 2.0 is on its way to become really nice piece of software. I read play wiki and have some thoughts about it in contrast to Ruby on Rails.

I'm not saying that play sucks because it's not rails, and that it should copy everything from it (please don't!). All I want to share is that some concepts were already proven by many people over the years, and there is no point in going through that again.

So here are my thoughts:

Routing

Rails conventions are havily based on RESTful resources. While play routes are similar to Rails' there are few differencies:

  • rails uses dsl written in ruby, play has custom file format (why not scala dsl?)
  • play allows to define one route at a time, like: METHOD PATH ACTION while rails has some helpers that simplfy common cases

Rails routing syntax basics:

# Simplest match, /users/1 will route to users_controller.show with param :id = 1
match "/users/:id" => "users#show"

# Instead of 'match', you can specify http method
get "/foo" => "foo#get_bar"
post "/foo" => "foo#post_bar"
# etc...

Resource routes:

resources :users

will generate 7 routes:

GET     /users            UsersController#index
GET     /users/:id        UsersController#show
POST    /users            UsersController#create
PUT     /users/:id        UsersController#update
DELETE  /users/:id        UsersController#destroy
GET     /users/new        UsersController#new
GET     /users/:id/edit   UsersController#edit

time has shown that people were in fact writing all those routes by themself, but with different names and paths. Having one standard way of creating CRUD controller not only cleans up code, but also makes it easier to maintain. Every Rails programmer knows this convention and sticks with it, so there are no surprises when looking at other people's code. Of course, this is not a silver bullet and it is impossible to build whole application with routes like above.

resources :users do collection do get :active end

 member do
   get :profile
 end

end

leads to:

GET   /users/active       UsersController#active
GET   /users/:id/profile  UsersController#profile

Other very useful feature of rails routing is namespacing. Consider this example:

namespace :api do
  resources :users
end

This will create 7 routes as described before, but prefixed with "/api/" and pointing to Api::UsersController. Again, simple convention that saves few keystrokes and increases readability. ('namespace' feature would probably be easier to implement using scala dsl).

Resources can also be nested:

resources :users do
  resources :comments
end

Will create:

GET   /users/:user_id/comments      CommentController#index
GET   /users/:user_id/comments/:id  CommentController#show
etc...

(from my experience, this is really handy)

Other interesting feature of rails routes are optional parameters:

match "/posts(/:id)" => "posts#show"

This will match both /posts and /posts/5 paths. From play perspective, this could be simply handled with Option[T] function argument.

Other usage of optional parameters:

match "/users/:id(.:format)" => "users#show"

In Rails, :format default to "html", and is havily used when creating responses (I'll talk about that later). This route will match e.g. /users/1 (format=html), /users/1.json (format=json), /users/1.xml (format=xml) etc.

Btw, why not make routing staticly typed? If there is a function def show(id: Int) it would be only valid if :id parameter was Int (early validation of incomming requests)

Rails routing is simple yet powerfull, even allowing routes like

match "/some_legacy_route" => redirect("/new_route")

Every modern ruby web framework is based on rack - small alyer that is interface between various servers and web frameworks. It introduces to the ruby world concept of middlewares and mountable engines - mulitple applications running at different path, sharing common data.

Request parameters

Rails takes care of incommint request body. By default it will parse it as form data, but if request have Content-Type header it will try to parse json or xml. On the user side, there is only one nested hash - params and one action can work with all kinds of input data without having to explicitly define type of request body.

Views

Play has hardcoded own templating engine, that may be good for java developers, but surely is "from 2006" for ruby community. At the beginning, rails used ERB: <div><%= some_ruby %></div>. It worked, but wasn't good enough. Nowedays, after few years of trying different approaches HAML is happen to be the choice of most rails programmers. What's most important, rails itself doesn't really care what do you use. And you can you both erb and haml in one application (or other templating launguage). Rails simply just look at the filename, and when it finds something like "index.html.erb" it checks if there is registered "erb" processor and creates "index.html" file using that processor. Same think with "index.html.haml" or "index.html.your_processor". Again, simple convention that simplifies a lot. You could even have "index.xml.builder" - processed with xml builder library.

This also applies to assets, but this will be next point of my message.

Rendering

in rails there are several ways of creating response:

render "template_name"      # well, render the template
render :json => {:foo => 1} # render some json, sets correct Content-Type
render :xml => {:bar => 2}  # render some xml, sets correct Content-Type

One magical method in rails is respond_to

def index
  posts = get_posts_from_database
  respond_with(posts)
end

this one takes care of :format request parameter and will render html, json, xml or any other registered format - internally rails calls "to_FORMAT" method on provided object, but I think that could be resolved with proper typeclasses

Assets

I've noticed that play 2.0 has hardcoded coffeescript and lesscsss support. This is similar case as with rendering templates. Rails uses the same convention: "myapp.js.coffee" -> "myapp.js", "style.css.sass" -> "style.css". Exactly the same behavior - register processor and that's it.

Rails 3.1 introduced assets pipeline, that could be simply described as:

  • process all js/css files (with coffee, sass, less, etc)
  • put it in one big application.js/css file
  • compress!
  • attach timestamp to result

In development mode, you could see tens on <script src="..."> tags, but in production environment you will see only one with application-TIMESTAMP_HASH.js - minified (optionally gzipped).

Easy, easy to server, easy to cache.

(It also allows serving assets from 3rd party plugins)

EOF

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment