In Rails when a resource create action fails and calls render :new, why must the URL change to the resource's index url?

后端 未结 5 1780
死守一世寂寞
死守一世寂寞 2020-12-07 14:40

I have a resource called Books. It\'s listed as a resource properly in my routes file.

I have a new action, which gives the new view the standard:

@         


        
相关标签:
5条回答
  • 2020-12-07 15:13

    It doesn't land you at /books/new since you are creating resource by posting to /books/. When your create fails it is just rendering the new action, not redirecting you to the new action. As @MrYoshiji says above you can try redirecting it to the new action, but this is really inefficient as you would be creating another HTTP request and round trip to the server, only to change the url. At that point if it matters you could probably use javascript change it.

    0 讨论(0)
  • 2020-12-07 15:22

    It can be fixed by using same url but different methods for new and create action.

    In the routes file following code can be used.

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

    Now you new page will render at url

    books/common_path_string

    In case any errors comes after validation, still the url will be same.

    Also in the form instead using

    books_path
    

    use

    url: common_path_string_books_path, method: :post
    

    Choose common_path_string of your liking.

    0 讨论(0)
  • 2020-12-07 15:23

    I just started with the Rails-Tutorial and had the same problem. The solution is just simple: If you want the same URL after submitting a form (with errors), just combine the new and create action in one action.

    Here is the part of my code, which makes this possible (hope it helps someone^^)

    routes.rb (Adding the post-route for new-action):

    ...
        resources :books
        post "books/new"
    ...
    

    Controller:

    ...
    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 %>
    
    0 讨论(0)
  • 2020-12-07 15:26

    It actually is sending you to the create path. It's in the create action, the path for which is /books, using HTTP method POST. This looks the same as the index path /books, but the index path is using HTTP method GET. The rails routing code takes the method into account when determining which action to call. After validation fails, you're still in the create action, but you're rendering the new view. It's a bit confusing, but a line like render :new doesn't actually invoke the new action at all; it's still running the create action and it tells Rails to render the new view.

    0 讨论(0)
  • 2020-12-07 15:31

    Just had the very same question, so maybe this might help somebody someday. You basically have to make 3 adjustments in order for this thing to work, although my solution is still not ideal.

    1) In the create action:

    if @book.save
      redirect_to(@book)
    else
      flash[:book] = @book
      redirect_to new_book_path
    end
    

    2) In the new action:

    @book = flash[:book] ? Book.new(flash[:book]): Book.new
    

    3) Wherever you parse the flash hash, be sure to filter out flash[:book].

    --> correct URL is displayed, Form data is preserved. Still, I somehow don't like putting the user object into the flash hash, I don't think that's it's purpose. Does anyboy know a better place to put it in?

    0 讨论(0)
提交回复
热议问题