0

我开发的应用主要有3种型号和许多单表继承机型:的Rails:类继承和多态复杂的has_many:通过关联

  1. 问题
  2. 用户
    1. 专业
    2. 代理人
  3. 分类标准
    1. 类别
    2. 主题
    3. 职业
    4. 局部性
    5. 地区
    6. 国家

有多种类型的用户(UserProfessional < UserRepresentant < User)所有继承具有单个表继承的User类。

有多种类型的分类法(Category < TaxonomyTopic < TaxonomyProfession < TaxonomyLocality < TaxonomyRegion < TaxonomyCountry < Taxonomy)其中所有从与单表继承的分类类继承的。

问题,以及专业人士也正在通过分类多对多关系(他们可以有很多话题,很多行业,很多类,等...)

现在,我正在寻找一种方式建立这些多态对象之间的多对多关系。我试过has_many :through解决方案并创建了一个Classification类。

迁移文件:

class CreateClassifications < ActiveRecord::Migration 
    def change 
    create_table :classifications, :id => false do |t| 
     t.references :classifiable, :null => false, :default => 0, :polymorphic => true 
     t.references :taxonomy,  :null => false, :default => 0, :polymorphic => true 
    end 

    add_index :classifications, [:classifiable_id, :taxonomy_id] 
    add_index :classifications, [:taxonomy_id, :classifiable_id] 
    end 
end 

型号文件:

class Classification < ActiveRecord::Base 

    attr_accessible :classifiable, :classifiable_id, :classifiable_type, 
        :taxonomy, :taxonomy_id, :taxonomy_type 

    belongs_to :classifiable, :polymorphic => true 
    belongs_to :taxonomy,  :polymorphic => true 

end 

我加入has_many :through协会有关的问题,专业人士和分类。

Taxonomy.rb

has_many :classifications, :as => :taxonomy, :foreign_key => :taxonomy_id 
has_many :classifiables, :through => :classifications, :source => :classifiable 
has_many :users,   :through => :classifications, :source => :classifiable, :source_type => "User" 
has_many :professionals, :through => :classifications, :source => :classifiable, :source_type => "Professional" 
has_many :representants, :through => :classifications, :source => :classifiable, :source_type => "Representant" 
has_many :questions,  :through => :classifications, :source => :classifiable, :source_type => "Question" 
has_many :guides,  :through => :classifications, :source => :classifiable, :source_type => "Guide" 

Question.rb

has_many :classifications, :as => :classifiable, :foreign_key => :classifiable_id, :dependent => :destroy 
has_many :taxonomies, :through => :classifications, :source => :taxonomy 
has_many :topics,  :through => :classifications, :source => :taxonomy, :source_type => "Topic" 

Professional.rb

has_many :classifications, :as => :classifiable, :foreign_key => :classifiable_id, :dependent => :destroy 
has_many :taxonomies, :through => :classifications, :source => :taxonomy 
has_many :topics,  :through => :classifications, :source => :taxonomy, :source_type => "Topic" 
has_many :professions, :through => :classifications, :source => :taxonomy, :source_type => "Profession" 

现在,设置这一切后,事情并没有很好地工作.. 。

  1. 我似乎无法将分类法分配给专业人员或问题(即除了未保存的主题外,Question.create(:title => "Lorem Ipsum Dolor Sit Amet", :author => current_user, :topics => [list of topics,...])的效果很好。)

  2. 在哪里,他们应该(即Question.joins(:topics).where(:conditions => {:topics => {:id => [list of topics,...]}})失败,出现错误no such column: "Topics"."id"条款不起作用。

任何帮助吗?谢谢!

UPDATE

我已经安装gem'store_base_sti_class'如图所示,它对分类模型具有预期效果。

#<Classification classifiable_id: 1, classifiable_type: "Professional", taxonomy_id: 17, taxonomy_type: "Topic"> 

然而,当我查询主题(Professional.find(1).topics),ActiveRecord的仍然是寻找类“用户”而不是“专业” ......

SELECT "taxonomies".* FROM "taxonomies" INNER JOIN "classifications" ON "taxonomies"."id" = "classifications"."taxonomy_id" WHERE "taxonomies"."type" IN ('Topic') AND "classifications"."classifiable_id" = 1 AND "classifications"."classifiable_type" = 'User' AND "classifications"."taxonomy_type" = 'Topic' 

不知道如何解决它的两个?

+0

我的问题是我没有has_many:through'语句在我的所有分类类(主题,专业等...)?如果这是问题,那么需要一个非DRY解决方案...... –

回答

3

对于问题#2,where子句中的键应映射到表名称,而不是映射到关联名称。所以,我想你会想:

Question.joins(:topics).where(Topic.table_name => {:id => [...]}) 

对于问题1,看来,当你设置question.topics = [...],其中的Rails会创建被设为“分类学”(而不是“主题”)的taxonomy_type分类对象。这似乎是由于Rails的through_association.rb:51,其中存储了模型的base_class,而不仅仅是实际的类名。

我能够在分类模型上用before_validation回调来解决这个问题。在我看来,替代方案是实际Rails关联代码的补丁,以使此行为可配置。

class Classification < ActiveRecord::Base 
    attr_accessible :classifiable, :classifiable_id, :classifiable_type, 
        :taxonomy, :taxonomy_id, :taxonomy_type 

    belongs_to :classifiable, polymorphic: true 
    belongs_to :taxonomy, polymorphic: true 
    before_validation :set_valid_types_on_polymorphic_associations 

    protected 

    def set_valid_types_on_polymorphic_associations 
    self.classifiable_type = classifiable.class.model_name if classifiable 
    self.taxonomy_type = taxonomy.class.model_name if taxonomy 
    end 
end 

UPDATE

似乎存在(在preloader/association.rb:113)另一导轨决定为协会设定范围时要使用的model.base_class.sti_name代替model.sti_name

那宝石应该照顾好你。有关如何包装has_many :as选项,请参阅store_base_sti_class_for_3_1_and_above.rb:135。在我的本地环境中,这是按预期工作:

$ bundle exec rails console 
irb(main):001:0> topics = 3.times.map { Topic.create } 
irb(main):002:0> p = Professional.new 
irb(main):003:0> p.topics = topics 
irb(main):004:0> p.save! 
irb(main):005:0> exit 

$ bundle exec rails console 
irb(main):001:0> puts Professional.find(1).topics.to_sql 
SELECT "taxonomies".* FROM "taxonomies" INNER JOIN "classifications" ON "taxonomies"."id" = "classifications"."taxonomy_id" WHERE "taxonomies"."type" IN ('Topic') AND "classifications"."classifiable_id" = 2 AND "classifications"."classifiable_type" = 'Professional' AND "classifications"."taxonomy_type" IN ('Topic') 
irb(main):002:0> Professional.find(1).topics.count 
=> 3 
+1

在通过GitHub进行[针对base_class引用的Rails问题]之后(https://github.com/rails/rails/issues/search?q = base_class),我找到了[store_base_sti_class](https://github.com/appfolio/store_base_sti_class)gem。它改变了这种行为,但是在整个Rails应用程序中这样做(这可能是也可能不是你想要的)。 –

+0

谢谢!我已经安装了宝石。它一半工作。请参阅我的更新。 –

+0

我已经用一些更多的研究和另一个链接更新了答案。但我可能需要查看更多的应用程序才能提供帮助。根据您在示例中发布的代码,我引用的宝石应该为您处理关联范围。 –