Take the 2-minute tour ×

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 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]]
   `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?

share|improve this question
Interesting to learn. I might start using the to_i hack in my own code if I really need it to zing. PS - you might want to put your solution as an answer - so that other people searching for the problem don't bypass it, thinking that it hasn't been answered yet. –  Taryn East Jun 21 '11 at 18:50
Thanks, will do that. However, I hope that someone else has an even better solution, since I've never seen a hack like this in any of the open source apps I have had a look at. [Update: can only answer my own question in 7 hours from now due to lack of proper reputation ...] –  emrass Jun 21 '11 at 18:52
@Taryn, that's indeed interesting, but I'm not sure I'd call it a "solution," exactly. More like a "workaround." I, too, would like to understand what's going on here. –  Craig Stuntz Jun 21 '11 at 18:56
Just created a fresh Rails 3.1 app and tried this out. Does caching as expected without the to_i call on the params ID. What database are you using? If you can reproduce this in a trivial app, I'd report it as a bug. –  Douglas F Shearer Jun 21 '11 at 19:04
Thanks for the hint, Douglas. I just created another fresh Rails 3.1 app, scaffolded the user and configured the mysql database. Was not able to reproduce the issue either. I'm calling 2 before_filters for user authorization - I'll play around with them and see if one of them is the cause of the issue ... –  emrass Jun 21 '11 at 20:07

2 Answers 2

up vote 3 down vote accepted

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:


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.

share|improve this answer
Thanks a lot, Yardboy, for the thorough answer. I now consider refactoring the UsersController to enforce @user ||= current_user and encapsulating admin logic in a separate Admin::UsersController. Will do some research on admin encapsulation beforehands. Answer accepted for going into detail about the different use cases and their implications for my issue. –  emrass Jun 22 '11 at 17:54

After some more tests I found out the reason for the 2 SELECTS:

  1. for accessing user through params[:id] in the edit action
  2. for accessing current_user (for authorization) through session[:user_id]

The former is executed with a string, whereas the latter is executed with an integer. I understand that for the simple cache that comes with Rails as default, the queries have to be exactly the same, so this explains the dual SELECT.

However, following Rails logic, I would now have to read the current user from the session with session[:user_id].to_s, which seems cumbersome to me.

As a result, I might have to switch to a more intelligent cache. Thanks for all your support and comments.

share|improve this answer

Your Answer


