我在应用程序中有以下两个模型
class City
end
class Suburb
end
一个城市正好有5个郊区,分别是北,东,南,西和中部。我想通过一种对应的方法来引用每个郊区,这样北就可以通过city访问。南北可以通过city.south访问。
我可以为cities
表中的每个郊区添加一个外键,并使用belongs_to
并has_one
定义每个关联。但是我发现它不像它应该的那样直观。这是因为郊区属于城市而不是城市。因此以下定义不直观。
class City
belongs_to :north, class_name: 'Suburb'
belongs_to :east, class_name: 'Suburb'
belongs_to :south, class_name: 'Suburb'
belongs_to :west, class_name: 'Suburb'
belongs_to :center, class_name: 'Suburb'
end
class Suburb
has_one :city
end
这按预期工作。但是当您阅读时,则相反。郊区属于城市,城市具有has_one:north,has_one:east,has_one:south,has_one:west和has_one:center。
我还尝试has_many :suburbs
在city
模型上定义一个,并向direction
郊区模型添加一个枚举属性,而不是定义一个方法,对每个方向使用define_method',但是我认为它是经过精心设计的。
有没有一种方法可以对此进行正确建模。
您的架构本质上没有错,但是为了讨论起见,让我提出一个满足您的建模问题的替代方案:
按照您的提议,我们Suburb
属于City
。为了增强郊区相对于城市的唯一性,我们在表格中添加了一个direction
列suburbs
,以及结合了city_id
和的唯一复合索引direction
。这样一Suburb
来,a完全属于一个城市,而一个城市Suburb
在给定的范围内不能有多个direction
。
db / migrate / ... create_suburbs.rb
class CreateDeviseUsers < ActiveRecord::Migration
def self.change
create_table(:suburbs) do |t|
# no need for `index: true` here because of composite key below
t.references :city, null: false
t.text :direction, null: false
t.index [:city_id, :direction], unique: true
end
end
end
app / models / city.rb
class City < ActiveRecord::Base
has_many :suburbs
end
我们的Suburb
模型现在稍微复杂一点。我们需要对进行验证direction
,并为每个可能的值指定一个范围。我喜欢添加一个确保direction
始终也是符号的吸气剂。
app / models / suburb.rb
class Suburb < ActiveRecord::Base
DIRECTIONS = [:north, :east, :south, :west]
belongs_to :city
validates :city, presence: true
validates :direction, inclusion: { in: DIRECTIONS }
# define a scope for each direction
DIRECTIONS.each { |d| scope d, -> { where(direction: d) } }
# convenience getter so that we can reason about direction using symbols
def direction
self[:direction].try(:to_sym)
end
end
现在,我们可以使用范围来访问和深入研究城市郊区:
# all north suburbs
north_suburbs = Suburb.north
# northern suburbs of a city (there can only be one!)
north_suburbs = city.suburbs.north
# as a model
north_suburb = city.suburbs.north.first
如果您真的不喜欢它first
,可以定义便捷访问器:
app / models / city.rb
class City < ActiveRecord::Base
has_many :suburbs
def north
suburbs.north.first
end
# ...
end
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句