1. ホーム
  2. ruby-on-rails

[解決済み] Railsで多対多のリレーションシップを作成する

2023-05-19 17:17:14

質問

これは私が達成しようとしていることの単純化された例です。私はRailsに比較的新しく、モデル間の関係を理解するのに苦労しています。

私は2つのモデルを持っています。 User モデルと Category モデルで定義されています。ユーザは多くのカテゴリと関連付けることができます。特定のカテゴリは、多くのユーザのカテゴリリストに表示されることができます。特定のカテゴリが削除された場合、これはユーザーのカテゴリリストに反映される必要があります。

この例では

私の Categories テーブルには5つのカテゴリが含まれています。


| ID|名前||||があります。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| 1 | スポーツ 
| 2|ニュース|
| 3|エンターテイメント
| 4|テクノロジー




私の Users テーブルには2人のユーザが含まれています。


| ID | 名前
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| 1 | ユーザーA 
| 2|ユーザーB




UserAはカテゴリとしてSportsとTechnologyを選択することができます。

ユーザーBはニュース、スポーツ、エンターテイメントを選択することができます

スポーツカテゴリが削除され、UserAとUserBの両方のカテゴリリストが削除を反映します。

を作成することを検討しました。 UserCategories テーブルを作成し、カテゴリとユーザーの両方の ID を保持しました。これは一種の動作で、カテゴリ名を調べることができましたが、カスケード削除を動作させることができず、ソリューション全体が間違っているように思えました。

私が見つけた belongs_to および has_many 関数の使用例では、1 対 1 の関係のマッピングについて議論しているようです。たとえば、ブログ投稿のコメントなどです。

  • この多対多の関係を、Railsの組み込み機能を使ってどのように表現しますか?
  • Railsを使用する場合、2つの間に別のテーブルを使用することは実行可能な解決策ですか?

どのように解決するのですか?

あなたは has_and_belongs_to_many の関係が必要です。このガイドでは、これがどのように機能するかについて、チャートとあらゆるものを使って見事に説明しています。

http://guides.rubyonrails.org/association_basics.html#the-has-and-belongs-to-many-association

このようなものができあがります。

# app/models/category.rb
class Category < ActiveRecord::Base
  has_and_belongs_to_many :users
end

# app/models/user.rb
class User < ActiveRecord::Base
  has_and_belongs_to_many :categories
end

ここで、Railsが使用する結合テーブルを作成する必要があります。Railsはこれを自動的にやってはくれません。これは事実上、CategoriesとUsersのそれぞれへの参照を持ち、主キーがないテーブルです。

このようにCLIからマイグレーションを生成します。

bin/rails g migration CreateCategoriesUsersJoinTable

そしてそれを開いて、一致するように編集します。

Rails 4.0.2+(Rails5.2を含む)用です。

def change
  # This is enough; you don't need to worry about order
  create_join_table :categories, :users

  # If you want to add an index for faster querying through this join:
  create_join_table :categories, :users do |t|
    t.index :category_id
    t.index :user_id
  end
end

Rails < 4.0.2。

def self.up
  # Model names in alphabetical order (e.g. a_b)
  create_table :categories_users, :id => false do |t|
    t.integer :category_id
    t.integer :user_id
  end

  add_index :categories_users, [:category_id, :user_id]
end

def self.down
  drop_table :categories_users
end

この状態で、マイグレーションを実行すると、カテゴリーとユーザーを、使い慣れた便利なアクセサで接続することができます。

User.categories  #=> [<Category @name="Sports">, ...]
Category.users   #=> [<User @name="UserA">, ...]
User.categories.empty?