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.