How to prevent the rails (3.1) from firing 2 picks for one record?

I have a custom CRUD controller. When I open the user edit page in a 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 just call the user of the private function, which returns

 @user ||= User.find(params[:id]) 

The view is 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 %> 

A route is defined as resources :users do ...

Any idea how to prevent second access to db would be greatly appreciated!

Update:

It seems that the second DB SELECT can be prevented by calling

 @user ||= User.find(params[:id].to_i) # notice the .to_i 

in action editing. Now I 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 right way to do this? Do you see any other side effects of this solution?

+6
source share
2 answers

Despite this, the #to_i workaround, if current_user is an administrator and can edit any user record, then this seems to be the correct behavior. It is just a coincidence that in this case current_user == user_to_be_edited, and you get two dB hits for the same data. In all other cases, when current_user edits other user data, you will have to hit the database twice.

However, if current_user is only editing its own data, then your controller instead:

 @user ||= User.find(params[:id]) 

would you use:

 @user ||= current_user 

... on the assumption that user authentication has already taken place before moving on to the action. Thus, you get only one click on the database, which occurs during authentication.

As a final note, in the first case, when the current_user administrator can edit any user, if you really want to get rid of this random edge when the database hits twice, you can do this:

 @user ||= current_user.id == params[:id].to_i ? current_user : User.find(params[:id]) 

This way you avoid the extra db hit when the user edits his own data.

+3
source

After several tests, I found out the reason for 2 ELECTIONS:

  • to access the user via params[:id] in the edit action
  • to access current_user (for authorization) through session[:user_id]

The first is executed with a string, and the last is executed with an integer. I understand that for the simple cache that comes with Rails by default, the queries must be exactly the same, so this explains the double SELECT.

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

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

0
source

Source: https://habr.com/ru/post/891042/


All Articles