Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The Plataformatec Way - by José Valim on Frozen...

The Plataformatec Way - by José Valim on Frozen Rails 2010

Plataformatec

March 08, 2012
Tweet

More Decks by Plataformatec

Other Decks in Technology

Transcript

  1. José Valim @josevalim blog.plataformatec.com Test Driven Development Talk with the

    client Deploy to staging Launch Maintenance Test Driven Development Talk with the client Deploy to staging Launch Maintenance Test Driven Development Talk with the client Deploy to staging Launch Maintenance Test Driven Development Talk with the client Deploy to staging Launch Maintenance Test Driven Development Talk with the client Deploy to staging Launch Maintenance Test Driven Development Talk with the client Deploy to staging Launch Maintenance Test Driven Development Talk with the client Deploy to staging Launch Maintenance Test Driven Development Talk with the client Deploy to staging Launch Maintenance Test Driven Development Talk with the client Deploy to staging Launch Maintenance
  2. José Valim @josevalim blog.plataformatec.com SUMMER 2009 AUTHLOGIC CLEARANCE ! Model

    logic ! Configurable ! Several roles ! Engine (MVC) ! Not flexible
  3. José Valim @josevalim blog.plataformatec.com SUMMER 2009 AUTHLOGIC CLEARANCE ! Model

    logic ! Configurable ! Several roles ! Engine (MVC) ! Not flexible ! Opinionated
  4. José Valim @josevalim blog.plataformatec.com SUMMER 2009 AUTHLOGIC CLEARANCE ! Model

    logic ! Configurable ! Several roles ! Engine (MVC) ! Not flexible ! Opinionated
  5. José Valim @josevalim blog.plataformatec.com SUMMER 2009 AUTHLOGIC CLEARANCE ! Model

    logic ! Configurable ! Several roles ! Engine (MVC) ! Not flexible ! Opinionated
  6. José Valim @josevalim blog.plataformatec.com SUMMER 2009 AUTHLOGIC CLEARANCE ! Model

    logic ! Configurable ! Several roles ! Engine (MVC) ! Not flexible ! Opinionated
  7. José Valim @josevalim blog.plataformatec.com SUMMER 2009 AUTHLOGIC CLEARANCE ! Model

    logic ! Configurable ! Several roles ! Engine (MVC) ! Not flexible ! Opinionated
  8. José Valim @josevalim blog.plataformatec.com DEVISE class User < ActiveRecord::Base devise

    :database_authenticatable, :validatable, :recoverable, :rememberable, :remember_for => 2.weeks end
  9. José Valim @josevalim blog.plataformatec.com class User < ActiveRecord::Base devise :database_authenticatable,

    :validatable, :recoverable, :rememberable, :remember_for => 2.weeks end You can choose each module/behavior to include DEVISE
  10. José Valim @josevalim blog.plataformatec.com class User < ActiveRecord::Base devise :database_authenticatable,

    :validatable, :recoverable, :rememberable, :remember_for => 2.weeks end Lots of configuration options for each module DEVISE
  11. José Valim @josevalim blog.plataformatec.com class User < ActiveRecord::Base devise :database_authenticatable,

    :validatable, :recoverable, :rememberable, :remember_for => 2.weeks end class Admin < ActiveRecord::Base devise :database_authenticatable, :timeoutable, :lockable end DEVISE
  12. José Valim @josevalim blog.plataformatec.com # app/models/user.rb class User < ActiveRecord::Base

    devise :database_authenticatable, :validatable, :recoverable, :rememberable, :remember_for => 2.weeks end # config/routes.rb devise_for :users # app/controller/application_controller.rb before_filter :authenticate_user! DEVISE
  13. José Valim @josevalim blog.plataformatec.com ! Form, http and token authentication

    ! Registerable ! Recoverable ! Rememberable ! Trackable ! Lockable ! Timeoutable ! Validatable ! Confirmable * the ones in bold were present in the first release DEVISE
  14. José Valim @josevalim blog.plataformatec.com WARDEN (Warden is a Rack Authentication

    Framework) Rails Sinatra Middleware Middleware WARDEN Middleware ROUTER RAILS 3 APP
  15. José Valim @josevalim blog.plataformatec.com WARDEN (Warden is a Rack Authentication

    Framework) Rails Sinatra Middleware Middleware WARDEN Middleware ROUTER RAILS 3 APP Creates a env[‘warden’] proxy
  16. José Valim @josevalim blog.plataformatec.com WARDEN (Warden is a Rack Authentication

    Framework) Rails Sinatra Middleware Middleware WARDEN Middleware ROUTER RAILS 3 APP Creates a env[‘warden’] proxy authenticate_user!
  17. José Valim @josevalim blog.plataformatec.com WARDEN (Warden is a Rack Authentication

    Framework) Rails Sinatra Middleware Middleware WARDEN Middleware ROUTER RAILS 3 APP Creates a env[‘warden’] proxy authenticate_user! env[‘warden’].authenticate!
  18. José Valim @josevalim blog.plataformatec.com WARDEN (Warden is a Rack Authentication

    Framework) Rails Sinatra Middleware Middleware WARDEN Middleware ROUTER RAILS 3 APP Creates a env[‘warden’] proxy env[‘warden’].authenticate! authenticate_user! env[‘warden’].authenticate!
  19. José Valim @josevalim blog.plataformatec.com Devise is a Rack-based, flexible, full-stack

    authentication solution for Rails (including Rails 3) with support for several roles
  20. José Valim @josevalim blog.plataformatec.com 1) rails g devise_install Copy an

    initializer for application configuration and a locale file for I18n
  21. José Valim @josevalim blog.plataformatec.com 1) rails g devise_install Copy an

    initializer for application configuration and a locale file for I18n 2) rails g devise User Create a model, migration and routes. At this point, you can sign in, sign up and sign out
  22. José Valim @josevalim blog.plataformatec.com 1) rails g devise_install Copy an

    initializer for application configuration and a locale file for I18n 2) rails g devise User Create a model, migration and routes. At this point, you can sign in, sign up and sign out 3) rails g devise_views Copy the views from the engine to the application for customization
  23. José Valim @josevalim blog.plataformatec.com <%= form_for @user do |f| %>

    ... <div class="email"> <%= f.label :email, "Email Address" %> <% if error = @user.errors[:email].first %> <%= content_tag(:div, error, :class => "error") %> <% end %> <%= f.text_field :email %> <%= content_tag(:div, "Don’t worry.", :class => "hint") %> </div> ... <% end %> RAILS FORM BUILDER
  24. José Valim @josevalim blog.plataformatec.com - form_for @user do |f| ...

    .email = f.label :email, "Email Address” - if error = @user.errors[:email].first .error= error = f.text_field :email .hint= "Don’t worry." ... RAILS FORM BUILDER + HAML
  25. José Valim @josevalim blog.plataformatec.com <%= simple_form_for @user do |f| %>

    ... <%= f.input :email %> ... <% end %> SIMPLE FORM
  26. José Valim @josevalim blog.plataformatec.com <%= f.input :email %> Gets the

    type from the database Handle error messages by default
  27. José Valim @josevalim blog.plataformatec.com <%= f.input :email %> Gets the

    type from the database Handle error messages by default Labels and hints are retrieved from I18n API
  28. José Valim @josevalim blog.plataformatec.com <%= f.input :email, :as => :string,

    :label => “Email address”, :hint => “Don’t worry” %>
  29. José Valim @josevalim blog.plataformatec.com SimpleForm.setup do |config| config.components = [

    :label, :error, :input, :hint ] config.hint_tag = :span config.error_tag = :span config.wrapper_tag = :div end
  30. José Valim @josevalim blog.plataformatec.com <%= f.input :email %> <div class="string

    required"> <label class="string required" for="user_email">E-mail <abbr title="required">*</abbr></label> <span class="error">Invalid e-mail address</span> <input class="string required" id="user_email" maxlength="255" name="user[email]" type="text" value=""> <span class="hint">Don't worry</span> </div>
  31. José Valim @josevalim blog.plataformatec.com SIMPLE FORM Mapping Input Column boolean

    check box boolean string text field string email email field string matching email url url field string matching url password password field string matching password text text area text file file field string respond to file methods hidden hidden field - numeric text field integer/float/decimal datetime date/time select datetime/data/time/timestamp association select/radio/check box associations country country select string matching country time_zone time zone select string matching time_zone
  32. José Valim @josevalim blog.plataformatec.com SIMPLE FORM Mapping Input Column boolean

    check box boolean string text field string email email field string matching email url url field string matching url password password field string matching password text text area text file file field string respond to file methods hidden hidden field - numeric text field integer/float/decimal datetime date/time select datetime/data/time/timestamp association select/radio/check box associations country country select string matching country time_zone time zone select string matching time_zone html5!
  33. José Valim @josevalim blog.plataformatec.com SimpleForm makes forms easy by providing

    a clean DSL (based on Formtastic) with no opinion on markup
  34. José Valim @josevalim blog.plataformatec.com rails g simple_form_install Copy an initializer

    for application configuration, a locale file for I18n and a generator template
  35. José Valim @josevalim blog.plataformatec.com rails g simple_form_install Copy an initializer

    for application configuration, a locale file for I18n and a generator template what?
  36. José Valim @josevalim blog.plataformatec.com $ rails g simple_form_install create config/initializers/simple_form.rb

    create config/locales/simple_form.en.yml create lib/templates/erb/scaffold/_form.html.erb
  37. José Valim @josevalim blog.plataformatec.com $ rails g simple_form_install create config/initializers/simple_form.rb

    create config/locales/simple_form.en.yml create lib/templates/erb/scaffold/_form.html.erb initializer
  38. José Valim @josevalim blog.plataformatec.com $ rails g simple_form_install create config/initializers/simple_form.rb

    create config/locales/simple_form.en.yml create lib/templates/erb/scaffold/_form.html.erb initializer locale
  39. José Valim @josevalim blog.plataformatec.com $ rails g simple_form_install create config/initializers/simple_form.rb

    create config/locales/simple_form.en.yml create lib/templates/erb/scaffold/_form.html.erb initializer locale generator template
  40. José Valim @josevalim blog.plataformatec.com Whenever the scaffold needs to generate

    a _form.html.erb, it will now use the template at lib/templates/erb/scaffold/_form.html.erb
  41. José Valim @josevalim blog.plataformatec.com <%% simple_form_for(@<%= singular_name %>) do |f|

    %> <div class="inputs"> <%- attributes.each do |attribute| -%> <%%= f.input :<%= attribute.name %> %> <%- end -%> </div> <div class="actions"> <%%= f.button :submit %> </div> <%% end %> LIB/TEMPLATES/ERB/SCAFFOLD/_FORM.HTML.ERB
  42. José Valim @josevalim blog.plataformatec.com RAILS 2.3 def index @users =

    User.all respond_to do |format| format.html # index.html.erb format.xml { render :xml => @users } end end
  43. José Valim @josevalim blog.plataformatec.com RAILS 3.0 respond_to :html, :xml def

    index @users = User.all respond_with(@users) end Navigational format
  44. José Valim @josevalim blog.plataformatec.com RAILS 3.0 respond_to :html, :xml def

    index @users = User.all respond_with(@users) end Navigational format API format
  45. José Valim @josevalim blog.plataformatec.com def index @users = User.all respond_to

    do |format| format.html # index.html.erb format.xml { render :xml => @users } end end
  46. José Valim @josevalim blog.plataformatec.com def create @user = User.new(params[:user]) respond_to

    do |format| if @user.save format.html { redirect_to @user, :notice => 'User was successfully created' } format.xml { render :xml => @user, :status => :created, :location => @user } else format.html { render :action => "new" } format.xml { render :xml => @user.errors, :status => :unprocessable_entity } end end end RAILS 2.3
  47. José Valim @josevalim blog.plataformatec.com RAILS 3.0 def create @user =

    User.new(params[:user]) flash[:notice] = 'User was successfully created' if @user.save respond_with(@user) end
  48. José Valim @josevalim blog.plataformatec.com Navigational API GET GET render template

    render collection.to_format POST Success redirect_to resource render resource.to_format POST Failure render :new render resource.errors PUT PUT DELETE DELETE
  49. José Valim @josevalim blog.plataformatec.com Navigational API GET GET render template

    render collection.to_format POST Success redirect_to resource render resource.to_format POST Failure render :new render resource.errors PUT Success redirect_to resource head :ok PUT Failure render :edit render resource.errors DELETE DELETE redirect_to collection head :ok
  50. José Valim @josevalim blog.plataformatec.com respond_with(@users) ActionController::Responder Navigational API GET GET

    render template render collection.to_format POST Success redirect_to resource render resource.to_format POST Failure render :new render resource.errors PUT Success redirect_to resource head :ok PUT Failure render :edit render resource.errors DELETE DELETE redirect_to collection head :ok
  51. José Valim @josevalim blog.plataformatec.com respond_with(@users) ActionController::Responder Navigational API GET GET

    render template render collection.to_format POST Success redirect_to resource render resource.to_format POST Failure render :new render resource.errors PUT Success redirect_to resource head :ok PUT Failure render :edit render resource.errors DELETE DELETE redirect_to collection head :ok
  52. José Valim @josevalim blog.plataformatec.com respond_with(@users) ActionController::Responder Navigational API GET GET

    render template render collection.to_format POST Success redirect_to resource render resource.to_format POST Failure render :new render resource.errors PUT Success redirect_to resource head :ok PUT Failure render :edit render resource.errors DELETE DELETE redirect_to collection head :ok table.to_code
  53. José Valim @josevalim blog.plataformatec.com a) Sit and cry b) *facepalm*

    c) Kill the client d) Create your own responder RAILS 3.0
  54. José Valim @josevalim blog.plataformatec.com Navigational API GET GET render template

    render collection.to_format POST Success redirect_to resource render resource.to_format POST Failure render :new render resource.errors PUT Success redirect_to resource head :ok PUT Failure render :edit render resource.errors DELETE DELETE redirect_to collection head :ok
  55. José Valim @josevalim blog.plataformatec.com Navigational API GET GET render template

    render collection.to_format POST Success redirect_to resource render resource.to_format POST Failure render :new render resource.errors PUT Success redirect_to resource head :ok PUT Failure render :edit render resource.errors DELETE DELETE redirect_to collection head :ok
  56. José Valim @josevalim blog.plataformatec.com Navigational API GET GET render template

    render collection.to_format POST Success redirect_to collection render resource.to_format POST Failure render :new render resource.errors PUT Success redirect_to collection head :ok PUT Failure render :edit render resource.errors DELETE DELETE redirect_to collection head :ok
  57. José Valim @josevalim blog.plataformatec.com RAILS 3.0 # app/controllers/users_controller.rb def create

    @user = User.new(params[:user]) flash[:notice] = 'User was successfully created' if @user.save respond_with(@user) end
  58. José Valim @josevalim blog.plataformatec.com RAILS 3.0 + RESPONDERS # app/controllers/users_controller.rb

    def create @user = User.new(params[:user]) @user.save respond_with(@user) end # config/locales/en.yml en: flash: users: create: success: “User was successfully created”
  59. José Valim @josevalim blog.plataformatec.com # config/locales/en.yml en: flash: actions: create:

    success: “%{resource_name} was successfully created” users: create: success: “User has a different message” default messages
  60. José Valim @josevalim blog.plataformatec.com API REQUESTS find resource 1 CLIENT

    SERVER GET /posts/1.xml HTTP 1.1 200 OK <post> <title>Rails 3 rocks</title> ... </post> find resource GET /posts/1.xml 2 3 4 5 6 HTTP 1.1 200 OK <post> <title>Rails 3 rocks</title> ... </post>
  61. José Valim @josevalim blog.plataformatec.com HTTP CACHE find resource 1 CLIENT

    SERVER GET /posts/1.xml HTTP 1.1 200 OK Last-Modified: Mon, 17 Apr 2010 14:00:00 GMT <post> <title>Rails 3 rocks</title> ... </post> find resource and check data GET /posts/1.xml If-Modified-Since: Mon, 17 Apr 2010 14:00:00 GMT HTTP 1.1 304 Not Modified 2 3 4 5 6
  62. José Valim @josevalim blog.plataformatec.com RESPONDERS ! FlashResponder ! HTTPCacheResponder !

    Configures scaffold generator to use respond_with by default
  63. José Valim @josevalim blog.plataformatec.com class AppResponder < ActionController::Responder include Responders::FlashResponder

    include Responders::HttpCacheResponder end ApplicationController.responder = AppResponder
  64. José Valim @josevalim blog.plataformatec.com ! Model specs ! Controller specs

    ! Routings specs ! View specs ! Helpers specs THE RSPEC WAY
  65. José Valim @josevalim blog.plataformatec.com The Rspec way is to test

    each layer in isolation (using mocks and stubs) and wire them in integration tests
  66. José Valim @josevalim blog.plataformatec.com ! Requires extensive use of mocks

    and stubs ! Skinny controllers, fat models CONTROLLER SPECS
  67. José Valim @josevalim blog.plataformatec.com ! Requires extensive use of mocks

    and stubs ! Skinny controllers, fat models ! respond_with CONTROLLER SPECS
  68. José Valim @josevalim blog.plataformatec.com ! Requires extensive use of mocks

    and stubs ! Skinny controllers, fat models ! respond_with ! In a Rack world, testing the controller in isolation is limited. No session, no authentication, etc CONTROLLER SPECS
  69. José Valim @josevalim blog.plataformatec.com ! Model specs ! Controller specs

    ! Routings specs ! View specs ! Helpers specs the way
  70. José Valim @josevalim blog.plataformatec.com resources :posts do resources :comments end

    get "/posts(/:year(/:month(/:day)))" => "posts#index" No need to test this
  71. José Valim @josevalim blog.plataformatec.com resources :posts do resources :comments end

    get "/posts(/:year(/:month(/:day)))" => "posts#index" No need to test this You may want to test this one
  72. José Valim @josevalim blog.plataformatec.com ! Model specs ! Controller specs

    ! Routings specs? ! View specs ! Helpers specs the way
  73. José Valim @josevalim blog.plataformatec.com config.generators do |g| g.test_framework :rspec, :controller_specs

    => false, :view_specs => false, :routing_specs => false end the way Integration tests +
  74. José Valim @josevalim blog.plataformatec.com We don’t use Cucumber unless the

    client is technical and would like to read/create Cucumber stories
  75. José Valim @josevalim blog.plataformatec.com story "As an user..." do background

    do sign_up "josevalim" end scenario "account already confirmed" do visit user_projects_url(@user) # ... end end
  76. José Valim @josevalim blog.plataformatec.com story "As an user..." do background

    do sign_up "josevalim" end scenario "account already confirmed" do visit user_projects_url(@user) # ... end end DSL to assist tests
  77. José Valim @josevalim blog.plataformatec.com ! Provides the same nice DSL

    as Webrat ! Allows you to run tests with Rack-Test, Selenium (Firefox, IE or Google Chrome) and Celerity (aka HtmlUnit) CAPYBARA
  78. José Valim @josevalim blog.plataformatec.com ! Provides the same nice DSL

    as Webrat ! Allows you to run tests with Rack-Test, Selenium (Firefox, IE or Google Chrome) and Celerity (aka HtmlUnit) ! Limited access to request and response objects CAPYBARA
  79. José Valim @josevalim blog.plataformatec.com fill_in "Username", :with => "josevalim" fill_in

    "Password", :with => "sekret" select "Frozen Rails", :from => "Event" click_button "Sign up!" CAPYBARA
  80. José Valim @josevalim blog.plataformatec.com A tool-chain which helps bootstrapping and

    at the same time provides a solid foundation for customizations and extensions