【发布时间】:2023-04-10 04:04:01
【问题描述】:
我的数据库中有一个用户表。用户可以是“admin”或“manager”类型。
鉴于下面的模型和架构,我希望对于“经理”用户的每个实例,“管理员”用户可以选择经理所属的租户的一个、部分或全部位置,以便选择哪个经理可以控制的位置。
我的模型
class User < ActiveRecord::Base
belongs_to :tenant
class Tenant < ActiveRecord::Base
has_many :users, dependent: :destroy
has_many :locations, dependent: :destroy
class Location < ActiveRecord::Base
belongs_to :tenant, inverse_of: :locations
我尝试了两条路径
首先,尝试在 User 和 Location 模型之间建立一个作用域 has_many 关联。但是,我无法集中精力构建此范围,以便“管理员”用户可以选择“经理”用户可以控制的位置。
第二,在 users 表中设置一个受控位置属性。然后我设置了一些代码,以便“管理员”用户可以选择“经理”可以控制的位置,并填充其“受控位置”属性。但是,保存在数据库中(在受控位置数组中)的是字符串而不是位置实例。
这是我为第二条路径尝试的代码:
迁移
def change
add_column :users, :controlled_locations, :string, array: true, default: []
end
在视图中
= f.input :controlled_locations, label: 'Select', collection: @tenant_locations, include_blank: "Anything", wrapper_html: { class: 'form-group' }, as: :check_boxes, include_hidden: false, input_html: {multiple: true}
在用户控制器中(在更新方法中)
if params["user"]["controlled_locations"]
params["user"]["controlled_locations"].each do |l|
resource.controlled_locations << Location.find(l.to_i)
end
resource.save!
end
我的期望
首先,我不太确定我尝试的第二条路径是一种好方法(将数组存储在数据库中)。因此,如果可能的话,我最好的选择是建立一个作用域关联。
如果第二条路径可行,我想得到的是这样的。假设登录管理员,我选择 ID 为 1 的用户(经理)可以控制一个位置(波士顿体育场):
user = User.find(1)
user.controlled_locations = [#<Location id: 55, name: "Boston Stadium", created_at: "2018-10-03 12:45:58", updated_at: "2018-10-03 12:45:58", tenant_id: 5>]
相反,我尝试后得到的是:
user = User.find(1)
user.controlled_locations = ["#<Location:0x007fd2be0717a8>"]
数组中保存的不是位置实例,而是纯字符串。
【问题讨论】:
-
你说得对,在数据库中存储数组不是一个很好的解决方案。它不适用于 ActiveRecord 关联,并且是糟糕的数据库设计。一个更好的想法是在用户和位置之间实际设置一个连接表,这就是关系数据库的使用方式。
-
你说得对,我可以简单地将用户和位置关联起来,将 'has_many :locations, through: :tenant' 添加到 User 模型中。但是,这会将所有位置与用户相关联,这不是我想要实现的目标。
-
不,我的意思是创建一个连接模型,描述用户和位置之间的关系,并将其设置为多对多关联。这种授权通常通过角色系统完成 - 如果您需要示例,请查看 rolify gem。
标签: ruby-on-rails arrays ruby associations