2009-07-05 60 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 

然後,您可以將您的索引操作代碼到管理行動。