ruby-on-rails - 具有 2 深度关联的嵌套资源
问题描述
我正在尝试设置 Active Admin,以便 AdminUser(已登录)可以查看分配给他们的所有 ServiceUser 的列表,然后单击特定 ServiceUser 旁边的链接以查看他们创建的所有支持会话(针对该特定 ServiceUser )。
模型:
class ServiceUser
has_many :support_allocations
has_many :admin_users, through: :support_allocations
has_many :support_budgets
class AdminUser < ApplicationRecord
has_many :support_allocations
has_many :service_users, through: :support_allocations
class SupportAllocation < ApplicationRecord
belongs_to :admin_user
belongs_to :service_user
has_many :support_sessions
class SupportSession < ApplicationRecord
belongs_to :invoice, optional: true
belongs_to :support_allocation
has_one :service_user, through: :support_allocation
has_one :admin_user, through: :support_allocation
我猜我需要让SupportSessions 成为ServiceUser 的嵌套资源,这样我就可以遵循restful 原则(即使用例如/service_users/1/support_sessions 的路由)。我设法像这样嵌套资源:
ActiveAdmin.register SupportSession do
belongs_to :service_user
但我意识到省略了关键的连接表 SupportAllocation。此外,它不起作用!错误信息是:
NoMethodError in SupportSessionsController#index
undefined method `support_sessions' for #<ServiceUser:0x00007fe6316b9030> Did you mean? support_allocations
以前,我可以使用以下代码查看分配给 AdminUser 的所有 ServiceUser 的所有 SupportSession:
ActiveAdmin.register SupportSession do
super.includes(support_allocation: [:service_user, :admin_user])
这个问题是我想在 ServiceUser 和 AdminUser 之间的 SupportAllocation 关系的上下文中使用资源。因此,登录的 AdminUser 可以看到分配给他们的所有 ServiceUser 的索引列表(通过 SupportAllocation),然后移动到所选 ServiceUser 的所有 SupportSessions 的索引列表(从第一个列表中)。
嵌套资源在这里是正确的解决方案,还是有一种更简单的方法来拥有一个通用的 SupportSession 资源页面,该页面可以显示所有服务用户的 SupportSessions 或特定的服务用户(通过 URL 中的“id”)?我如何处理与中间表的这种棘手的两级关联?
非常感谢你的帮助。
这是我在 app/admin/ 中的 support_sessions.rb 控制器的代码
ActiveAdmin.register SupportSession do
menu label: 'My sessions'
#belongs_to :support_allocation
belongs_to :service_user
# Eager loading to speed up queries
includes :service_user, :admin_user, :support_allocation
sidebar :help, priority: 0 do
"Need help? Email us at help@example.com"
end
# Default sort order
config.sort_order = 'support_sessions.date_held_asc'
controller do
def scoped_collection
#super.includes :support_allocation
super.includes(support_allocation: [:service_user, :admin_user])
#SupportSession.includes(support_allocation: [:service_user, :admin_user])
#super.includes :service_user, :admin_user
end
end
scope :all, :default => true
scope :invoiced
scope :uninvoiced
index do
selectable_column
column 'Date held', :date_held
#column 'Service user', :full_name, :sortable => 'service_users.family_name' do |ss|
#service_user = ServiceUser.find(ss.support_allocation.service_user.service_user_id).full_name
#ss.support_allocation.service_user
#end
#column 'Based at', sortable: 'support_allocation.service_user.organisation.org_name' do |ss|
#ss.support_allocation.service_user.organisation.org_name
#end
column 'Venue', :venue
#column 'Support worker', :full_name, :sortable => 'admin_users.family_name' do |ss|
#support_worker = AdminUser.find(ss.admin_user_id).full_name
#ss.support_allocation.admin_user
#end
actions
end
permit_params(:admin_user_id, :service_user_id, :venue, :mode_of_delivery, :date_held, :time_start, :time_end, :total_breaks, :status)
form do |f|
f.semantic_errors *f.object.errors.keys
f.inputs 'Support session details' do
# Code to check if creating a new record or editing an existing record:
#if f.object.new_record?
#if current_admin_user.super_admin == false
# Pre-select only current support worker (so no other choices)
#f.input :admin_user, :label => 'Support worker', as: :select, collection: AdminUser.where(super_admin: 0, #id: current_admin_user.id), include_blank: false
#else
# Otherwise list all support workers
#f.input :admin_user, :label => 'Support worker', as: :select, collection: AdminUser.where(super_admin: 0), include_blank: true, allow_blank: false
#end
#f.input :support_allocation
#f.input :service_user, :label => 'Service user', as: :select, collection: ServiceUser.all, include_blank: true, allow_blank: false
f.input :mode_of_delivery, as: :select, collection: SupportSession.mode_of_deliveries.keys, include_blank: true, allow_blank: false
f.input :venue, :label => 'Venue'
f.input :date_held, :label => 'Date held', :as => :datepicker
f.input :time_start, :label => 'Start time'
f.input :time_end, :label => 'End time'
f.input :total_breaks, :label => 'Total breaks (in minutes)', :input_html => { :value => '0' }
if current_admin_user.super_admin == false
f.input :status, as: :select, collection: SupportSession.statuses.keys, include_blank: true, allow_blank: false
end
end
f.actions
end
end
解决方案
感谢您对我的模型的提示。
为了解决我最初的问题,我将 SupportSession ActiveAdmin 控制器嵌套在 SupportAllocation 中:
ActiveAdmin.register SupportSession do
menu label: 'My sessions'
belongs_to :support_allocation
这会在 SupportAllocation(定义 ServiceUser 和 SupportSession 之间的关系)的上下文中为 SupportSession 创建一个新的嵌套路由,让我创建一个从 SupportAllocation 直接到单个 ServiceUser 的所有 SupportSessions 的链接(例如 /support_allocations/2/support_sessions),使用通常的路径助手:
actions defaults: false do |support_allocation|
link_to 'Manage support sessions', support_allocation_support_sessions_path(support_allocation_id: support_allocation.id), class: 'member_link'
end
推荐阅读
- css - Bootstrap 4工具提示文本左对齐
- mysql - SQL:返回关于另一个值的唯一值列表
- hadoop - 我可以将 API 与 STORM 或 KAFKA 连接吗
- java - 我可以在两个 openapi 客户端之间共享模型吗?
- haskell - 用纯函数式语言制作游戏
- node.js - 未使用自制 npm,正在使用 npm 系统
- angular-material - 如何在多列下拉列表中过滤 Angular Mat Table
- c# - 如何在 asp.net core 2.0 Web 应用程序中获取浏览网站的用户的用户名?
- javascript - 如何使用来自另一个数组的值的 javascript 标记我的数组?
- flutter - 在没有 onPressed 的情况下自动运行 StatefulWidget