has_many/belongs_to 关系和查询问题
has_many/belongs_to relationships & query questions
我现在正在构建一个考勤跟踪器。我目前有三个模型。我正在为我的用户模型使用设计
class User < ActiveRecord::Base
has_many :clients
has_many :attendances
class Client < ActiveRecord::Base
belongs_to :user
has_many :attendances
class Attendance < ActiveRecord::Base
belongs_to :user
belongs_to :client
出勤率table的栏是user_id
client_id
created_at
和updated_at
这是我的思考过程:
我可以获得每个 User
的所有出席人数
我还可以获得特定 Client
的所有出席人数
我可以通过以下方式获取特定 User
和 Client
的所有出勤记录:Attendance.joins(:user, :client).where(:user_id => current_user)
其中 returns 和
<ActiveRecord::Relation [#<Attendance id: 18, client_id: 151, created_at: "2015-07-24 21:36:16", updated_at: "2015-07-24 21:36:16", user_id: 4>, #<Attendance id: 19, client_id: 101, created_at: "2015-07-24 21:37:10", updated_at: "2015-07-24 21:37:10", user_id: 4>, #<Attendance id: 20, client_id: 114, created_at: "2015-07-24 21:37:39", updated_at: "2015-07-24 21:37:39", user_id: 4>, #<Attendance id: 21, client_id: 123, created_at: "2015-07-24 21:38:26", updated_at: "2015-07-24 21:38:26", user_id: 4>]>
我能否以某种方式参考 Client
table 以获取 first_name
或 email
等信息以及另一个 where
、include
、或 joins
声明?
或者我是否完全遗漏了一些东西,可能需要加入 table 并建立 has_many, through:
关系?
Brad 的上述评论在技术上是正确的,但由于您查询中的 .joins
子句仅包含用于执行实际查询的那些 table,来自用户和客户的数据 tables 实际上不会被 Rails 加载,所以为了获取它们的所有数据,你最终将执行 N+1 次查询(Rails 应用程序缓慢的常见原因!)。即:
irb> User.joins(:groups).each { |u| u.groups.map(&:name) }
User Load (8.6ms) SELECT "users".* FROM "users" INNER JOIN "groups" ON "groups"."user_id" = "users"."id"
Group Load (1.2ms) SELECT "groups".* FROM "groups" WHERE "groups"."user_id" = [["user_id", 1]]
Group Load (0.6ms) SELECT "groups".* FROM "groups" WHERE "groups"."user_id" = [["user_id", 1]]
Group Load (0.7ms) SELECT "groups".* FROM "groups" WHERE "groups"."user_id" = [["user_id", 1]]
Group Load (0.7ms) SELECT "groups".* FROM "groups" WHERE "groups"."user_id" = [["user_id", 2]]
Group Load (0.6ms) SELECT "groups".* FROM "groups" WHERE "groups"."user_id" = [["user_id", 3]]
现在还不错,但想象一下如果您有 1000 个用户!不过,我们可以解决这个问题。如果您使用 .includes
方法,您将同时加入其他 table(s) 并将它们的数据加载到内存中。它仍然运行 2 个查询,但这是一个改进:
irb(main):016:0> User.includes(:groups).each { |u| u.groups.map(&:name) }
User Load (0.6ms) SELECT "users".* FROM "users"
Group Load (1.2ms) SELECT "groups".* FROM "groups" WHERE "groups"."user_id" IN (1, 2, 3, 4)
所以,对于你的情况,试试这个:
Attendance.includes(:user, :client).where(user_id: current_user)
有关 includes
和 joins
之间区别的更多信息,请参阅 this blog post 或 Google "rails joins vs includes"。
我现在正在构建一个考勤跟踪器。我目前有三个模型。我正在为我的用户模型使用设计
class User < ActiveRecord::Base
has_many :clients
has_many :attendances
class Client < ActiveRecord::Base
belongs_to :user
has_many :attendances
class Attendance < ActiveRecord::Base
belongs_to :user
belongs_to :client
出勤率table的栏是user_id
client_id
created_at
和updated_at
这是我的思考过程:
我可以获得每个 User
的所有出席人数
我还可以获得特定 Client
的所有出席人数
我可以通过以下方式获取特定 User
和 Client
的所有出勤记录:Attendance.joins(:user, :client).where(:user_id => current_user)
其中 returns 和
<ActiveRecord::Relation [#<Attendance id: 18, client_id: 151, created_at: "2015-07-24 21:36:16", updated_at: "2015-07-24 21:36:16", user_id: 4>, #<Attendance id: 19, client_id: 101, created_at: "2015-07-24 21:37:10", updated_at: "2015-07-24 21:37:10", user_id: 4>, #<Attendance id: 20, client_id: 114, created_at: "2015-07-24 21:37:39", updated_at: "2015-07-24 21:37:39", user_id: 4>, #<Attendance id: 21, client_id: 123, created_at: "2015-07-24 21:38:26", updated_at: "2015-07-24 21:38:26", user_id: 4>]>
我能否以某种方式参考 Client
table 以获取 first_name
或 email
等信息以及另一个 where
、include
、或 joins
声明?
或者我是否完全遗漏了一些东西,可能需要加入 table 并建立 has_many, through:
关系?
Brad 的上述评论在技术上是正确的,但由于您查询中的 .joins
子句仅包含用于执行实际查询的那些 table,来自用户和客户的数据 tables 实际上不会被 Rails 加载,所以为了获取它们的所有数据,你最终将执行 N+1 次查询(Rails 应用程序缓慢的常见原因!)。即:
irb> User.joins(:groups).each { |u| u.groups.map(&:name) }
User Load (8.6ms) SELECT "users".* FROM "users" INNER JOIN "groups" ON "groups"."user_id" = "users"."id"
Group Load (1.2ms) SELECT "groups".* FROM "groups" WHERE "groups"."user_id" = [["user_id", 1]]
Group Load (0.6ms) SELECT "groups".* FROM "groups" WHERE "groups"."user_id" = [["user_id", 1]]
Group Load (0.7ms) SELECT "groups".* FROM "groups" WHERE "groups"."user_id" = [["user_id", 1]]
Group Load (0.7ms) SELECT "groups".* FROM "groups" WHERE "groups"."user_id" = [["user_id", 2]]
Group Load (0.6ms) SELECT "groups".* FROM "groups" WHERE "groups"."user_id" = [["user_id", 3]]
现在还不错,但想象一下如果您有 1000 个用户!不过,我们可以解决这个问题。如果您使用 .includes
方法,您将同时加入其他 table(s) 并将它们的数据加载到内存中。它仍然运行 2 个查询,但这是一个改进:
irb(main):016:0> User.includes(:groups).each { |u| u.groups.map(&:name) }
User Load (0.6ms) SELECT "users".* FROM "users"
Group Load (1.2ms) SELECT "groups".* FROM "groups" WHERE "groups"."user_id" IN (1, 2, 3, 4)
所以,对于你的情况,试试这个:
Attendance.includes(:user, :client).where(user_id: current_user)
有关 includes
和 joins
之间区别的更多信息,请参阅 this blog post 或 Google "rails joins vs includes"。