Modifiez le nom du paramètre: id dans Routing resources for Rails


107

J'ai regardé autour de moi pour savoir comment changer l'emplacement des paramètres dynamiques et j'ai trouvé ce post qui fait exactement la chose. Le message est https://thoughtbot.com/blog/rails-patch-change-the-name-of-the-id-parameter-in

Fondamentalement, ce qu'il fait est, si les itinéraires suivants sont:

map.resources :clients, :key => :client_name do |client|
  client.resources :sites, :key => :name do |site|
    site.resources :articles, :key => :title
  end
end

Ces itinéraires créent les chemins suivants:

/clients/:client_name
/clients/:client_name/sites/:name
/clients/:client_name/sites/:site_name/articles/:title

Une solution consiste à remplacer la def to_paramméthode dans le modèle, mais je veux cela sans toucher au modèle lui-même.

Mais comme c'est pour Rails 2.x, comment puis-je obtenir la même chose pour Rails 3?

Mettre à jour

Cette application utilise Mongoid. Pas AR. Ainsi, la gemme amicale ne peut pas être utilisée afaik.

Réponses:


192

Rails 4 et 5

Dans Rails 4, l' :paramoption a été ajoutée, qui semble faire exactement ce que vous recherchez. Vous pouvez jeter un oeil au code Rails 3 par rapport au code Rails 4 .

Détails

Vous pouvez facilement l'implémenter dans votre routes.rbfichier:

# config/routes.rb

resources :posts, param: :slug

# app/controllers/posts_controller.rb

# ...
@post = Post.find_by(slug: params[:slug])
# ...

Depuis la sortie de Rails 4, cette fonctionnalité est documentée dans les guides Rails .

Rails 3

Malheureusement, dans Rails 3, l' :keyoption pour a resourcesété supprimée, vous ne pouvez donc plus changer facilement le nom des routes créées de cette manière en passant simplement une option supplémentaire.

Détails

Je suppose que vous avez déjà fait fonctionner l'application comme vous le souhaitez au cours de la dernière année, mais je vais trouver un moyen d'obtenir l'effet que vous décrivez dans Rails 3 routes.rb. Cela impliquera juste un peu plus de travail que la to_paramméthode. Vous pouvez toujours définir des paramètres personnalisés dans des itinéraires définis à l' aide scopeet match(ou cousins de elle get, put, postet delete). Il vous suffit d'écrire le nom du paramètre souhaité dans le matcher:

get 'clients/:client_name', :to => 'clients#show', :as => client

scope 'clients/:client_name' do
  get 'sites/:name', :to => 'sites#show', :as => site
end

Vous devrez ajouter manuellement tous les itinéraires créés resourcesautomatiquement pour vous, mais cela permettrait d'obtenir ce que vous recherchez. Vous pouvez également utiliser efficacement l' :controlleroption avec scopeet des scopeblocs supplémentaires pour supprimer une partie de la répétition.


EDIT (8 mai 2014): Rendez plus évident la réponse contient des informations pour les deux Rails 3 et 4. Mettez à jour les liens vers le code pour aller aux numéros de ligne et commits exacts afin qu'ils fonctionnent pendant une période plus longue.

EDIT (16 novembre 2014): Rails 4 devrait être au sommet maintenant et inclure des informations pertinentes car il s'agit de la version actuelle de Rails depuis un certain temps maintenant.

EDIT (9 août 2016): pensez que la solution fonctionne toujours dans Rails 5 et mettez à jour les liens obsolètes.


1
Donc, fondamentalement, Rails3 a créé l'option de ressources dans le routeur pour être reposante, mais doit être remplacée pour avoir des noms de variables personnalisés ...
Augustin Riedinger

1
Voici un backport de l' paramoption pour les rails 3: gist.github.com/sj26/44ef47fe8b98b46ee32d
sj26

Cela finit par casser les assistants d'URL. Ils finissent par générer une route basée sur un identifiant normal si je passe un objet ou se plaignent d'une clé [: slug] manquante si je passe le slug. Des idées pour résoudre le problème?
RonLugge

9
Pour info, si vous utilisez des ressources imbriquées, le paramètre de la ressource parent sera post_slug, ce qui peut prêter à confusion.
ghayes

4
C'est vraiment bien mais que puis-je faire si je ne veux pas de nom de paramètre de l'id parent comme post_post_id pour la ressource imbriquée?
Asnad Atta

45

dans Rails 4, passez l'option param pour modifier les paramètres: id. Par exemple resources :photos, param: :photo_nameva générer / photos /: photo_name


1

Si je vous comprends bien, ce que vous voulez, c'est avoir la client_nameplace de iddans votre URL, non?

Vous pouvez le faire en remplaçant la to_paramméthode dans votre modèle. Vous pouvez obtenir plus d'informations ici .


1
Comme je l'ai déjà mentionné, j'ai la contrainte de ne pas changer de modèle. L'exemple susmentionné n'est-il pas pris en charge ou obsolète dans Rails 3?
Autodidacte du

1

Il y a un bijou pour ça, tout comme il y a un bijou pour tout;)

J'utilise FriendlyId pour ce genre de comportement dans les rails 3.

Il vous faudra cependant ajouter du code à votre modèle, comme ceci:

class Client < ActiveRecord::Base
  has_friendly_id :name
end

... et si vos clients n'ont pas de noms compatibles URI, vous pouvez utiliser un slug pour cela, ce que vous pouvez faire has_friendly_id :name, :use_slug => true. Lorsque vous utilisez des slugs, vous devrez évidemment les conserver dans la base de données.

Et comme déjà mentionné, vous pouvez toujours utiliser l' to_paramastuce avec les rails 3, comme documenté ici . Je trouve cependant FriendlyId un peu plus polyvalent.


J'aime les identités amicales et l'ai utilisé dans de nombreux projets. En fait, mon application utilise Mongoid. Et friendly_id ne le supporte pas afaik. Et comme je l'ai déjà mentionné, ma contrainte n'est pas de changer de modèle.
Autodidacte du

1
Si vous utilisez mongoid, il y a mongoid-slug pour atteindre cette fonctionnalité. Il utilise en fait to_param, mais il fait également d'autres choses intelligentes en arrière-plan. J'ai trouvé le lien ici: stackoverflow.com/questions/4744446/…
Frost

J'ai aimé ce bijou. Il existe un autre slugoïde similaire . Mais comme je l'ai dit, j'ai la contrainte de ne pas modifier le modèle. Cela to_parambrise ma partie frontale de l'application. En fait, je cherche désespérément l'approche de routage, c'est que je dois changer mon API mais sans casser la partie modèle et frontend de l'application. Pourquoi ne puis-je pas simplement avoir l'approche de modifier les itinéraires uniquement comme je l'ai indiqué et l'exemple de poste pour l'ancienne version des rails ci-dessus ???
Autodidacte du

Avez-vous essayé de réécrire vos contrôleurs afin qu'ils utilisent vos clés de route personnalisées? Par exemple @client = Client.find(:name => param[:client_name]dans ClientsController#show? Cela pourrait marcher.
Frost

Client.where(:name => param[:client_name]).first, C'est.
Frost

0

Dans Rails 3, vous pouvez renommer les clés d'identifiant en utilisant une combinaison d'espaces de noms et d'étendues comme celle-ci (pas très bien cependant):

namespace :clients do
  scope "/:client_name" do
    namespace :sites do
      scope "/:name" do
         post "/:title" => "articles#create"
         ...
      end
    end
  end
end
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.