Dies ist ein vereinfachtes Beispiel für das, was ich erreichen möchte. Ich bin relativ neu bei Rails und habe Mühe, mich mit den Beziehungen zwischen Modellen auseinanderzusetzen.
Ich habe zwei Modelle, das User
Modell und das Category
Modell. Ein Benutzer kann vielen Kategorien zugeordnet werden. Eine bestimmte Kategorie kann für viele Benutzer in der Kategorieliste angezeigt werden. Wenn eine bestimmte Kategorie gelöscht wird, sollte dies in der Kategorieliste für einen Benutzer angezeigt werden.
In diesem Beispiel:
Meine Categories
Tabelle enthält fünf Kategorien:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ID | Name | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 1 | Sport | | 2 | Nachrichten | | 3 | Unterhaltung | | 4 | Technologie | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Meine Users
Tabelle enthält zwei Benutzer:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ID | Name | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 1 | UserA | | 2 | UserB | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
UserA kann Sport und Technologie als seine Kategorien auswählen
Benutzer B kann Nachrichten, Sport und Unterhaltung wählen
Die Sportkategorie wird gelöscht. Sowohl UserA- als auch UserB-Kategorielisten spiegeln die Löschung wider
Ich habe damit herumgespielt, eine UserCategories
Tabelle zu erstellen , die die IDs einer Kategorie und eines Benutzers enthält. Diese Art von funktionierte, ich konnte die Kategorienamen nachschlagen, aber ich konnte kein kaskadierendes Löschen zum Laufen bringen und die ganze Lösung schien einfach falsch zu sein.
Die Beispiele für die Verwendung der Funktionen "Gehorsam" und "Habe_Viele", die ich gefunden habe, scheinen die Zuordnung einer Eins-zu-Eins-Beziehung zu erörtern. Zum Beispiel Kommentare zu einem Blog-Beitrag.
- Wie stellen Sie diese Viele-zu-Viele-Beziehung mithilfe der integrierten Rails-Funktionalität dar?
- Ist die Verwendung einer separaten Tabelle zwischen beiden eine praktikable Lösung bei der Verwendung von Rails?
quelle
UserCategory
Modells, es ist in den meisten Fällen sogar wünschenswert. Sie müssen nur verwendenUser.has_many :categories, through: :user_categories
. Vielleicht könnte ein besserer Name gefunden werden.Antworten:
Du willst eine
has_and_belongs_to_many
Beziehung. Der Leitfaden beschreibt hervorragend, wie dies mit Diagrammen und allem funktioniert:http://guides.rubyonrails.org/association_basics.html#the-has-and-belongs-to-many-association
Sie werden am Ende so etwas haben:
# 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
Jetzt müssen Sie eine Join-Tabelle erstellen, die Rails verwenden kann. Rails erledigt dies nicht automatisch für Sie. Dies ist effektiv eine Tabelle mit einem Verweis auf jede der Kategorien und Benutzer und ohne Primärschlüssel.
Generieren Sie eine Migration von der CLI wie folgt:
bin/rails g migration CreateCategoriesUsersJoinTable
Öffnen Sie es dann und bearbeiten Sie es entsprechend:
Für Rails 4.0.2+ (einschließlich Rails 5.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
Schienen <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
Führen Sie Ihre Migrationen aus, und Sie können Kategorien und Benutzer mit allen praktischen Accessoren verbinden, die Sie gewohnt sind:
User.categories #=> [<Category @name="Sports">, ...] Category.users #=> [<User @name="UserA">, ...] User.categories.empty?
quelle
Am beliebtesten ist 'Mono-transitive Association'. Sie können dies tun:
class Book < ApplicationRecord has_many :book_authors has_many :authors, through: :book_authors end # in between class BookAuthor < ApplicationRecord belongs_to :book belongs_to :author end class Author < ApplicationRecord has_many :book_authors has_many :books, through: :book_authors end
quelle
Nur zur Ergänzung Antwort des coreyward oben: Wenn Sie bereits ein Modell, das eine hat
belongs_to
,has_many
Beziehung und Sie wollen eine neue Beziehung erstellenhas_and_belongs_to_many
mit der gleichen Tabelle , die Sie benötigen:Dann,
rake db:migrate
Danach müssen Sie Ihre Beziehungen definieren:
User.rb:
class Region < ApplicationRecord has_and_belongs_to_many :categories end
Category.rb
class Facility < ApplicationRecord has_and_belongs_to_many :users end
Um die neue Join-Tabelle mit den alten Daten zu füllen, müssen Sie in Ihrer Konsole Folgendes tun:
User.all.find_each do |u| Category.where(user_id: u.id).find_each do |c| u.categories << c end end
Sie können entweder die
user_id
Spalte und diecategory_id
Spalte aus den Kategorien- und Benutzertabellen verlassen oder eine Migration erstellen, um sie zu löschen.quelle
Wenn Sie zusätzliche Daten zur Beziehung hinzufügen möchten , ist dies
has_many :things, through: :join_table
möglicherweise das, wonach Sie suchen. Oft müssen Sie jedoch keine zusätzlichen Metadaten (wie eine Rolle) für eine Join-Beziehung benötigen. In diesem Fallhas_and_belongs_to_many
ist dies definitiv der einfachste Weg (wie in der akzeptierten Antwort für diesen SO-Beitrag).Angenommen, Sie erstellen eine Forum-Site, auf der Sie mehrere Foren haben und Benutzer unterstützen müssen, die in jedem Forum, an dem sie teilnehmen, unterschiedliche Rollen innehaben. Es kann hilfreich sein, zu verfolgen, wie ein Benutzer mit einem Forum im Forum in Beziehung steht mach mit:
class Forum has_many :forum_users has_many :users, through: :forum_users has_many :admin_forum_users, -> { administrating }, class_name: "ForumUser" has_many :viewer_forum_users, -> { viewing }, class_name: "ForumUser" has_many :admins, through: :admin_forum_users, source: :user has_many :viewers, through: :viewer_forum_users, source: :user end class User has_many :forum_users has_many :forums, through: :forum_users end class ForumUser belongs_to :user belongs_to :forum validates :role, inclusion: { in: ['admin', 'viewer'] } scope :administrating, -> { where(role: "admin") } scope :viewing, -> { where(role: "viewer") } end
Und Ihre Migration würde ungefähr so aussehen
class AddForumUsers < ActiveRecord::Migration[6.0] create_table :forum_users do |t| t.references :forum t.references :user t.string :role t.timestamps end end
quelle