Rails:具有多态关联和自定义class_name

时间:2017-08-08 13:22:22

标签: ruby-on-rails postgresql activerecord

考虑以下学校的例子。有一个教室(在术语'课程中选择,以避免任何语法混淆)。每个教室都有许多学生和一名长官,他们是这些学生中的一员。下面显示的是我如何编写模型:

class Classroom
    has_many :students, inverse_of: :classroom
    belongs_to :prefect, class_name: "Student", inverse_of: :classroom
end

class Student
    belongs_to :classroom, inverse_of: :students
    belongs_to :house, inverse_of: :members
end

class House
    has_many :members, class_name: "Student", inverse_of: :house, foreign_key: "house_id"
    has_one :address, as: :addressable
end

class Address
    # attribute city: :string
    belongs_to :addressable, polymorphic: true
end

房子的目的是跟踪来自同一所房子的学生。每个房子都有一个地址,其中一个地址属性是city。当然,为简洁起见,我在这些模型中还有其他属性。例如,Address属于此处未列出的其他模型,因此属于多态关联。

目标

我的目标是获得其长官来自特定城市的教室清单。我知道有很多方法可以在Ruby中解决这个问题,但是如何使用ActiveRecord / SQL查询实现这一目标呢?我使用的是Rails 5.0和Postgres 9.6。

我尝试过什么

我已经尝试了几种方法,都是通过加入表格来完成的。但是,我面临的问题是由于非常规名称,AR无法生成apt查询。这是我尝试过的最有希望的变体:

Classroom.joins(prefect: {house: :address}).where(prefect: {house: {address: {city: "Barcelona"}}})

联接似乎工作正常。但是,由于完美的基础表为where,因此students位变得疯狂。运行它的结果只是一个ActiveRecord Relation对象。但是运行.to_a,我得到以下结果:

ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR:  missing FROM-clause entry for table "address"

我成功地能够检索其长官具有特定名字的教室,如下所示:

Classroom.joins(prefect: {house: :address}).where(students: {first_name: "Juliana"})

但那是我得到的最好的。当嵌套进来时,我无法应用相同的逻辑:

Classroom.joins(prefect: {house: :address}).where(students: {house: {address: {city: "Barcelona"}}})

运行此错误会导致以下错误:

NoMethodError: undefined method `_reflect_on_association' for nil:NilClass
from /home/vagrant/.rvm/gems/ruby-2.3.1@school/gems/activerecord-5.0.0.1/lib/active_record/table_metadata.rb:47:in `associated_table'

我在这里应该做些什么?

1 个答案:

答案 0 :(得分:1)

Classroom.joins(prefect: {house: :address}).where(prefects: { houses: { addresses: { city: "Barcelona"}}})

旁注:我认为你过度使用:inverse_of。来自Rails指南

  

Active Record支持大多数关联的自动识别   标准名称。但是,Active Record不会自动进行   识别包含以下任何内容的双向关联   选项:

  •   

    :条件

  •   

    :通过

  •   

    :多晶型

  •   

    :CLASS_NAME

  •   

    :foreign_key

class Author < ApplicationRecord
  has_many :books, inverse_of: 'writer'
end

class Book < ApplicationRecord
  belongs_to :writer, class_name: 'Author', foreign_key: 'author_id'
end

因此,您可以将模型简化为此

class Classroom
  has_many :students
  belongs_to :prefect, class_name: "Student"
end

class Student
  belongs_to :classroom
  belongs_to :house, inverse_of: :members
end

class House
  has_many :members, class_name: "Student", foreign_key: "house_id"
  has_one :address, as: :addressable
end

class Address
  belongs_to :addressable, polymorphic: true
end