Ответ 1
В Rails 3, 4 и 5 вы можете использовать:
Rails.application.routes.url_helpers
например
Rails.application.routes.url_helpers.posts_path
Rails.application.routes.url_helpers.posts_url(:host => "example.com")
Скажем, у меня есть модель Rails под названием Thing. Вещь имеет атрибут url, который может произвольно устанавливать URL-адрес где-то в Интернете. В коде зрения мне нужна логика, которая делает следующее:
<% if thing.url.blank? %>
<%= link_to('Text', thing_path(thing)) %>
<% else %>
<%= link_to('Text', thing.url) %>
<% end %>
Эта условная логика в представлении является уродливой. Конечно, я мог бы создать вспомогательную функцию, которая изменила бы представление на это:
<%= thing_link('Text', thing) %>
Это решает проблему многословности, но я бы предпочел иметь функциональность в самой модели. В этом случае код представления:
<%= link_to('Text', thing.link) %>
Это, очевидно, потребует метода ссылок на модель. Здесь он должен содержать:
def link
(self.url.blank?) ? thing_path(self) : self.url
end
В вопросе вопроса thing_path() является методом undefined внутри кода модели. Я предполагаю, что можно "втягивать" некоторые вспомогательные методы в модель, но как? И есть ли реальная причина, что маршрутизация работает только на контроллере и просматривает уровни приложения? Я могу придумать множество случаев, когда код модели может потребоваться для обработки URL-адресов (интеграция с внешними системами и т.д.).
В Rails 3, 4 и 5 вы можете использовать:
Rails.application.routes.url_helpers
например
Rails.application.routes.url_helpers.posts_path
Rails.application.routes.url_helpers.posts_url(:host => "example.com")
Я нашел ответ о том, как это сделать сам. Внутри кода модели просто поставьте:
Для Rails <= 2:
include ActionController::UrlWriter
Для Rails 3:
include Rails.application.routes.url_helpers
Это волшебным образом возвращает thing_path(self)
URL-адрес текущей вещи или other_model_path(self.association_to_other_model)
возвращает другой URL-адрес.
Вы также можете найти следующий подход более чистым, чем включать все методы:
class Thing
delegate :url_helpers, to: 'Rails.application.routes'
def url
url_helpers.thing_path(self)
end
end
Любая логика, связанная с тем, что отображается в представлении, должна быть делегирована вспомогательному методу, так как методы в модели строго предназначены для обработки данных.
Вот что вы могли бы сделать:
# In the helper...
def link_to_thing(text, thing)
(thing.url?) ? link_to(text, thing_path(thing)) : link_to(text, thing.url)
end
# In the view...
<%= link_to_thing("text", @thing) %>
Мне очень нравится следовать чистому решению.
class Router
include Rails.application.routes.url_helpers
def self.default_url_options
ActionMailer::Base.default_url_options
end
end
router = Router.new
router.posts_url # http://localhost:3000/posts
router.posts_path # /posts
Это из http://hawkins.io/2012/03/generating_urls_whenever_and_wherever_you_want/
Несмотря на то, что может быть способ, я хотел бы оставить такую модель из Модели. Я согласен, что вы не должны помещать это в представление (держать его тощим), но если модель не возвращает URL-адрес в виде части данных к контроллеру, материал маршрутизации должен находиться в контроллере.
(Edit: Забудьте о моем предыдущем болтовне...)
Хорошо, могут быть ситуации, когда вы переходите либо к модели, либо к другому URL-адресу... Но я действительно не думаю, что это принадлежит модели, представление (или, может быть, модель) звучит более подходящим.
О маршрутах, насколько я знаю, маршруты предназначены для действий в контроллерах (обычно "магически" использует представление), а не непосредственно к представлениям. Контроллер должен обрабатывать все запросы, представление должно представлять результаты, и модель должна обрабатывать данные и подавать их на просмотр или контроллер. Я слышал, как много людей говорили о маршрутах к моделям (до такой степени, что я начинаю все это начинать), но, насколько я понимаю, маршруты идут к контроллерам. Конечно, многие контроллеры являются контроллерами для одной модели и часто называются <modelname>sController
(например, "UsersController" является контроллером модели "Пользователь" ).
Если вы обнаружите, что пишете довольно неприятные количества логики в представлении, попробуйте переместить логику где-то более уместно; логика запроса и внутренней связи, вероятно, принадлежит контроллеру, логика, связанная с данными, может быть помещена в модель (но не логика отображения, которая включает в себя теги ссылок и т.д.), а логика, которая является чисто связанной с отображением, будет помещена в помощник.