2009-07-05 62 views
4

我刚刚向我的Rails应用程序添加了联系表单,以便网站访问者可以向我发送消息。应用程序有一个Message资源,我定义这个自定义路由,使URL更好,更明显:模型验证失败后使用自定义路由

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

我如何才能让网址为/contact当模型验证失败?目前,验证失败后URL更改为/messages

这是create方法在我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 

在此先感谢。

回答

8

一个解决办法是,以与这两个条件的路线下面的代码:

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 

这将使所有get请求(直接请求等)使用“新”的行动,并发布请求的“创建”行动。 (还有其他两种类型的请求:put和delete,但这些都无关紧要这里)。现在

,形式要在其中创建的消息对象变化

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

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

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

应该解决你的麻烦。

(这也不会导致地址栏闪烁的其他地址。它绝不会使用另一个地址。)

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

编辑

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

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'}) 

我喜欢,虽然原来的方法...

0

我怀疑你是从创建消息的表单发布到'/ 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 
+0

不会工作,错误不会保留在对象上 – 2009-07-05 10:47:02

+0

我也认为这是一个非常丑陋的解决方案......请参阅我的解决方案。 – 2009-07-05 13:28:58

0

据我所知,没有。因为我假设你想渲染,以便保持@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 
1

我只是想出了一个第二个解决方案,由奥马尔的评论对我的第一个引导。

如果你写这是你的资源路线

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

这给(其中包括)以下航线,当你移动你的“新”的动作代码到你的“索引”

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

所以行动,你会有相同的结果。没有闪烁和更容易阅读路线文件。但是,你的控制器将没有更多的意义。

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

Btw。如果你想保持一种指数的动作,你可以这样做

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

这会给你以下的路径,

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

然后,您可以将您的索引操作代码到管理行动。