Reputation: 961
In my app I have overwritten current_user devise method a bit. The idea is that if certain cookie is present method check the organization by the id inside that cookie and returns owner of this organization instead of regular user:
def current_user
user = warden.authenticate(scope: :user)
return nil if user.nil?
if user.admin? && cookies.key?('mock_admin_login')
organization = Organization.includes(:creator).find(cookies.encrypted[:mock_admin_login])
return organization.creator
end
user
end
Everything works correct but when I take a look at my console I noticed that Organization query is performed multiple times:
CACHE Organization Load (0.5ms) SELECT "organizations".* FROM "organizations" WHERE "organizations"."id" = $1 LIMIT $2 [["id", 9], ["LIMIT", 1]] ↳ app/controllers/concerns/current_methods_overwritten.rb:11:in
current_user' CACHE User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 [["id", 10]] ↳ app/controllers/concerns/current_methods_overwritten.rb:11:in
current_user' CACHE Organization Load (0.9ms) SELECT "organizations".* FROM "organizations" WHERE "organizations"."id" = $1 LIMIT $2 [["id", 9], ["LIMIT", 1]] ↳ app/controllers/concerns/current_methods_overwritten.rb:11:incurrent_user' CACHE User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 [["id", 10]] ↳ app/controllers/concerns/current_methods_overwritten.rb:11:in
current_user' CACHE Organization Load (0.7ms) SELECT "organizations".* FROM "organizations" WHERE "organizations"."id" = $1 LIMIT $2 [["id", 9], ["LIMIT", 1]] ↳ app/controllers/concerns/current_methods_overwritten.rb:11:incurrent_user' CACHE User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 [["id", 10]] ↳ app/controllers/concerns/current_methods_overwritten.rb:11:in
current_user' CACHE Organization Load (0.3ms) SELECT "organizations".* FROM "organizations" WHERE "organizations"."id" = $1 LIMIT $2 [["id", 9], ["LIMIT", 1]] ↳ app/controllers/concerns/current_methods_overwritten.rb:11:incurrent_user' CACHE User Load (0.8ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 [["id", 10]] ↳ app/controllers/concerns/current_methods_overwritten.rb:11:in
current_user' CACHE Organization Load (0.4ms) SELECT "organizations".* FROM "organizations" WHERE "organizations"."id" = $1 LIMIT $2 [["id", 9], ["LIMIT", 1]] ↳ app/controllers/concerns/current_methods_overwritten.rb:11:incurrent_user' CACHE User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 [["id", 10]] ↳ app/controllers/concerns/current_methods_overwritten.rb:11:in
current_user' CACHE Organization Load (2.0ms) SELECT "organizations".* FROM "organizations" WHERE "organizations"."id" = $1 LIMIT $2 [["id", 9], ["LIMIT", 1]] ↳ app/controllers/concerns/current_methods_overwritten.rb:11:incurrent_user' CACHE User Load (4.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 [["id", 10]] ↳ app/controllers/concerns/current_methods_overwritten.rb:11:in
current_user' CACHE Organization Load (0.4ms) SELECT "organizations".* FROM "organizations" WHERE "organizations"."id" = $1 LIMIT $2 [["id", 9], ["LIMIT", 1]] ↳ app/controllers/concerns/current_methods_overwritten.rb:11:incurrent_user' CACHE User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 [["id", 10]] ↳ app/controllers/concerns/current_methods_overwritten.rb:11:in
current_user' CACHE Organization Load (42.8ms) SELECT "organizations".* FROM "organizations" WHERE "organizations"."id" = $1 LIMIT $2 [["id", 9], ["LIMIT", 1]] ↳ app/controllers/concerns/current_methods_overwritten.rb:11:incurrent_user' CACHE User Load (0.9ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 [["id", 10]] ↳ app/controllers/concerns/current_methods_overwritten.rb:11:in
current_user' CACHE Organization Load (4.5ms) SELECT "organizations".* FROM "organizations" WHERE "organizations"."id" = $1 LIMIT $2 [["id", 9], ["LIMIT", 1]] ↳ app/controllers/concerns/current_methods_overwritten.rb:11:incurrent_user' CACHE User Load (1.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 [["id", 10]] ↳ app/controllers/concerns/current_methods_overwritten.rb:11:in
current_user'
Although It might seem like a not big deal but server spends additional 30-40ms to perform this action every time when current_user method is called. Why this query is called so many times instead of one and how can I fix it?
Upvotes: 0
Views: 694
Reputation: 101811
You need to memoize the result so that its not reevaluated every time you call current_user
.
If you look at the helper that devise generates you can see that it does just that:
def current_#{mapping}
@current_#{mapping} ||= warden.authenticate(scope: :#{mapping})
end
If you want to fix your existing method you want to make sure to memoize the DB calls:
def current_user
@current_user ||= warden.authenticate(scope: :#{mapping})
if @current_user&.admin? && cookies.key?('mock_admin_login')
@current_org || = Organization.includes(:creator)
.find(cookies.encrypted[:mock_admin_login])
@current_user = @current_org.creator
end
@current_user
end
But you really should implement this as a custom Warden strategy instead.
Upvotes: 3