59
MADRID · NOV 21-22 · 2014 10 cosas de Rails que deberías saber Carlos Sánchez & Gabriel Ortuño

10 cosas de rails que deberías saber

Embed Size (px)

DESCRIPTION

Te has preguntado alguna vez ¿Existe vida después de ActiveRecord::Base? si es así, en esta charla vamos descubrir que Rails es algo más que un simple MVC, es un framework repleto de herramientas cuyo conocimiento nos va a facilitar enormemente la vida. Con estas herramientas vas a poder extender Rails de una forma que no habías imaginado hasta ahora: crearas tus propios validadores, responders y renderers; serás capaz de enviar datos por streaming, de interceptar mails o añadir un nuevo middleware a tu stack. Queremos mostrar 10 de estas herramientas junto con ejemplos de uso de cada una de ellas, para que las puedas incorporar poco a poco en tu día a día y descubras el mundo de posibilidades que realmente tienes en tus manos. El conjunto de herramientas que vamos a mostrar es: ActiveModel::Model ActiveModel::Validator ActiveSupport::Concern ActionSupport::Notifications ActionController::Renderers ActionController::Responder ActionController::Live ActionView::Resolvers ActionMailer Interceptors Rack Middleware

Citation preview

Page 1: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

10 cosas de Rails que deberías saber

Carlos Sánchez & Gabriel Ortuño

Page 2: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

Carlos Sánchez Pérez

Person.new(

name: "Carlos Sánchez Pérez",

job: "ASPgems",

twitter: "carlossanchezp",

github: "carlossanchezp",

Blog: carlossanchezperez.wordpress.com")

Page 3: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

Gabriel Ortuño

Person.new(

name: "Gabriel Ortuño",

job: "jobandtalent",

web: "arctarus.com",

twitter: "arctarus",

github: "arctarus")

Page 4: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

Madrid.rb

Group.new(

name: "Madrid.rb",

google_group: "madrid-rb",

twitter: "madridrb",

vimeo: "madridrb")

¡El último jueves de cada mes en el Irish Rover!

Page 5: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

Ruby on Rails

Page 6: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

Rails 4 Features

Page 7: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

Hoja de Ruta1. ActiveSupport::Concern2. ActiveModel::Validator3. ActiveModel::Model4. ActiveSupport::Notifications5. ActionController::Renderer6. ActionController::Responder7. ActionController::Live8. ActionView::Resolver9. ActionMailer::Interceptor

10. RackMiddleware

Page 8: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

1. ActiveSupport::Concern

¿Qué es?➔ Simple Syntactic Sugar sobre modulos de Ruby➔ Forma estándar de extender clases desde Rails 4.0

¿Para qué se usa?➔ Agrupa métodos que definen una responsabilidad➔ Mejora cohesión➔ Permite reutilización

Page 9: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

# app/models/message.rbclass Message < ActiveRecord::Base default_scope -> { where(trashed: false) } scope :trashed, -> { where(trashed: true) } def trash update_attribute :trashed, true endend

Page 10: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

# app/models/concerns/trashable.rbmodule Trashable extend ActiveSupport::Concern

included do default_scope -> { where(trashed: false) } scope :trashed, -> { where(trashed: true) } end

def trash update_attribute :trashed, true endend

Page 11: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

# app/models/message.rbclass Message < ActiveRecord::Base include Trashable, Subscribable, Commentableend

# app/models/post.rbclass Post < ActiveRecord::Base include Trashable, Commentableend

Page 12: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

2. ActiveModel::Validator

¿Qué es?➔ Es una clase base para implementar

validadores que pueden ser usados por ActiveModel

¿Para qué sirve?➔ Permite extraer lógica de validación de una

forma sencilla y reutilizable

Page 13: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

# app/models/user.rb

class User < ActiveRecord::Base validates_format_of :email, with: \A[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+\z/end

Page 14: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

# lib/email_validator.rbclass EmailValidator < ActiveModel::EachValidator def validate_each(record, attribute, value) message = options.fetch :message, I18n.t("validators.email") unless value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i record.errors[attribute] << message end endend

Page 15: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

class Person < ActiveRecord::Base validates :email, presence: true, email: trueend

Page 16: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

person = Person.new(email: '[email protected]')

person.valid?

# ActiveModel ejecuta algo como....

validator = EmailValidator.new

validator.validate_each(person, :email, '[email protected]')

Page 17: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

3. ActiveModel::Model

¿Qué es?➔ Incluir funcionalidades de ActiveModel::Model sobre

clases de Ruby ➔ Naming, Translation, Validation, Conversions.

¿Para qué se usa?➔ Crear una clase con validaciones➔ Utilizarla en las vistas

Page 18: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

class Contact include ActiveModel::Model

attr_accessor :name, :email, :message

validates :name, presence: true validates :email, presence: true, email: true validates :message, presence: trueend

Page 19: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

class ContactsController < ApplicationController def new... def create @contact = Contact.new(params[:contact]) if @contact.valid? ContactMailer.new_contact(@contact).deliver redirect_to root_path else render :new end endend

Page 20: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

<h1>Contact Us</h1><%= form_for @contact do |f| %> <%= f.label :name %> <%= f.text_field :name %>

<%= f.label :email %> <%= f.email_field :email %>

<%= f.label :message %> <%= f.text_area :message %>

<%= f.submit %><% end %>

Page 21: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

4. ActiveSupport::Notifications

¿Qué es?➔ Envio de notificaciones cuando se producen acciones

estándar.

¿Para qué se usa?➔ Imagina que nos preguntamos “¿Por qué nuestra

página es tan lenta?" ➔ Cómo podemos utilizar las notificaciones para obtener

las métricas.

Page 22: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

# config/initializers/notification.rb

ActiveSupport::Notifications.subscribe "process_action.

action_controller" do|name,start,finish,id,payload|

PageRequest.create! do |page_request|

page_request.path = payload[:path]

page_request.page_duration = (finish - start) * 1000

page_request.view_duration = payload[:view_runtime]

page_request.db_duration = payload[:db_runtime]

end

end

Page 23: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

Page 24: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

class Product < ActiveRecord::Base

def self.search_by_name(text) ActiveSupport::Notifications.instrument( "products.search_by_name", search: text)

where("name LIKE ?", "%#{text}%") endend

Page 25: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

# config/initializers/notification.rb

ActiveSupport::Notifications.subscribe "products.search_by_name"

do |name, start, finish, id, payload|

Rails.logger.debug "SEARCH: #{payload[:search]}"

end

Page 26: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

5. ActionController::Renderer

¿Qué es?➔ Un hook que expone el método render para

personalizar su comportamiento.

¿Para qué se usa?➔ Nos permite devolver respuestas con formatos

personalizados como csv, pdf, zip, etc.

Page 27: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

# app/controllers/csvable_controller.rb

def show

@csvable = Csvable.find(params[:id])

respond_to do |format|

format.html

format.csv { render csv: @csvable, filename: @csvable.name }

end

end

Page 28: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

# lib/renderers/csv_renderer.rb

ActionController::Renderers.add :csv do |obj, options|

filename = options.fetch(:filename, 'data')

str = obj.respond_to?(:to_csv) ? obj.to_csv : obj.to_s

send_data str, type: Mime::CSV,

disposition: "attachment; filename=#{filename}.csv"

end

# config/initializer/mime_types.rb

Mime::Type.register "text/csv", :csv

Page 29: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

6. ActionController::Responder

¿Qué es?➔ Abstrae como funciona los controllers según:

◆ Tipo de request: HTML, XML, JSON◆ Verbo http usando: GET, POST, PUT, PATCH, DELETE◆ Estado del recurso: válido, con errores

¿Para qué se usa?➔ Evita que repitamos lógica entre controladores➔ FlashResponder, HttpCacheResponder...

Page 30: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

def create @user = User.new(params[:user]) respond_to do |format| if @user.save flash[:notice] = 'User was successfully created.' format.html { redirect_to @user } format.xml { render xml: @user, status: :created, location: @user } else format.html { render action: "new" } format.xml { render xml: @user.errors, status: :unprocessable_entity } end endend

Page 31: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

class UsersController < ApplicationController respond_to :html, :xml def create @user = User.new(params[:user]) flash[:notice] = 'User was successfully created.' if @user.save respond_with @user endend

Page 32: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

# lib/flash_responder.rbclass FlashResponder < ActionController::Responder

def to_html set_flash_message! unless get? super end

private

def set_flash_message! status = has_errors? ? :alert : :notice return if controller.flash[status].present? message = i18n_lookup(status) controller.flash[status] = message if message.present? endend

Page 33: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

# app/controllers/application_controller.rbclass ApplicationController < ActionController::Base self.responder = FlashResponder respond_to :htmlend

Page 34: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

7. ActionController::Live

¿Qué es?➔ Módulo que permite el envío datos en streaming.➔ Requiere el uso un servidor como de Puma o Thin➔ ActionController::Live::SSE (Server Side Events)

¿Para qué se usa?➔ Envio de datos al clientes sin necesidad de iniciar una

nueva request.

ActionController::Live::SS

Page 35: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

class MessagesController < ApplicationController include ActionController::Live

def events 3.times do |n| response.stream.write "#{n}...\n\n" sleep 2 end ensure response.stream.close endend

Page 36: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

class MessagesController < ApplicationController

include ActionController::Live

def create

attributes = params.require(:message).permit(:content, :name)

@message = Message.create!(attributes)

$redis.publish('messages.create', @message.to_json)

end

end

Page 37: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

# app/controllers/messages_controller.rb

def events

response.headers['Content-Type'] = 'text/event-stream'

sse = SSE.new(response.stream, event: "live.messages")

$redis.psubscribe('messages.create') do |on|

on.pmessage do |pattern, event, data|

sse.write(data, event: event, retry: 500)

end

end

ensure

sse.close

end

Page 38: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

# app/assets/javascript/messages.js.coffee

source = new EventSource('/messages/events')

source.addEventListener 'live.messages', (e) ->

message = $.parseJSON(e.data).message

$('#chat').append($('<li>').

text("#{message.name}: #{message.content}"))

Page 39: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

8. ActionView::Resolver

¿Qué es?➔ Es el responsable de encontrar el template que debe

ser renderizado.

¿Para qué se usa?➔ Obtener templates directamente de la base de datos.➔ Modificar el directorio de vistas a renderizar en caso de

no existir para el controlador actual.

ActionController::Live::SS

Page 40: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

# lib/admin/resolver.rb

class Admin::Resolver < ::ActionView::FileSystemResolver

def initialize

super("app/views")

end

def find_templates(name, prefix, partial, details)

super(name, "admin/defaults", partial, details)

end

end

Page 41: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

# app/controllers/admin/application_controller.rb

class Admin::ApplicationController < ActionController::Base

append_view_path Admin::Resolver.new

end

Page 42: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

class SqlResolver < ActionView::Resolver def find_templates(name, prefix, partial, details) conditions = { path: normalize_path(name, prefix, partial), locale: normalize_array(details[:locale]).first, format: normalize_array(details[:formats]).first, handler: normalize_array(details[:handlers]), partial: partial || false } ::SqlTemplate.where(conditions).map do |record| initialize_template(record) end endend

Page 43: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

9. ActionMailer::Interceptor

¿Qué es?

➔ Son hooks en el proceso de enviar emails➔ Podríamos decir que ActionMailer ofrece una forma de

manipular los atributos de nuestros emails justo antes de su envío.

¿Para qué se usa?➔ Un ejemplo sería si tenemos correos electrónicos de usuarios

reales, modificar el destinatario y el asunto de un email de desarrollo.

Page 44: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

class EnvironmentInterceptor

def self.delivering_email(message)

message.to = "[email protected]"

message.subject = "#{Rails.env} #{message.subject}"

end

end

Page 45: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

# Ahora registramos nuestro interceptor:

# config/initializers/mail.rb

require 'environment_interceptor'

unless Rails.env.production?

ActionMailer::Base.register_interceptor(EnvironmentInterceptor)

end

Page 46: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

10. Rack Middleware

¿Qué es?➔ Clase ruby que intercepta una request dentro de una

Rack app y la procesa para acabar devolviendo una response.

➔ Es una implementación de Pipeline Design Pattern

¿Para que se usa?➔ Modificar cabeceras de la respuesta, caching, manage

exceptions, almacenar cookies, etc

Page 47: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

Rack

Rack proporciona una interfaz mínima entre servidores web

y frameworks Ruby

Page 48: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

$ bin/rake middlewareuse Rack::Lockuse Rack::Runtimeuse Rack::MethodOverrideuse ActionDispatch::RequestIduse Rails::Rack::Loggeruse ActionDispatch::ShowExceptionsuse ActionDispatch::DebugExceptionsuse ActionDispatch::RemoteIpuse ActionDispatch::Reloaderuse ActionDispatch::Callbacksuse ActiveRecord::Migration::CheckPendinguse ActiveRecord::ConnectionAdapters::ConnectionManagementuse ActiveRecord::QueryCache...

Page 49: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

class RackMiddleware def initialize(app) @app = app # Rack app end def call(env) status, headers, response = @app.call(env) ... [status, headers, response] end end

Simplest Rack Middleware

Page 50: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

require 'digest/md5'module Rack # Automatically sets the ETag header on all String bodies class ETag def initialize(app) @app = app end def call(env) status, headers, body = @app.call(env) if !headers.has_key?('ETag') parts = [] body.each { |part| parts << part.to_s } headers['ETag'] = %("#{Digest::MD5.hexdigest(parts.join(""))}") [status, headers, parts] else [status, headers, body] end end endend

Page 51: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

# Rack::Etagdef call(env) status, headers, body = @app.call(env) if !headers.has_key?('ETag') parts = [] body.each { |part| parts << part.to_s } etag = %("#{Digest::MD5.hexdigest(parts.join(""))}") headers['ETag'] = etag [status, headers, parts] else [status, headers, body] endend

Page 52: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

# config/application.rb

# Push Rack::ETag at the bottomconfig.middleware.use Rack::ETag

# Add Rack::ETag after ActiveRecord::QueryCache.config.middleware.insert_after ActiveRecord::QueryCache, Rack::ETag

Page 53: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

Rails es adaptable a tus necesidades

Page 54: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

Domina las herramientas que usas

Page 55: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

¡¡Gracias!!

Page 56: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

Referencias

Page 57: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

ActiveSupport::Concern● Put chubby models on a diet with concerns : https://signalvnoise.com/posts/3372-put-chubby-

models-on-a-diet-with-concerns

ActiveModel::Validator● Seven useful validator: http://viget.com/extend/seven-useful-activemodel-validators

ActiveModel::Model● ActiveModel::Model [Rails 4 Countdown to 2013]: http://blog.remarkablelabs.

com/2012/12/activemodel-model-rails-4-countdown-to-2013

ActionController::Responder● http://blog.plataformatec.com.br/2009/08/embracing-rest-with-mind-body-and-soul/● https://github.com/plataformatec/responders

Page 58: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

ActionView::Resolver● Plataformatec: http://blog.plataformatec.com.br/2011/04/default-views-in-rails-3-0-with-custom-

resolvers/

ActionController::Live

● Railscast #401: http://railscasts.com/episodes/401-actioncontroller-live● Tenderlove, Is it live?: http://tenderlovemaking.com/2012/07/30/is-it-live.html

Rack Middlewares● Railscast #151: http://railscasts.com/episodes/151-rack-middleware● Stackoverflow: http://stackoverflow.com/questions/2256569/what-is-rack-middleware● Amberit: https://www.amberbit.com/blog/2011/07/13/introduction-to-rack-middleware/

Page 59: 10 cosas de rails que deberías saber

MADRID · NOV 21-22 · 2014

¿Preguntas?