如何使用活动记录正确定义此关联?

时间:2015-09-27 13:54:15

标签: ruby-on-rails activerecord associations has-one

我在应用程序中有以下两个模型

class City
end

class Suburb
end
一个城市正好有5个郊区,北,东,南,西和中心。我想通过一种相应的方法来引用每个郊区,这样, 北通过city.north访问 南通过city.south进入

我可以在cities表中为每个郊区添加外键,并使用belongs_tohas_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

这可以按预期工作。但是当你读它时,它是相反的。 a郊区属于城市和城市has_one:north,has_one:east,has_one:south,has_one:west和has_one:center。

我还尝试在has_many :suburbs模型上定义city,并为郊区模型添加枚举属性direction,而不是为每个方向使用define_method'定义方法,但是我看到它过度设计了。

有没有办法对此进行正确建模。

2 个答案:

答案 0 :(得分:1)

您的架构没有任何内在错误,但为了便于讨论,让我提出一个满足您的架构问题的替代方案:

正如您所建议的那样,让Suburb属于City。为了强制郊区对其城市的唯一性,我们在direction表格中添加suburbs列,以及结合city_id和{{1}的唯一复合索引}。这样,direction只属于一个城市,而某个城市在给定的Suburb中不能有多个Suburb

<强>分贝/迁移/ ... create_suburbs.rb

direction

应用/模型/ city.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

我们的class City < ActiveRecord::Base has_many :suburbs end 模型现在有点复杂了。我们需要Suburb的验证,以及每个可能值的范围。我想添加一个确保direction始终是符号的getter。

应用/模型/ suburb.rb

direction

现在我们可以使用范围访问和深入了解郊区:

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 位,你可以定义便利访问器:

应用/模型/ city.rb

first

答案 1 :(得分:0)

我想说你需要一个额外的模型,CitySuburb,这样城市和郊区都有很多CitySuburbs,CitySuburb属于City和Suburb。

您可以在CitySuburb上为北部,南部等设置范围,从而将City与north_suburb,south_suburb等关联。