it-swarm.com.de

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 optional irgendwo im Internet auf eine URL gesetzt werden kann. Im View-Code benötige ich eine Logik, die Folgendes ausführt:

<% 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 aufbauen, die die Ansicht dazu ä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 lautet der Ansichtscode:

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

Dies würde natürlich eine Verknüpfungsmethode im Modell erfordern. Folgendes müsste enthalten sein:

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

Bis zur Frage ist thing_path () eine undefinierte Methode im Model-Code. Ich gehe davon aus, dass es möglich ist, einige Hilfsmethoden in das Modell "einzubeziehen", aber wie? Und gibt es einen echten Grund dafür, dass das Routing nur auf den Controller- und Ansichtsebenen der App funktioniert? Ich kann mir viele Fälle vorstellen, in denen Modellcode möglicherweise mit URLs umgehen muss (Integration mit externen Systemen usw.).

337
Aaron Longwell

In den Rails 3, 4 und 5 können Sie Folgendes verwenden:

Rails.application.routes.url_helpers

z.B.

Rails.application.routes.url_helpers.posts_path
Rails.application.routes.url_helpers.posts_url(:Host => "example.com")
650
Paul Horsfall

Ich habe die Antwort gefunden, wie ich das selbst machen kann. Im Code des Modells einfach Folgendes einfügen:

Für Rails <= 2:

include ActionController::UrlWriter

Für Rails 3:

include Rails.application.routes.url_helpers

Dies bewirkt, dass thing_path(self) auf magische Weise die URL für das aktuelle Objekt zurückgibt oder other_model_path(self.association_to_other_model) eine andere URL zurückgibt.

177
Aaron Longwell

Möglicherweise finden Sie den folgenden Ansatz sauberer als alle Methoden:

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

  def url
    url_helpers.thing_path(self)
  end
end
111
matthuhiggins

Jede Logik, die sich auf das bezieht, was in der Ansicht angezeigt wird, sollte an eine Hilfsmethode delegiert werden, da die Methoden im Modell ausschließlich zum Umgang mit Daten dienen.

Folgendes 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) %>
13
Josh Delsman

Während es einen Weg gibt, neige ich dazu, diese Art von Logik aus dem Modell herauszuhalten. Ich bin damit einverstanden, dass Sie dies nicht in der Ansicht anzeigen sollten ( Keep Skinny ), aber wenn das Modell keine URL als Datenstück an den Controller zurückgibt, sollte sich das Routing im Controller befinden.

1
Ryan Montgomery

Ich mag es, eine saubere Lösung zu finden.

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 basiert auf http://hawkins.io/2012/03/generating_urls_whenever_and_wherever_you_want/

0
Swar Shah

(Edit: Vergiss mein vorheriges Geschwätz ...)

Ok, es könnte Situationen geben, in denen Sie entweder zum Modell oder zu einer anderen URL gehen würden ... Aber ich glaube nicht, dass dies in das Modell gehört, die Ansicht (oder vielleicht auch das Modell) klingt angemessener.

Über die Routen, soweit ich weiß, sind die Routen für die Aktionen in Controllern (die normalerweise "magisch" eine View verwenden), nicht direkt auf Views. Der Controller sollte alle Anforderungen verarbeiten, die Ansicht sollte die Ergebnisse präsentieren und das Modell sollte die Daten verarbeiten und sie der Ansicht oder dem Controller bereitstellen. Ich habe viele Leute hier über Routen zu Modellen reden hören (bis zu dem Punkt, an dem ich fast anfange, es zu glauben), aber so wie ich es verstehe: Routen gehen an Controller. Natürlich sind viele Controller Controller für ein Modell und werden oft <modelname>sController genannt (z. B. "UsersController" ist der Controller des Modells "User"). 

Wenn Sie feststellen, dass Sie unangenehme Mengen an Logik in eine Ansicht schreiben, versuchen Sie, die Logik an einen geeigneten Ort zu verschieben. Anforderungs- und interne Kommunikationslogik gehört wahrscheinlich in die Steuerung, datenbezogene Logik kann in das Modell eingefügt werden (jedoch keine Anzeigelogik, die Verbindungskennungen usw. enthält), und eine rein displaybezogene Logik würde in einen Helfer gestellt.

0