在 Ruby on Rails 6 中处理具有相同名称、类型和用途的一组属性在整个应用程序中的多个模型上重复的场景的最佳方法是什么?
例如,(请注意,这实际上只是一个示例,而不是我的实际设置),假设我们有一个Person
具有以下数据库迁移的模型:
def change
create_table :persons do |t|
# The usual attributes...
t.string :first_name
t.string :last_name
t.string :email
# ...
# Location attributes:
t.string :country
t.string :address
t.string :city
t.string :zip_code
end
end
现在假设我们有另一个完全不同的模型 ,Building
它也有一个 location,如下所示:
def change
create_table :buildings do |t|
# Some attributes...
t.string :name
t.decimal :height
t.references :type, foreign_key: { to_table: :building_types }
# ...
# Location attributes (the exact same ones as for Person):
t.string :country
t.string :address
t.string :city
t.string :zip_code
end
end
可能还有更多带有“位置”的模型。
现在,假设在整个应用程序中使用位置的任何地方,都会计算出近似的纬度/经度。那么我怎样才能以这样的方式编写它,以便我不是 1)在迁移中重复属性和 2)不重复相关逻辑(即纬度/经度计算)?
一种选择
我想到的一个潜在解决方案是创建一个单独的模型,并在和Location
中引用它。例如:Person
Building
# xxx_create_persons.rb
class CreatePersons < ActiveRecord::Migration[6.1]
def change
create_table :persons do |t|
# The usual attributes...
t.string :first_name
t.string :last_name
t.string :email
# ...
# Just a single location reference:
t.references :location
end
end
end
# xxx_create_buildings.rb
class CreateBuildings < ActiveRecord::Migration[6.1]
def change
create_table :buildings do |t|
# Some attributes...
t.string :name
t.decimal :height
t.references :type, foreign_key: { to_table: :building_types }
# ...
# Just a single location reference:
t.references :location
end
end
end
# xxx_create_locations.rb
class CreateLocations < ActiveRecord::Migration[6.1]
def change
create_table :locations do |t|
t.string :country
t.string :address
t.string :city
t.string :zip_code
end
end
end
在模型类中:
# person.rb
class Person < ApplicationRecord
# ...
belongs_to :location
end
# building.rb
class Building < ApplicationRecord
# ...
belongs_to :location
end
# location.rb
class Location < ApplicationRecord
# ...
# With a little work, a polymorphic `has_one` could be added here.
def calc_latitude
# ...
end
def calc_longitude
# ...
end
end
然后,当然,我可以做这样的事情:@building.location.calc_longitude
.
然而,这似乎有点矫枉过正。是不是每次我想访问 a Person
or的位置时都必须查询数据库Building
,即使我已经加载了它们?最好的解决方案是什么?