Rails: URL после проверки завершается неудачно при создании новых записей через форму - PullRequest
18 голосов
/ 18 марта 2011

Допустим, я создаю новый Foo, используя форму и стандартный контроллер restful 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 (как указано выше), то при создании Foo я нахожусь на example.com/foos/new, и если я отправляю форму и она сохраняется правильно, я на example.com/foos, показывая Индекс действия. Тем не менее, если форма заполнена неправильно, она отображается снова и отображаются сообщения об ошибках. Это все простая ваниль.

Однако, если отображаются ошибки, страница формы будет отображаться, но URL будет example.com/foos, потому что действие CREATE отправляет этот URL-адрес. Однако можно ожидать, что индекс Foos # будет найден в example.com/foos, а не в форме, которую они только что отправили, с добавленными сообщениями об ошибках.

Кажется, это стандартное поведение Rails, но оно не имеет большого смысла для меня. Очевидно, я мог бы перенаправить обратно на новое вместо рендеринга нового из действия create, но проблема с этим - сообщения об ошибках и т. Д. Будут потеряны вместе с частично завершенными Foos в памяти.

Есть ли чистое решение этой проблемы, способ отправить людей обратно на example.com/foos/new, когда в новой отправленной ими форме Foo есть ошибки?

Спасибо!

Ответы [ 4 ]

9 голосов
/ 03 апреля 2011

Чтобы ответить на ваш комментарий к другому ответу:

Мне интересно, есть ли способ, вообще не переписывая контроллер, сообщить rails, что вы хотите, чтобы 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 по правильному пути.

4 голосов
/ 05 апреля 2011

Вы можете подключиться к маршрутизации рельсов, добавив это в инициализаторе: https://gist.github.com/903411

Тогда просто поместите обычные ресурсы в ваши маршруты. Rb:

resources :users

Он должен создать маршруты и поведение, которое вы ищете.

2 голосов
/ 03 апреля 2011

Вы можете настроить маршрутизацию вручную, если вас беспокоит, какой URL будет отображаться.Для того, что вы хотите, вы можете сделать визуальную форму от GET до /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

Это должно работать без каких-либо изменений вваш контроллер (ууу!) - все три действия из вашего примера выполняются.Несколько заявлений об отказе от ответственности:

  1. Это основано на моей маршрутизации для приложения 2.3.8 - некоторые синтаксические (семантические?) Изменения, вероятно, необходимы, чтобы привести его в стиль маршрутизации Rails 3.
  2. Мои попытки смешать этот стиль маршрутизации с map.resources ужасно потерпели неудачу - если вы не знакомы с этим больше, чем я, или если маршрутизация Rails 3 лучше (оба легко возможны), вам придется делать это для каждого маршрутак контроллеру.
  3. И, наконец, не забудьте добавить /:id, (.:format) и т. д. к маршрутам, которые в них нуждаются (в этом примере нет, но см. # 2).

Надеюсь, это поможет!

Редактировать: И последнее: вам нужно жестко закодировать URL в вашем form_for помощнике на /foos/new.html.erb.Просто добавьте :url => create_foo_path, чтобы Rails не пытался публиковать в /foos, что будет по умолчанию (возможно, есть способ изменить URL-адрес создания в модели, но я не знаю об этом, если естьодин).

1 голос
/ 18 марта 2011

Вы можете использовать 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...