В Rails 3, когда действие создания ресурса завершается неудачей и вызывает render:new, почему URL-адрес должен измениться на url-адрес индекса ресурса?
у меня есть ресурс под названием книги. Он указан как ресурс правильно в моем файле маршрутов.
у меня есть новое действие, которое дает новый вид стандарта:
@book = Book.new
в модели есть некоторые атрибуты, которые проверяются присутствием, поэтому, если действие сохранения не выполняется, будут созданы ошибки.
в моем контроллере:
@book = Book.create
... # some logic
if @book.save
redirect_to(@book)
else
render :new
end
Это довольно стандартно; и обоснование использования render: new заключается в том, что объект передается обратно вид и ошибки могут быть представлены, записи в форме повторного заполнения, и т. д.
это работает, за исключением того, что каждый раз, когда я отправляюсь обратно в форму (через render :new), мои ошибки появляются, но мой URL-адрес является URL-адресом индекса, который
/books
, а не
/books/new
где я начал в первую очередь. Я видел несколько других сообщений об этой проблеме, но никаких ответов. Как минимум, можно было бы предположить, что это приведет вас в /books / create, у которого также есть файл представления for (идентично новому в данном случае).
Я могу сделать это:
# if the book isn't saved then
flash[:error] = "Errors!"
redirect_to new_book_path
но тогда данные @book теряются вместе с сообщениями об ошибках, что является целым моментом наличия формы и действий и т. д.
почему render: new landing me at /books, мое действие индекса, когда обычно этот URL вызывает метод индекса, в котором перечислены все книги?
6 ответов:
Это на самом деле и отправка в путь создания. Это в
create
действие, путь к которому/books
, используя HTTP метод POST. Это выглядит так же, как путь индекса/books
, но путь к индексу использует метод HTTP GET. Код маршрутизации rails учитывает метод при определении того, какое действие вызывать. После сбоя проверки вы все еще находитесь в действии create, но вы визуализируетеnew
вид. Это немного запутанно, но строка, какrender :new
на самом деле не вызывает новое действие вообще; он все еще запускает действие create и сообщает Rails для отображения нового посмотреть.
Я только начал с Рельсы-Учебник и была та же проблема. Решение просто: если вы хотите тот же URL-адрес после отправки формы (с ошибками), просто объедините новое и создайте действие в одном действии.
вот часть моего кода, которая делает это возможным (надеюсь, это поможет кому-то^^)
маршруты.rb (добавление пост-маршрута для new-action):
:... resources :books post "books/new" ...
... def create @book = Book.new(book_params) if @book.save # save was successful print "Book saved!" else # If we have errors render the form again render 'new' end end def new if book_params # If data submitted already by the form we call the create method create return end @book = Book.new render 'new' # call it explicit end private def book_params if params[:book].nil? || params[:book].empty? return false else return params.require(:book).permit(:title, :isbn, :price) end end
новый.формат html.Эрб:
<%= form_for @book, :url => {:action => :new} do |f| %> <%= f.label :title %> <%= f.text_field :title %> <%= f.label :isbn %> <%= f.text_field :isbn %> <%= f.label :price %> <%= f.password_field :price %> <%= f.submit "Save book" %> <% end %>
просто был такой же вопрос, так что, возможно, это может помочь кому-нибудь. Вы в основном должны сделать 3 корректировки для того, чтобы эта вещь работала, хотя мое решение все еще не идеально.
1) в действии создать:
if @book.save redirect_to(@book) else flash[:book] = @book redirect_to new_book_path end
2) в новом действии:
@book = flash[:book] ? Book.new(flash[:book]): Book.new
3) везде, где вы анализируете флэш-хэш, не забудьте отфильтровать flash[:book].
--> отображается правильный URL, данные формы сохраняются. Все-таки мне как-то не нравится помещая объект пользователя во флэш-хэш, я не думаю, что это его цель. Кто-нибудь знает лучшее место, чтобы положить его?
не на
/books/new
Так как вы создаете ресурс, разместив на/books/
. Когда ваше создание терпит неудачу, оно просто отображает новое действие, а не перенаправляет вас на новое действие. Как @MrYoshiji говорит выше, вы можете попробовать перенаправить его на новое действие, но это действительно неэффективно, поскольку вы создадите еще один HTTP-запрос и туда и обратно на сервер, только чтобы изменить url. В этот момент, если это имеет значение, вы, вероятно, можете использовать javascript, чтобы изменить его.
это может быть исправлено с помощью того же url, но разные методы для новых и создать действие.
в файле маршрутов можно использовать следующий код.
resources :books do get :common_path_string, on: :collection, action: :new post :common_path_string, on: :collection, action: :create end
Теперь вы новая страница будет отображаться по url
книги/common_path_string
в случае возникновения каких-либо ошибок после проверки, все равно url будет таким же.
также в форме вместо использования
books_path
использовать
url: common_path_string_books_path, method: :post
выбрать common_path_string своему вкусу.
вот мое решение. Не уверен, что это успокоительно, и Рейли и все остальное (как я еще новичок), но это работает, по крайней мере, пока:
# routes.rb post 'posts/new', to: 'posts#create', as: 'post_create' resources :posts # posts_controller.rb def new end def create if Post.save? redirect_to posts_path else render action: 'new' end # new.html.erb <%= form_with model: Post.new, url: :post_create, method: :post, local: true do |f| %> <%= f.submit 'Submit' %>
обновление
несмотря на то, что решение технически работает, учитывая эту цель
create
действие творения (и в большинстве случаев оно будет положительным), я собираюсь рассмотреть этот:вы не должны делать браузер нужно сделать новый вызов, если вы действительно должны, так что всегда вопрос когда вы используете
redirect_to
и если это правильно, или, возможно,render
будет лучше.отсюда статьи