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

No More Dragons: Defeating the Darkness with Presenters

No More Dragons: Defeating the Darkness with Presenters

By Kevin Hopkins and Allison McMillan.

Feel like you need a sword and shield to tame your monstrous views? Rails is great when it comes to our opinionated model, view, controller pattern, but as your codebase grows, the view layer bloats to gigantic proportions. Presentation logic is riddled in models, model queries litter our views, and our helpers become a monolithic nightmare! There’s not much scarier than this conundrum - unmaintainable, disorganized spaghetti code - but wait, it’s hard to test! With presenters in our hilt, we can slay these problems until our codebase is at peace, and our castle is tested at safe again.

Fcb33b7af6bc3fa2890946410f154034?s=128

Allison McMillan

June 12, 2015
Tweet

Transcript

  1. @allie_p Defeating the Darkness with Presenters No More Dragons Allison

    McMillan @devneck Kevin Hopkins
  2. Allison Kevin

  3. None
  4. .row .large-12.columns %table %thead %tr %th ID %th Email %tbody

    %tr %td= @user.id %td= @user.email
  5. None
  6. .row .large-12.columns %table %tbody %tr %td= @user.id %td= @user.email %td=

    @user.claimed? ? 'Yes' : 'No'
  7. .row .large-12.columns %table %tbody %tr %td= @user.id %td= @user.email %td=

    @user.claimed? ? 'Yes' : 'No' %td - if @user.last_sign_in_at.present? = "#{time_ago_in_words(@user.last_sign_in_at)} ago" - else Never :(
  8. .row .large-10.columns %h1= @user.name %span= link_to 'Github', @user.github_link %span= link_to

    'Twitter', @user.twitter_link .large-2.columns - if @user == current_user = link_to 'Edit', edit_user_path(@user), class: 'button' .row .large-12.columns %table %tbody %tr %td= @user.id %td= @user.email %td= @user.claimed? ? 'Yes' : 'No' %td - if @user.last_sign_in_at.present? = "#{time_ago_in_words(@user.last_sign_in_at)} ago" - else Never :(
  9. None
  10. None
  11. None
  12. None
  13. A Presenter is a class that has knowledge of view

    and logic - Ryan Bates
  14. .row
 .large-12.columns
 %table
 %tbody
 %tr
 %td= @user.id
 %td= @user.email
 %td=

    @user.claimed? ? 'Yes' : 'No'
 %td
 - if @user.last_sign_in_at.present?
 = "#{time_ago_in_words (@user.last_sign_in_at)} ago"
 - else
 Never :( .row
 .large-12.columns
 %table
 %tbody
 %tr
 %td= p.id
 %td= p.email
 %td= p.user_claimed?
 %td= p.last_signed_in Without Presenter With Presenter
  15. - if @user.last_sign_in_at.present?
 = "#{time_ago_in_words (@user.last_sign_in_at)} ago"
 - else
 Never

    :( = @profile.last_signed_in
  16. None
  17. None
  18. Look at some messy, ugly code Refactor it step by

    step into a presenter Talk about some of the benefits of doing this
  19. None
  20. Our Feature As a user, I want to be able

    to see my profile with identifying information about me
  21. class User < ActiveRecord::Base def name "#{first_name} #{last_name}" end def

    github_link "https://github.com/#{github_handle}" end def twitter_link "https://twitter.com/#{twitter_handle}" end def claimed? last_sign_in_at.present? end end
  22. class User < ActiveRecord::Base
 def name
 "#{first_name} #{last_name}"
 end
 


    def github_link
 "https://github.com/#{github_handle}"
 end
 
 def twitter_link
 "https://twitter.com/#{twitter_handle}"
 end
 
 def claimed?
 last_sign_in_at.present?
 end
 end
  23. Basic UsersController class UsersController < ApplicationController
 def show
 @user =

    User.find(params[:id])
 end
 end
  24. .row
 .large-10.columns
 %h1= @user.name
 %span= link_to 'Github', @user.github_link
 %span= link_to

    'Twitter', @user.twitter_link
 .large-2.columns
 - if @user == current_user
 = link_to 'Edit', edit_user_path(@user), class: 'button' %table %tbody
 %tr
 %td= @user.id
 %td= @user.email
 %td= @user.claimed? ? 'Yes' : 'No'
 %td
 - if @user.last_sign_in_at.present?
 = "#{time_ago_in_words(@user.last_sign_in_at)} ago"
 - else
 Never :(
  25. None
  26. .row
 .large-10.columns
 %h1= @user.name
 %span= link_to 'Github', @user.github_link
 %span= link_to

    'Twitter', @user.twitter_link
 .large-2.columns
 - if @user == current_user
 = link_to 'Edit', edit_user_path(@user), class: 'button' %table %tbody
 %tr
 %td= @user.id
 %td= @user.email
 %td= @user.claimed? ? 'Yes' : 'No'
 %td
 - if @user.last_sign_in_at.present?
 = "#{time_ago_in_words(@user.last_sign_in_at)} ago"
 - else
 Never :(
  27. .row
 .large-10.columns
 %h1= @user.name
 %span= link_to 'Github', @user.github_link
 %span= link_to

    'Twitter', @user.twitter_link
 .large-2.columns
 - if @user == current_user
 = link_to 'Edit', edit_user_path(@user), class: 'button' %table %tbody
 %tr
 %td= @user.id
 %td= @user.email
 %td= @user.claimed? ? 'Yes' : 'No'
 %td
 - if @user.last_sign_in_at.present?
 = "#{time_ago_in_words(@user.last_sign_in_at)} ago"
 - else
 Never :(
  28. Can’t we put it in a helper? 
 %td
 -

    if @user.last_sign_in_at.present?
 = "#{time_ago_in_words(@user.last_sign_in_at)} ago"
 - else
 Never :(
  29. Can’t we put it in a helper? What about in

    app/helpers/users_profile_helper.rb? 
 %td
 - if @user.last_sign_in_at.present?
 = "#{time_ago_in_words(@user.last_sign_in_at)} ago"
 - else
 Never :(
  30. None
  31. The HERO we need… Presenters!

  32. Lets build a Presenter

  33. User Presenter class UserPresenter
 attr_accessor :user
 
 def initialize(user)
 @user

    = user
 end
 end app/presenters/user_presenter.rb
  34. class UsersController < ApplicationController
 def show
 @user = User.find(params[:id])
 @profile

    = UserPresenter.new(@user)
 end
 end
  35. None
  36. .row
 .large-10.columns
 %h1= @user.name
 .large-2.columns
 - if @user == current_user


    = link_to 'Edit', edit_user_path(@user), class: 'button'
  37. class User < ActiveRecord::Base has_many :posts def name
 "#{first_name} #{last_name}"


    end
 
 def github_link
 "https://github.com/#{github_handle}"
 end
 
 def twitter_link
 "https://twitter.com/#{twitter_handle}"
 end
 
 def claimed?
 last_sign_in_at.present?
 end
 end
  38. class User < ActiveRecord::Base has_many :posts def name
 "#{first_name} #{last_name}"


    end
 
 def github_link "https://github.com/#{github_handle}"
 end
 
 def twitter_link
 "https://twitter.com/#{twitter_handle}"
 end
 
 def claimed?
 last_sign_in_at.present?
 end
 end class UserPresenter
 attr_accessor :user
 
 def initialize(user)
 @user = user
 end
 
 def name
 "#{user.first_name} #{user.last_name}"
 end
 end
  39. class UserPresenter
 attr_accessor :user
 
 def initialize(user)
 @user = user


    end
 
 def name
 "#{user.first_name} #{user.last_name}" end
 def github_link
 "https://github.com/#{user.github_handle}"
 end
 
 def twitter_link
 "https://twitter.com/#{user.twitter_handle}"
 end
 end class User < ActiveRecord::Base has_many :posts
 
 def github_link
 "https://github.com/#{github_handle}"
 end
 
 def twitter_link
 "https://twitter.com/#{twitter_handle}"
 end
 
 def claimed?
 last_sign_in_at.present?
 end
 end
  40. class User < ActiveRecord::Base has_many :posts
 
 def claimed?
 last_sign_in_at.present?


    end
 end class UserPresenter
 attr_accessor :user
 
 def initialize(user)
 @user = user
 end
 
 def name
 "#{user.first_name} #{user.last_name}" end
 def github_link
 "https://github.com/#{user.github_handle}"
 end
 
 def twitter_link
 "https://twitter.com/#{user.twitter_handle}"
 end
 end
  41. None
  42. class UserPresenter
 attr_accessor :user
 
 def initialize(user)
 @user = user


    end
 
 def name
 "#{user.first_name} #{user.last_name}" end
 def github_link
 "https://github.com/#{user.github_handle}"
 end
 
 def twitter_link
 "https://twitter.com/#{user.twitter_handle}"
 end
 end
  43. None
  44. .row
 .large-10.columns
 %h1= @user.name
 %span= link_to 'Github', @user.github_link
 %span= link_to

    'Twitter', @user.twitter_link
 .large-2.columns
 - if @user == current_user
 = link_to 'Edit', edit_user_path(@user), class: ‘button'
  45. .row
 .large-10.columns
 %h1= @profile.name
 %span= link_to 'Github', @profile.github_link
 %span= link_to

    'Twitter', @profile.twitter_link
 .large-2.columns
 - if @user == current_user
 = link_to 'Edit', edit_user_path(@user), class: ‘button'
  46. .row
 .large-10.columns
 %h1= @profile.name
 %span= link_to 'Github', @profile.github_link
 %span= link_to

    'Twitter', @profile.twitter_link
 .large-2.columns
 - if @user == current_user
 = link_to 'Edit', edit_user_path(@user), class: ‘button'
  47. Placeholder image

  48. None
  49. class UserPresenter
 attr_accessor :user
 
 def initialize(user)
 @user = user


    end … …
 
 private
 
 def method_missing(*args, &block)
 @user.send(*args, &block)
 end
 end
  50. .row .large-10.columns %h1= @profile.name %span= link_to 'Github', @profile.github_link %span= link_to

    'Twitter', @profile.twitter_link .large-2.columns - if @user == current_user = link_to 'Edit', edit_user_path(@user), class: 'button' %table %tbody %tr %td= @user.id %td= @user.email %td= @user.claimed? ? 'Yes' : 'No' %td - if @user.last_sign_in_at.present? = "#{time_ago_in_words(@user.last_sign_in_at)} ago" - else Never :(
  51. .row .large-10.columns %h1= @profile.name %span= link_to 'Github', @profile.github_link %span= link_to

    'Twitter', @profile.twitter_link .large-2.columns - if @profile.user == current_user = link_to 'Edit', edit_user_path(@profile.user), class: 'button' %table %tbody %tr %td= @profile.id %td= @profile.email %td= @profile.claimed? ? 'Yes' : 'No' %td - if @profile.last_sign_in_at.present? = "#{time_ago_in_words(@profile.last_sign_in_at)} ago" - else Never :(
  52. .row .large-10.columns %h1= @profile.name %span= link_to 'Github', @profile.github_link %span= link_to

    'Twitter', @profile.twitter_link .large-2.columns - if @profile.user == current_user = link_to 'Edit', edit_user_path(@profile.user), class: 'button' %table %tbody %tr %td= @profile.id %td= @profile.email %td= @profile.claimed? ? 'Yes' : 'No' %td - if @profile.last_sign_in_at.present? = "#{time_ago_in_words(@profile.last_sign_in_at)} ago" - else Never :(
  53. .row .large-10.columns %h1= @profile.name %span= link_to 'Github', @profile.github_link %span= link_to

    'Twitter', @profile.twitter_link .large-2.columns - if @profile.user == current_user = link_to 'Edit', edit_user_path(@profile.user), class: 'button' %table %tbody %tr %td= @profile.id %td= @profile.email %td= @profile.claimed? ? 'Yes' : 'No' %td - if @profile.last_sign_in_at.present? = "#{time_ago_in_words(@profile.last_sign_in_at)} ago" - else Never :(
  54. class UserPresenter
 attr_accessor :user
 ...
 
 def user_claimed?
 claimed? ?

    'Yes' : 'No'
 end ...
 end
  55. .row .large-10.columns %h1= @profile.name %span= link_to 'Github', @profile.github_link %span= link_to

    'Twitter', @profile.twitter_link .large-2.columns - if @profile.user == current_user = link_to 'Edit', edit_user_path(@profile.user), class: 'button' %table %tbody %tr %td= @profile.id %td= @profile.email %td= @profile.claimed? ? 'Yes' : 'No' %td - if @profile.last_sign_in_at.present? = "#{time_ago_in_words(@profile.last_sign_in_at)} ago" - else Never :(
  56. .row .large-10.columns %h1= @profile.name %span= link_to 'Github', @profile.github_link %span= link_to

    'Twitter', @profile.twitter_link .large-2.columns - if @profile.user == current_user = link_to 'Edit', edit_user_path(@profile.user), class: 'button' %table %tbody %tr %td= @profile.id %td= @profile.email %td= @profile.user_claimed? %td - if @profile.last_sign_in_at.present? = "#{time_ago_in_words(@profile.last_sign_in_at)} ago" - else Never :(
  57. .row .large-10.columns %h1= @profile.name %span= link_to 'Github', @profile.github_link %span= link_to

    'Twitter', @profile.twitter_link .large-2.columns - if @profile.user == current_user = link_to 'Edit', edit_user_path(@profile.user), class: 'button' %table %tbody %tr %td= @profile.id %td= @profile.email %td= @profile.user_claimed? %td - if @profile.last_sign_in_at.present? = "#{time_ago_in_words(@profile.last_sign_in_at)} ago" - else Never :(
  58. class UserPresenter
 attr_accessor :user
 
 ...
 
 def user_claimed?
 claimed?

    ? 'Yes' : 'No'
 end
 
 def last_signed_in
 last_sign_in_at ? "#{time_ago_in_words(last_sign_in_at)} ago" : 'Never :('
 end 
 ...
 end
  59. .row .large-10.columns %h1= @profile.name %span= link_to 'Github', @profile.github_link %span= link_to

    'Twitter', @profile.twitter_link .large-2.columns - if @profile.user == current_user = link_to 'Edit', edit_user_path(@profile.user), class: 'button' %table %tbody %tr %td= @profile.id %td= @profile.email %td= @profile.user_claimed? %td - if @profile.last_sign_in_at.present? = "#{time_ago_in_words(@profile.last_sign_in_at)} ago" - else Never :(
  60. .row .large-10.columns %h1= @profile.name %span= link_to 'Github', @profile.github_link %span= link_to

    'Twitter', @profile.twitter_link .large-2.columns - if @profile.user == current_user = link_to 'Edit', edit_user_path(@profile.user), class: 'button' %table %tbody %tr %td= @profile.id %td= @profile.email %td= @profile.user_claimed? %td= @profile.last_signed_in
  61. class UserPresenter
 attr_accessor :user
 
 ...
 
 def user_claimed?
 claimed?

    ? 'Yes' : 'No'
 end
 
 def last_signed_in
 last_sign_in_at ? "#{time_ago_in_words(last_sign_in_at)} ago" : 'Never :('
 end 
 ...
 end
  62. View Context view_context() public An instance of a view class

    ActionView::Rendering
  63. class UserPresenter
 attr_accessor :user, :context
 
 def initialize(user, context)
 @user

    = user @context = context
 end …
 end class UsersController < ApplicationController
 def show
 @user = User.find(params[:id])
 @profile = UserPresenter.new(@user, view_context)
 end
 end
  64. class UserPresenter
 attr_accessor :user, :context
 
 ...
 
 def user_claimed?


    claimed? ? 'Yes' : 'No'
 end
 
 def last_signed_in
 last_sign_in_at ? "#{context.time_ago_in_words(last_sign_in_at)} ago" : 'Never :('
 end 
 ...
 end
  65. .row
 .large-12.columns %table
 %tbody
 %tr
 %td= @user.id
 %td= @user.email
 %td=

    @user.claimed? ? 'Yes' : 'No'
 %td
 - if @user.last_sign_in_at.present?
 = "#{time_ago_in_words (@user.last_sign_in_at)} ago"
 - else
 Never :( .row
 .large-12.columns
 %table
 %tbody
 %tr
 %td= p.id
 %td= p.email
 %td= p.user_claimed?
 %td= p.last_signed_in
  66. class UserPresenter
 attr_accessor :user, :context
 
 def initialize(user, context)
 @user

    = user @context = context
 end
 
 def name; end
 
 def github_link; end
 
 def twitter_link; end
 
 def user_claimed?; end
 
 def last_signed_in; end
 
 private
 
 def method_missing(*args, &block); end
 end
  67. As a user, I want to be able to see

    my published posts On my profile page
  68. Now our app needs Posts! class User < ActiveRecord::Base
 has_many

    :posts
 
 def can_edit?(post)
 id == post.user_id
 end
 end class Post < ActiveRecord::Base
 belongs_to :author, class_name: User scope :published, -> { where(published: true) }
 end
  69. - if @profile.posts.published.present?
 .post-container
 - @profile.posts.published.each do |post|
 .post-block
 %h4=

    post.title
 .body-small
 = post.body.truncate(140)
 .posted-on
 = post.created_at.strftime('%B %e, %Y')
 
 = link_to 'Read More', post_path(@post)
 
 - if current_user.can_edit?(@post)
 = link_to 'Edit', edit_post_path(@post)
 - else
 = "#{@profile.first_name} hasn't posted anything yet."
  70. - if @profile.posts.published.present?
 .post-container
 - @profile.posts.published.each do |post|
 .post-block
 %h4=

    post.title
 .body-small
 = post.body.truncate(140)
 .posted-on
 = post.created_at.strftime('%B %e, %Y')
 
 = link_to 'Read More', post_path(@post)
 
 - if current_user.can_edit?(@post)
 = link_to 'Edit', edit_post_path(@post)
 - else
 = "#{@profile.first_name} hasn't posted anything yet."
  71. - if @profile.posts.published.present?
 .post-container
 - @profile.posts.published.each do |post|
 .post-block
 %h4=

    post.title
 .body-small
 = post.body.truncate(140)
 .posted-on
 = post.created_at.strftime('%B %e, %Y')
 
 = link_to 'Read More', post_path(@post)
 
 - if current_user.can_edit?(@post)
 = link_to 'Edit', edit_post_path(@post)
 - else
 = "#{@profile.first_name} hasn't posted anything yet."
  72. - if @profile.posts.published.present?
 .post-container
 - @profile.posts.published.each do |post|
 .post-block
 %h4=

    post.title
 .body-small
 = post.body.truncate(140)
 .posted-on
 = post.created_at.strftime('%B %e, %Y')
 
 = link_to 'Read More', post_path(@post)
 
 - if current_user.can_edit?(@post)
 = link_to 'Edit', edit_post_path(@post)
 - else
 = "#{@profile.first_name} hasn't posted anything yet."
  73. None
  74. None
  75. Create PostPresenter class PostPresenter
 attr_accessor :post, :context
 
 def initialize(post,

    context)
 @post = post @context = context
 end
 end app/presenters/post_presenter.rb
  76. class PostPresenter
 attr_accessor :post, :context
 
 def initialize(post, context)
 @post

    = post @context = context
 end private
 
 def method_missing(*args, &block)
 @post.send(*args, &block)
 end
 end
  77. None
  78. class PostPresenter
 attr_accessor :post, :context
 
 def initialize(post, context)
 @post

    = post @context = context
 end ... private
 
 def method_missing(*args, &block)
 @post.send(*args, &block)
 end
 end class UserPresenter
 attr_accessor :user, :context
 
 def initialize(user, context)
 @user = user @context = context
 end ...
 
 private
 
 def method_missing(*args, &block)
 @user.send(*args, &block)
 end
 end
  79. class BasePresenter
 
 end

  80. class PostPresenter
 attr_accessor :post, :context
 
 def initialize(post, context)
 @post

    = post @context = context
 end ... private
 
 def method_missing(*args, &block)
 @post.send(*args, &block)
 end
 end class UserPresenter
 attr_accessor :user, :context
 
 def initialize(user, context)
 @user = user @context = context
 end ...
 
 private
 
 def method_missing(*args, &block)
 @user.send(*args, &block)
 end
 end
  81. class BasePresenter attr_accessor :object, :context def initialize(object, context)
 @object, @context

    = object, context
 end
 private
 
 def method_missing(*args, &block)
 @object.send(*args, &block)
 end
 end
  82. .row
 .large-10.columns
 %h1= @profile.name
 %span= link_to 'Github', @profile.github_link
 %span= link_to

    'Twitter', @profile.twitter_link
 .large-2.columns
 - if @profile.user == current_user
 = link_to 'Edit', edit_user_path(@profile.user), class: 'button'
  83. class UserPresenter < BasePresenter
 def user
 @object end def name


    "#{first_name} #{last_name}" end
 def github_link
 "https://github.com/#{github_handle}"
 end
 
 def twitter_link
 "https://twitter.com/#{twitter_handle}"
 end
 end
  84. class PostPresenter < BasePresenter
 def post
 @object end
 
 end

    class UserPresenter < BasePresenter
 def user
 @object end def name
 "#{first_name} #{last_name}" end
 def github_link
 "https://github.com/#{github_handle}"
 end
 
 def twitter_link
 "https://twitter.com/#{twitter_handle}"
 end
 
 end
  85. Now we’re getting somewhere...

  86. - if @profile.posts.published.present?
 .post-container
 - @profile.posts.published.each do |post|
 .post-block
 %h4=

    post.title
 .body-small
 = post.body.truncate(140)
 .posted-on
 = post.created_at.strftime('%B %e, %Y')
 
 = link_to 'Read More', post_path(post)
 
 - if current_user.can_edit?(post)
 = link_to 'Edit', edit_post_path(post)
 - else
 = "#{@profile.first_name} hasn't posted anything yet."
  87. class PostPresenter < BasePresenter
 def post
 @object
 end
 
 def

    short_body
 post.body.truncate(140)
 end
 
 def published_on
 post.created_at.strftime('%B %e, %Y')
 end
 
 def editable_link
 context.link_to('Edit', edit_post_path(@post)) if context.current_user.can_edit?(post)
 end
 end
  88. class PostPresenter < BasePresenter
 def post
 @object
 end
 
 def

    short_body
 post.body.truncate(140)
 end
 
 def published_on
 post.created_at.strftime('%B %e, %Y')
 end
 
 def editable_link
 context.link_to('Edit', edit_post_path(post)) if context.current_user.can_edit?(post)
 end
 end
  89. - if @profile.posts.published.present?
 .post-container
 - @profile.posts.published.each do |post|
 .post-block
 %h4=

    post.title
 .body-small
 = post.body.truncate(140)
 .posted-on
 = post.created_at.strftime('%B %e, %Y')
 
 = link_to 'Read More', post_path(post)
 
 - if current_user.can_edit?(post)
 = link_to 'Edit', edit_post_path(post)
 - else
 = "#{@profile.first_name} hasn't posted anything yet."
  90. - if @profile.posts.published.present?
 .post-container
 - @profile.posts.published.map{|p| PostPresenter.new(post, view_context) }.each do

    | post|
 .post-block
 %h4= post.title
 .body-small
 = post.short_body
 .posted-on
 = post.published_on
 
 = link_to 'Read More', post_path(post)
 = post.editable_link.html_safe
 - else
 = "#{@profile.first_name} hasn't posted anything yet."
  91. - if @profile.posts.published.present?
 .post-container
 - @profile.posts.published.map{|p| PostPresenter.new(post, view_context) }.each do

    | post|
 .post-block
 %h4= post.title
 .body-small
 = post.short_body
 .posted-on
 = post.published_on
 
 = link_to 'Read More', post_path(post)
 = post.editable_link.html_safe
 - else
 = "#{@profile.first_name} hasn't posted anything yet."
  92. - if @profile.posts.published.present?
 .post-container
 - @profile.posts.published.map{|p| PostPresenter.new(post, view_context) }.each do

    | post|
 .post-block
 %h4= post.title
 .body-small
 = post.short_body
 .posted-on
 = post.published_on
 
 = link_to 'Read More', post_path(post)
 = post.editable_link.html_safe
 - else
 = "#{@profile.first_name} hasn't posted anything yet."
  93. class UserPresenter < BasePresenter
 ...
 
 def published_posts
 @published_posts ||=

    user.posts.published.map do |p| PostPresenter.new(p, context) end
 end
 
 def has_published_posts?
 published_posts.present?
 end 
 end
  94. def published_posts
 @published_posts ||= user.posts.published.map do |p| PostPresenter.new(p, context) end


    end
  95. - if @profile.posts.published.present?
 .post-container
 - @profile.posts.published.map{|p| PostPresenter.new(post, view_context) }.each do

    | post|
 .post-block
 %h4= post.title
 .body-small
 = post.short_body
 .posted-on
 = post.published_on
 
 = link_to 'Read More', post_path(post)
 = post.editable_link.html_safe
 - else
 = "#{@profile.first_name} hasn't posted anything yet."
  96. - if @profile.has_published_posts?
 .post-container
 - @profile.published_posts.each do |post|
 .post-block
 %h4=

    post.title
 .body-small
 = post.short_body
 .posted-on
 = post.published_on
 
 = link_to 'Read More', post_path(post)
 = post.editable_link.html_safe
 - else
 = "#{@profile.first_name} hasn't posted anything yet."
  97. .row
 .large-10.columns
 %h1= @user.name
 %span= link_to 'Github', @user.github_link
 %span= link_to

    'Twitter', @user.twitter_link
 .large-2.columns
 - if @user == current_user
 = link_to 'Edit', edit_user_path(@user), class: 'button medium radius'
 .row
 .large-12.columns
 %table
 %tbody
 %tr
 %td= @user.id
 %td= @user.email
 %td= @user.claimed? ? 'Yes' : 'No'
 %td
 - if @user.last_sign_in_at.present?
 = "#{time_ago_in_words(@user.last_sign_in_at)} ago"
 - else
 Never :(
 
 .- if @profile.posts.published.present?
 .post-container
 - @profile.posts.published.each do |post|
 .post-block
 %h4= post.title
 .body-small
 = post.body.truncate(140)
 .posted-on
 = post.created_at.strftime('%B %e, %Y')
 
 = link_to 'Read More', post_path(@post)
 
 - if current_user.can_edit?(@post)
 = link_to 'Edit', edit_post_path(@post)
 - else
 = "#{@profile.first_name} hasn't posted anything yet."
  98. - if @profile.has_published_posts?
 .post-container
 - @profile.published_posts.each do |post|
 .post-block
 %h4=

    post.title
 .body-small
 = post.short_body
 .posted-on
 = post.published_on
 
 = link_to 'Read More', post_path(@post)
 = post.editable_link.html_safe
 - else
 = "#{@profile.first_name} hasn't posted anything yet." .row .large-12.columns %table
 %tbody
 %tr
 %td= @profile.id
 %td= @profile.email
 %td= @profile.user_claimed?
 %td= @profile.last_signed_in .row
 .large-10.columns
 %h1= @profile.name
 %span= link_to 'Github', @profile.github_link
 %span= link_to 'Twitter', @profile.twitter_link
 .large-2.columns
 - if @profile.user == current_user
 = link_to 'Edit', edit_user_path(@profile.user), class: 'button'
  99. - Testable - Maintainable - Simple - Clear - Encapsulated

  100. None
  101. class UserNavigationPresenter < BasePresenter presents :user attr_accessor :partials def initialize(object,

    template, partials = []) super(object, template) @partials = partials end def render_search_bar h.render nav_path('search_bar') if partials.include?(:search_bar) end def render_nav_content partial = user.present? ? nav_path(current_user_nav) : nav_path('anonymous_user') h.render partial end def render_tabs h.content_tag :div, class: 'nav__tabs' do h.succeed(h.link_to 'Jobs', h.jobs_path, class: job_tab_css, disabled: user.blank?) do h.link_to 'Graduates', h.profiles_path, class: grad_tab_css end end end def render_job_button(css_class) h.link_to 'Post a Job', h.new_employer_job_path, class: "button small js-job-button #{css_class}" if user && user.can_message_students? end def render_form_later_button if defined?(h.step) && (['publish','complete'].include?(h.wizard_value(h.step))) h.link_to 'Exit and continue later', h.after_publish_path, class: "button small nav--steps__button-save" else h.link_to 'Save and continue later', '', class: "button small nav--steps__button-save js-save-and-exit-profile", data: { disable_with: 'Saving…' } end end end
  102. class Admin::Instance::EnrollmentPresenter < ApplicationPresenter attr_accessor :enrollment def initialize(enrollment) @enrollment =

    enrollment end %W( created_at user_name user_first_name user_last_name localized_created_at user_email ).map do |meth| define_method(meth) { enrollment.send(meth) } end %W( confirmation_number quantity ticket_price total_paid front_row_subscriber? discount_code discount_link ).map do |meth| define_method(meth) { nil } end def user_email_link link_to enrollment.user_email, admin_user_path(enrollment.user) end def user_id enrollment.user.id end def enrollments [enrollment] end def user_waitlisted? true end end
  103. .row .large-12.columns %strong Email: %a{href:"mailto: #{@instructor.email}"}= @instructor.email %br %strong Website:

    %a{href:@instructor.website}= @instructor.website %br %strong Phone: %a{href:"tel:#{@instructor.phone}"}= @instructor.phone if @instructor.phone.present? %br %strong Twitter: %a{href:"https://twitter.com/#{@instructor.twitter}"}= '@' + @instructor.twitter if @instructor.twitter.present? %br %strong LinkedIn: %a{href: @instructor.linkedin}= @instructor.linkedin if @instructor.linkedin.present? %br %strong Bio: = simple_format(@instructor.bio) unless @instructor.bio.blank? %br %strong Resume: - if @instructor.resume.present? = link_to "Download resume", @instructor.resume.url - else No resume on file %br %strong How They Found GA: = @instructor.hear_about_us.try :capitalize %br %strong Notes: = @instructor.hear_about_us_details
  104. None
  105. None
  106. None
  107. Thank You Allison McMillan @allie_p Kevin Hopkins @devneck A Special

    Thank You to Courtney Jones for our awesome dragons!
  108. Questions?