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

В 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, в котором перечислены все книги?

4b9b3361

Ответ 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 будет лучше.

Из этого статьи