質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.07%

Railsにて相互にポリモーフィックな中間テーブルの構築はアンチパターンか?

受付中

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 2,352
退会済みユーザー

退会済みユーザー

問題の概要

railsで求人情報サイトの設計を行っており、表題にあるような、
相互にポリモーフィック(?)な中間テーブルを使った設計が理想かと考えているのですが、
・パフォーマンスやスケールの観点で問題がないか(特にここの知識が皆無です)
・DRY、かつ、リーダブルなコードがかけるか(現状、ここはクリアできているのではないかと考えていますが、まだまだ初心者なので不安です)
などなど、設計に問題がないかをアドバイス頂きたいです。

以下にサービスの仕様やモデルのリレーションを実際どのように書いているかを説明致しますので、ご教授頂ければ嬉しいです。。!

サービスの仕様


  1.  求人の検索、企業の検索、企業経営者の検索を、それぞれ独立して行える(求人データベース、企業データベース、経営者データベースが独立して存在するということです。)
  2.  それぞれの検索軸には、業種や都道府県など、共通しているものが多い

モデルの設計をどのようにしているか


・Jobモデル(求人情報)
・Companyモデル(求人をする企業情報)
・Presidentモデル(企業の経営者情報)

上記、「検索の対象」となる3つのモデルと、

・Genreモデル(業界。IT、コンサル、飲食、のような項目。)
・Areaモデル(都道府県)

上記2つの検索項目となる2つのモデルがあり、

・ContentsTaxonomy

「検索の対象」と「検索項目」を繋ぐモデルを用意しました。

それぞれ、
「検索の対象」のモデルは、
job.rb
class Job < ActiveRecord::Base
  has_many :contents_taxonomies, :as => :contentable
  has_many :genres, through: :contents_taxonomies, source: :taxonomisable, source_type: 'Genre'
  has_many :areas, through: :contents_taxonomies, source: :taxonomisable, source_type: 'Area'
end

company.rb
class company < ActiveRecord::Base
  has_many :contents_taxonomies, :as => :contentable
  has_many :genres, through: :contents_taxonomies, source: :taxonomisable, source_type: 'Genre'
  has_many :areas, through: :contents_taxonomies, source: :taxonomisable, source_type: 'Area'
end

Presidentも同様、、


「検索項目」は、

genre.rb
class Genre < ActiveRecord::Base
  has_many :contents_taxonomies, :as => :taxonomisable
  has_many :jobs, through: :contents_taxonomies, source: :contentable, source_type: 'Job'
  has_many :company, through: :contents_taxonomies, source: :contentable, source_type: 'Company'
  has_many :president, through: :contents_taxonomies, source: :contentable, source_type: 'President'
end

Areaも同様、


最後に、contents_yaxonomy.rbは、
class ContentsTaxonomy < ActiveRecord::Base
  belongs_to :taxonomisable, polymorphic: true
  belongs_to :contentable, polymorphic: true
end

としています。
また、中間テーブルのmigrateは、
class CreateContentsTaxonomies < ActiveRecord::Migration
  def change
    create_table :contents_taxonomies do |t|
      t.references :taxonomisable, polymorphic: true, index: true
      t.integer :taxonomisable_id
      t.string :taxonomisable_type

      t.references :contentable, polymorphic: true, index: true
      t.integer :contentable_id
      t.string :contentable_type

      t.timestamps null: false
    end
  end
end

となっております。


これで以下のようなリーダブルなコードは実現できています。
job = Job.new
job.genres << Genre.find(1) #あらかじめGenreにname: 'IT業界'をいれてある。
job.genres
=> [#<Genre:0x007f04e2a3e330
  id: 1,
  name: "IT業界",
  created_at: Sat, 31 Oct 2015 12:56:32 UTC +00:00,
  updated_at: Sat, 31 Oct 2015 12:56:32 UTC +00:00>]
検索なども、求人、企業、企業経営者のどの検索も同じようなコード使いまわせるかと思ってます。

パフォーマンスなど設計に問題ないか。。?

以上が設計(実際よりも簡略化はされてますが)の概要です。
ポリモーフィックを使わずに、JobとGenreの中間テーブル、JobとAreaの中間テーブル、、、と大量に中間テーブルを作る方法もあると思うのですが、煩雑な気がしてこの設計に至りました。

このような設計例を見たことがなく、ポリモーフィックは気をつけて使えという記事も多数あったのでアドバイス頂きたいです。

宜しくお願いします。
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

0

交差テーブル中心に考えると、意味の無いテーブルが一つになって良い考えかと思いました。
ただ、ポリモーフィック(メタデータ混入)を避けるために、交差テーブルを採用ならわかりますが、その中でポリモーフィックを利用しているので、あまり交差テーブルを採用する旨味を感じません。
この設計上で気をつけるべき所は、同じ項目が入らないようにすることです。DB上では制約ができ無いかと思います。

job.genres << Genre.find(1) 
job.genres << Genre.find(1) 
job.genres << Genre.find(1) 
#同じ項目がいくつも入る可能性がある。

好みとしてになりますが、
Searchテーブルを作りtarget先をポリモーフィックにして、
SearchContentテーブル作って、子として各検索項目として持つと、親子で向きがはっきりして、DB上で見やすいと思いました。

パフォーマンスに関しては、特に触れていません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.07%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問