matewka
(matewka)
1
大家好,
我已经为自己的问题搜索了好几个星期,现在几乎要放弃了。
背景:
我正在开发并维护一个面向体育俱乐部的多租户管理面板。
我的自托管 Discourse 论坛目前仅对俱乐部成员开放,但我希望将其改为公开访问。我自己的 SSO 集成会在用户登录后,自动将数据库中用户的完整姓名同步到 Discourse 用户中。
问题:
目前我无法将论坛设为公开,因为用户的完整姓名应当仅对同一俱乐部的用户可见。
作为一名 Ruby 开发者,我的经验为零(我是一名 JS 开发者),但到目前为止,我已经弄懂了以下代码部分:
# plugin.rb
after_initialize {
require_dependency 'basic_user_serializer'
require_dependency 'current_user'
class ::BasicUserSerializer
attributes :name
def name
# 表示属于某个俱乐部的固定组名集合
clubGroups = Array['foo', 'bar', 'baz']
# 我无法弄明白的部分:
# 仅当目标用户与当前登录用户共享同一个 clubGroups 时,才显示该用户的姓名,
# 例如:我作为属于 'bar' 组的用户登录,意味着我属于 Bar 俱乐部。我应该只能看到同样属于 'bar' 组的用户的姓名
???
end
end
}
我无法弄明白以下两点:
- 如何获取当前用户的所属组
- 如何获取目标用户的所属组
一旦我有了上述信息,我就可以将这两个数组与 clubGroups 进行比较,从而决定是否显示该用户的姓名。
另一个对我来说具有挑战性的任务是关闭用户编辑自己姓名的功能,但那是另一回事了。
GroupUser 模型包含用户所属的群组关系。
您可以使用类似 GroupUser.where(user_id: current_user.id) 的查询来获取当前用户所属的群组 ID。
这将返回一个 Active Record 关联对象。
然后,您可以将其 map 为数组:
GroupUser.where(user_id: myuser.id).map {|gu| gu.group_id}
对您的精选用户采用相同的处理方式。
matewka
(matewka)
3
完美!谢谢 
我目前还不知道如何将其转化为可行的解决方案,但这已经是一个重要的提示。
matewka
(matewka)
5
另一个障碍:
在尝试获取当前用户的 ID 以传递给查询时,我不太清楚该如何获取。
当我导航到代码中的 CurrentUser 模型时,唯一看起来与我的需求相关的方法是 current_user,但当我执行以下操作时:
pp CurrentUser.current_user
它会报错:
undefined method `current_user' for CurrentUser:Module
我想我肯定缺少一些关于 Ruby 的基础知识,但也许你能轻松帮我解决这个问题?
RGJ
(Richard - Communiteq)
6
您可能想查看此插件的代码。它能为同一群组中的成员添加头像标识,以便他们能够识别彼此为群组成员。这虽然有所不同,但其中确实包含了检查查看用户是否与发帖用户属于同一群组的代码。
这里的线索是这个方法:
def user_is_current_user
object.id == scope.user&.id
end
被序列化的用户是 object。
当前用户实际上在 scope.user 中,因此:
GroupUser.where(user_id: scope.user&.id).map {|gu| gu.group_id}
可能对当前用户有效。
等等。
一些有用的提示:
- 阅读 Discourse 源代码
- 按照 @RGJ 的建议,查看一些开源插件,看看它们是如何实现功能的
- 在 Rails 控制台中进行原型设计
rails c --sandbox
matewka
(matewka)
9
为了将来访问此主题的访客,以下是我最终得出的解决方案。
它并不完美,也没有经过优化,但能正常工作!这是第一步,也是最重要的一步 
after_initialize {
require_dependency 'basic_user_serializer'
class ::BasicUserSerializer
attributes :name
def name
if user_is_current_user
return _old_name_method
else
# TODO: 使此列表可编辑
clubGroups = Array['...']
if scope.user
ownGroups = GroupUser.where(user_id: scope.user.id)
.map { |gu| gu.group_id }
.map { |group_id| Group.find_by(id: group_id) }
.filter { |group| clubGroups.include? group.name }
if ownGroups.length > 0
ownGroupsIds = ownGroups.map { |g| g.id }
if GroupUser.exists?(user_id: user.id, group_id: ownGroupsIds)
return _old_name_method
end
end
end
end
return ''
end
private def _old_name_method
return Hash === user ? user[:name] : user.try(:name)
end
end
}