has_many / belongs_to relations&查询问题

时间:2015-07-25 04:20:34

标签: ruby-on-rails activerecord devise sqlite

我正在建立一个考勤跟踪器。我目前有三种型号。我正在为我的用户模型使用设计

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

考勤表上的列为user_id client_id created_atupdated_at

这是我的思考过程:
我可以获得每个User的所有参加人数 我还可以获得特定Client的所有出席情况 我可以通过以下方式获取特定UserClient的所有出勤记录:Attendance.joins(:user, :client).where(:user_id => current_user)返回

<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表,以获取first_nameemail与其他whereincludejoins等信息声明?

或者我完全错过了某些内容,可能需要一个联接表并建立has_many, through:关系?

1 个答案:

答案 0 :(得分:0)

Brad上面的评论在技术上是正确的,但由于查询中的.joins子句仅包含用于执行实际查询的那些表,因此来自Users和Clients表的数据实际上不会被加载在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" = $1  [["user_id", 1]]
  Group Load (0.6ms)  SELECT "groups".* FROM "groups" WHERE "groups"."user_id" = $1  [["user_id", 1]]
  Group Load (0.7ms)  SELECT "groups".* FROM "groups" WHERE "groups"."user_id" = $1  [["user_id", 1]]
  Group Load (0.7ms)  SELECT "groups".* FROM "groups" WHERE "groups"."user_id" = $1  [["user_id", 2]]
  Group Load (0.6ms)  SELECT "groups".* FROM "groups" WHERE "groups"."user_id" = $1  [["user_id", 3]]

现在还不错,但想象一下,如果你有一千个用户!不过,我们可以解决这个问题。如果使用.includes方法,则您将加入其他表并将其数据加载到内存中。它仍然运行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)

有关includesjoins之间差异的详细信息,请参阅this blog post或Google“rails joins vs includes”。