简体   繁体   中英

Rails 3: Custom Restful Routes: Change Edit-Action behavior

For my project i need to have custom urls that should not be easy to guess as it is with increasing integer ids of objects. To solve this problem i gave my objects a unique_id attribute which is a string and wrote the seven actions that would be generated by resources :objects myself, which looks like:

  get '/objects' => 'objects#index', as: :objects 
  post '/objects' => 'objects#create'
  get '/objects/new' => 'objects#new', as: :new_object
  get '/:unique_id/edit' => 'objects#edit', as: :edit_object
  get '/:unique_id' => 'objects#show', as: :object
  put '/:unique_id' => 'objects#update'
  delete '/:unique_id' => 'objects#destroy'

It all works out great, I simply had to tell the controller to find the Objects via Object.find_by_unique_id(params[:unique_id]) instead of Object.find(params[:id]) I can create, read and delete perfect, but i can not update.

When I open the edit_object_path it renders the form correctly, but when i click on "Update Object" it screws up. From the WEBrick output i can see that it creates a PUT request, but it requests for the id of the object and not the unique_id. So for instance, instead of requesting PUT /osefushe7398hr9 it states PUT /26 . The update method is not even called, but instead it asks to create a new object with unique_id of 26.

I really don't know where to change that behavior or how to pass along the unique_id instead of the id.

Rails models have a method that you may want to override to accomplish this, called the to_param method. The default behavior of this method is to return the ID of the instance of the model (which is what I believe you're trying to change).

With your current layout, I'd toss all your route changes. In the model, add:

def to_param
  "#{unique_id.parameterize}"
end

So now, with normal routing, a request of /objects/:variable will behave as you want.

Using the parameterize method, you're safe to not run into unfriendly URLs.

A minor downside to overriding the to_param method is that now in other actions within the controller that use the Model.find method (:edit, :update, and :destroy) will all need to be changed to Model.find_by_unique_id [if you remain RESTful].

In a form you can tell it explicitly what URL to post to and what parameters to go along with it. For example (using HAML and form_tag)

= form_tag object_path(@object.unique_id), :method => :put do

You can also be even more explicit with:

= form_tag object_path(:id => @object.unique_id), :method => :put do

Okay the solution was to add

def to_param
  unique_id
end

to the Object model without parameterize or the #{} syntax. I actually found that out on accident trying to pass the unique_id to the form as mentioned in the second solution. It turns out that i did not have to change the form_for tag like it was suggested in solution two. The parameterize was the reason why the unique_id was made to lower case.

Now everything works as intended (and still is restful)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM