我有一个模型Place
。
例如,地方可以是一个城市,一个地区,一个地区或一个国家,但我认为一个模型就足够了,因为为了我的目的,城市和地区之间没有太大的区别。
并且地方可以彼此属于,例如一个地区可以有很多城市,一个国家可以有很多地区等。
但我的问题是它的历史项目和一个城市可以属于许多地区。例如,从1800年到1900年,一个城市属于一个历史区域(现在不存在),从1900年到现在,属于另一个。将这些地区存放在不同的地方非常重要,尽管它们可以有相似的地理边界,但只有名称不同。
我猜它是多对多的,但是也许有人可以给出更好的主意?
如果它是多对多的,我如何在一个查询中获得一系列父级地方,以制作简单的字符串,例如" Place,Parent place 1,Parent place 2,Parent place 3&#34 ;,例如"美国加利福尼亚州旧金山"?
这是我的代码:
create_table :places do |t|
t.string :name
t.timestamps null: false
end
create_table :place_relations, id: false do |t|
t.integer :sub_place_id
t.integer :parent_place_id
t.timestamps null: false
end
class Place < ActiveRecord::Base
has_and_belongs_to_many :parent_places,
class_name: "Place",
join_table: "place_relations",
association_foreign_key: "parent_place_id"
has_and_belongs_to_many :sub_places,
class_name: "Place",
join_table: "place_relations",
association_foreign_key: 'sub_place_id'
end
请不要犹豫,给我一些想法!
答案 0 :(得分:2)
这使得在不干预该模型的情况下,将多个与多个关系直接关联到另一个模型。但是如果你想像Polymorphic Association那样你可以使用更高级的东西。
有关详细信息,请访问Rails指南:Polymorphic Association
答案 1 :(得分:2)
这是第一个出现在我脑海中的解决方案,可能有很多其他方法可以做到,但我相信这可能是最干净的。
您已经有了正确的总体思路,但您只需对联接表稍作修改即可。基本上,您将使用has_many... through
关系,以便您可以附加某种时间帧鉴别符。
在我的示例中,我使用日期时间字段来指示关联的相关点。结合默认范围,通过时间鉴别器(在我的示例中称为effective_from
)对结果进行排序,您可以轻松选择&#34;当前&#34;没有额外努力的地方的父母和孩子,或者在where子句中使用单个日期比较选择历史数据。 请注意,您不需要像我一样处理时间框架歧视,它只是为了演示这个概念。根据需要进行修改。
class PlaceRelation < ActiveRecord::Base
default_scope { order "effective_from DESC" }
belongs_to :parent, class_name: "Place"
belongs_to :child, class_name: "Place"
end
class Place < ActiveRecord::Base
has_many :parent_places, class_name: "PlaceRelation", foreign_key: "child_id"
has_many :child_places, class_name: "PlaceRelation", foreign_key: "parent_id"
has_many :parents, through: :parent_places, source: :parent
has_many :children, through: :child_places, source: :child
end
并且place_relations
表的迁移应如下所示:
class CreatePlaceRelations < ActiveRecord::Migration
def change
create_table :place_relations do |t|
t.integer :parent_id
t.integer :child_id
t.datetime :effective_from
t.timestamps
end
end
end
因此,如果我们创建了一些&#34;顶级&#34;国家地方:
country1 = Place.create(name: "USA")
country2 = Place.create(name: "New California Republic")
和州名
state = Place.create("California")
和一个城市
city = Place.create("San Francisco")
最后将它们捆绑在一起:
state.parent_places.create(parent_id: country1.id, effective_from: DateTime.now - 1.year)
state.parent_places.create(parent_id: country2.id, effective_from: DateTime.now)
city.parent_places(parent_id: state.id, effective_from: DateTime.now)
然后你会有一个城市(&#34;旧金山&#34;)属于州&#34;加利福尼亚&#34;,历史属于该国&#34; ;美国&#34;,后来&#34;新加利福尼亚共和国&#34;。
此外,如果您想构建一个包含该地点名称及其所有&#34;父母&#34;的字符串,您可以通过递归方式&#34;像这样:
def full_name(name_string = [])
name_string << self.name
parent = self.parents.first
if parent.present?
return parent.full_name name_string
else
return name_string.join(", ")
end
end
对于我们的城市&#34;旧金山&#34;,考虑到"San Francisco, California, New California Republic"
字段的排序,应该生成effective_from
。