В Rails 3, когда ресурс создает действие с ошибкой и вызывает render: new, почему URL должен быть изменен на URL-адрес индекса ресурса?
У меня есть ресурс под названием Books. Он правильно указан в ресурсе в файле маршрутов.
У меня есть новое действие, которое дает новый вид стандарту:
@book = Book.new
В модели есть некоторые атрибуты, которые проверяются присутствием, поэтому, если действие сохранения завершится неудачно, будут созданы ошибки.
В моем контроллере:
@book = Book.create
... # some logic
if @book.save
redirect_to(@book)
else
render :new
end
Это довольно стандартный; и обоснование использования render: new - это то, что объект передается обратно в представление и могут быть сообщены ошибки, заполнять записи в форме и т.д.
Это работает, но каждый раз, когда я отправляюсь обратно в форму (через render: new), появляются мои ошибки, но мой URL-адрес - это индекс INDEX, который
/books
Вместо
/books/new
Что именно я начал в первую очередь. Я видел несколько других сообщений об этой проблеме, но ответов нет. Как минимум, можно было бы предположить, что он приземлится на вас /books/create, и у меня также есть файл вида (идентичный новому в этом случае).
Я могу это сделать:
# if the book isn't saved then
flash[:error] = "Errors!"
redirect_to new_book_path
Но тогда данные @book теряются вместе с сообщениями об ошибках, которые являются всей точкой наличия формы и действий и т.д.
Почему рендер: новая посылка меня в/книги, действие моего индекса, когда обычно этот URL-адрес вызывает метод INDEX, в котором перечислены все книги?
Ответы
Ответ 1
Он фактически отправляет вас на путь создания. Он находится в действии create
, путь для которого равен /books
, используя HTTP-метод POST. Это выглядит так же, как индексный путь /books
, но путь указателя использует метод HTTP GET. Код маршрутизации рельсов учитывает этот метод при определении действия для вызова. После неудачной проверки вы все еще находитесь в действии create, но вы показываете представление new
. Это немного запутанно, но строка типа render :new
вообще не вызывает новое действие; он все еще запускает действие create, и он сообщает Rails для визуализации нового представления.
Ответ 2
Я только начинал с Rails-Tutorial и имел ту же проблему.
Решение простое: если вы хотите получить тот же URL-адрес после отправки формы (с ошибками), просто соедините новое и создайте действие в одном действии.
Вот часть моего кода, которая делает это возможным (надеюсь, что это поможет кому-то ^^)
routes.rb(добавление post-route для нового действия):
...
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
new.html.erb:
<%= 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
У меня был тот же самый вопрос, так что, возможно, это когда-нибудь может кому-то помочь. Вы должны сделать 3 корректировки, чтобы эта вещь работала, хотя мое решение все еще не идеально.
1) В действии create:
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) Где бы вы ни разобрали флэш-хэш, обязательно отфильтруйте флеш [: book].
- > отображается правильный URL, данные формы сохраняются. Тем не менее, мне как-то не нравится помещать объект пользователя во флэш-хеш, я не думаю, что это цель. Кто-нибудь знает, куда лучше поместить его?
Ответ 4
Он не помещает вас в /books/new
, так как вы создаете ресурс, отправляя его на /books/
. Когда ваше создание терпит неудачу, оно просто создает новое действие, а не перенаправляет вас на новое действие. Как говорит @MrYoshiji выше, вы можете попробовать перенаправить его на новое действие, но это действительно неэффективно, так как вы бы создали другой HTTP-запрос и обратились к серверу только для изменения URL-адреса. В этом случае, если это имеет значение, вы, вероятно, можете использовать javascript, чтобы изменить его.
Ответ 5
Его можно исправить, используя тот же 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 по своему вкусу.
Ответ 6
Вот мое решение. Не уверен, что это RESTful, и Raily и все остальное (как я все еще начинаю), но он работает, по крайней мере еще:
# 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' %>
Update
Несмотря на то, что решение технически работает, принимая во внимание, что целью create
является создание (и в большинстве случаев оно будет положительным), я буду рассматривать это:
Вы не должны заставлять браузер делать свежий вызов, если вам действительно не нужно, поэтому всегда задавайте вопрос, когда вы используете redirect_to
, и если это правильно, или возможно, render
будет лучше.
Из этого статьи