我正在我的应用程序上设置多态关联。我有一个用户表和一个地址表。基本上,我想实现多个用户可以共享同一地址之类的目标。
我的用户模型:
class User < ApplicationRecord
has_one :address, as: :addressable
end
我的地址模型:
class Address < ApplicationRecord
belongs_to :addressable, polymorphic: true
end
当我创建一个用户和该用户的地址时,它工作正常。但是,如果我的第二个用户的地址与第一个用户完全相同,该怎么办?我知道通过创建另一个带有addressable_type
的地址并addressable_id
指向第二个用户来正常工作。
user1: #<User: id: 1>
,user1.address
返回address1
:#<Address: id: 1, street: 'Fifth Avenue', city: 'New York', state: 'NY', addressable_type: 'User', addressable_id: 1
如何在不创建另一个如下所示的地址记录的情况下将我的第二个用户user2: #<User: id: 2>
链接到address1
:#<Address: id: 2, street: 'Fifth Avenue', city: 'New York', state: 'NY', addressable_type: 'User', addressable_id: 2
我计划引入更多可能与User
模型具有相同地址的表。
因此,您有几种不同的问题:
规范化地址
您需要规范化您的地址,否则不同的拼写将导致新记录。非常简单的方法可能是例如存储街道和城市的缩小版本并删除任何空格,否则Fifth Avenue
和fifth avenue
是不同的记录。但是,这并不能阻止您使用不同的正确拼写,例如5th Avenue
和Fifth Avenue
.也许您可以使用像地理编码器这样的 gem 来更好地规范您的地址。
向地址模型添加验证
为了确保不会多次存储相同的地址,您可能需要向地址模型添加唯一性验证。
validates :street, uniqueness: { scope: [:city, :state, :country] }
https://guides.rubyonrails.org/active_record_validations.html#uniqueness
创建新地址记录时使用find_or_create_by
现在,您可以使用find_or_create_by
来避免在控制器(或创建地址的任何位置(中创建重复记录。
Address.find_or_create_by(street: "5th Avenue", city: "New York", state: "NY")
Address.find_or_create_by(street: "5th Avenue", city: "New York", state: "NY")
# -> will only create one address object with these attributes
https://apidock.com/rails/v4.0.2/ActiveRecord/Relation/find_or_create_by
但如前所述,困难的问题是首先规范化您的地址。
你需要一个连接表,就像这样
class User < ApplicationRecord
has_one :user_address
has_one :address, through: user_address
end
# user_addresses table has columns user_id and address_id
class UserAddress < ApplicationRecord
belongs_to :user
belongs_to :address
end
class Address < ApplicationRecord
has_many :user_addresses
has_many :users, through: user_addresses
end