在模型validation失败时使用自定义路径

我刚刚在我的Rails应用程序中添加了一个联系表单,以便站点访问者可以向我发送消息。 该应用程序有一个Message资源,我已经定义了这个自定义路由,使URL更好,更明显:

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

当模型validation失败时,如何将URL保持为/contact ? 目前,在validation失败时,URL会更改为/messages

这是我的messages_controllercreate方法:

 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 

提前致谢。

一种解决方案是使用以下代码创建两个条件路由:

 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 

这将使所有获取请求(直接请求等)使用“新”操作,并且post请求“创建”操作。 (还有另外两种类型的请求:put和delete,但这些都与此无关。)

现在,在您创建消息对象更改的表单中

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

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

(表单助手将自动选择发布请求类型,因为在创建新对象时这是默认值。)

应该解决你的烦恼。

(这也不会导致地址栏闪烁其他地址。它从不使用其他地址。)

  • 解释为什么在这里使用connect不是问题map.name_of_route引用JUST THE PATH。 因此,第二条路线不需要新的命名路线。 您可以使用原始路径,因为路径相同。 所有其他选项仅在新请求到达rails时使用,并且需要知道将其发送到何处。

编辑

如果你认为额外的路线有点乱(特别是当你经常使用它时),你可以创建一个特殊的方法来创建它们。 这种方法不是很漂亮(可怕的变量名称),但它应该完成这项工作。

 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 

然后像这样使用它

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

我更喜欢原来的方法……

我刚刚提出了第二个解决方案,在奥马尔对我的第一个评论的指导下。

如果你把它写成你的资源路线

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

这给出了(以及其他)以下路线

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

因此,当您将“新”操作代码移动到“索引”操作中时,您将获得相同的结果。 没有闪烁和更容易阅读的路线文件。 但是,你的控制器将没有任何意义。

但是,我认为这是一个更糟糕的解决方案,因为您很快就会忘记为什么要将“新”代码放入索引操作中。

顺便说一句。 如果你想保留一种索引动作,你可以这样做

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

这将为您提供以下路线

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

然后,您可以将索引操作代码移动到manage操作中。

我怀疑你是从表单中发布’/ messages’来创建消息,这解释了为什么你在URL中看到了这个消息。

任何原因导致这种情况无效:

 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 

据我所知,没有。 因为即时通讯假设您想要渲染,以便保持@message对象不变,附加错误。

有一个可怕的解决方案,我会让你这样做,但是,它太可怕了,我不推荐它:

 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