web-dev-qa-db-ja.com

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 URLです。

/books

のではなく

/books/new

そもそも私が始めたところです。この問題に関する他の投稿をいくつか見ましたが、回答はありません。少なくとも、/ books/createに移動すると想定しますが、これにもビューファイルがあります(この場合は新規と同じです)。

私がすることができます:

# if the book isn't saved then
flash[:error] = "Errors!"
redirect_to new_book_path

ただし、@ bookデータはエラーメッセージとともに失われます。これは、フォームやアクションなどの重要なポイントです。

通常、そのURLがすべての本をリストするINDEXメソッドを呼び出すときに、render:newが私のインデックスアクションである/ booksに私をランディングするのはなぜですか?

57
rcd

実際にはisが作成パスに移動します。これはcreateアクションにあり、そのパスは/booksであり、HTTPメソッドPOSTを使用しています。これはインデックスパス/booksと同じように見えますが、インデックスパスはHTTPメソッドGETを使用しています。 Railsルーティングコードは、呼び出すアクションを決定するときにメソッドを考慮に入れます。検証に失敗した後も、作成アクションのままですが、newをレンダリングしています少し混乱しますが、render :newのような行は実際には新しいアクションをまったく呼び出さず、まだcreateアクションを実行しており、Railsに新しいビュー

27
Jim Stewart

Rails-Tutorial で始めたばかりで、同じ問題がありました。解決策は単純です。(エラーのある)フォームを送信した後で同じURLが必要な場合は、新しいアクションとcreateアクションを1つのアクションに組み合わせます。

これがこれを可能にする私のコードの一部です(誰かを助けることを願っています^^)

routes.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

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 %>
8
ofhouse

ちょうど同じ質問があったので、これはいつか誰かを助けるかもしれません。これを機能させるには、基本的に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が表示され、フォームデータは保持されます。それでも、どういうわけかユーザーオブジェクトをフラッシュハッシュに入れるのは好きではありません。それが目的ではないと思います。誰もがそれを置くためのより良い場所を知っていますか?

4
panepeter

着陸しない/books/newに投稿してリソースを作成しているため、/books/。作成が失敗した場合、新しいアクションにリダイレクトするのではなく、新しいアクションをレンダリングするだけです。 @MrYoshijiが上で述べたように、新しいアクションにリダイレクトすることができますが、URLを変更するだけで、別のHTTPリクエストとサーバーへのラウンドトリップを作成するので、これは本当に非効率的です。その時点で問題がある場合は、おそらくJavaScriptを使用して変更できます。

2
Doon

同じURLを使用することで修正できますが、新しいアクションと作成アクションのメソッドは異なります。

ルートファイルでは、次のコードを使用できます。

resources :books do
  get :common_path_string, on: :collection, action: :new
  post :common_path_string, on: :collection, action: :create
end

これで、新しいページがURLでレンダリングされます

books/common_path_string

検証後にエラーが発生した場合でも、URLは同じです。

また、代わりに使用する形で

books_path

使用する

url: common_path_string_books_path, method: :post

お好みのcommon_path_stringを選択してください。

1
Bot