TLDR:创建用户可以使用邀请功能加入的组返回一个明显的错误:
PG::UndefinedColumn: ERROR: column user_groups.user_id does not exist
但我不清楚答案。用户组有一个邀请者和一个被邀请者。因此,我如何设置此项以确保不会返回错误?
问题:我希望设置一个用户,他可以加入一个组。此关系将由UserGroup管理,因为用户可以是多个组的成员。一个组也将有一个用户作为所有者,他是该组的创建者和管理者。
用户也可以是邀请方,也可以邀请作为受邀方的用户。为了邀请朋友加入群,在这种情况下,用户会向受邀者发送邀请。然后,受邀者需要接受才能成为小组成员。
架构.rb
ActiveRecord::Schema.define(version: 2020_09_29_204316) do
enable_extension "plpgsql"
create_table "addresses", force: :cascade do |t|
t.string "address_type"
t.string "address_line_1"
t.string "address_line_2"
t.string "address_line_3"
t.string "city"
t.string "county"
t.string "postcode"
t.string "country"
t.bigint "user_id"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["user_id"], name: "index_addresses_on_user_id"
end
create_table "groups", force: :cascade do |t|
t.string "group_name"
t.bigint "owner_id"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["owner_id"], name: "index_groups_on_owner_id"
end
create_table "offers", force: :cascade do |t|
t.string "partner"
t.string "offer_copy"
t.string "offer_url"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
create_table "requests", force: :cascade do |t|
t.bigint "requester_id"
t.bigint "requestee_id"
t.integer "accepted", default: 0
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["requestee_id"], name: "index_requests_on_requestee_id"
t.index ["requester_id"], name: "index_requests_on_requester_id"
end
create_table "user_groups", force: :cascade do |t|
t.bigint "group_id", null: false
t.bigint "invitee_id"
t.bigint "inviter_id"
t.integer "accepted", default: 0
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["group_id"], name: "index_user_groups_on_group_id"
t.index ["invitee_id"], name: "index_user_groups_on_invitee_id"
t.index ["inviter_id"], name: "index_user_groups_on_inviter_id"
end
create_table "users", force: :cascade do |t|
t.string "first_name", default: "", null: false
t.string "last_name", default: "", null: false
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.date "birthday", default: "2020-10-22", 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.inet "current_sign_in_ip"
t.inet "last_sign_in_ip"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.string "invitation_token"
t.datetime "invitation_created_at"
t.datetime "invitation_sent_at"
t.datetime "invitation_accepted_at"
t.integer "invitation_limit"
t.string "invited_by_type"
t.bigint "invited_by_id"
t.integer "invitations_count", default: 0
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["invitation_token"], name: "index_users_on_invitation_token", unique: true
t.index ["invitations_count"], name: "index_users_on_invitations_count"
t.index ["invited_by_id"], name: "index_users_on_invited_by_id"
t.index ["invited_by_type", "invited_by_id"], name: "index_users_on_invited_by_type_and_invited_by_id"
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
add_foreign_key "addresses", "users"
add_foreign_key "groups", "users", column: "owner_id"
add_foreign_key "requests", "users", column: "requestee_id"
add_foreign_key "requests", "users", column: "requester_id"
add_foreign_key "user_groups", "groups"
add_foreign_key "user_groups", "users", column: "invitee_id"
add_foreign_key "user_groups", "users", column: "inviter_id"
end
组迁移
class CreateGroups < ActiveRecord::Migration[6.0]
def change
create_table :groups do |t|
t.string :group_name
t.references :owner, foreign_key: { to_table: :users }
t.timestamps
end
end
end
用户组迁移
class CreateUserGroups < ActiveRecord::Migration[6.0]
def change
create_table :user_groups do |t|
t.references :group, null: false, foreign_key: true, null: false
t.references :invitee, foreign_key: { to_table: :users }
t.references :inviter, foreign_key: { to_table: :users }
t.integer :accepted, default: 0
t.timestamps
end
end
end
User.rb(模型(
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :invitable, :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable, :trackable
validates :first_name, :last_name, :birthday, presence: true
has_many :accepted_sent_requests, -> { where accepted: 1 }, foreign_key: :requester_id, class_name: 'Request'
has_many :friends, through: :accepted_sent_requests, source: :requestee
has_many :sent_requests, foreign_key: :requester_id, class_name: 'Request', dependent: :destroy
has_many :received_requests, foreign_key: :requestee_id, class_name: 'Request', dependent: :destroy
has_many :requestees, through: :sent_requests, dependent: :destroy
has_many :requesters, through: :received_requests, dependent: :destroy
has_many :user_groups
has_many :accepted_sent_invites, -> { where accepted: 1 }, foreign_key: :inviter_id, class_name: 'UserGroup'
has_many :friend_groups, through: :accepted_sent_invites, source: :invitee
has_many :sent_invites, foreign_key: :inviter_id, class_name: 'UserGroup', dependent: :destroy
has_many :received_invites, foreign_key: :invitee_id, class_name: 'UserGroup', dependent: :destroy
has_many :invitees, through: :sent_invites, dependent: :destroy
has_many :inviters, through: :received_invites, dependent: :destroy
has_many :groups, through: :user_groups
has_many :groups_owned, foreign_key: :owner_id, class_name: 'Group'
has_many :addresses, dependent: :destroy
searchkick match: :word, searchable: [:email]
after_create :send_welcome_email
private
def send_welcome_email
unless invitation_token?
UserMailer.with(user: self).welcome.deliver_now
end
end
def search_data
{
email: email
}
end
end
UserGroup.rb(模型(
class UserGroup < ApplicationRecord
belongs_to :inviter, class_name: 'User', optional: true
belongs_to :invitee, class_name: 'User', optional: true
belongs_to :group, optional: true
def accept
self.update_attributes(accepted: 1)
Request.create!(inviter_id: self.invitee_id,
invitee_id: self.inviter_id,
accepted: 1)
end
end
Group.rb(模型(
class Group < ApplicationRecord
has_many :user_groups
has_many :users, through: :user_groups
belongs_to :owner, class_name: 'User'
end
通过编辑用户模型以包含User_groups:的关联,解决了上述错误
has_many :user_groups, foreign_key: :inviter_id, class_name: 'UserGroup'
has_many :user_groups, foreign_key: :invitee_id, class_name: 'UserGroup'
has_many :groups, through: :user_groups, foreign_key: :inviter_id, class_name: 'UserGroup'
has_many :groups, through: :user_groups, foreign_key: :invitee_id, class_name: 'UserGroup'
引用@james00794:
错误非常明显。据说没有user_id列在user_groups表上,根据您的模式,这是真的。你的has_many:groups,通过::user_groups可能是导致调用user.groups时出错,因为has_many:user_groups关系不指定外键。Rails然后隐式地假设该列称为user_id。如果在has_many:user_groups关系,这应该可以解决您的错误。虽然您可能需要为受邀者和受邀者建立单独的直通关系。