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.).
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")
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.
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
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) %>
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.
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/
(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.