首页 > 解决方案 > 具有 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

标签: ruby-on-railsrubyactiveadmincancancan

解决方案


感谢您对我的模型的提示。

为了解决我最初的问题,我将 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

推荐阅读