[Отредактировано после пояснения из ОП]
Отношение состоит в том, что в группах есть пользователи, у пользователей есть жанры (любимые жанры!), Они имеют отношения к связям через таблицы объединения (несколько жанров напользователь и несколько групп на пользователя).В каждой группе есть список воспроизведения, и будет несколько списков воспроизведения
Во-первых, вам не нужен столбец user_id
для групп или жанров, поскольку это не так, как должна работать установка.
class Genre < ApplicationRecord
has_many :favorite_genres
has_many :users, through: :favorite_genres
[... other stuff]
end
class User < ApplicationRecord
has_many :group_memberships
has_many :groups, through: :group_memberships
has_many :favorite_genres
has_many :users, through: :favorite_genres
[... other stuff]
end
class Group < ApplicationRecord
has_many :group_memberships
has_many :users, through: :group_memberships
has_many :playlists
[... other stuff]
end
class Playlist < ApplicationRecord
belongs_to :group
end
class GroupMemberships < ApplicationRecord
belongs_to :user
belongs_to :group
[... other stuff]
end
class FavoriteGenres < ApplicationRecord
belongs_to :user
belongs_to :genre
[... other stuff]
end
Таким образом, вы бы отбросили столбец user_id в группах.Соединение происходит в: group_memberships (таблица, ранее известная как users_groups), которая представляет собой user_id, group_id, и затем вы можете иметь дополнительные столбцы метаданных по мере необходимости (например, логический / роль администратора и т. Д.).Это называется отношением «имеет много сквозного» (http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association)
Аналогично, любимые жанры пользователя настроены со сквозным отношением. Таким образом, у вас будет отдельный файл таблицы базы данных И файл модели для этих сквозных объединений.
Я не думаю, что вам нужны вообще ни вызовы add_foreign_key
на этом уровне, ни многие из ваших индексов. Вероятно, вы сделаете более энергичную загрузку или, возможно, добавите индексы в таблицы соединений через тору, и вы ''сделайте так в схеме:
t.index ["user_id", "genre_id"], name: "index_favorite_genres_on_user_id_and_genre_id"
Помните, что belongs_to
теперь создает проверку для того, чтобы это присутствовало в 5.x. Вы можете переопределить это, добавив optional: true
в этой строке вмодель, например, belongs_to :foo, optional: true
Итак, все, что говорится, вот ваша новая схема:
create_table "genres", id: :serial, force: :cascade do |t|
t.string "tag"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "groups", id: :serial, force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "favorite_genres", id: false, force: :cascade do |t|
t.bigint "user_id", null: false
t.bigint "genre_id", null: false
end
create_table "groups_memberships", id: false, force: :cascade do |t|
t.bigint "user_id", null: false
t.bigint "group_id", null: false
end
create_table "playlists", id: :serial, force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "name"
t.string "link"
t.text "description"
t.bigint "group_id"
t.index ["group_id"], name: "index_playlists_on_group_id"
end
create_table "users", id: :serial, force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.string "name"
t.string "token"
t.date "birthday"
t.string "link"
t.string "playlistId"
t.string "country"
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
Дайте это вихрь (я не встроил это в приложение, так чтомогут быть некоторые ошибки в коде), и теперь вы сможете запустить консоль:
u = User.create([values])
u.genres (should return nil until you create some relationships)
и т. д.