Rails 带 Namespace 的 Polymorphic 关联如何查询

davidwei · April 27, 2016 · Last by as181920 replied at December 30, 2017 · 2821 hits

是这样的,我们有 A 和 B 两个项目,在 A 项目里面需要只读地访问 B 项目的数据库。A 和 B 项目都有一个类叫 Resource,但是他们对应的数据库不是一个,只是同名。

现在在 A 项目里面,有下面的代码:

module B
  class Base  < ActiveRecord::Base
  end
end

module B
  class Resource < Base
    belongs_to :resourceable, polymorphic: true
  end
end

module B
  class Stuff < Base
    has_many :resources, as: :resourceable
  end
end

在执行:

Stuff.includes(:resources).where(id: [1,2,3]).to_a 

的时候,SQL 语句是这样的:

select * from stuff where id in (1,2,3);
select * from resources where resourceable_id in (1, 2, 3) and resourceable_type = "B::Stuff";

最后一个 SQL 语句,是带有 namespace 的,但是此数据在 B 项目里面是不带有B::的。如何做到查询不带 namespace 呢?这种情况如何破?希望大家指点一二。 谢谢

module B
  class Stuff < Base
    has_many :resources, -> (object) { unscope(where: :resourceable_type).where(resourceable_type: object.class.name.split("::").last)) } as: :resourceable
  end
end

可以这样试试

我感觉你需要的是覆盖 resourceable_type 的名称

http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#module-ActiveRecord::Associations::ClassMethods-label-Polymorphic+Associations

class Asset < ActiveRecord::Base
  belongs_to :attachable, polymorphic: true

  def attachable_type=(class_name)
     super(class_name.constantize.base_class.to_s)
  end
end

#1 楼 @angelfan 单个查询是 OK 的,但是放在 includes 做批量查询的时候就跪掉了。

#2 楼 @huacnlee rails 4.1.2 , 在方法定义的地方加了 log,但是没看到输出。:(

#2 楼 @huacnlee 我是需要覆盖 resouceable_type 的名称。文档中的用途是,如果涉及到单表继承,在保存关联的时候,可以自定义保存时,xx_type 的值。不过在查询的时候,应该没有去调用这个方法。

估计这个东西需要修改 AR 底层的东西。

也遇到,处理代码:

module Aaa
  module Bbb
    class ApplicationRecord < ActiveRecord::Base
      self.abstract_class = true
      self.store_full_sti_class = false

      def self.belongs_to(name, scope = nil, options = {})
        super(name, scope, options).tap do |hash|
          reflection = hash[name.to_s]
          def reflection.association_class
            if polymorphic?
              BelongsToPolymorphicAssociation
            else
              super
            end
          end unless store_full_sti_class
        end
      end
    end

    class BelongsToPolymorphicAssociation < ActiveRecord::Associations::BelongsToPolymorphicAssociation
      def klass
        type = owner[reflection.foreign_type]
        type.presence && Aaa::Bbb.const_get(type)
      end
    end
  end
end
You need to Sign in before reply, if you don't have an account, please Sign up first.