2

我有一个名为 Place 的父类。

# Parent class for Country, City and District
class Place < ActiveRecord::Base
end

class Country < Place
  has_many :cities, foreign_key: "parent_id"
  has_many :districts, through: :cities
end

class City < Place
  belongs_to :country, foreign_key: "parent_id"
  has_many :districts, foreign_key: "parent_id"
end

class District < Place
  belongs_to :city, foreign_key: 'parent_id'
  has_one :country, through: :city
end

架构:

create_table "places", force: true do |t|
  t.string   "name"
  t.string   "type"
  t.integer  "parent_id"
  t.datetime "created_at"
  t.datetime "updated_at"
end

add_index "places", ["parent_id"], name: "index_places_on_parent_id"
add_index "places", ["type"], name: "index_places_on_type"

以下按预期工作:

@country.cities # => Returns all of the cities that belong to this country
@city.districts # => Returns all of the districts that belong to this city

但这并不像我想象的那样工作:

@country.districts # => Does not return all of the districts belonging to cities in this country

谁能解释我应该如何处理性传播感染?

更新

这是来自的输出 SQL 查询@country.districts

SELECT "places".* FROM "places" INNER JOIN "places" "cities_districts_join" ON "places"."parent_id" = "cities_districts_join"."id" WHERE "places"."type" IN ('City') AND "places"."type" IN ('District') AND "cities_districts_join"."parent_id" = ?  [["parent_id", 1]]

我认为问题在于它对两个关系使用相同的连接表,但我不确定是否有“Rails 方式”来更改连接表的名称(优雅地)

4

2 回答 2

2

这对 ActiveRecord 来说是一个具有挑战性的案例。它需要推断需要查找的自连接中的列districts是 STI 实例。显然它不够聪明,无法做到这一点。由于唯一的表是places,因此生成此查询也就不足为奇了:

SELECT "places".* FROM "places" 
INNER JOIN "places" "cities_districts_join" 
ON "places"."parent_id" = "cities_districts_join"."id" 
WHERE "places"."type" IN ('City')   <<<<< ERROR HERE
AND "places"."type" IN ('District') 
AND "cities_districts_join"."parent_id" = ?  

如您所见,类型检查必须失败,因为一个字符串不能同时是Cityand District。如果 the 中的第一个子句WHERE代替,所有都可以

WHERE "cities_districts_join"."type" IN ('City')  

我在关系上尝试了几种选择(认为:class_name可能会这样做),但没有任何乐趣。

您可以使用 SQL 解决此限制。删除类has_many ... through中的Country并替换为

def districts
  District.find_by_sql(['SELECT * from places AS city 
                           INNER JOIN places AS district 
                         ON district.parent_id = city.id 
                         WHERE city.parent_id = ?', id])
end

或者也许其他人会看到更优雅的方式。如果没有,您可以考虑将其作为 Rails 开发中的问题发布。这是一个有趣的案例。

于 2013-10-07T02:28:26.093 回答
-1

我认为您需要更改模型的继承。

class Country < Place

class City < Country

class District < City

然后删除

has_one :country through: :city 

线。

向下滚动以查找有关 STI http://api.rubyonrails.org/classes/ActiveRecord/Base.html的信息

于 2013-10-03T03:40:07.577 回答