Rails: URL-адрес после проверки не удался при создании новых записей через форму
Предположим, что я создаю новый Foo с использованием формы и стандартного контроллера Rails, который выглядит примерно так:
class FoosController < ApplicationController
...
def index
@foos = Foo.all
end
def new
@foo = Foo.new
end
def create
@foo = Foo.create(params[:foo])
if @foo.save
redirect_to foos_path, :notice => 'Created a foo.'
else
render 'new'
end
end
...
end
Итак, если я использую стандартный restful controller (как указано выше), тогда, когда я создаю Foo, я нахожусь в example.com/foos/new
, и если я отправлю форму, и она будет сохранена правильно, я нахожусь в example.com/foos
, показывая действие индекса. Однако, если форма не заполнена правильно, форма снова отображается и отображаются сообщения об ошибках. Это все простые ванилы.
Однако, если отображаются ошибки, страница формы будет отображаться, но URL будет example.com/foos
, потому что действие CREATE отправляется на этот URL-адрес. Однако можно было бы ожидать индекса Foos # в example.com/foos
, а не в форме, которую они только что отправили, с добавленными сообщениями об ошибках.
Это похоже на стандартное поведение Rails, но для меня это не имеет большого смысла. Очевидно, что я мог бы перенаправить обратно на новый, а не на новый, но проблема с сообщениями об ошибках и т.д. Будет потеряна вместе с частично заполненными Foos в памяти.
Есть ли чистое решение для этой проблемы, способ отправить людей обратно в example.com/foos/new
, когда в новой форме Foo они отправлены ошибки?
Спасибо!
Ответы
Ответ 1
Вы можете подключиться к маршрутизации маршрутов, добавив это в инициализатор:
https://gist.github.com/903411
Затем просто поместите регулярные ресурсы в свои маршруты. rb:
resources :users
Он должен создать маршруты и поведение, которые вы ищете.
Ответ 2
Чтобы ответить на свой ответ на другой ответ:
Мне интересно, есть ли способ, не переписывая контроллер вообще, сказать рельсы, что вы хотите, чтобы URL-адрес соответствовал отображенному шаблону, а не вызванное им действие контроллера.
Я так не думаю; URL-адреса привязаны непосредственно к маршрутизации, которая привязана к контроллеру и паре действий - слой рендеринга вообще не трогает его.
Чтобы ответить на ваш исходный вопрос, здесь информация из другого подобного вопроса, я ответил.
Как вы нашли, по умолчанию, когда вы указываете resources :things
, путь POST для создания новой вещи находится в /things
. Здесь вывод для rake routes
:
things GET /things(.:format) {:action=>"index", :controller=>"things"}
POST /things(.:format) {:action=>"create", :controller=>"things"}
new_thing GET /things/new(.:format) {:action=>"new", :controller=>"things"}
edit_thing GET /things/:id/edit(.:format) {:action=>"edit", :controller=>"things"}
thing GET /things/:id(.:format) {:action=>"show", :controller=>"things"}
PUT /things/:id(.:format) {:action=>"update", :controller=>"things"}
DELETE /things/:id(.:format) {:action=>"destroy", :controller=>"things"}
Похоже, вы хотите что-то большее:
create_things POST /things/new(.:format) {:action=>"create", :controller=>"things"}
things GET /things(.:format) {:action=>"index", :controller=>"things"}
new_thing GET /things/new(.:format) {:action=>"new", :controller=>"things"}
edit_thing GET /things/:id/edit(.:format) {:action=>"edit", :controller=>"things"}
thing GET /things/:id(.:format) {:action=>"show", :controller=>"things"}
PUT /things/:id(.:format) {:action=>"update", :controller=>"things"}
DELETE /things/:id(.:format) {:action=>"destroy", :controller=>"things"}
Хотя это и не рекомендуется, вы можете получить этот результат по следующему маршруту:
resources :things, :except => [ :create ] do
post "create" => "things#create", :as => :create, :path => 'new', :on => :collection
end
Вам также нужно будет изменить свои формы, чтобы сделать их POST на правильный путь.
Ответ 3
Вы можете настроить маршрутизацию вручную, если вас беспокоит, какой URL-адрес будет отображаться. Для чего вы хотите, чтобы GET
to /foos/new
отображал вашу форму, а POST
к тому же URL-адресу создавал:
map.with_options :controller => :foos do |foo|
foo.new_foo '/foos/new', :conditions => {:method => :get}, :action => :new
foo.create_foo '/foos/new', :conditions => {:method => :post}, :action => :create
foo.foos '/foos', :conditions => {:method => :get}, :action => :index
end
Это должно работать без каких-либо изменений в вашем контроллере (yay!) - все три действия из вашего примера позаботятся. Несколько оговорок:
- Это основано на моей маршрутизации для приложения 2.3.8. Вероятно, необходимы некоторые изменения синтаксиса (семантики?), чтобы получить его в стиле маршрутизации Rails 3.
- Мои попытки смешать этот стиль маршрутизации с
map.resources
потерпели неудачу ужасно - если вы не знакомы с этим, чем я, или лучшая маршрутизация Rails 3 (как можно легко), вам придется сделать это для каждый маршрут к контроллеру.
- И, наконец, не забудьте добавить
/:id
, (.:format)
и т.д. к маршрутам, которые им нужны (в этом примере нет ни одного, но см. # 2).
Надеюсь, это поможет!
Изменить:. Последнее: вам нужно жестко закодировать URL-адрес своего помощника form_for
на /foos/new.html.erb
. Просто добавьте :url => create_foo_path
, поэтому Rails не пытается отправить сообщение в /foos
, которое оно будет по умолчанию (возможно, есть способ изменить URL-адрес создания в модели, но я не знаю об этом, если является одним).
Ответ 4
Вы можете использовать Rack:: Flash, чтобы сохранить параметры, которые вы хотели в сеансе пользователя, а затем перенаправить на ваш URL-адрес формы.
def create
@foo = Foo.new(params[:foo])
if @foo.save
redirect_to foos_path, :notice => 'Created a foo.'
else
flash[:foo] = params[:foo]
flash[:errors] = @foo.errors
redirect_to new_foo_path #sorry - can't remember the Rails convention for this route
end
end
def new
# in your view, output the contents of flash[:foo]
@foo = Foo.new(flash[:foo])
end