of 73 /73
Ruby over Rails Ruby Day 2014

Ruby over Rails

Embed Size (px)

DESCRIPTION

Ruby has a powerful set of libs and tools that we don't use in our day to day jobs as ruby developers. The main reason for this is because we force logic where it should not be: the template. By refactoring a simple application I'll show you how to unlock the power of Ruby and how to write code that you will love to work with in the future.

Text of Ruby over Rails

  • 1. Ruby over Rails Ruby Day 2014
  • 2. Giuseppe Modarelli Ruby Developer Javascript Developer Drummer gmodarelli gmodarelli gmodarelli.com
  • 3. xml2json
  • 4. Why Ruby over Rails?
  • 5. Your app uses Rails
  • 6. Your app is not Rails
  • 7. Whats Rails?
  • 8. Corey Haines
  • 9. A set of helpers that takes us from a url to a method for both incoming requests and outgoing responses (HTTP) An ORM (DoneRecord) that serves as a database adapter Corey Haines
  • 10. HTTP YOUR APP DB
  • 11. A real life example
  • 12.
    ! !
  • 13.
    ! !
  • 14.
    ! !
  • 15.
    ! !
  • 16.
    ! !
  • 17.
    ! !
  • 18. WHAT THE SHISH!!?!?!?
  • 19.
    ! !
  • 20.
    !
    ! How can we solve this?
  • 21.
    !
    ! Dont start over!
  • 22.
    !
    ! Clean up existing code
  • 23.
    ! !
  • 24.
    !
    ! HAML
  • 25. %div{ id: "dates" } %div{ class: "date #{@contract.signed_at.past? ? 'done' : 'pending'}" } - month = @contract.signed_at.strftime('%B').downcase - day = @contract.signed_at.day.to_s %div{ class: "#{month}" } %div{ class: "#{day}" } %div{ class: "date #{@contract.activation_date.past? ? 'done' : 'pending'}" } - month = @contract.activation_date.strftime('%B').downcase - day = @contract.activation_date.day.to_s %div{ class: "#{month}" } %div{ class: "#{day}" } %div{ class: "date #{@contract.first_invoice_sent_at.past? ? 'done' : 'pending'}" } - month = @contract.first_invoice_sent_at.strftime('%B').downcase - day = @contract.first_invoice_sent_at.day.to_s %div{ class: "#{month}" } %div{ class: "#{day}" }
  • 26. %div{ id: "dates" } %div{ class: "date #{@contract.signed_at.past? ? 'done' : 'pending'} - month = @contract.signed_at.strftime('%B') - day = %div{ class: "#{month} %div %div{ class: "date #{@contract.activation_date.past? ? 'done' : 'pending'} - month = @contract.activation_date.strftime('%B') - day = SLIM %div{ class: "#{month} %div %div{ class: "date #{@contract.first_invoice_sent_at.past? ? 'done' : 'pending'} - month = @contract.first_invoice_sent_at.strftime('%B') - day = %div{ class: "#{month} %div
  • 27. div#dates div class="date #{@contract.signed_at.past? ? 'done' : 'pending'}" - month = @contract.signed_at.strftime('%B').downcase - day = @contract.signed_at.day.to_s div class=month div class=day div class="date #{@contract.activation_date.past? ? 'done' : 'pending'}" - month = @contract.activation_date.strftime('%B').downcase - day = @contract.activation_date.day.to_s div class=month div class=day div class="date #{@contract.first_invoice_sent_at.past? ? 'done' : 'pending'}" - month = @contract.first_invoice_sent_at.strftime('%B').downcase - day = @contract.first_invoice_sent_at.day.to_s div class=month div class=day
  • 28. div#dates div - month = - day = div div div - month = - day = div div div - month = - day = div div SLIM LOGIC-LESS
  • 29. div#dates div - month = - day = div div div - month = - day = Programming by Wishful Thinking div div div - month = - day = div div
  • 30. div#dates - @dates div class="date #{status}" div class=month div class=day
  • 31. div - div Ok cool. But we do need that logic! div div
  • 32. div - div div M V C div
  • 33. div - div div M V C div
  • 34. div - div div M V C div
  • 35. div - div div M V C div
  • 36. div - div div PORO div
  • 37. div#dates - @dates div class="date #{status}" div class=month div class=day
  • 38. describe Presenters::CalendarWidget do let(:date) { DateTime.parse '2014/09/26 08:00:00' } ! describe '#status' do it 'is "done" when the date is in the past' do calendar_widget = described_class.new date expect(calendar_widget.status).to eq('done') end end end
  • 39. class Presenters::CalendarWidget def initialize date end ! def status "done" end end
  • 40. describe Presenters::CalendarWidget do let(:date) { DateTime.parse '2014/09/26 08:00:00' } ! describe '#status' do it 'is "done" when the date is in the past' do calendar_widget = described_class.new date expect(calendar_widget.status).to eq('done') end ! it 'is "pending" when the date is in the future' do calendar_widget = described_class.new date + 1.day expect(calendar_widget.status).to eq('pending') end end end
  • 41. class Presenters::CalendarWidget def initialize date @date = date end ! def status return "done" if @date.past? "pending" end end
  • 42. describe Presenters::CalendarWidget do let(:date) { DateTime.parse '2014/09/26 08:00:00' } ! . . . ! describe '#month' do it 'is the month downcased' do calendar_widget = described_class.new date expect(calendar_widget.month).to eq('september') end end end
  • 43. class Presenters::CalendarWidget . . . ! def month @date.strftime('%B').downcase end end
  • 44. describe Presenters::CalendarWidget do let(:date) { DateTime.parse '2014/09/26 08:00:00' } ! . . . ! describe '#day' do it 'is the day of the month' do calendar_widget = described_class.new date expect(calendar_widget.day).to eq('26') end end end
  • 45. class Presenters::CalendarWidget ! . . . ! def day @date.day.to_s end end
  • 46. class Presenters::CalendarWidget def initialize date @date = date end ! def status return "done" if @date.past? "pending" end ! def month @date.strftime('%B').downcase end ! def day @date.day.to_s end end
  • 47. div#dates - @dates div class="date #{status}" div class=month div class=day
  • 48. Where does @dates come from?
  • 49. class DashboardController def index @dates = [ Presenter::CalendarWidget.new(current_user.contract.signed_at), Presenter::CalendarWidget.new(current_user.contract.activation_date), Presenter::CalendarWidget.new(current_user.contract.invoices.first.sent_at) ] end end
  • 50. class DashboardController def index @dates = [ Presenter::CalendarWidget.new(current_user.contract.signed_at), Presenter::CalendarWidget.new(current_user.contract.activation_date), Presenter::CalendarWidget.new(current_user.contract.invoices.first.sent_at) ] end end
  • 51. class DashboardController def index @dates = Presenters::CalendarWidget.for([ current_user.contract.signed_at, current_user.contract.activation_date, current_user.contract.invoices.first.sent_at ]) end end
  • 52. class DashboardController def index @dates = Presenters::CalendarWidget.for( current_user.relevant_contract_dates ) end end
  • 53. describe Presenters::CalendarWidget do let(:date) { DateTime.parse '2014/09/26 08:00:00' } ! . . . ! describe '.for' do it 'returns a list of widgets' do dates = [ date, date + 2.month ] widgets = described_class.for dates ! expect(widgets.count).to be(2) expect(widgets.first.status).to be('done') expect(widgets.last.status).to be('pending') end end end
  • 54. class Presenters::CalendarWidget . . . ! def self.for dates dates.each.map do |date| new date end end end
  • 55. class User < ActiveRecord::Base . . . ! def relevant_contract_dates [ contract.signed_at, contract.activation_date, contract.invoices.first.sent_at ] end end
  • 56. class User < ActiveRecord::Base . . . ! delegate: :signed_at, :activation_date, :invoices, to: :contract ! def relevant_contract_dates [ signed_at, activation_date, invoices.first.sent_at ] end end
  • 57. class User < ActiveRecord::Base . . . ! delegate: :signed_at, :activation_date, :first_invoice_date, to: :contract ! def relevant_contract_dates [ signed_at, activation_date, first_invoice_date ] end end
  • 58. class Contract < ActiveRecord::Base . . . ! def first_invoice_date invoices.first.sent_at end end
  • 59. class Contract < ActiveRecord::Base . . . ! def first_invoice_date first_invoice.sent_at end ! def first_invoice invoices.first end end
  • 60. class Contract < ActiveRecord::Base . . . ! def first_invoice_date first_invoice.sent_at end ! def first_invoice invoices.first || invoices.new( sent_at: activation_date + 2.month) end end
  • 61. class Presenters::CalendarWidget def self.for dates dates.each.map {|date| new date } end ! def initialize date @date = date end ! def status return "done" if @date.past? "pending" end ! def month @date.strftime('%B').downcase end ! def day @date.day.to_s end end
  • 62. class Collection::CalendarWidgets def self.for dates new dates end ! def all @dates end ! private def initialize dates @dates = dates.map do |date| Presenter::CalendarWidget.new date end end end
  • 63. class Collection::CalendarWidgets . . . ! def pending all.select { |date| date.status == "pending" } end ! def done all.select { |date| date.status == "done" } end end
  • 64. When to use these techniques
  • 65. DHH Style
  • 66. BULLSHIT!!!
  • 67. ALWAYS
  • 68. Thank You
  • 69. Giuseppe Modarelli Ruby Developer Javascript Developer Drummer gmodarelli gmodarelli gmodarelli.com