具有2级深度关联的嵌套资源

时间:2019-06-28 11:09:50

标签: ruby-on-rails ruby activeadmin cancancan

我正在尝试设置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的嵌套资源,以便我可以遵循宁静的原则(即,使用到/ 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可以查看(通过SupportAllocation)分配给他们的所有ServiceUser的索引列表,然后移至所选ServiceUser的所有SupportSession的索引列表(从第一个列表开始)。

嵌套资源是这里的正确解决方案,还是有一种简单的方法来拥有通用的SupportSession资源页面,该页面可以显示所有ServiceUser的SupportSession或特定ServiceUser(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

2 个答案:

答案 0 :(得分:0)

我相信您的ActiveAdmin注册需要以与模型中相同的方式反映出来。

例如,您有:

SupportSession

但是您的class SupportSession < ApplicationRecord ... has_one :service_user, through: :support_allocation ... 模型定义为:

has_one

假设您的模型正确,则ActiveAdmin注册也应该是ServiceUser关系。

此外,您似乎还没有完全定义模型关系。您的belongs_to模型没有对应的{{1}}关系。

答案 1 :(得分:0)

感谢我的模特技巧。

要解决我原来的问题,我在SupportAllocation中嵌套了SupportSession ActiveAdmin控制器:

ActiveAdmin.register SupportSession do
  menu label: 'My sessions'
  belongs_to :support_allocation

这会在SupportAllocation(定义ServiceUser和SupportSession之间的关系)的上下文中为SupportSession创建新的嵌套路由,让我创建一个从SupportAllocation直接链接到所有SupportSession的链接(例如/ support_allocations / 2 / support_sessions)。单个ServiceUser,使用通常的路径助手:

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