web-dev-qa-db-fra.com

Les aides de routage Rails (par exemple, mymodel_path (model)) peuvent-elles être utilisées dans des modèles?

Disons que j'ai un modèle Rails appelé Thing. Thing a un attribut url qui peut éventuellement être défini sur une URL quelque part sur Internet. Dans le code d'affichage, j'ai besoin d'une logique qui effectue les tâches suivantes:

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

Cette logique conditionnelle dans la vue est laide. Bien sûr, je pourrais créer une fonction d’aide, qui changerait la vue en ceci:

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

Cela résout le problème de verbosité, mais je préférerais vraiment avoir la fonctionnalité dans le modèle lui-même. Dans ce cas, le code de vue serait:

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

Cela nécessiterait évidemment une méthode de lien sur le modèle. Voici ce qu'il faut contenir:

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

Au point de la question, thing_path () est une méthode non définie dans le code du modèle. Je suppose qu'il est possible "d'intégrer" certaines méthodes d'assistance dans le modèle, mais comment? Et y a-t-il une vraie raison pour laquelle le routage ne fonctionne que sur le contrôleur et affiche les couches de l'application? Je peux penser à de nombreux cas où le code de modèle doit parfois traiter des URL (intégration à des systèmes externes, etc.).

337
Aaron Longwell

Dans Rails 3, 4 et 5, vous pouvez utiliser:

Rails.application.routes.url_helpers

par exemple.

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

J'ai trouvé la réponse concernant la façon de procéder moi-même. Dans le code du modèle, il suffit de mettre:

Pour les rails <= 2:

include ActionController::UrlWriter

Pour les rails 3:

include Rails.application.routes.url_helpers

Comme par magie, thing_path(self) renvoie l'URL de l'élément en cours ou other_model_path(self.association_to_other_model) renvoie une autre URL.

177
Aaron Longwell

Vous pouvez également trouver l'approche suivante plus propre que d'inclure chaque méthode:

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

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

Toute logique liée à ce qui est affiché dans la vue doit être déléguée à une méthode d'assistance, car les méthodes du modèle servent uniquement à traiter des données.

Voici ce que vous pourriez faire:

# 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

Bien qu'il y ait peut-être un moyen, j'aurais tendance à garder ce genre de logique en dehors du modèle. Je conviens que vous ne devriez pas mettre cela dans la vue ( gardez-le maigre ), mais à moins que le modèle ne renvoie une url sous forme de données au contrôleur, le truc de routage doit être dans le contrôleur.

1
Ryan Montgomery

J'aime vraiment suivre la solution propre.

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

Il est basé sur http://hawkins.io/2012/03/generating_urls_whenever_and_wherever_you_want/

0
Swar Shah

(Edit: Oubliez mon précédent babillage ...)

Ok, il peut y avoir des situations où vous iriez soit au modèle, soit à une autre URL ... Mais je ne pense pas vraiment que cela appartient au modèle, la vue (ou peut-être le modèle) semble plus appropriée.

Autant que je sache, les routes sont destinées aux actions des contrôleurs (qui utilisent généralement une vue comme par magie), pas directement aux vues. Le contrôleur doit gérer toutes les demandes, la vue doit présenter les résultats et le modèle doit gérer les données et les transmettre à la vue ou au contrôleur. J'ai entendu beaucoup de gens ici parler des routes vers les modèles (au point que je commence à peine à la croire), mais si je comprends bien, les routes vont aux contrôleurs. Bien sûr, de nombreux contrôleurs sont des contrôleurs pour un modèle et sont souvent appelés <modelname>sController (par exemple, "UsersController" est le contrôleur du modèle "User"). 

Si vous vous retrouvez en train d'écrire de vilaines quantités de logique dans une vue, essayez de déplacer la logique dans un endroit plus approprié; la logique de requête et de communication interne appartient probablement à l'automate, la logique relative aux données peut être placée dans le modèle (mais pas la logique d'affichage, qui inclut les balises de lien, etc.) et la logique purement liée à l'affichage serait placée dans un assistant.

0