I have a CRUD users controller. When I open the "user edit" page in the browser, my log shows this:
Started GET "/users/1/edit" for 127.0.0.1 at 2011-06-21 20:09:37 +0200
Processing by UsersController#edit as HTML
Parameters: {"id"=>"1"}
User Load (0.2ms) SELECT `users`.* FROM `users` WHERE
`users`.`id` = ? LIMIT 1 [["id", 1]]
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE
`users`.`id` = ? LIMIT 1 [["id", "1"]]
In the edit action, I simply call a private function user, which returns
@user ||= User.find(params[:id])
The view looks as follows:
<%= settings_title(@user.username) %>
<%= form_for @user, :html => { :multipart => true } do |f| %>
<%= render "form", :user => @user
<div class="action"><%= submit_tag t("users.edit.submit"), :class => "button" %></div>
<%= end %>
The route is defined as resources :users do ...
Any idea how to prevent the second db access would be greatly appreciated!
It seems like the second DB SELECT can be prevented by calling
@user ||= User.find(params[:id].to_i) # notice the .to_i
in the edit action. I now get:
User Load (0.1ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = ? LIMIT 1 [["id", 1]]
CACHE (0.0ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = ? LIMIT 1
but is this the proper way to do it? Do you see any other side-effects of this solution?
Your #to_i workaround notwithstanding, if current_user is an admin and can edit any user record, then it would seem this is the correct behavior. It's just a coincidence that in this case current_user == user_to_be_edited and you're getting two db hits for the same data. In all the other cases where the current_user is editing someone else's user data, you will have to hit the database twice by necessity.
However, if current_user only ever edits his/her own data, then in your controller instead of:
@user ||= User.find(params[:id])
you would use:
@user ||= current_user
...under the assumption that user authentication has already occurred prior to getting to the action. In this manner, you will only have the one hit on the database that happens in authentication.
As a final note, in the former case, where a current_user admin can edit any user, if you really want to get rid of that one coincidental edge case where the database gets hit twice, you can do this:
@user ||= current_user.id == params[:id].to_i ? current_user : User.find(params[:id])
In this manner, you'll avoid the extra db hit when a user is editing his/her own data.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With