如何获取`has_many`多态关联的对象集合?

时间:2016-06-19 06:24:45

标签: ruby-on-rails activerecord

我想创建一个gem(github),其中包含可与之关联的ActiveRecord模型Site 现有Rails应用程序中的AdminUser模型。

模型Site

module C80SassSeo
  class Site < ActiveRecord::Base
    belongs_to :owner, :polymorphic => true
  end
end

模型Owner

module C80SassSeo

  module Owner

    extend ActiveSupport::Concern

    #  ERROR THROWN: Cannot define multiple 'included' blocks for a Concern
    # included do
    #
    # end

    def self.included(klass)
      klass.extend ClassMethods
      # klass.send(:include, InstanceMethods)
    end

    module ClassMethods
      def act_as_owner
        class_eval do
          has_many :sites, :as => :owner, :class_name => 'C80SassSeo::Site'
        end
      end
    end

  end
end

ActiveRecord::Base.send :include, C80SassSeo::Owner

迁移Sitec80_sass_seo_ - 表格前缀):

class CreateC80SassSeoSites < ActiveRecord::Migration
  def change
    create_table :c80_sass_seo_sites, :options => 'COLLATE=utf8_unicode_ci' do |t|
      t.string :url
      t.string :owner_type # NOTE:: without this activeadmin throws an error on index Sites page
      t.references :owner, index: true
      t.timestamps
    end
    # add_foreign_key :c80_sass_seo_sites, :owners # NOTE:: migration error occurs, comment it
  end
end

Site的activeadmin:

 ActiveAdmin.register C80SassSeo::Site, as: 'Site' do

   scope_to :current_admin_user, association_method: :sites_list

   menu :label => "Sites"

   permit_params :url, :owner_id

   config.sort_order = 'id_asc'

   index do
     column :url
     actions
   end

   form(:html => {:multipart => true}) do |f|

     f.inputs 'Properties' do
       f.input :owner_id, :input_html => { :value => current_admin_user.id }, as: :hidden
       f.input :url
     end

     f.actions
   end

 end

但是当我尝试访问AdminUser实例的admin_user.sites时,我收到一个空集合:

=> #<ActiveRecord::Associations::CollectionProxy []>

通过实施'sites_list'等方法获取管理员用户网站的正确方法是什么?

模型AdminUser(主机应用程序):

require 'c80_sass_seo/owner'

class AdminUser < ActiveRecord::Base
  devise :database_authenticatable, 
         :recoverable, :rememberable, :trackable, :validatable

  act_as_owner

  def sites_list
    C80SassSeo::Site.where(:owner_id => self.id)
  end

end

1 个答案:

答案 0 :(得分:0)

根据您对表单的实现,您可能会错过C80SassSeo::Site记录的其他属性,即owner_type

两种解决方案:

  1. owner_type添加为隐藏输入,就像owner_id
  2. 一样
  3. 不要添加任何隐藏的输入,使用admin_user.sites.create(parameters)创建网站,ActiveRecord将为您提供正确的关联
  4. 你提到了:

    BUT I'm getting an empty collection any time I try to access admin_user.sites for a AdminUser instance:
    
    => #<ActiveRecord::Associations::CollectionProxy []>
    

    当你看到这个时,你应该仔细检查admin_user是否真的拥有任何网站?

    C80SassSeo::Site.where(owner_id: admin_user.id, owner_type: 'AdminUser')