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

Conhecendo Variants do Rails 4.1

Conhecendo Variants do Rails 4.1

O Rails está em uma fase evolutiva bastante interessante. Com releases menores e mais rápidos, está adicionando novas funcionalidades aos poucos. O Rails 4.1 trouxe uma funcionalidade chamada de variants, que permite definir views alternativas para uma mesma action e formato.

Nessa palestra vou mostrar como você pode renderizar views alternativas para dispositivos móveis, além de abstrair lógica das views sem muito esforço.

Nando Vieira

June 21, 2014
Tweet

More Decks by Nando Vieira

Other Decks in Programming

Transcript

  1. Rails
    Variants

    View full-size slide

  2. O Rails tem content negotiation faz tempo.

    View full-size slide

  3. class TasksController < ApplicationController
    def index
    @tasks = Task.all
    !
    respond_to do |format|
    format.html
    format.xml { render xml: @tasks }
    format.json { render json: @tasks }
    end
    end
    end

    View full-size slide

  4. Para renderizar cada formato, basta
    especificar o parâmetro :format.

    View full-size slide

  5. $ rake routes
    Prefix Verb URI Pattern Controller#Action
    root GET / site#index
    tasks GET /tasks(.:format) tasks#index
    POST /tasks(.:format) tasks#create
    new_task GET /tasks/new(.:format) tasks#new
    edit_task GET /tasks/:id/edit(.:format) tasks#edit
    task GET /tasks/:id(.:format) tasks#show
    PATCH /tasks/:id(.:format) tasks#update
    PUT /tasks/:id(.:format) tasks#update
    DELETE /tasks/:id(.:format) tasks#destroy

    View full-size slide

  6. O formato pode ser especificado para
    cada uma das rotas que você definiu.

    View full-size slide

  7. /tasks.json
    /tasks?format=json

    View full-size slide

  8. À partir do Rails 3 você pode otimizar
    o processo de content negotiation.

    View full-size slide

  9. class TasksController < ApplicationController
    respond_to :html, :json, :xml
    !
    def index
    @tasks = Task.all
    respond_with(@tasks)
    end
    end

    View full-size slide

  10. Você pode acessar e definir explicitamente
    o formato de uma requisição.

    View full-size slide

  11. request.format
    request.format = :json

    View full-size slide

  12. Você pode criar responders personalizados que
    alteram o comportamento padrão do Rails.

    View full-size slide

  13. class TaskCreateResponder < ActionController::Responder
    delegate :t, :flash, to: :controller
    def to_html
    if resource.new_record?
    flash.notice = t('flash.tasks.create.notice')
    else
    flash.alert = resource.errors.full_messages
    .to_sentence
    end
    !
    redirect_to navigation_location
    end
    end

    View full-size slide

  14. Para usar um responder,
    especifique a opção :responder.

    View full-size slide

  15. class TasksController < ApplicationController
    respond_to :html, :json
    !
    def create
    @task = Task.create(task_params)
    respond_with @task,
    location: tasks_path,
    responder: TaskCreateResponder
    end
    end

    View full-size slide

  16. O Rails Variants permite criar uma especialização
    para o formato que está sendo renderizado.

    View full-size slide

  17. A primeira ideia que vem à cabeça é renderizar um
    template específico para dispositivos móveis.

    View full-size slide

  18. class ApplicationController < ActionController::Base
    before_action :set_variant
    !
    private
    !
    def set_variant
    request.variant = :tablet if browser.tablet?
    request.variant = :mobile if browser.mobile?
    end
    end

    View full-size slide

  19. http://fnando.me/14l

    View full-size slide

  20. Caso uma dessas condições seja satisfeita, o
    template para aquela variante será usado.

    View full-size slide

  21. application.html.erb
    application.html+tablet.erb
    application.html+mobile.erb
    !
    index.html.erb
    index.html+tablet.erb
    index.html+mobile.erb

    View full-size slide

  22. Você pode combinar respond_to com variantes.

    View full-size slide

  23. respond_to do |format|
    format.html do |variant|
    variant.none(&block)
    variant.tablet(&block)
    variant.mobile(&block)
    end
    !
    format.json
    end

    View full-size slide

  24. Todos os exemplos de variantes são sempre
    baseados em detecção de dispositivos.

    View full-size slide

  25. Mas variantes podem ser usadas para
    abstrair a lógica de renderização.

    View full-size slide

  26. User#security_mode
    none, card, sms, totp

    View full-size slide

  27. class SecurityModeController < ApplicationController
    def edit
    request.variant = SecurityMode.fetch(params[:security_mode])
    !
    respond_to do |format|
    format.html do |variant|
    variant.none
    variant.card { initialize_card_security_mode }
    variant.sms { initialize_sms_security_mod }
    variant.totp { initialize_totp_security_mode }
    end
    end
    end
    end

    View full-size slide

  28. edit.html+card.erb
    edit.html+none.erb
    edit.html+sms.erb
    edit.html+totp.erb

    View full-size slide

  29. A inicialização dos objetos necessários para
    renderizar a view pode ser feita dinamicamente.

    View full-size slide

  30. class SecurityModeController < ApplicationController
    def edit
    security_mode = SecurityMode.fetch(params[:security_mode])
    request.variant = security_mode
    !
    initializer = "initialize_#{security_mode}_security_mode"
    send(initialize) if respond_to?(initializer, true)
    end
    end

    View full-size slide

  31. Instancie apenas um objeto no controller.
    Sandi Metz, http://fnando.me/14v

    View full-size slide

  32. class Dashboard
    def initialize(user)
    @user = user
    end
    !
    def new_status
    @new_status ||= Status.new
    end
    !
    def statuses
    Status.for(user)
    end
    !
    def notifications
    @notifications ||= user.notifications
    end
    !
    private
    !
    attr_reader :user
    end

    View full-size slide

  33. class DashboardsController < ApplicationController
    before_filter :authorize
    !
    def show
    @dashboard = Dashboard.new(current_user)
    end
    end

    View full-size slide

  34. <%= render 'profile' %>
    <%= render 'groups', groups: @dashboard.group %>
    !
    <%= render 'statuses/form', status: @dashboard.new_status %>
    <%= render 'statuses', statuses: @dashboard.statuses %>

    View full-size slide

  35. Outros casos de uso
    Testes A/B
    Rollout para beta testers
    Logado vs não logado

    View full-size slide

  36. Evite adicionar tudo como variantes.

    View full-size slide

  37. request.variant = [:logged, :iphone].join('_').to_sym
    application.html+logged_iphone.erb

    View full-size slide

  38. A quantidade de combinações
    possíveis pode fugir do seu controle.

    View full-size slide

  39. Tenha bom senso.

    View full-size slide

  40. http://howtocode.com.br

    View full-size slide