Rails 中的一对一关系很奇怪

Weirdness with one to one relationship in Rails

我有一个(相对)简单的 Rails 应用程序。我有三个模型,一个评估、一个用户和一个团队。一个团队有很多用户,每个用户都可以有一个评估。以下是模型及其相关模式的截断版本:

class Assessment < ApplicationRecord
  belongs_to :user, optional: true
end


create_table "assessments", force: :cascade do |t|
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
  t.string "aasm_state"
  t.integer "user_id"
end

class User < ApplicationRecord
  has_one :assessment
  belongs_to :team, optional: true
end


create_table "users", force: :cascade do |t|
  t.string "email"
  t.string "name"
  t.string "organisation_type"
  t.string "position"
  t.string "location"
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
  t.integer "team_id"
  t.string "locale", default: "en", null: false
end

class Team < ApplicationRecord
  has_many :users
  has_many :assessments, through: :users    
end

create_table "teams", force: :cascade do |t|
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
end

当我尝试获取团队中没有评估的所有用户时 (team.users.where(assessment: nil)),我收到以下错误:

 ActiveRecord::StatementInvalid:
   PG::UndefinedColumn: ERROR:  column users.user_id does not exist
   LINE 1: ...".* FROM "users" WHERE "users"."team_id" =  AND "users"."u...
                                                                ^
   : SELECT "users".* FROM "users" WHERE "users"."team_id" =  AND "users"."user_id" IS NULL

结果 SQL,如错误所示,有点古怪:

  SELECT "users".* FROM "users" WHERE "users"."team_id" =  AND "users"."user_id" IS NULL

当我尝试在评估确实存在时从评估中获取用户时,它 returns 无。

我怀疑我在这里做的事情真的很愚蠢,但是有人可以帮忙吗?

我建议您需要在此处使用左外连接。在 Rails 5 中,这可以写成:

users = team.users.left_outer_join(:assessment)
                  .where(assessments: { id: nil })
                  .uniq

来源:https://blog.bigbinary.com/2016/03/24/support-for-left-outer-joins-in-rails-5.html

根据您在问题中的解释,我对上述查询所做的更改是:

  1. 从评估 Table 中删除列 'user_id'。
  2. 在用户 Table 中添加列 'assessment_id'。
  3. 从用户模型中删除 has_one :assessment 并在用户模型中添加 belongs_to :assessment
  4. 从评估模型中删除 belongs_to :user 并在评估模型中添加 has_one :user

唯一需要注意的是,a.user = u 将提交更改,而不是 u.assessment = a。 (a是评价,u是用户)