首页 > 解决方案 > Ruby on Rails:单表继承和 has_and_belongs_to_many 关系的问题

问题描述

我正在设计我的系统架构。为此,我有不同角色的用户。鉴于我想要 Devise 给出的常见行为,我决定赌单表继承。

所以,除了普通用户(普通客户)之外,我还有编辑。

网络:假设它就像一个显示内容的固定结构。您可以想象这些具有旋转内容的屏幕网络。

编辑:负责发布内容的用户子集。编辑需要(由管理员)预先授权才能在特定网络中发布内容。可能很多。但这并不意味着每次编辑都会发帖,都会发给他授权的所有网络。最后,他可以选择哪些网络将显示特定事件。

事件:为编辑器编写的一段内容,可能会显示在编写它的编辑器有权访问的所有网络中。

最后,用控制台测试,我得到这个错误:

irb(main):001:0> E = Editor.find_by_email("info@adeter.org")
  Editor Load (0.4ms)  SELECT "users".* FROM "users" WHERE "users"."type" = $1 AND "users"."email" = $2 LIMIT $3  [["type", "Editor"], ["email", "info@adeter.org"], ["LIMIT", 1]]
=> #<Editor id: 3, email: "info@adeter.org", role: "editor", first_name: ni...
irb(main):002:0> E.networks
Traceback (most recent call last):
ActiveRecord::StatementInvalid (PG::UndefinedColumn: ERROR:  column networks_users.editor_id does not exist)
LINE 1: ...works"."id" = "networks_users"."network_id" WHERE "networks_...
                                                             ^
irb(main):003:0> 

我在这里超出了我的舒适区,我真的不知道我在做什么。最初的计划是错误的还是我做错了什么?

为什么我无法访问关系?

编辑器.rb

class Editor < User
  has_and_belongs_to_many :networks
end

事件.rb

class Event < ApplicationRecord
  belongs_to :editor
  has_and_belongs_to_many :network
  has_one_attached :image, dependent: :destroy
end

网络.rb

class Network < ApplicationRecord
  belongs_to :user

  has_many :prospects, dependent: :destroy

  has_many :nodes, dependent: :destroy
  has_many :highlights, dependent: :destroy
  has_many :companies, dependent: :destroy
  has_many :promos, dependent: :destroy

  has_and_belongs_to_many :editors
  has_and_belongs_to_many :events

  has_one_attached :header, dependent: :destroy

  validates :name, presence: true, length:{ minimum: 3 }, uniqueness: true
  validates :user_id, :presence => true, :if => Proc.new { user.superadmin? }
end

从 schema.rb 中提取

  create_table "events", force: :cascade do |t|
    t.string "title"
    t.string "info"
    t.datetime "date_from"
    t.datetime "date_till"
    t.integer "version", default: 0
    t.bigint "user_id", null: false
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["user_id"], name: "index_events_on_user_id"
  end

  create_table "events_networks", id: false, force: :cascade do |t|
    t.bigint "network_id", null: false
    t.bigint "event_id", null: false
    t.index ["event_id"], name: "index_events_networks_on_event_id"
    t.index ["network_id"], name: "index_events_networks_on_network_id"
  end


  create_table "networks", force: :cascade do |t|
    t.string "name"
    t.integer "number_of_highlights"
    t.integer "number_of_promos"
    t.boolean "open_to_request", default: false
    t.boolean "public", default: false
    t.integer "number_of_events"
    t.integer "time_between_slides"
    t.integer "time_delay_with_header"
    t.bigint "user_id", null: false
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["user_id"], name: "index_networks_on_user_id"
  end

  create_table "networks_users", id: false, force: :cascade do |t|
    t.bigint "network_id", null: false
    t.bigint "user_id", null: false
    t.index ["network_id"], name: "index_networks_users_on_network_id"
  end

  create_table "users", force: :cascade do |t|
    t.string "email", default: "", null: false
    t.string "encrypted_password", default: "", null: false
    t.integer "role", default: 0
    t.string "first_name"
    t.string "last_name"
    t.date "birthdate"
    t.string "id_number"
    t.string "vat_number"
    t.string "vat_company_name"
    t.string "phone"
    t.string "address"
    t.integer "current_company_id"
    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 "type"
    t.integer "failed_attempts", default: 0, null: false
    t.datetime "locked_at"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    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

标签: ruby-on-railsrubyassociations

解决方案


问题是,当使用继承模型时,rails 不知道从哪里来。解决方案是指定所有内容:外键和连接表。

class Editor < User
  has_and_belongs_to_many :networks, join_table: "networks_users", foreign_key: 'user_id', association_foreign_key: 'network_id'
  ...
end

现在,它起作用了。


推荐阅读