Могут ли в моделях использовать Rails Routing Helpers (т.е. Mymodel_path (model))?

Скажем, у меня есть модель 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-адресов (интеграция с внешними системами и т.д.).

Ответ 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")

Ответ 2

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

Для 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-адрес.

Ответ 3

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

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

  def url
    url_helpers.thing_path(self)
  end
end

Ответ 4

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

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

# 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) %>

Ответ 5

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

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/

Ответ 6

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

Ответ 7

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

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

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

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