2009-07-05 3 views
4

Я только что добавил форму контакта в мое приложение Rails, чтобы посетители сайта могли отправить мне сообщение. Приложение имеет Message ресурс и я определил этот пользовательский маршрут, чтобы сделать URL лучше и более очевидным:Использовать собственный маршрут при отказе проверки модели

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

Как я могу сохранить URL в /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 

Это сделает все получить запрос (прямые запросы и т.д.) использовать «новый» действие, и запрос на почту действие «создать». (Есть два типа запросов: поставить и удалить, но это не имеет значения здесь.)

Теперь, в форме, где вы создаете изменение объекта сообщения

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

к

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

(Помощник формы автоматически выбирает тип запроса сообщения, потому что это значение по умолчанию при создании новых объектов.)

Должно решить ваши проблемы.

(Это также не приведет к адресной строке мерцать другой адрес. Он никогда не использует другой адрес.)

.

  • Объяснение, почему использование подключения не проблема здесь Ссылки map.name_of_route РАЗ ПУТЬ. Поэтому для второго маршрута вам не нужен новый именованный маршрут. Вы можете использовать оригинальный, потому что пути одинаковы. Все остальные параметры используются только тогда, когда новый запрос достигает рельсов, и ему нужно знать, куда его отправить.

.

EDIT

Если вы думаете, что дополнительные маршруты сделать немного беспорядок (особенно если вы используете его чаще) вы можете создать специальный метод для их создания. Этот метод не очень красив (ужасные имена переменных), но он должен выполнять эту работу.

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

Это блестяще - спасибо! –

+0

Ну, спасибо;) –

+0

Мне нравится это решение, однако рассмотрим map.resources: foo кажется немного ужасным добавить два дополнительных сопоставления маршрута на полностью используемый ресурс (один для нового/создания, один для редактирования/обновления) чтобы вы перенаправлялись в/foo/new и/foo/foo_id/edit при сбое создания/обновления. –

0

Я подозреваю, что вы отправляете сообщения/сообщения из формы, которая создает сообщение, объясняющее, почему вы видите это в своем 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

Wont work, ошибки не будут сохранены на объекте –

+0

Я также считаю, что это действительно уродливое решение ... См. Мое решение. –

0

Насколько мне известно, нет. Поскольку im предполагает, что вы хотите сделать так, чтобы вы сохраняли объект @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 

Так что, когда вы перемещаете свой «новый» код действия в свой «индекс» действие, вы получите тот же результат. Нет мерцания и легче читать файл маршрутов. Однако ваш контроллер не будет иметь никакого смысла.

Я, однако, считаю, что это худшее решение, потому что вы скоро забудете, почему вы ввели свой «новый» код в действие индекса.

КПП. Если вы хотите сохранить своего рода индекс действия, вы могли бы сделать это

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

Это даст вам следующий маршрут

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

Вы могли бы затем переместить свой код индекса действий в действие управления.

Смежные вопросы