2015-10-09 8 views
23

Ho cercato il modo "consigliato" per utilizzare gli helper di visualizzazione di Rails (ad esempio link_to, content_tag) in una classe plain ruby, ad esempio un presenter. Sembra che ci siano pochissime informazioni su questo fronte e volevo avere un'idea di quello che pensava la comunità di Stack.Modo consigliato per utilizzare gli helper di visualizzazione di Rails in una classe di presentazione

Quindi, le opzioni che abbiamo sono .. (notare sto usando Rails 4, e sono meno preoccupati per le versioni precedenti)

Includere i moduli necessari manualmente

Questo è probabilmente il più pulito modo, poiché sono inclusi solo gli helper necessari. Tuttavia, ho riscontrato che questo metodo non funziona in alcuni casi, poiché il solito contesto di visualizzazione fornito in semplici helper di Rails è configurato per la richiesta corrente. url_for non saprebbe, ad esempio, la richiesta corrente, quindi l'host potrebbe non corrispondere.

class MyPresenter 
    include ActionView::Helpers::UrlHelper 
    include ActionView::Helpers::CaptureHelper 

    def wrapped_link 
     content_tag :div, link_to('My link', root_url) 
    end 
end 

Uso ActionController::Base.helpers

Da Rails 3, ActionController::Base ha incluso un metodo helpers di accedere al contesto vista corrente. Credo che il contesto di visualizzazione fornito da questo metodo sia configurato come sarebbe in un helper di rotaie, ma potrei sbagliarmi. Non c'è davvero alcuna documentazione su questo che sembra preoccupante, ma funziona abbastanza bene nella pratica.

class MyPresenter 
    def wrapped_link 
     h.content_tag :div, h.link_to('My link', h.root_url) 
    end 

    protected 

    def h 
     ActionController::Base.helpers 
    end 
end 

Credo che questo contesto di vista può anche essere mescolato con include, ma i binari visualizzare aiutanti avere centinaia di metodi e ci si sente sporca di includerli tutti indistintamente.

Iniettare contesto vista quando chiama il presentatore

Infine, potremmo passare il contesto di visualizzazione alla classe quando è inizializzato (o alternativamente in un metodo render)

class MyPresenter 
    attr_accessor :context 
    alias_method :h, :context 

    def initialize(context) 
     @context = context 
    end 

    def wrapped_link 
     h.content_tag :div, h.link_to('My link', h.root_url) 
    end 
end 

class MyController < ApplicationController 
    def show 
     # WARNING - `view_context` in a controller creates an object 
     @presenter = MyPresenter.new(view_context) 
    end 
end 
personalmente

I tendono ad inclinarsi verso le ultime due opzioni, ma senza una risposta definitiva dal team Rails (che sono stato in grado di trovare) mi sono sentito un po 'insicuro. Chi meglio chiedere che Stack!

risposta

5

vorrei andare con il mix di seconda e terza opzione, qualcosa di simile a:

class MyPresenter 
    def initialize(helpers) 
    @h = helpers 
    end 

    def wrapped_link 
    h.content_tag :div, h.link_to('My link', h.root_url) 
    end 

    private 
    attr_reader :h 
end 

La seconda opzione richiede tutti i test di unità per essere sradicate come ActionController::Base.helpers, che forse non è una buona opzione e la vostra terza opzione stai usando un contesto enorme per accedere ad alcuni metodi.

+0

Buon punto sullo stubbing' ActionController: : Base.helpers', non ci avevo pensato. Stilisticamente questa sembra la migliore strada da percorrere, e dopo un po 'di ricerche penso che il migliore (solo) 'view_context' da usare sia quello fornito dal controller o dall'helper che chiama il presentatore. – tombeynon

1

Lo farei davvero dipendere dal tipo di metodi che utilizzi. Se sono solo le basi come content_tag ecc. Vorrei andare per il modo ActionController::Base.helpers. È anche possibile chiamare alcuni helper direttamente, ad es. per i percorsi all'interno dei modelli ho quasi sempre usato qualcosa sulla falsariga di Rails.application.routes.url_helpers.comment_path.

Per i contenuti specifici del controller, la terza opzione potrebbe essere utile, ma personalmente il modo "puro" sembra più bello. Draper ha un approccio interessante anche: Essi salvare il view_context per la richiesta corrente e quindi delegare le chiamate a h -helpers ad esso: https://github.com/drapergem/draper/blob/master/lib/draper/view_context.rb

E 'davvero solo una questione di preferenza. Non includerei mai tutti gli aiutanti in una volta, come hai già detto. Ma la seconda opzione è molto carina se vuoi creare il livello di presentazione da solo senza utilizzare una gemma come Draper o Celle.

+0

Grazie Rudolf, anche io avevo guardato su Draper. È interessante anche che utilizzino il controller 'view_context', anche se sembra che abbiano avuto molti problemi con questo in passato - https://github.com/drapergem/draper/issues/124 – tombeynon