402 Stimmen

Können Rails Routing-Helfer (d.h. mymodel_path(model)) in Modellen verwendet werden?

Angenommen, ich habe ein Rails-Modell namens Thing. Thing hat ein url-Attribut, das wahlweise auf eine URL irgendwo im Internet gesetzt werden. Im Ansichtscode benötige ich eine Logik, die das Folgende tut:

<% if thing.url.blank? %>
<%= link_to('Text', thing_path(thing)) %>
<% else %>
<%= link_to('Text', thing.url) %>
<% end %>

Diese bedingte Logik in der Ansicht ist hässlich. Natürlich könnte ich eine Hilfsfunktion erstellen, die die Ansicht in diese ändert:

<%= thing_link('Text', thing) %>

Das löst das Problem der Ausführlichkeit, aber ich würde es wirklich vorziehen, die Funktionalität im Modell selbst zu haben. In diesem Fall würde der Code der Ansicht sein:

<%= link_to('Text', thing.link) %>

Dies würde natürlich eine Verknüpfungsmethode für das Modell erfordern. Hier ist, was sie enthalten müsste:

def link
  (self.url.blank?) ? thing_path(self) : self.url
end

Um auf die Frage einzugehen: thing_path() ist eine undefinierte Methode im Model-Code. Ich nehme an, dass es möglich ist, einige Hilfsmethoden in das Model "hineinzuziehen", aber wie? Und gibt es einen wirklichen Grund dafür, dass das Routing nur auf den Controller- und View-Schichten der App funktioniert? Ich kann mir viele Fälle vorstellen, in denen Modell-Code mit URLs (Integration mit externen Systemen, etc.) umgehen müssen.

746voto

Paul Horsfall Punkte 8002

In Rails 3 und höher:

Rails.application.routes.url_helpers

z.B..

Rails.application.routes.url_helpers.posts_path
Rails.application.routes.url_helpers.posts_url(:host => "example.com")

190voto

Aaron Longwell Punkte 8083

Ich habe die Antwort auf die Frage, wie man das macht, selbst gefunden. Innerhalb der Modell-Code, nur setzen:

Für Rails <= 2:

include ActionController::UrlWriter

Für Rails 3:

include Rails.application.routes.url_helpers

Dies macht auf magische Weise thing_path(self) die URL für das aktuelle Ding zurückgeben, oder other_model_path(self.association_to_other_model) eine andere URL zurückgeben.

134voto

matthuhiggins Punkte 1923

Möglicherweise finden Sie auch die folgende Vorgehensweise sauberer als die Einbeziehung aller Methoden:

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

  def url
    url_helpers.thing_path(self)
  end
end

15voto

Josh Delsman Punkte 3006

Jede Logik, die mit der Anzeige in der Ansicht zu tun hat, sollte an eine Hilfsmethode delegiert werden, da die Methoden im Modell ausschließlich für die Verarbeitung von Daten bestimmt sind.

Das können Sie tun:

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

12voto

Swar Shah Punkte 123

Die folgende saubere Lösung gefällt mir sehr gut.

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

Es ist von http://hawkins.io/2012/03/generating_urls_whenever_and_wherever_you_want/

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X