0

私が開発しているアプリには、3 つの主要なモデルと多くの単一テーブル継承モデルがあります。

  1. 質問
  2. ユーザー
    1. プロ
    2. 代表者
  3. 分類法
    1. カテゴリー
    2. トピック
    3. 職業
    4. 地域性
    5. 領域

複数の種類のユーザー ( UserProfessional < UserRepresentant < User) があり、それらはすべて単一テーブル継承の User クラスから継承されます。

複数の種類のタクソノミ ( Category < TaxonomyTopic < TaxonomyProfession < TaxonomyLocality < Taxonomy、 ) がありRegion < TaxonomyCountry < Taxonomyそれらはすべて単一テーブル継承のタクソノミ クラスから継承されます。

質問だけでなく、専門家も、多対多の関係を介して分類されます (多くのトピック、多くの職業、多くのカテゴリなどを持つことができます...)。

今、私はこれらのポリモーフィック オブジェクト間の多対多の関係を確立する方法を探しています。私はhas_many :through解決策を試し、分類クラスを作成しました。

移行ファイル:

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"

プロフェッショナル.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. Where 句が正常に機能しません (つまりQuestion.joins(:topics).where(:conditions => {:topics => {:id => [list of topics,...]}})、エラーで失敗しno such column: "Topics"."id"ます。

何か助けはありますか?ありがとう!

アップデート

示されているように、宝石「store_base_sti_class」をインストールしました。分類モデルに望ましい効果がありました。

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

ただし、トピック ( Professional.find(1).topics) を照会すると、ActiveRecord は「Professional」ではなく「User」クラスを探しています...

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'

両方でそれを修正する方法はありますか?

4

1 に答える 1

3

質問2の場合、where句のキーは、関連付け名ではなくテーブル名にマップする必要があります。だから私はあなたが望むだろうと思います:

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

質問1の場合、を設定するとquestion.topics = [...]、Railsが作成する分類オブジェクトが(「トピック」ではなく)「Taxonomy」のtaxonomy_typeで設定されているように見えます。base_classこれは、実際のクラス名だけでなく、格納されているモデルを取得するRailsのthrough_association.rb:51が原因のようです。

分類モデルの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

アップデート

アソシエーションのスコープを設定するときに代わりに使用するという別のRailsの決定(preloader / association.rb:113)があるようです。model.base_class.sti_namemodel.sti_name

その宝石はあなたのためにこれを世話する必要があります。オプションのラップ方法については、store_base_sti_class_for_3_1_and_above.rb:135を参照してください。has_many :as私のローカル環境では、これは期待どおりに機能します。

$ 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
于 2012-12-31T17:42:34.487 に答える