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.

Cb5d9e9095cd41b636764a85e57ade4b?s=128

Nando Vieira

June 21, 2014
Tweet

Transcript

  1. Rails Variants

  2. O Rails tem content negotiation faz tempo.

  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
  4. Para renderizar cada formato, basta especificar o parâmetro :format.

  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
  6. O formato pode ser especificado para cada uma das rotas

    que você definiu.
  7. /tasks.json /tasks?format=json

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

    de content negotiation.
  9. class TasksController < ApplicationController respond_to :html, :json, :xml ! def

    index @tasks = Task.all respond_with(@tasks) end end
  10. Você pode acessar e definir explicitamente o formato de uma

    requisição.
  11. request.format request.format = :json

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

    do Rails.
  13. None
  14. None
  15. 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
  16. Para usar um responder, especifique a opção :responder.

  17. class TasksController < ApplicationController respond_to :html, :json ! def create

    @task = Task.create(task_params) respond_with @task, location: tasks_path, responder: TaskCreateResponder end end
  18. Variants

  19. O Rails Variants permite criar uma especialização para o formato

    que está sendo renderizado.
  20. A primeira ideia que vem à cabeça é renderizar um

    template específico para dispositivos móveis.
  21. 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
  22. http://fnando.me/14l

  23. Caso uma dessas condições seja satisfeita, o template para aquela

    variante será usado.
  24. application.html.erb application.html+tablet.erb application.html+mobile.erb ! index.html.erb index.html+tablet.erb index.html+mobile.erb

  25. Você pode combinar respond_to com variantes.

  26. respond_to do |format| format.html do |variant| variant.none(&block) variant.tablet(&block) variant.mobile(&block) end

    ! format.json end
  27. Todos os exemplos de variantes são sempre baseados em detecção

    de dispositivos.
  28. Mas variantes podem ser usadas para abstrair a lógica de

    renderização.
  29. None
  30. User#security_mode none, card, sms, totp

  31. 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
  32. edit.html+card.erb edit.html+none.erb edit.html+sms.erb edit.html+totp.erb

  33. A inicialização dos objetos necessários para renderizar a view pode

    ser feita dinamicamente.
  34. 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
  35. Instancie apenas um objeto no controller. Sandi Metz, http://fnando.me/14v

  36. 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
  37. class DashboardsController < ApplicationController before_filter :authorize ! def show @dashboard

    = Dashboard.new(current_user) end end
  38. <%= render 'profile' %> <%= render 'groups', groups: @dashboard.group %>

    ! <%= render 'statuses/form', status: @dashboard.new_status %> <%= render 'statuses', statuses: @dashboard.statuses %>
  39. Outros casos de uso Testes A/B Rollout para beta testers

    Logado vs não logado
  40. Evite adicionar tudo como variantes.

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

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

  43. Tenha bom senso.

  44. Obrigado.

  45. * * *

  46. http://howtocode.com.br