rails, adding a parameter to new route

2019-05-14 13:24发布

问题:

The new action normally doesn't require parameters, since it creates a new resource from scratch. In my application whenever i create a certain type of resource say a book i need to provide a template, that is the id of another book. So my new route always has a parameter. I don't know how to represent this fact into routes.rb file.

Since i don't even know whether it is feasible, just in the case it isn't, then i will create a new_wp, a "new with parameter" action.
I tried to add it to my

resources :books, :only => [:edit, :update, :show, :new] do

  member do
    get 'new_wp/:template_id', :action => 'new_wp'
  end

end

but rake routes say that it isn't quite what i want:

GET        /books/:id/new_wp/:template_id(.:format)   books#new_wp

that is, it has two params.

回答1:

Try:

resource ...
  get "new/:template_id", :to => "Books#new_wp", :on => :collection
end

#  GET  /books/new/:template_id(.:format)  Books#new_wp 


回答2:

I do this often, the easiest way, I believe is to just adjust the path_names. That way your route names don't get messed up. Let me explain.

Scenario 1 - Standard Rails

Code

resources :books

Output

    books GET      /books(.:format)                         books#index
          POST     /books(.:format)                         books#create
 new_book GET      /books/new(.:format)                     books#new
edit_book GET      /books/:id/edit(.:format)                books#edit
     book GET      /books/:id(.:format)                     books#show
          PATCH    /books/:id(.:format)                     books#update
          PUT      /books/:id(.:format)                     books#update
          DELETE   /books/:id(.:format)                     books#destroy

Scenario 2 - Chris Heald Version

Code

resources :books do
  get "new/:template_id", to: "books#new_wp", on: :collection
end

# You can also do, same result with clearer intention
# resources :books do
#  get ":template_id", to: "books#new_wp", on: :new
# end

Output

          GET      /books/new/:template_id(.:format)        books#new_wp        
    books GET      /books(.:format)                         books#index
          POST     /books(.:format)                         books#create
 new_book GET      /books/new(.:format)                     books#new
edit_book GET      /books/:id/edit(.:format)                books#edit
     book GET      /books/:id(.:format)                     books#show
          PATCH    /books/:id(.:format)                     books#update
          PUT      /books/:id(.:format)                     books#update
          DELETE   /books/:id(.:format)                     books#destroy

Scenario 3 - My preferred and noted by steakchaser above

Code

resources :books, path_names: {new: 'new/:template_id' }

Output

    books GET      /books(.:format)                         books#index
          POST     /books(.:format)                         books#create
 new_book GET      /books/new/:template_id(.:format)        books#new
edit_book GET      /books/:id/edit(.:format)                books#edit
     book GET      /books/:id(.:format)                     books#show
          PATCH    /books/:id(.:format)                     books#update
          PUT      /books/:id(.:format)                     books#update
          DELETE   /books/:id(.:format)                     books#destroy

You will notice that in scenario 2 you are missing a path name, which means you would want to add an as: :new which would generate new_new_book. Fixing this you can change from get ":template_id" ... to get path: ":template_id"... which will generate new_book

My preference is scenario 3 if all you want to do is pass arguments for new. If you want to change the action then you would want to consider using scenario 2 but exclude :new from the resource or in your case don't add :new to the only: argument.