如何实现 has_many :through 关联两种方式?
Posted
技术标签:
【中文标题】如何实现 has_many :through 关联两种方式?【英文标题】:How can I implement a has_many :through association two ways? 【发布时间】:2018-08-21 00:36:54 【问题描述】:我有一个属性模型和一个用户模型。
具有“admin”角色的用户(由 users 表中的一列表示)可以具有许多属性。
具有“guest”角色的用户也可以属于某个属性,这使他们可以访问该属性。
我应该如何在 Rails 中做到这一点?
【问题讨论】:
【参考方案1】:授权表 -> user_id, property_id
class Authorization < ActiveRecord::Base
belongs_to :user
belongs_to :property
end
class User < ActiveRecord::Base
has_many :authorizations
has_many :properties, through: :authorizations
end
class Property < ActiveRecord::Base
has_many :authorizations
has_many :users, through: :authorizations
end
那你就可以User.find(id).properties
【讨论】:
【参考方案2】:首先,您的模型User
和Property
之间需要has_many :through 关联。因此,创建一个新表 properties_users,其中包含列 user_id 和 propety_id。并对模型进行以下更改:
class PropertiesUser < ActiveRecord::Base
belongs_to :user
belongs_to :property
end
class User < ActiveRecord::Base
has_many :properties_users
has_many :properties, through: :properties_users
end
class Property < ActiveRecord::Base
has_many :properties_users
has_many :users, through: :properties_users
end
现在,我们需要确保来宾用户没有多个属性。为此,我们可以向模型 PropertiesUser
添加验证,如下所示:
class PropertiesUser < ActiveRecord::Base
validate :validate_property_count_for_guest
private
def validate_property_count_for_guest
return unless user && user.guest?
if user.properties.not(id: self.id).count >= 1
self.errors.add(:base, 'guest user cannot have more than one properties')
end
end
end
class User < ActiveRecord::Base
def guest?
# return `true` if user is guest
end
end
最后,要访问访客用户的属性,在模型User
中定义一个专用方法:
class User < ActiveRecord::Base
def property
# Raise error if `property` is called on non-guest users
raise 'user has multiple properties' unless guest?
properties.first
end
end
现在,您可以通过运行获取来宾用户的属性:
user = User.first
user.guest?
=> true
user.property
=> <#Property 1> # A record of Property
【讨论】:
以上是关于如何实现 has_many :through 关联两种方式?的主要内容,如果未能解决你的问题,请参考以下文章
使用 `:has_many :through` 记录关联处理复选框表单
ActiveRecord、has_many :through 和多态关联
has_and_belongs_to_many 或多态 has_many :through?