181 votes

Meilleures pratiques pour gérer les itinéraires pour les sous-classes STI dans les rails

Mon Rails de vues et les contrôleurs sont jonché redirect_to, link_to, et form_for des appels de méthode. Parfois, link_to et redirect_to sont explicites dans les chemins qu'ils sont de liaison (par exemple, link_to 'New Person', new_person_path), mais de nombreuses fois les chemins sont implicites (par exemple, link_to 'Show', person).

J'ai ajouter un peu unique de l'héritage de table (STI) pour mon modèle (disons Employee < Person), et l'ensemble de ces méthodes de pause pour une instance de la sous-classe (disons Employee); lorsque les rails exécute link_to @person, c'erreurs avec undefined method employee_path' for #<#<Class:0x000001022bcd40>:0x0000010226d038>. Rails est à la recherche d'un itinéraire défini par le nom de la classe de l'objet, qui est employé. Ces employés routes ne sont pas définies, et il n'est pas un employé du contrôleur afin que les actions ne sont pas définis.

Cette question a été posée:

  1. À StackOverflow, la réponse est d'éditer chaque instance de link_to etc dans l'ensemble de votre base de code, et de l'état du chemin explicitement
  2. Sur StackOverflow de nouveau, deux personnes suggèrent d'utiliser routes.rb de la carte de la sous-classe des ressources pour la classe parent (map.resources :employees, :controller => 'people'). La réponse sommet dans la même DONC, la question suggère de conversion de type, chaque instance de l'objet dans la base de code à l'aide de .becomes
  3. Encore un autre à StackOverflow, la réponse sommet est la façon de le Faire Répéter Vous-même camp, et suggère la création d'dupliquer un échafaudage pour chaque sous-classe.
  4. Voici la même question, DONC, où la première réponse semble juste être mauvais (les Rails de la magie Fonctionne, tout Simplement!)
  5. Ailleurs sur le web, j'ai trouvé ce blog où F2Andy recommande d'édition dans le chemin d'accès partout dans le code.
  6. Sur le post de blog Unique de l'Héritage de Table et de repos des Routes à la Logique de la Réalité de la Conception, il est recommandé de recenser les ressources pour la sous-classe de super-classe de contrôleur, comme dans la réponse à la question 2 ci-dessus.
  7. Alex Reisner a un post Unique Héritage de Table dans les Rails, dans lequel il dénonce la cartographie des ressources de l'enfant des classes de la classe parente en routes.rb, étant donné que seules les captures de routage des ruptures de link_to et redirect_to, mais pas à partir d' form_for. Donc, il recommande plutôt l'ajout d'une méthode de la classe parente pour obtenir les sous-classes à mentir à propos de leur classe. Sonne bien, mais sa méthode m'a donné l'erreur undefined local variable or method `child' for #.

Donc la réponse qui semble le plus élégant et le plus consensus (mais c'est pas tout qu' élégant, ni que le niveau de consensus), est le complément de ressources pour votre routes.rb. Sauf que ça ne fonctionne pas pour form_for. J'ai besoin d'un peu de clarté! Pour en distiller les choix ci-dessus, sont mes options

  1. la carte des ressources de la sous-classe à la manette de la super-classe en routes.rb (et j'espère que je n'avez pas besoin d'appeler form_for sur toutes les sous-classes)
  2. Remplacer les rails internes des méthodes pour rendre les classes mentir les uns aux autres
  3. Modifier tous les cas, dans le code où le chemin d'accès à un objet de l'action est appelée implicitement ou explicitement, soit de modifier le chemin d'accès ou de conversion de type de l'objet.

Avec toutes ces réponses conflictuelles, j'ai besoin d'une décision. Il me semble qu'il y est pas de bonne réponse. Est-ce un défaut dans les rails de conception"? Si oui, est-ce un bug qui peut obtenir fixe? Ou si non, alors j'espère que quelqu'un pourra m'a tout droit sur cet, me promener à travers les avantages et les inconvénients de chaque option (ou d'expliquer pourquoi ce n'est pas une option), et que l'on est la bonne réponse, et pourquoi. Ou est-il un droit de réponse que je ne suis pas à trouver sur le web?

143voto

Prathan Thananart Points 1746

C'est la solution la plus simple que j'ai pu trouver avec un effet secondaire minime.

 class Person < Contact
  def self.model_name
    Contact.model_name
  end
end
 

Maintenant, url_for @person correspondra à contact_path comme prévu.

Comment ça marche: les aides URL reposent sur YourModel.model_name pour réfléchir sur le modèle et générer (entre autres choses) des clés de routage singulières / plurielles. Ici, Person dit essentiellement que je suis juste comme Contact mec, demandez lui .

47voto

James Points 855

J'ai eu le même problème. Après avoir utilisé STI, la méthode form_for était enregistrée dans la mauvaise URL enfant.

 NoMethodError (undefined method `building_url' for
 

J'ai fini par ajouter les routes supplémentaires pour les classes enfants et les diriger vers les mêmes contrôleurs

  resources :structures
 resources :buildings, :controller => 'structures'
 resources :bridges, :controller => 'structures'
 

Aditionellement:

 <% form_for(@structure, :as => :structure) do |f| %>
 

dans ce cas, la structure est en fait un bâtiment (classe enfant)

Cela semble fonctionner pour moi après avoir fait une soumission avec form_for .

35voto

Siwei Shen Points 5814

Je vous suggère de jeter un oeil à: http://stackoverflow.com/a/605172/445908 , en utilisant cette méthode vous permettra d'utiliser "form_for".

 ActiveRecord::Base#becomes
 

18voto

jobwat Points 1213

16voto

El_Hoy Points 646

Suivant l'idée de @ Thanathan Thanathan mais en essayant de ne rien détruire. (car il y a tellement de magie impliquée)

 class Person < Contact
  model_name.class_eval do
    def route_key
     "contacts"
    end
    def singular_route_key
      superclass.model_name.singular_route_key
    end
  end
end
 

Maintenant, url_for @person mappera comme prévu sur contact_path.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X