在使用activerecord查询时,Rails无法理解关联

时间:2015-06-24 10:11:04

标签: ruby-on-rails ruby activerecord

我有一个模型,TaskTaskable& Supply。他们有这种关联关系。

class Task < AR::Base
  has_one :taskable, inverse_of: :task, autosave: true
  enum status: { :awaiting, :restarting, ... }

class Taskable < AR::Base
  belongs_to :task, inverse_of: :taskable, autosave: true
  has_many :supplies

class Supply < AR::Base
  belongs_to :taskable

我需要查找耗材,这些耗材与具有某些枚举值的任务相关联。以下是我构建查询的方法:

Supply.where(
  taskable: {
    task: {
      status: [ :awaiting, :starting ]
    }
  })

但是我遇到了一个例外:

PG::UndefinedTable: ERROR:  missing FROM-clause entry for table "taskable"
LINE 1: ...upplies" WHERE "supplies"."component_id" = $1 AND "taskable"...
: SELECT  "supplies".* FROM "supplies" WHERE "supplies"."component_id" =  $1 AND "taskable"."task_id" = '---
:status:
- :awaiting
- :starting
'  ORDER BY "supplies"."id" ASC LIMIT 1
(0.1ms)  ROLLBACK
ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR:  missing FROM-clause entry for table "taskable"
LINE 1: ...upplies" WHERE "supplies"."component_id" = $1 AND "taskable"...                                                             ^
: SELECT  "supplies".* FROM "supplies" WHERE "supplies"."component_id" = $1 AND "taskable"."task_id" = '---
:status:
- :awaiting
- :starting
'  ORDER BY "supplies"."id" ASC LIMIT 1

如何才能确切地查询我想要的内容?

已更新

db/schema.rb

create_table "tasks", force: :cascade do |t|
  t.string   "title"
  t.datetime "created_at",      null: false
  t.datetime "updated_at",      null: false
  t.integer  "responsible_id",  null: false
  t.integer  "status",          null: false
end

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

create_table "supplies", force: :cascade do |t|
  t.integer  "taskable_id",  null: false
  t.datetime "expired_at"
  t.datetime "created_at",   null: false
  t.datetime "updated_at",   null: false
end

2 个答案:

答案 0 :(得分:1)

您收到PG::UndefinedTable错误,因为在查询关联的where-clauses时,您需要指定表名,而不是关联名。

这可能会给你一个更好的结果:

Supply.where(
  taskables: {
    tasks: { 
      status: [:awaiting, :starting]
    }
  }
)

您可能还必须包含或加入实际关联,具体取决于您是否只需要连接查询,还是希望预加载关联。使用.includes进行预加载,使用.joins进行加入查询。

Supply.includes(taskable: :task).where(...)

Supply.joins(taskable: :task).where(...)

编辑:感谢@Pavling提及.joins.includes之间的区别。

答案 1 :(得分:1)

据我所知where无法深入了解关系。 从我的角度看它应该是什么样的:

class Task < AR::Base
  has_one :taskable, inverse_of: :task, autosave: true
  enum status: { :awaiting, :restarting, ... }
class Taskable < AR::Base
  belongs_to :task, inverse_of: :taskable, autosave: true
  has_many :supplies
class Supply < AR::Base
  belongs_to :taskable
  has_many :supplies, through: :taskable

为了得到你想要的东西,你将能够使用: Supply.joins(:tasks).where(tasks: {status: [:awaiting, :starting]})

还要注意where子句中的状态值。如果您使用的是rails 4.1,则必须传递状态的数值。

<强>已更新

或者没有has_many :through

的简单方法

Supply.joins(taskable: :tasks).where(tasks: {status: [:awaiting, :starting]})