Использовать пользовательский маршрут при сбое проверки модели

Я только что добавил контактную форму в свое приложение на 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

Заранее спасибо.

Ответы на вопрос(4)

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

Я подозреваю, что вы отправляете сообщения в "/ 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
 05 июл. 2009 г., 15:28
Я также думаю, что это действительно уродливое решение ... Смотрите мое решение.
 05 июл. 2009 г., 12:47
Не будет работать, ошибки не будут сохранены на объекте

Я только что предложил второе решение, руководствуясь комментариями Омара по поводу моего первого.

Если вы напишите это как маршрут ваших ресурсов

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

Затем вы можете переместить код действия индекса в действие управления.

Решение Вопроса

Одним из решений будет создание двух условных маршрутов со следующим кодом:

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| %>

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

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

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

.

Explanation why using connect is not a problem here The map.name_of_route references JUST THE PATH. Therefore you don't need a new named route for the second route. You can use the original one, because the paths are the same. All the other options are used only when a new request reaches rails and it needs to know where to send it.

.

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

Я предпочитаю оригинальный метод, хотя ...

 John Topley05 июл. 2009 г., 15:54
Это блестяще - спасибо!
 05 июл. 2009 г., 16:03
Что ж, спасибо тебе ;)
 05 июл. 2009 г., 21:36
Мне действительно нравится это решение, однако, рассмотрим map.resources: foo кажется немного ужасным добавлять два дополнительных сопоставления маршрутов для каждого полностью используемого ресурса (одно для нового / создания, одно для редактирования / обновления), чтобы гарантировать, что вы будете перенаправлены на / foo / new и / foo / foo_id / edit при неудаче создания / обновления
 06 июл. 2009 г., 10:39
Поскольку посетители, вероятно, не могут редактировать свои сообщения, я не думаю, что на самом деле проблема заключается в том, что решение требует нового маршрута для каждого действия. Тем не менее, вы можете использовать мое другое решение, если вы хотите, чтобы ваши маршруты были как можно более простыми (но усложняли работу ваших контроллеров).
 05 июл. 2009 г., 21:38
извините, не перенаправляйте .. действия поста были бы / foo / new и / foo / foo_id / edit и подобраны маршрутизацией!

Ваш ответ на вопрос