ruby over rails

Post on 02-Dec-2014

215 Views

Category:

Education

0 Downloads

Preview:

Click to see full reader

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.

TRANSCRIPT

Ruby over RailsRuby Day 2014

Giuseppe Modarelli

Ruby DeveloperJavascript Developer

Drummer

gmodarelli gmodarelli gmodarelli.com

xml2json

Why Ruby over Rails?

Your app uses Rails

Your app is not Rails

What’s Rails?

Corey Haines

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

HTTP DBYOUR APP

A real life example

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

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

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

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

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

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

WHAT THE SHISH!!?!?!?

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

<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?

<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!

<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

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

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

HAML

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

%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

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

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

SLIM LOGIC-LESS

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

Programming by Wishful Thinking

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

div - div div div

Ok cool. But we do need that logic!

div - div div div

M V C

div - div div div

M V C

div - div div div

M V C

div - div div div

M V C

div - div div div

PORO

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

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

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

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

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

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

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

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

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

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

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

Where does @dates come from?

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

When to use these techniques

DHH Style

BULLSHIT!!!

ALWAYS

Thank You

Giuseppe Modarelli

Ruby DeveloperJavascript Developer

Drummer

gmodarelli gmodarelli gmodarelli.com

top related