首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >关系模型未按预期工作

关系模型未按预期工作
EN

Stack Overflow用户
提问于 2018-06-04 05:38:08
回答 1查看 32关注 0票数 0

我使用迁移创建了以下Active Record架构,但关系与架构不对应。我尝试过重置、删除、创建和迁移,但在Rails C中,如果我创建了一个用户方法!(...),然后查询u.groups或u.genres,我得到了'undefined u.User.create‘

谢谢你的帮忙

代码语言:javascript
复制
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

以下是模型:

代码语言:javascript
复制
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

这种关系是组有用户,用户有流派(最喜欢的流派!),这些都是通过连接表(每个用户有多个流派,每个用户有多个组)具有并属于关系。每个组都有一个播放列表,并且会有多个播放列表

EN

回答 1

Stack Overflow用户

发布于 2018-06-04 06:01:05

从操作中澄清后编辑

关系是组有用户,用户有流派(最喜欢的流派!),这些都是通过连接表(每个用户有多个流派,每个用户有多个组)的关系。每个组都有一个播放列表,并且会有多个播放列表

首先,您不需要关于组或流派的user_id专栏,因为这不应该是设置的工作方式。

代码语言:javascript
复制
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,然后您可以根据需要拥有额外的元数据列(例如admin boolean/group_id等)。这就是所谓的“多点直通”关系(http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association)。

同样,用户最喜欢的流派也是通过关系设置的。因此,您将有一个单独的数据库表和模型文件用于这些通过连接。

我认为在这个级别上根本不需要add_foreign_key调用,也不需要很多索引。您可能会执行更多的急切加载,或者可能在thorugh join表上添加索引,并且您将在模式中执行以下操作:

代码语言:javascript
复制
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

所以,这就是你的新模式:

代码语言:javascript
复制
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

试一试(我还没有在应用程序中构建它,所以代码中可能有一些错误),你现在应该能够运行你的控制台了:

代码语言:javascript
复制
u = User.create([values])
u.genres (should return nil until you create some relationships)

等。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50671212

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档