Можно ли использовать в моделях помощники маршрутизации Rails (т.е. mymodel_path (model))? - PullRequest
347 голосов
/ 04 декабря 2008

Скажем, у меня есть модель 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 () - это неопределенный метод внутри кода модели. Я предполагаю, что в модель можно добавить некоторые вспомогательные методы, но как? И есть ли реальная причина, по которой маршрутизация работает только на контроллере и уровнях просмотра приложения? Я могу вспомнить множество случаев, когда коду модели может потребоваться URL-адреса (интеграция с внешними системами и т. Д.).

Ответы [ 7 ]

662 голосов
/ 28 марта 2011

В 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")
179 голосов
/ 04 декабря 2008

Я нашел ответ относительно того, как сделать это сам. Внутри кода модели просто введите:

для рельсов <= 2: </p>

include ActionController::UrlWriter

Для рельсов 3:

include Rails.application.routes.url_helpers

Это волшебным образом заставляет thing_path(self) возвращать URL для текущей вещи, или other_model_path(self.association_to_other_model) возвращает какой-то другой URL.

113 голосов
/ 24 августа 2011

Вы также можете найти следующий подход чище, чем каждый метод:

class Thing
  delegate :url_helpers, to: 'Rails.application.routes' 

  def url
    url_helpers.thing_path(self)
  end
end
13 голосов
/ 04 декабря 2008

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

Вот что вы могли бы сделать:

# 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) %>
2 голосов
/ 05 февраля 2019

Мне очень нравится следующее чистое решение.

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/

1 голос
/ 04 декабря 2008

Хотя, возможно, есть способ, которым я стараюсь не допускать такую ​​логику в Модель. Я согласен с тем, что вы не должны указывать это в представлении ( держать его тощим ), но если модель не возвращает URL-адрес в виде фрагмента данных в контроллер, данные о маршрутизации должны находиться в контроллере.

0 голосов
/ 04 декабря 2008

(Редактировать: Забудьте мою предыдущую болтовню ...)

Хорошо, могут быть ситуации, когда вы переходите либо к модели, либо к другому URL-адресу ... Но я не думаю, что это относится к модели, вид (или, возможно, модель) звучит более подходящим.

О маршрутах, насколько я знаю, маршруты предназначены для действий в контроллерах (которые обычно «магическим образом» используют представление), а не непосредственно к представлениям. Контроллер должен обрабатывать все запросы, представление должно представлять результаты, а модель должна обрабатывать данные и передавать их представлению или контроллеру. Я слышал, что многие люди здесь говорят о маршрутах к моделям (до такой степени, что я начинаю верить в это), но, насколько я понимаю, маршруты идут к контролерам. Конечно, многие контроллеры являются контроллерами для одной модели и часто называются <modelname>sController (например, «UsersController» - это контроллер модели «Пользователь»).

Если вы обнаружите, что пишете отвратительное количество логики в представлении, попробуйте переместить логику куда-нибудь более подходящую; Логика запросов и внутренней связи, вероятно, принадлежит контроллеру, логика, связанная с данными, может быть помещена в модель (но не логика отображения, которая включает теги ссылок и т. д.), а логика, которая связана исключительно с отображением, будет помещена в помощник.

...