Download - Rails Gems realize RESTful modeling patterns
Rails Gems realize RESTful modeling patterns@tkawaRubyKaigi 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 2006June 11, 2006
# config/routes.rbFoobar::Application.routes.draw do resources :usersend
resources :users
GET /users users#indexPOST /users users#createGET /users/new users#newGET /users/:id/edit users#editGET /users/:id users#showPUT /users/:id users#updateDELETE /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...
SimpleConsistentTo reap the benefits of HTTP (“HTTP way”)
Generally:
Easy to designEasy to understand
On Rails “resources” particularly:
“resources” makes iteasy 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 iteasy 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 iteasy to design & understand
Rails has demonstrated thatthis simplicity goes well“Constraints are liberating”
You might think it does not go well in these cases:
AuthenticationSearchState changesExecution of procedural operationOperation to a list / SortWizard / Confirmation page
AuthenticationSearchState changesExecution of procedural operationOperation to a list / SortWizard / 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 iteasy to design & understand
A pattern makes iteasy 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
AuthenticationSearchState changesExecution of procedural operationOperation to a list / SortWizard / Confirmation page
Authentication
“Sign in” / “Sign out”Those are represented as what?
devise.plataformatec.com.br
Deviseby Plataformatec
GET /users/sign_in devise/sessions#newPOST /users/sign_in devise/sessions#createDELETE /users/sign_out devise/sessions#destroy…
# config/routes.rbdevise_for :users
“Sessions” is a resource(that doesn’t involve a model)
GET /users/sign_in devise/sessions#newPOST /users/sign_in devise/sessions#createDELETE /users/sign_out devise/sessions#destroy…
# config/routes.rbdevise_for :users
Session is singular
Only one “authentication session” for each user
Session Resource patternProposal
GET /sessionPUT(POST) /session →sign inDELETE /session →sign out
rest-pattern.hatenablog.com/entry/session-resource
Singular resource in Rails
resources :usersresource :user
resource :session
POST /session sessions#createGET /session/new sessions#newGET /session/edit sessions#editGET /session sessions#showPUT /session sessions#updateDELETE /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 destroyThis is also a pattern
Authlogic
github.com/binarylogic/authlogic
by Ben Johnson of Binary Logic
# app/models/session.rbclass Session < Authlogic::Session::Baseend
# app/models/session.rbclass Session < Authlogic::Session::Baseend
If they have no model, let them create it.(not an ActiveRecord)
# app/controllers/sessions_controler.rbclass 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 endend
resource :session
Rails way!!
I wish Devise were like that...I’m planning to do this...
AuthenticationSearchState changesExecution of procedural operationOperation to a list / SortWizard / 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]=tkawaGET /users?q[created_at_lt]=2013-01-01
Search from collection= Filtering
Filtered Collection patternProposal
/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: /\A\d{4}-\d{2}-\d{2}\Z/ }, q: { length: { maximum: 20 } } ) end end helper_method :filter_paramsend
github.com/tkawa/collection_filter
Query parameters like models
AuthenticationSearchState changesExecution of procedural operationOperation to a list / SortWizard / Confirmation page
Wizard
Enter data in multiple steps with page transitions
Wickedby Richard Schneeman
github.com/schneems/wicked
GET /user_steps/personalPUT /user_steps/personalGET /user_steps/socialPUT /user_steps/socialGET /user_steps/finish
Partial Resource patternProposal
/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 patternProposal
POST /transactionsPUT /transactions/123PUT /transactions/123/committed
rest-pattern.hatenablog.com/entry/transaction-resource
Rest of patterns are...Proposal
Filtered SubresourceMulti-member ResourcePrivate Resource / Private NamespaceImplicit 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 possibleLet'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