реляционные модели не работают должным образом - PullRequest
0 голосов
/ 04 июня 2018

Я создал следующую схему активной записи, используя миграции, но отношения не соответствуют схеме.Я пытался сбросить, удалить, создать и перенести, но в Rails C, если я создаю User u.User.create! (...), а затем запрашиваю u.groups или u.genres, я получаю «неопределенный метод»

Спасибо за вашу помощь

ActiveRecord::Schema.define(version: 20180603211047) do

  # These are extensions that must be enabled in order to support this database
  enable_extension "plpgsql"

  create_table "genres", force: :cascade do |t|
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "tag"
    t.bigint "user_id"
    t.index ["user_id"], name: "index_genres_on_user_id"
  end

  create_table "genres_users", id: false, force: :cascade do |t|
    t.bigint "user_id", null: false
    t.bigint "genre_id", null: false
  end

  create_table "groups", force: :cascade do |t|
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "name"
    t.bigint "user_id"
    t.index ["user_id"], name: "index_groups_on_user_id"
  end

  create_table "groups_users", id: false, force: :cascade do |t|
    t.bigint "user_id", null: false
    t.bigint "group_id", null: false
  end

  create_table "playlists", 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", 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

  add_foreign_key "genres", "users"
  add_foreign_key "groups", "users"
  add_foreign_key "playlists", "groups"
end

вот модели:

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
    #before_action :authenticate_user!
    has_and_belongs_to_many :genres, :through => :genres_users
    has_and_belongs_to_many :groups, :through => :groups_users
    include Enumerable
end

class Genre < ApplicationRecord
    has_and_belongs_to_many :users, :through => :genres_users
end

class Group < ApplicationRecord
    has_and_belongs_to_many :users, :through => :groups_users
    has_one :playlist
end

class Playlist < ApplicationRecord
    belongs_to :group
end

Отношение состоит в том, что в группах есть пользователи, пользователи имеют жанры (любимые жанры!), Этоимеет и принадлежит отношениям через таблицы соединений (несколько жанров на пользователя и несколько групп на пользователя).В каждой группе есть плейлист, и будет несколько плейлистов

1 Ответ

0 голосов
/ 04 июня 2018

[Отредактировано после пояснения из ОП]

Отношение состоит в том, что в группах есть пользователи, у пользователей есть жанры (любимые жанры!), Они имеют отношения к связям через таблицы объединения (несколько жанров напользователь и несколько групп на пользователя).В каждой группе есть список воспроизведения, и будет несколько списков воспроизведения

Во-первых, вам не нужен столбец 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)

и т. д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...