Rails Gems realize RESTful
modeling patterns
@tkawa
RubyKaigi 2013, June 1
@tkawa
Ruby programmer (2000-)*
RESTafarian (2005-)
inspired by @yohei
Rails programmer (2006-)*
Sendagaya.rb (2012-)
Toru KAWAMURA
* with some blank of career
Sendagaya.rb 『千駄ヶ谷.rb』
Every Monday 19:00 - 21:30
Sendagaya.rb
Organized by @ppworks, @fukajun, and me
Concept: Looking forward to the weekly
meetup makes our everyday working fun
Held currently at Shinjuku(!?), formerly at
Sendagaya
#50 anniversary on June 3!
sendagayarb.github.io
Rails Gems realize RESTful
modeling patterns
@tkawa
Rails Gems realize RESTful
resource modeling patterns
@tkawa
Point of Departure
Rails is RESTful
Since RubyKaigi 2006
June 11, 2006
# config/routes.rb
Foobar::Application.routes.draw do
resources :users
end
resources :users
GET /users users#index
POST /users users#create
GET /users/new users#new
GET /users/:id/edit users#edit
GET /users/:id users#show
PUT /users/:id users#update
DELETE /users/:id users#destroy
$ rake routes
GET POST PUT DELETE
/users index create - -
/users/:id show - update destroy
in addition, “new” and “edit” as supplementary resources
resources :users
That’s it.
That makes for really simple design.
REST’s advantage is...
Simple
Consistent
To reap the benefits of
HTTP (“HTTP way”)
Generally:
Easy to design
Easy to understand
On Rails “resources”
particularly:
“resources” makes it
easy to design
For developer him/herself
“resources” decides on a resource form
All you have to do is to decide on a
resource name, such as “users”
/user/1 /users/1 /users/user/1 /users/user-1
“resources” makes it
easy to understand
For developer him/herself, co-developer,
and external developer (e.g. using API)
Suggest that there are corresponding
controller, model, view, etc, such as
UsersController, User model
“resources” makes it
easy to design & understand
Rails has demonstrated that
this simplicity goes well
“Constraints are liberating”
You might think it does not
go well in these cases:
Authentication
Search
State changes
Execution of procedural operation
Operation to a list / Sort
Wizard / Confirmation page
Authentication
Search
State changes
Execution of procedural operation
Operation to a list / Sort
Wizard / Confirmation page
How do I write routes.rb?
How about Controller? Model?
We need another technique.
But...
resources :users
GET POST PUT DELETE
/users index create - -
/users/:id show - update destroy
in addition, “new” and “edit” as supplementary resources
GET POST PUT DELETE
/users index create - -
/users/:id show - update destroy
This is a pattern
“resources” makes it
easy to design & understand
A pattern makes it
easy to design & understand
“resources” is the fundamental pattern
If there is a smaller and more concrete
pattern, we can design well accordingly
We want more (concrete)
patterns!
コストがかかるかもしれない問題解決を実際に行う
前の先行調査として大変役に立つ
パターンには名前がついていることが重要である。な
ぜなら、名前がついていることで問題や解決策を記
述したり、会話の中で取り上げたりすることができ
るようになるからである
ja.wikipedia.org/wiki/デザインパターン_(ソフトウェア)
A pattern is not a wild card,
but a card with many benefits
Using a pattern is similar
to Rails way, and...
We have “RubyGems”
Suppose a gem provides the
implementation of a specific pattern
Then routes.rb will be the description of
the patterns to be used
Discover the pattern
from RubyGems
Authentication
Search
State changes
Execution of procedural operation
Operation to a list / Sort
Wizard / Confirmation page
Authentication
“Sign in” / “Sign out”
Those are represented as what?
devise.plataformatec.com.br
Devise
by Plataformatec
GET /users/sign_in devise/sessions#new
POST /users/sign_in devise/sessions#create
DELETE /users/sign_out devise/sessions#destroy
…
# config/routes.rb
devise_for :users
“Sessions” is a resource
(that doesn’t involve a model)
GET /users/sign_in devise/sessions#new
POST /users/sign_in devise/sessions#create
DELETE /users/sign_out devise/sessions#destroy
…
# config/routes.rb
devise_for :users
Session is singular
Only one “authentication session” for
each user
Session Resource pattern
Proposal
GET /session
PUT(POST) /session →sign in
DELETE /session →sign out
rest-pattern.hatenablog.com/entry/session-resource
Singular resource in Rails
resources :users
resource :user
resource :session
POST /session sessions#create
GET /session/new sessions#new
GET /session/edit sessions#edit
GET /session sessions#show
PUT /session sessions#update
DELETE /session sessions#destroy
$ rake routes
GET POST PUT DELETE
/session show create update destroy
in addition, “new” and “edit” as supplementary resources
GET POST PUT DELETE
/session show create update destroy
This is also a pattern
Authlogic
github.com/binarylogic/authlogic
by Ben Johnson of Binary Logic
# app/models/session.rb
class Session < Authlogic::Session::Base
end
# app/models/session.rb
class Session < Authlogic::Session::Base
end
If they have no model, let them create it.
(not an ActiveRecord)
# app/controllers/sessions_controler.rb
class SessionsController < ApplicationController
# POST /session
def create
@session = Session.new(session_params)
if @session.save
flash[:notice] = "Login successful!"
redirect_back_or_default account_url
else
render :action => :new
end
end
end
resource :session
Rails way!!
I wish Devise were like that...
I’m planning to do this...
Authentication
Search
State changes
Execution of procedural operation
Operation to a list / Sort
Wizard / Confirmation page
Search
Search for users with the name that
contains “tkawa”
Search for users that were created before
2012
Ransack
github.com/ernie/ransack
by Ernie Miller
GET /users?q[name_cont]=tkawa
GET /users?q[created_at_lt]=2013-01-01
Search from collection
= Filtering
Filtered Collection pattern
Proposal
/users?role=admin
/users?since_id=123
/users?page=2
rest-pattern.hatenablog.com/entry/filtered-collection
Kaminari
github.com/amatsuda/kaminari
by Akira Matsuda
GET /users?page=2&per=10
I wish I could use query parameters
like models (w/ validation)...
class PostsController < ApplicationController
private
def filter_params # using strong parameters
@_filter_params ||= begin
params.default( # you can set default value
per: '10'
).permit(
:date, :q, :page, :per
).validate( # you can validate like a model
date: { format: /Ad{4}-d{2}-d{2}Z/ },
q: { length: { maximum: 20 } }
)
end
end
helper_method :filter_params
end
github.com/tkawa/collection_filter
Query parameters like models
Authentication
Search
State changes
Execution of procedural operation
Operation to a list / Sort
Wizard / Confirmation page
Wizard
Enter data in multiple steps with page
transitions
Wicked
by Richard Schneeman
github.com/schneems/wicked
GET /user_steps/personal
PUT /user_steps/personal
GET /user_steps/social
PUT /user_steps/social
GET /user_steps/finish
Partial Resource pattern
Proposal
/users/1/personal
/users/1/name,email
/users/1?fields=name,email
rest-pattern.hatenablog.com/entry/partial-resource
Provides only some attributes (fields)
to GET/PUT
Transaction Resource pattern
Proposal
POST /transactions
PUT /transactions/123
PUT /transactions/123/committed
rest-pattern.hatenablog.com/entry/transaction-resource
Rest of patterns are...
Proposal
Filtered Subresource
Multi-member Resource
Private Resource / Private Namespace
Implicit Collection
rest-pattern.hatenablog.com
Conclusion
RESTful patterns including “resources”
are significant
Focusing on these patterns encourages
good resource design
RubyGems are also useful for this purpose
If you are at a loss on
resource modeling...
Focus on gems’ pattern
You will come up with the right resource
by referring to the design of a good gem
“resources” is fundamental
Diverging from the “resources” is the
last resort
If you are creating a gem...
You should consider designing around
resources, if possible
Let's stick to the fundamentals of
“resources”
And your gem will realize a pattern!
Thank you for your attention.
Let me know if you discover
more patterns!
rest-pattern.hatenablog.com

Rails Gems realize RESTful modeling patterns