2011-01-17 11 views

risposta

74

Ci sono alcuni motivi per cui è necessario collegare link a un modello. Sì, @andy, è una violazione di MVC, ma ciò non significa che dovresti ottenere punti per non rispondere alla domanda.

@schwabsauce, è più facile di così. La prima riga non è nemmeno strettamente necessaria se lo si fa in un inizializzatore o qualcosa del genere. La stessa cosa funziona per .sanitize e .raw e un intero carico di altre fantastiche funzioni.

ActionView::Base.send(:include, Rails.application.routes.url_helpers) 
ActionController::Base.helpers.link_to(whatever) 

Se si desidera utilizzare autopaths si può avere a che fare questo all'interno del vostro link_to:

Rails.application.routes.url_helpers.page_path(@page) 
+0

Questa domanda è stata posta qualche tempo fa e in quel momento il consiglio di @ andy mi ha aiutato a risolvere questo problema. Tuttavia, hai ragione nel senso che non risponde alla domanda reale. – Krule

-6

Non senza hackery.

Se si ritiene che sia necessario il modello link_to in un modello, è probabile che violare alcuni principi dello Model-View-Controller architecture.

Un modello deve essere un luogo per dati e business logic, ma la generazione di collegamenti è quasi certamente un lavoro per il controller o la vista (o, in particolare Rails, in una classe helper).

+1

Grazie. Spostate le cose per vedere l'helper. Tutto va bene adesso. – Krule

+18

Ci sono buoni motivi per utilizzare gli helper nei modelli. Ma più che altro, se hai intenzione di offrire un'opinione, almeno offri una soluzione nel caso in cui ci abbiano pensato. È possibile che qualcuno con 2k rep abbia la testa dritta. –

5

ho avuto questo lavoro con le seguenti inclusioni:

include ActionView::Helpers::UrlHelper 
include ActionController::UrlFor 
include Rails.application.routes.url_helpers 

cattr_accessor :controller 
def controller; self.class.controller; end 
def request; controller.request; end 

Poi nel mio controller ho popolato l'attributo (creando un controller da zero richiede una notevole quantità di dati negli argomenti cancelletto).

Lead.controller = self 
+1

fwiw, la documentazione di Rails apre la strada a questa soluzione. I documenti per ActionDispatch :: Routing :: UrlFor sottolineano che "Suggerimento: se devi generare URL dai tuoi modelli o da qualche altra posizione, allora ActionController :: UrlFor è quello che stai cercando." Quindi quando includi quel file che offre come messaggio di errore: raise "Per utilizzare #url_for, devi includere esplicitamente helper di routing." "Ad esempio,' include Rails.application.routes.url_helpers " Quindi penso che questo è accettabile dalle convenzioni Rails - a volte questo è il modo migliore/luogo migliore per generare un collegamento :) – schwabsauce

+0

Sì, ad esempio, se il modello gestisce l'autorizzazione di pagamento a un terzo, gateway offsite e deve generare URL di ritorno/annullamento torna alla app. – hoffmanc

30

essere molto attenti seguendo i consigli delineato nel post di Chuck se si sta facendo questo in Rails 3.2. 1. Sembrerebbe che questo approccio non sia un modo sicuro per includere il link_to helper nelle classi non-view in Rails 3.2.1. C'è un modo più sicuro (che funziona per noi in ogni caso) delineato di seguito.

Quando abbiamo utilizzato l'approccio nel post di Chuck in una delle nostre classi, ha finito per avere conseguenze molto spinose e difficili da debugare. Ha finito per causare effetti collaterali/bug che si sono presentati solo in circostanze molto specifiche (e rare).

Il problema, per quanto possiamo dire, è che questa linea:

ActionView::Base.send(:include, Rails.application.routes.url_helpers) 

sta dicendo ActionView::Base per includere il Rails.application.routes.url_helpers, che a quanto pare ActionView::Base fa già per conto suo. Avere incluso la url_helpers una seconda volta, sembra causare la reinizializzazione dello stato dei percorsi (@_routes nelle classi che hanno incluso il modulo ActionDispatch :: Routing :: UrlFor).

questo porta a apparentemente casuale e inspiegabile "metodo non definito 'url_for' per nil: NilClass" eccezioni in viste che tentano di chiamare, direttamente o indirettamente, il metodo url_for dopoActionView::Base ha incluso la url_helpers la seconda volta.

La soluzione che ha funzionato per noi era invece di dire ActionView::Base per includere il url_helpers ancora una volta, è sufficiente includere il modulo UrlHelper te, ovunque si potrebbe averne bisogno.

Poi, quando è necessario utilizzare link_to e avere accesso al percorso si può semplicemente fare questo (login_path supponendo che è valido per la vostra applicazione):

include ActionView::Helpers::UrlHelper 
... 
link = link_to('here', Rails.application.routes.url_helpers.login_path) 

C'è voluto un tempo molto lungo e un bel po ' di grattarsi la testa per rintracciare i bug causati dalla doppia inclusione e volevo solo avvertire gli altri di fare attenzione nel modificare il comportamento delle classi base di Rails.

+0

Grazie per averlo condiviso! Sono felice che tu abbia trovato un modo migliore! –

+1

One-liner: 'include ActionView :: Helpers :: UrlHelper' – karlingen

+0

@karlingen - omettendo il riferimento a' Rails.application.routes ... 'può portare al messaggio" gli argomenti passati a url_for non possono essere gestiti. richiedere percorsi o fornire la propria implementazione " – Del

2

link_to aiutante, MVC violazione

Cosa Andy ha detto,

se si sta generando HTML nel modello probabilmente bisogno di prendere un lungo sguardo grande a quello che si sta facendo e perché.

URL aiutanti

URL d'altra parte spesso tornare utile al di fuori del codice di view-controller, in tutti i tipi di servizi/form/api/... classi per esempio, anche nei modelli se dovere.

Sì, Rails.application.routes.url_helpers è un modulo, ma questo non significa che si dovrebbe solo includere ovunque o cose divertenti avrà inizio accadendo come Gary dirla:

https://www.destroyallsoftware.com/blog/2011/one-base-class-to-rule-them-all

Cosa si può fare è:

delegate :url_helpers, :to => 'Rails.application.routes' 

e quindi utilizzare, per esempio

url_helpers.home_url 
Problemi correlati