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

时间:2009-07-05 10:18:41

标签: ruby-on-rails

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

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

如果模型验证失败,如何将URL保留为/contact?目前,在验证失败时,网址会更改为/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

提前致谢。

4 个答案:

答案 0 :(得分: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

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

现在,以您创建消息对象的形式更改

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

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

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

应该解决你的烦恼。

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

  • 解释为什么在这里使用连接不是问题 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'})

我更喜欢原始方法......

答案 1 :(得分:1)

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

如果你把它写成资源路线

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

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

答案 2 :(得分:0)

我怀疑您是从表单中发布'/ messages'来创建邮件,该邮件解释了您在网址中看到的原因。

任何原因都不起作用:

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

答案 3 :(得分: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