Download - Ruby over Rails

Transcript
Page 1: Ruby over Rails

Ruby over RailsRuby Day 2014

Page 2: Ruby over Rails

Giuseppe Modarelli

Ruby DeveloperJavascript Developer

Drummer

gmodarelli gmodarelli gmodarelli.com

Page 3: Ruby over Rails
Page 4: Ruby over Rails
Page 5: Ruby over Rails

xml2json

Page 6: Ruby over Rails
Page 7: Ruby over Rails

Why Ruby over Rails?

Page 8: Ruby over Rails

Your app uses Rails

Page 9: Ruby over Rails

Your app is not Rails

Page 10: Ruby over Rails

What’s Rails?

Page 11: Ruby over Rails

Corey Haines

Page 12: Ruby over Rails

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

Page 13: Ruby over Rails

HTTP DBYOUR APP

Page 14: Ruby over Rails

A real life example

Page 15: Ruby over Rails

<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> <div class="<%= day %>"></div> </div> ! <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> <div class="<%= day %>"></div> </div> ! <div class="date <%= @contract.invoices.first.sent_at.past? ? 'done' : 'pending' %>"> <% month = @contract.invoices.first.sent_at.strftime(‘%B’).downcase %> <% day = @contract.invoices.first.sent_at.day.to_s %> <div class="<%= month %>"></div> <div class="<%= day %>"></div> </div> </div>

Page 16: Ruby over Rails

<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> <div class="<%= day %>"></div> </div> ! <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> <div class="<%= day %>"></div> </div> ! <div class="date <%= @contract.invoices.first.sent_at.past? ? 'done' : 'pending' %>"> <% month = @contract.invoices.first.sent_at.strftime(‘%B’).downcase %> <% day = @contract.invoices.first.sent_at.day.to_s %> <div class="<%= month %>"></div> <div class="<%= day %>"></div> </div> </div>

Page 17: Ruby over Rails

<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> <div class="<%= day %>"></div> </div> ! <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> <div class="<%= day %>"></div> </div> ! <div class="date <%= @contract.invoices.first.sent_at.past? ? 'done' : 'pending' %>"> <% month = @contract.invoices.first.sent_at.strftime(‘%B’).downcase %> <% day = @contract.invoices.first.sent_at.day.to_s %> <div class="<%= month %>"></div> <div class="<%= day %>"></div> </div> </div>

Page 18: Ruby over Rails

<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> <div class="<%= day %>"></div> </div> ! <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> <div class="<%= day %>"></div> </div> ! <div class="date <%= @contract.invoices.first.sent_at.past? ? 'done' : 'pending' %>"> <% month = @contract.invoices.first.sent_at.strftime(‘%B’).downcase %> <% day = @contract.invoices.first.sent_at.day.to_s %> <div class="<%= month %>"></div> <div class="<%= day %>"></div> </div> </div>

Page 19: Ruby over Rails

<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> <div class="<%= day %>"></div> </div> ! <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> <div class="<%= day %>"></div> </div> ! <div class="date <%= @contract.invoices.first.sent_at.past? ? 'done' : 'pending' %>"> <% month = @contract.invoices.first.sent_at.strftime(‘%B’).downcase %> <% day = @contract.invoices.first.sent_at.day.to_s %> <div class="<%= month %>"></div> <div class="<%= day %>"></div> </div> </div>

Page 20: Ruby over Rails

<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> <div class="<%= day %>"></div> </div> ! <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> <div class="<%= day %>"></div> </div> ! <div class="date <%= @contract.invoices.first.sent_at.past? ? 'done' : 'pending' %>"> <% month = @contract.invoices.first.sent_at.strftime(‘%B’).downcase %> <% day = @contract.invoices.first.sent_at.day.to_s %> <div class="<%= month %>"></div> <div class="<%= day %>"></div> </div> </div>

Page 21: Ruby over Rails

WHAT THE SHISH!!?!?!?

Page 22: Ruby over Rails

<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> <div class="<%= day %>"></div> </div> ! <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> <div class="<%= day %>"></div> </div> ! <div class="date <%= @contract.invoices.first.sent_at.past? ? 'done' : 'pending' %>"> <% month = @contract.invoices.first.sent_at.strftime(‘%B’).downcase %> <% day = @contract.invoices.first.sent_at.day.to_s %> <div class="<%= month %>"></div> <div class="<%= day %>"></div> </div> </div>

Page 23: Ruby over Rails

<div id= <div <% month = <% day = <div <div </div> ! <div <% month = <% day = <div <div </div> ! <div <% month = <% day = <div <div </div> </div>

How can we solve this?

Page 24: Ruby over Rails

<div id= <div <% month = <% day = <div <div </div> ! <div <% month = <% day = <div <div </div> ! <div <% month = <% day = <div <div </div> </div>

Don’t start over!

Page 25: Ruby over Rails

<div id= <div <% month = <% day = <div <div </div> ! <div <% month = <% day = <div <div </div> ! <div <% month = <% day = <div <div </div> </div>

Clean up existing code

Page 26: Ruby over Rails

<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> <div class="<%= day %>"></div> </div> ! <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> <div class="<%= day %>"></div> </div> ! <div class="date <%= @contract.invoices.first.sent_at.past? ? 'done' : 'pending' %>"> <% month = @contract.invoices.first.sent_at.strftime(‘%B’).downcase %> <% day = @contract.invoices.first.sent_at.day.to_s %> <div class="<%= month %>"></div> <div class="<%= day %>"></div> </div> </div>

Page 27: Ruby over Rails

<div id= <div <% month = <% day = <div <div </div> ! <div <% month = <% day = <div <div </div> ! <div <% month = <% day = <div <div </div> </div>

HAML

Page 28: Ruby over Rails

%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}" }

Page 29: Ruby over Rails

%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 = %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

SLIM

Page 30: Ruby over Rails

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

Page 31: Ruby over Rails

div#dates div - month = - day = div div div - month = - day = div div div - month = - day = div div

SLIM LOGIC-LESS

Page 32: Ruby over Rails

div#dates div - month = - day = div div div - month = - day = div div div - month = - day = div div

Programming by Wishful Thinking

Page 33: Ruby over Rails

div#dates - @dates div class="date #{status}" div class=month div class=day

Page 34: Ruby over Rails

div - div div div

Ok cool. But we do need that logic!

Page 35: Ruby over Rails

div - div div div

M V C

Page 36: Ruby over Rails

div - div div div

M V C

Page 37: Ruby over Rails

div - div div div

M V C

Page 38: Ruby over Rails

div - div div div

M V C

Page 39: Ruby over Rails

div - div div div

PORO

Page 40: Ruby over Rails

div#dates - @dates div class="date #{status}" div class=month div class=day

Page 41: Ruby over Rails

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

Page 42: Ruby over Rails

class Presenters::CalendarWidget def initialize date end ! def status "done" end end

Page 43: Ruby over Rails

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

Page 44: Ruby over Rails

class Presenters::CalendarWidget def initialize date @date = date end ! def status return "done" if @date.past? "pending" end end

Page 45: Ruby over Rails

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

Page 46: Ruby over Rails

class Presenters::CalendarWidget . . . ! def month @date.strftime('%B').downcase end end

Page 47: Ruby over Rails

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

Page 48: Ruby over Rails

class Presenters::CalendarWidget ! . . . ! def day @date.day.to_s end end

Page 49: Ruby over Rails

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

Page 50: Ruby over Rails

div#dates - @dates div class="date #{status}" div class=month div class=day

Page 51: Ruby over Rails

Where does @dates come from?

Page 52: Ruby over Rails

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

Page 53: Ruby over Rails
Page 54: Ruby over Rails

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

Page 55: Ruby over Rails

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

Page 56: Ruby over Rails

class DashboardController def index @dates = Presenters::CalendarWidget.for( current_user.relevant_contract_dates ) end end

Page 57: Ruby over Rails

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

Page 58: Ruby over Rails

class Presenters::CalendarWidget . . . ! def self.for dates dates.each.map do |date| new date end end end

Page 59: Ruby over Rails

class User < ActiveRecord::Base . . . ! def relevant_contract_dates [ contract.signed_at, contract.activation_date, contract.invoices.first.sent_at ] end end

Page 60: Ruby over Rails

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

Page 61: Ruby over Rails

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

Page 62: Ruby over Rails

class Contract < ActiveRecord::Base . . . ! def first_invoice_date invoices.first.sent_at end end

Page 63: Ruby over Rails

class Contract < ActiveRecord::Base . . . ! def first_invoice_date first_invoice.sent_at end ! def first_invoice invoices.first end end

Page 64: Ruby over Rails

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

Page 65: Ruby over Rails

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

Page 66: Ruby over Rails

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

Page 67: Ruby over Rails

class Collection::CalendarWidgets . . . ! def pending all.select { |date| date.status == "pending" } end ! def done all.select { |date| date.status == "done" } end end

Page 68: Ruby over Rails

When to use these techniques

Page 69: Ruby over Rails

DHH Style

Page 70: Ruby over Rails

BULLSHIT!!!

Page 71: Ruby over Rails

ALWAYS

Page 72: Ruby over Rails

Thank You

Page 73: Ruby over Rails

Giuseppe Modarelli

Ruby DeveloperJavascript Developer

Drummer

gmodarelli gmodarelli gmodarelli.com


Top Related