Подтвердить что ты не робот

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 они отправлены ошибки?

Спасибо!

4b9b3361

Ответ 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