2011-01-17 2 views

ответ

74

Есть несколько причин, по которым вам может понадобиться link_to в модели. Да, @andy, это нарушение MVC, но это не значит, что вы должны получить очки за то, что не ответили на вопрос.

@schwabsauce, это проще, чем это. Первая строка даже не нужна, если вы делаете это в инициализаторе или что-то в этом роде. То же самое работает для .sanitize и .raw и цельной загрузки других потрясающих функций.

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

Если вы хотите использовать autopaths вы, возможно, придется сделать это внутри link_to:

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

Этот вопрос был задан некоторое время назад, и в этот момент совет @ andy помог мне решить эту проблему. Однако вы правы в том смысле, что это не отвечает на реальный вопрос. – Krule

-6

Не без хакеров.

Если вы считаете, что вам нужна модель link_to, вы, вероятно, нарушите какой-либо принцип Model-View-Controller architecture.

Модель должна быть местом для данных и бизнес-логики, но генерация ссылок почти наверняка является заданием для контроллера или представления (или Rails специально для вспомогательного класса).

+1

Спасибо. Перемещено для просмотра помощника. Теперь все подходит. – Krule

+18

Есть веские причины использовать помощников в моделях. Но более того, если вы собираетесь предложить мнение, по крайней мере, предложите решение, если они это продумают. Возможно, у кого-то с 2-мя повторителями голова прямо. –

5

Я получил эту работу со следующими включениями:

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 

Тогда в моем контроллере я заселен атрибут (создание контроллера с нуля требует значительного объема данных в аргументах хэша).

Lead.controller = self 
+1

fwiw, Rails-документация действительно ведет к этому решению. Документы для ActionDispatch :: Routing :: UrlFor отмечают, что «Совет. Если вам нужно создавать URL-адреса с ваших моделей или в каком-либо другом месте, то ActionController :: UrlFor - это то, что вы ищете». Затем, когда вы включаете этот файл, он предлагает в качестве сообщения об ошибке: raise «Чтобы использовать #url_for, вы должны явно указать помощники маршрутизации». «Например,« include Rails.application.routes.url_helpers » Так что я думаю, что это приемлемо по соглашениям Rails - иногда это лучший способ/лучшее место для создания ссылки :) – schwabsauce

+0

Да, например, если ваша модель обрабатывает авторизацию платежа стороннему внешнему шлюзу и должна генерировать URL-адрес возврата/отмены Вернуться к приложению. – hoffmanc

30

Будьте очень осторожны, следуя советам, изложенным в должности Чака, если вы делаете это в Rails 3.2. 1. Казалось бы, этот подход небезопасен, включая помощник link_to в классах без просмотра в Rails 3.2.1. Существует более безопасный способ (который работает для нас в любом случае), описанный ниже.

Когда мы использовали подход в сообщении Чак в одном из наших классов, он оказался очень тревожным и трудно отлаживающим. Это привело к возникновению побочных эффектов/ошибок, которые появились только в очень специфических (и редких) обстоятельствах.

Проблема, насколько мы можем сказать, что эта строка:

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

говорит ActionView::Base включить Rails.application.routes.url_helpers, который ActionView::Base, по-видимому, уже делает сама по себе. При этом он включает в себя url_helpers второй раз, кажется, вызывает повторную инициализацию состояния маршрутов (@_routes в классах, в которые включен модуль ActionDispatch :: Routing :: UrlFor).

Это приводит к, казалось бы, случайный и необъяснимый «неопределенный метод„url_for“для ноля: NilClass» исключений в представлениях, которые пытаются вызвать, прямо или косвенно, метод url_for послеActionView::Base включила url_helpers во второй раз.

Решение, которое сработало для нас, было вместо того, чтобы сообщать ActionView::Base, чтобы снова включить url_helpers, просто включите модуль UrlHelper, где бы он ни понадобился.

Затем, когда вам нужно использовать link_to и иметь доступ к пути, который вы можете просто сделать это (при условии, login_path действительна для вашего приложения):

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

Потребовалось очень много времени и довольно много от царапин на голове, чтобы отследить ошибки, вызванные двойным включением, и я просто хотел предупредить других о том, чтобы быть осторожными при настройке поведения базовых классов Rails.

+0

Спасибо, что поделились этим! Я рад, что ты нашел лучший способ! –

+1

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

+0

@karlingen - опуская ссылку на« Rails.application.routes ... »может привести к сообщению« аргументы, переданные в url_for, не могут быть обработаны. требуют маршрутов или предоставляют свою собственную реализацию " – Del

2

link_to хелперов, нарушение MVC

Что сказал Энди,

если вы генерации HTML в модели вы, вероятно, нужно сделать большой долго смотреть на то, что вы делаете и почему.

URL помощники

URL-адрес с другой стороны, часто приходят в удобных снаружи кода вида-контроллер, во всех видах услуг/виде/API/... классы, например, даже в моделях, если вам должен.

Да, Rails.application.routes.url_helpers представляет собой модуль, но это не означает, что вы просто должны включить его везде, где или забавный материал начнет происходит, как Гэри выразился:

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

Что вы можете сделать это:

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

, а затем использовать, например

url_helpers.home_url