2009-07-05 5 views
4

Je viens d'ajouter un formulaire de contact à mon application Rails afin que les visiteurs du site puissent m'envoyer un message. L'application dispose d'une ressource Message et je l'ai défini cet itinéraire personnalisé pour rendre l'URL plus agréable et plus évidente:Utilisation d'une route personnalisée lors de l'échec de la validation du modèle

map.contact '/contact', :controller => 'messages', :action => 'new' 

Comment puis-je conserver l'URL comme /contact lorsque le modèle validation échoue? Pour le moment, l'URL passe à /messages en cas d'échec de la validation.

Ceci est la méthode create dans mon messages_controller:

def create 
    @message = Message.new(params[:message]) 

    if @message.save 
    flash[:notice] = 'Thanks for your message etc...' 
    redirect_to contact_path 
    else 
    render 'new', :layout => 'contact' 
    end 
end 

Merci à l'avance.

Répondre

8

Une solution serait de faire deux routes conditionnelles avec le code suivant:

map.contact 'contact', :controller => 'messages', :action => 'new', :conditions => { :method => :get } 
map.connect 'contact', :controller => 'messages', :action => 'create', :conditions => { :method => :post } # Notice we are using 'connect' here, not 'contact'! See bottom of answer for explanation 

Cela fera toute requête get (demandes directes, etc.) utiliser l'action « nouveau », et la demande après l'action « créer ». (Il existe deux autres types de demandes: mettre et supprimer, mais ceux-ci ne sont pas pertinentes ici.)

Maintenant, sous la forme où vous créez l'objet de message changement

<%= form_for @message do |f| %> 

à

<%= form_for @message, :url => contact_url do |f| %> 

(L'assistant de formulaire choisira automatiquement le type de demande de publication, car il s'agit de la valeur par défaut lors de la création de nouveaux objets.)

Pour résoudre vos problèmes.

(Ce ne sera pas aussi provoquer le scintillement de la barre d'adresses autre adresse. Il utilise jamais une autre adresse.)

.

  • Explication pourquoi l'utilisation de la connexion est pas un problème ici Les références map.name_of_route JUSTE PATH. Par conséquent, vous n'avez pas besoin d'une nouvelle route nommée pour la deuxième route. Vous pouvez utiliser l'original, car les chemins sont les mêmes. Toutes les autres options sont utilisées uniquement lorsqu'une nouvelle requête atteint les rails et qu'elle doit savoir où l'envoyer.

.

EDIT

Si vous pensez que les routes supplémentaires font un peu de désordre (surtout quand vous utilisez le plus souvent), vous pouvez créer une méthode spéciale pour les créer. Cette méthode n'est pas très belle (noms de variables terribles), mais elle devrait faire l'affaire.

def map.connect_different_actions_to_same_path(path, controller, request_types_with_actions) # Should really change the name... 
    first = true # There first route should be a named route 
    request_types_with_actions.each do |request, action| 
    route_name = first ? path : 'connect' 
    eval("map.#{route_name} '#{path}', :controller => '#{controller}', :action => '#{action}', :conditions => { :method => :#{request.to_s} }") 
    first = false 
    end 
end 

Et puis l'utiliser comme ceci

map.connect_different_actions_to_same_path('contact', 'messages', {:get => 'new', :post => 'create'}) 

Je préfère la méthode originale mais ...

+0

C'est génial - merci! –

+0

J'aime cette solution, cependant, considérons map.resources: foo il semble un peu horrible d'ajouter deux mappages d'itinéraires supplémentaires par ressource pleinement utilisée (une pour new/create, une pour edit/update) pour vous assurer que vous êtes redirigé vers/foo/new et/foo/foo_id/edit en cas d'échec de création/mise à jour –

+0

désolé, pas de redirection .. les actions de publication seraient/foo/new et/foo/foo_id/éditer et ramasser par le routage! –

0

Je suppose que vous publiez sur '/ messages' à partir du formulaire qui crée le message qui explique pourquoi vous voyez cela dans votre URL.

Toute raison pour laquelle cela ne fonctionnera pas:

def create 
    @message = Message.new(params[:message]) 

    if @message.save 
    flash[:notice] = 'Thanks for your message etc...' 
    redirect_to contact_path 
    else 
    flash[:notice] = 'Sorry there was a problem with your message' 
    redirect_to contact_path 
    end 
end 
+0

Ne fonctionne pas, les erreurs ne seront pas retenues sur l'objet –

+0

Je pense aussi que c'est une solution vraiment moche ... Voir ma solution. –

0

Pas à ma connaissance, non. Puisque je suppose que vous voulez rendre afin que vous gardiez l'objet @ message comme c'est avec les erreurs attachées.

Il y a une solution horrible je qui vous permettra de le faire, mais son si horrible, je ne le recommanderais pas:

before_filter :find_message_in_session, :only => [:new] 

def new 
    @message ||= Message.new 
end 

def create 
    @message = Message.new(params[:message]) 
    if @message.save 
    flash[:notice] = 'Thanks for your message etc...' 
    redirect_to contact_path 
    else 
    flash[:notice] = 'Sorry there was a problem with your message' 
    store_message_in_session 
    redirect_to contact_path 
    end 
end 

private 

def find_message_in_session 
    @message = session[:message]; session[:message] = nil 
end 

def store_message_in_session 
    session[:message] = @message 
end 
1

Je suis venu avec une deuxième solution, guidée par les commentaires de Omar sur mon premier .

Si vous écrivez ce que votre itinéraire ressources

map.resources :messages, :as => 'contact' 

Cela donne (entre autres) les routes suivantes

/contact # + GET = controller:messages action:index 
/contact # + POST = controller:messages action:create 

Ainsi, lorsque vous déplacez votre code d'action 'nouveau' dans votre 'index' action, vous aurez le même résultat. Pas de scintillement et un fichier d'itinéraires plus facile à lire. Cependant, votre contrôleur n'aura plus de sens. Cependant, je pense que c'est une solution pire parce que vous oublierez bientôt pourquoi vous mettez votre «nouveau» code dans l'action d'index.

Btw. Si vous voulez garder une sorte d'action d'index, vous pouvez le faire

map.resources :messages, :as => 'contact', :collection => { :manage => :get } 

Cela vous donnera l'itinéraire suivant

manage_messages_path # = /contact/manage controller:messages action:manage 

Vous pouvez ensuite déplacer votre code d'action d'index dans l'action gérer.

Questions connexes