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

Blow Up Your Views

j3
September 22, 2011

Blow Up Your Views

Whether you're new to Rails or have been around few years, chances are that your views are primitive. Detonate what you know about how views are written and let's start over.

In this session you'll learn:

- Why your views suck
- Guidelines for view code quality
- Kill Helpers and work with Objects
- Instance Variables are Stupid
- Embracing Rails 3's intelligence
- JavaScript is not a four letter word

By the end you'll be dying to blow up your views.

j3

September 22, 2011
Tweet

More Decks by j3

Other Decks in Technology

Transcript

  1. 3 Templating is Hard ▪ HTML ▪ CSS ▪ JavaScript

    ▪ Ruby Thursday, September 22, 11
  2. 5 First, A Puzzle JkYmI2NGQ2ZGQ5ODVhMDRlODFJIhBfY3NyZl90b2tlbgY7AEZJIjE2TFNER1BrMXhBN0RVYzFVUkt3ek9GcnBM c29vUC9CVDF1aGs0UVJ4QUQ4PQY7AEY%3D--6d75dba5938dbe9ccd2201dd3288846e3a56f64e", "rack.request.cookie_hash"=>{"_jsblogger_session"=>"BAh7B0kiD3Nlc3Npb25faWQGOgZFRiIlZTFkNDRmYzBlYjBk NmJkYmI2NGQ2ZGQ5ODVhMDRlODFJIhBfY3NyZl90b2tlbgY7AEZJIjE2TFNER1BrMXhBN0RVYzFVUkt3ek9Gcn BMc29vUC9CVDF1aGs0UVJ4QUQ4PQY7AEY=--6d75dba5938dbe9ccd2201dd3288846e3a56f64e"}, "action_dispatch.cookies"=>{"_jsblogger_session"=>"BAh7B0kiD3Nlc3Npb25faWQGOgZFRiIlZTFkNDRmYzBlYjBk

    NmJkYmI2NGQ2ZGQ5ODVhMDRlODFJIhBfY3NyZl90b2tlbgY7AEZJIjE2TFNER1BrMXhBN0RVYzFVUkt3ek9Gcn BMc29vUC9CVDF1aGs0UVJ4QUQ4PQY7AEY=--6d75dba5938dbe9ccd2201dd3288846e3a56f64e"}, "action_dispatch.request.unsigned_session_cookie"=>{"session_id"=>"e1d44fc0eb0d6bdbb64d6dd985a04e81", "_csrf_token"=>"6LSDGPk1xA7DUc1URKwzOFrpLsooP/BT1uhk4QRxAD8="}, "action_dispatch.request.path_parameters"=>{:controller=>"articles", :action=>"index"}, "action_controller.instance"=>#<ArticlesController:0x007fc4f30d9098 ...>, "action_dispatch.request.content_type"=>nil, "action_dispatch.request.request_parameters"=>{}, "rack.request.query_string"=>"", "rack.request.query_hash"=>{}, "action_dispatch.request.query_parameters"=>{}, "action_dispatch.request.parameters"=>{"controller"=>"articles", "action"=>"index"}, "action_dispatch.request.formats"=>[text/html]}, @lookup_context=#<ActionView::LookupContext: 0x007fc4f30da330 @details_key=#<ActionView::LookupContext::DetailsKey:0x007fc4f4bf9120 @hash=-1525974507177383497>, @details={:handlers=>[:erb, :rjs, :builder, :rhtml, :rxml], :formats=>[:html], :locale=>[:en, :en]}, @skip_default_locale=false, @frozen_formats=true, @view_paths=[/Users/jcasimir/RubymineProjects/jsblogger/app/ views]>, @_action_name="index", @_response_body=nil, @_config={}, @_params={"controller"=>"articles", "action"=>"index"}, @articles=[#<Article id: 11, title: "Checking Time Distance", body: "Hi.", created_at: "2011-08-11 19:39:10", updated_at: "2011-08-12 18:03:16", active: true>, #<Article id: 10, title: "Composite Redirect/Flash", body: "Tada.....\r\n", created_at: "2011-08-11 15:01:31", updated_at: "2011-08-11 15:01:39", active: true>, #<Article id: 4, title: "Edited Sample 4", body: "Edited body again.....", created_at: "2011-08-10 19:22:44", updated_at: "2011-08-12 18:03:16", active: true>, #<Article id: 8, title: "Flash Tester", body: "Was it created?", created_at: "2011-08-11 14:35:58", updated_at: "2011-08-12 18:03:16", active: true>, #<Article id: 7, title: "Sampler Edited More!", body: "Here is the body.", created_at: "2011-08-11 13:51:32", updated_at: "2011-08-12 18:03:16", active: true>]>> self.inspect.length == 51496 Thursday, September 22, 11
  3. 7 Rails MVC, Reality Request Request Processing Data Formatting Database

    Router Response Data Interface Template Rendering Persistence Translation Business Logics Thursday, September 22, 11
  4. Data Interface 8 Controller supplies data to views Views format

    data via helpers Template injects data into HTML Generating HTML in Rails Template Rendering Data Formatting Thursday, September 22, 11
  5. Data Interface 10 The Cake is a Lie Interface A

    common means for unrelated objects to communicate with each other. These are definitions of methods and values which the objects agree upon in order to cooperate. Thursday, September 22, 11
  6. Data Interface 10 The Cake is a Lie The Controller

    and View template pretend to share context, but really the instance variables are just copied from one to another. Interface A common means for unrelated objects to communicate with each other. These are definitions of methods and values which the objects agree upon in order to cooperate. Thursday, September 22, 11
  7. Data Interface 10 The Cake is a Lie The Controller

    and View template pretend to share context, but really the instance variables are just copied from one to another. This is not an interface, it is tight coupling Interface A common means for unrelated objects to communicate with each other. These are definitions of methods and values which the objects agree upon in order to cooperate. Thursday, September 22, 11
  8. class ArticlesController < ApplicationController def index @articles = Article.order :created_at

    end def show @article = Article.find(params[:id]) end end %h1 Articles = render @articles 12 A Real Interface %h1= @article.title %p= @article.body Thursday, September 22, 11
  9. class ArticlesController < ApplicationController def index @articles = Article.order :created_at

    end def show @article = Article.find(params[:id]) end end %h1 Articles = render @articles 12 A Real Interface class ArticlesController < ApplicationController expose(:articles){ Article.order :created_at } expose(:article) def index end def show end end %h1= @article.title %p= @article.body Thursday, September 22, 11
  10. class ArticlesController < ApplicationController def index @articles = Article.order :created_at

    end def show @article = Article.find(params[:id]) end end %h1 Articles = render @articles 12 A Real Interface class ArticlesController < ApplicationController expose(:articles){ Article.order :created_at } expose(:article) def index end def show end end %h1 Articles = render articles %h1= @article.title %p= @article.body %h1= article.title %p= article.body Thursday, September 22, 11
  11. 13 Decent Exposure Wins ▪ Defined interface between views and

    controllers ▪ Simplifies much of the controller logic ▪ No more instance variable litter Thursday, September 22, 11
  12. Objects 15 ▪ In Ruby, “everything is an object” ▪

    In Rails, we use objects everywhere Thursday, September 22, 11
  13. Objects 15 ▪ In Ruby, “everything is an object” ▪

    In Rails, we use objects everywhere ▪ Then, at the very last minute, we get procedural? Thursday, September 22, 11
  14. Data Processing 16 ▪ Hypothetical: object-neutral data processing ▪ Ex:

    formatting timestamps for all models Thursday, September 22, 11
  15. Data Processing 16 ▪ Hypothetical: object-neutral data processing ▪ Ex:

    formatting timestamps for all models ▪ Reality: Object specific data processing ▪ Ex: Convert a user object to a printable name Thursday, September 22, 11
  16. Just Use Objects 17 = print_name(user) Instead of using helpers

    like this.... Thursday, September 22, 11
  17. Just Use Objects 17 = print_name(user) = user.print_name Instead of

    using helpers like this.... How about having model-like methods... Thursday, September 22, 11
  18. Just Use Objects 17 = print_name(user) = user.print_name = format_time(user.created_at)

    = user.created_at Instead of using helpers like this.... How about having model-like methods... Thursday, September 22, 11
  19. Data Formatting 18 Rails MVC, Reality Request Request Processing Database

    Router Response Data Interface Template Rendering Persistence Translation Business Logic Thursday, September 22, 11
  20. Data Formatting 18 Rails MVC, Reality Request Request Processing Database

    Router Response Data Interface Template Rendering Persistence Translation Business Logic Thursday, September 22, 11
  21. Decorator / Presenter 18 Rails MVC, Reality Request Request Processing

    Database Router Response Data Interface Template Rendering Persistence Translation Business Logic Thursday, September 22, 11
  22. Decorator Pattern 19 ▪ Take in a data model ▪

    Decorate it with view-specific methods Thursday, September 22, 11
  23. Decorator Pattern 19 ▪ Take in a data model ▪

    Decorate it with view-specific methods ▪ Make use of Rails helpers like link_to and content_tag Thursday, September 22, 11
  24. View Objects Implemented 20 ▪ Create an /app/decorators folder ▪

    Create object-specific decorator classes Thursday, September 22, 11
  25. View Objects Implemented 20 ▪ Create an /app/decorators folder ▪

    Create object-specific decorator classes ▪ Wrap the data object with the decorator Thursday, September 22, 11
  26. Solving Other Problems 21 ▪ Preparing alternate representations with to_xml

    and to_json while respecting authorization Thursday, September 22, 11
  27. Solving Other Problems 21 ▪ Preparing alternate representations with to_xml

    and to_json while respecting authorization ▪ Enforcing an interface, like attr_accessible for your views Thursday, September 22, 11
  28. 23 Draper <h1><%= product.title %></h1> <p><%= product.description %></p> <p><%= product.price

    %></p> <p><%= product.stock %></p> <p> <em>Updated:</em> <%= product.updated_at %> </p> <p><%= product.links %></p> Thursday, September 22, 11
  29. 24 Draper <h1><%= product.title %></h1> <p><%= product.description %></p> <p><%= product.price

    %></p> <p><%= product.stock %></p> <p> <em>Updated:</em> <%= product.updated_at %> </p> <p><%= product.links %></p> Thursday, September 22, 11
  30. 25 Draper class ProductsController < ApplicationController #... def show @product

    = ProductDecorator.find(params[:id]) end #... end Thursday, September 22, 11
  31. 26 Draper class ProductDecorator < ApplicationDecorator decorates :product def price

    number_to_currency(model.price) end def delete_link link_to "Destroy", self, :confirm => 'Are you sure?', :method => :delete end Thursday, September 22, 11
  32. 27 Draper :confirm => 'Are you sure?', :method => :delete

    end def edit_link link_to "Edit", edit_product_path(self) end def index_link link_to "View All", products_path end def stock if model.stock > 0 content_tag :span, "In Stock (#{model.stock})", :class => "in_stock" else content_tag :span, "Out of Thursday, September 22, 11
  33. 28 Draper end end def to_json(*args) {:title => model.title, :price

    => price, :stock => stock, :description => model.description, :created_at => created_at, :updated_at => updated_at, :edit => edit_link, :delete => delete_link, :index => index_link }.to_json end end Thursday, September 22, 11
  34. 29 Draper <h1><%= product.title %></h1> <p><%= product.description %></p> <p><%= product.price

    %></p> <p><%= product.stock %></p> <p> <em>Updated:</em> <%= product.updated_at %> </p> <p><%= product.links %></p> Thursday, September 22, 11
  35. 33 Traditional Sequence Request Router Controller Data Formatting Template Rendering

    JavaScript Processing Model Database JS Assets Response Client Server Time Thursday, September 22, 11
  36. 34 ▪ Controller provides a defined interface ▪ Decorator layer

    consumes data, prepares formatted output Splitting Responsibilities Thursday, September 22, 11
  37. 34 ▪ Controller provides a defined interface ▪ Decorator layer

    consumes data, prepares formatted output ▪ Client receives decorated JSON and a template in HTML/JavaScript Splitting Responsibilities Thursday, September 22, 11
  38. 34 ▪ Controller provides a defined interface ▪ Decorator layer

    consumes data, prepares formatted output ▪ Client receives decorated JSON and a template in HTML/JavaScript ▪ Client renders the template with the data Splitting Responsibilities Thursday, September 22, 11
  39. 35 Client Side Rendering Request Router Controller JS Template JS

    Assets JavaScript Processing Model Database Data Response JS Template Client Server JS Assets Time Thursday, September 22, 11
  40. Time 38 Client-Side Rendering with Flushing Request Router Controller JS

    Assets Data Formatting Asset Response JavaScript Processing Model Database JS Template Data Response Template Response Client Server Thursday, September 22, 11
  41. ▪ Write interface methods in the Controller that... 39 How

    do we do it? Thursday, September 22, 11
  42. ▪ Write interface methods in the Controller that... ▪ Retrieve

    data from the model 39 How do we do it? Thursday, September 22, 11
  43. ▪ Write interface methods in the Controller that... ▪ Retrieve

    data from the model ▪ Render out JSON 39 How do we do it? Thursday, September 22, 11
  44. ▪ Write interface methods in the Controller that... ▪ Retrieve

    data from the model ▪ Render out JSON ▪ Pass to the client 39 How do we do it? Thursday, September 22, 11
  45. ▪ Write interface methods in the Controller that... ▪ Retrieve

    data from the model ▪ Render out JSON ▪ Pass to the client ▪ A rendering engine 39 How do we do it? Thursday, September 22, 11
  46. ▪ Write interface methods in the Controller that... ▪ Retrieve

    data from the model ▪ Render out JSON ▪ Pass to the client ▪ A rendering engine ▪ The template 39 How do we do it? Thursday, September 22, 11
  47. ▪ Write interface methods in the Controller that... ▪ Retrieve

    data from the model ▪ Render out JSON ▪ Pass to the client ▪ A rendering engine ▪ The template ▪ The data 39 How do we do it? Thursday, September 22, 11
  48. ▪ Plain HTML with jQuery Replacement ▪ Mustache ▪ Handlebars

    (SproutCore) 40 Rendering Engine? Thursday, September 22, 11
  49. ▪ Plain HTML with jQuery Replacement ▪ Mustache ▪ Handlebars

    (SproutCore) ▪ ICanHazJS (seriously) 40 Rendering Engine? Thursday, September 22, 11
  50. ▪ Less processing work on the server side means more

    requests per second 41 Achievements Thursday, September 22, 11
  51. ▪ Less processing work on the server side means more

    requests per second ▪ Parallelizing database access with asset feeding speeds up time to first response 41 Achievements Thursday, September 22, 11
  52. ▪ Less processing work on the server side means more

    requests per second ▪ Parallelizing database access with asset feeding speeds up time to first response ▪ Views become API customers, unifying the data interface 41 Achievements Thursday, September 22, 11
  53. ▪ Instance variables are stupid, use a proper interface ▪

    Kill helpers and use decorator objects ▪ Unify controllers and treat views as API customers ▪ Use JavaScript to render templates on the client 42 Blow Up Your Views Jeff Casimir / @j3 Thursday, September 22, 11