简体   繁体   English

Ruby on Rails:迭代关系或关联的最佳方式

[英]Ruby on Rails: Best way to Iterate a Relation or Associations

I see that .where statement make so much request with a lot of CACHE User Load message than association. 我看到.where语句使用大量的CACHE用户加载消息而不是关联来提出如此多的请求。 Is this true or not? 这是真的吗?

In this case I get an ActiveRecord_Relation: 在这种情况下,我得到一个ActiveRecord_Relation:

@dogs = Dog.where(user_id: current_user.id).order('created_at DESC')

In this other case, I get a ActiveRecord_Associations_CollectionProxy: 在另一个案例中,我得到一个ActiveRecord_Associations_CollectionProxy:

@dogs = current_user.dogs.order('created_at DESC')

When I iterate in the view 当我在视图中迭代

<% @dogs.each do |dog| %>
<div><%= dog.name %></div>
<% end %>

I get different message in my console log: 我在控制台日志中收到不同的消息:

ActiveRecord_Relation: ActiveRecord_Relation:

User Load (0.3ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 15], ["LIMIT", 1]]
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 15], ["LIMIT", 1]]
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 15], ["LIMIT", 1]]
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 15], ["LIMIT", 1]]
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 15], ["LIMIT", 1]]
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 15], ["LIMIT", 1]]
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 15], ["LIMIT", 1]]
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 15], ["LIMIT", 1]]
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 15], ["LIMIT", 1]]
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 15], ["LIMIT", 1]]
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 15], ["LIMIT", 1]]
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 15], ["LIMIT", 1]]
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 15], ["LIMIT", 1]]
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 15], ["LIMIT", 1]]
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 15], ["LIMIT", 1]]
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 15], ["LIMIT", 1]]
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 15], ["LIMIT", 1]]
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 15], ["LIMIT", 1]]
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 15], ["LIMIT", 1]]
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 15], ["LIMIT", 1]]

ActiveRecord_Associations_CollectionProxy: ActiveRecord_Associations_CollectionProxy:

User Load (0.3ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 15], ["LIMIT", 1]]
Dog Load (0.6ms)  SELECT "dogs".* FROM "dogs" WHERE "dogs"."user_id" = ? ORDER BY "dogs"."created_at" DESC  [["user_id", 15]]

Wich is the better way? 哪个更好? Thank you very much. 非常感谢你。

It seems like in both cases current_user should be invoked only once. 看起来在两种情况下都应该只调用一次current_user Presumably the current_user method has an implementation like this: 据推测, current_user方法有如下实现:

def current_user
  # read some cookies or something
  User.find_by([...])
end

It's not clear to me why User.find_by would be invoked many times in the "ActiveRecord_Relation" version, but that seems like it must be what's happening. 我不清楚为什么在“ActiveRecord_Relation”版本中会多次调用User.find_by ,但这似乎一定是正在发生的事情。 Rails is caching the result of this query, so every time after the first time you hit a warm cache. Rails正在缓存此查询的结果,因此每次第一次点击热缓存后都是如此。

To rule this out, you can memoize #current_user . 为了排除这一点,您可以memoize的 #current_user This should prevent Active Record from every seeing the query after the first invocation of current_user . 这应该防止在第一次调用current_user之后每次看到查询的Active Record。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM