65 votes

Ruby on rails : ressource singulière et form_for

Je veux que l'utilisateur travaille avec une seule commande connectée à sa session. J'ai donc défini une ressource unique pour la commande

routes.rb :

resource :order

vues/commandes/nouvelles.html.erb :

<%= form_for @order do |f| %>
   ...
<% end %>

Mais lorsque j'ouvre la page de la nouvelle commande, j'obtiens une erreur :

undefined method `orders_path`

Je sais, que je peux mettre :url => order_path en form_for mais quelle est la véritable façon de résoudre cette collision ?

0 votes

Je ne suis pas sûr de comprendre pourquoi vous n'utilisez pas le singulier pour vos ressources.

0 votes

Parce que le guide des rails conseille d'utiliser la forme plurielle de contrôleur. Mais dans la forme singulière de contrôleur existe le même bug...

0 votes

Si vous avez juste une ressource singulière imbriquée qui vous pose problème, vous pouvez utiliser form_for [@user, :subscription, @payment] pour générer des chemins pour user_subscription_payment_path(@user, @payment) avec des chemins comme action="/users/21/subscription/payments/29" .

61voto

mckeed Points 6200

Malheureusement, c'est un bug . Vous devrez définir l'url comme vous le mentionnez.

= form_for @order, :url => order_path do |f|

Notez que ceci va correctement router vers create o update selon que @order est persistante.


Mise à jour

Il y a maintenant une autre option. Vous pouvez l'ajouter à la configuration de vos routes :

resolve("Order") { [:order] }

Ensuite, lorsque le polymorphic_url reçoit un objet avec le nom de classe "Ordre", il utilisera la méthode suivante [:order] comme composant url au lieu d'appeler model_name.route_key comme décrit dans La réponse de jskol .

Cette méthode est limitée par le fait qu'elle ne peut pas être utilisée dans des scopes ou des espaces de noms. Vous pouvez acheminer un modèle d'espace de noms au niveau supérieur de la configuration des routes :

resolve('Shop::Order') { [:shop, :order] }

Mais cela n'aura pas d'effet sur les routes avec des composants supplémentaires, alors

url_for(@order)           # resolves to shop_order_url(@order)
url_for([:admin, @order]) # resolves to admin_shop_orders_url(@order) 
                          #        note plural 'orders' 
                          #        also, 'shop' is from module name, not `resolve` in the second case

5 votes

Les problèmes de Rails ont été déplacés de Lighthouse vers Github. Voici le problème dans Github : github.com/rails/rails/issues/1769

2 votes

1 votes

C'est toujours un problème à la fin de 2016. Tout le monde est à jour ;)

52voto

jshkol Points 867

D'où vient ce chemin magique ?

Cela m'a pris beaucoup de temps, mais j'ai fini par découvrir que l'url_for détermine le chemin d'accès à votre modèle en utilisant l'attribut polymorphic_path définie dans ActionDispatch::Routing::PolymorphicRoutes . polymorphic_path obtient finalement le chemin automatique pour votre modèle en appelant quelque chose du genre :

record.class.model_name.route_key

Je simplifie un peu, mais c'est en gros ce qu'il faut faire. Si vous avez un tableau (par ex. form_for[@order, @item] ), l'opération ci-dessus est appelée sur chaque élément et les résultats sont joints à l'aide de la commande _ .

Le site model_name de votre classe provient de ActiveRecord::Nommage .

module ActiveModel
  ...
  module Naming
    ...
    def model_name
      @_model_name ||= begin
        namespace = self.parents.detect do |n|
          n.respond_to?(:use_relative_model_naming?) && 
                                                 n.use_relative_model_naming?
        end
        ActiveModel::Name.new(self, namespace)
      end
    end
  end
end

Comment puis-je le changer ?

Heureusement, ActiveModel::Nom précalcule toutes les valeurs, y compris route_key, donc pour remplacer cette valeur, il suffit de changer la valeur de la variable d'instance.

Pour le :order ressource dans votre question :

class Order < ActiveRecord::Base
  model_name.instance_variable_set(:@route_key, 'order')
  ...
end

# new.html.erb
<%= form_for @order do |f| # Works with action="/order" %>
    ...
<% end %>

Essayez-le !

1 votes

@aidan merci ! L'autre réponse avait déjà été acceptée depuis un certain temps lorsque j'ai rencontré ce problème moi-même.

2 votes

C'est beaucoup d'investigation pour une réponse super rad. Bravo.

0 votes

C'est une réponse de ninja.

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