如何创建可以邀请、邀请和拥有用户的群组?
How do I create groups users can be invited to, invite to and own?
TLDR:创建用户可以使用邀请功能加入的群组returns 一个明显的错误:
PG::UndefinedColumn: ERROR: column user_groups.user_id does not exist
但我不清楚答案。用户组有邀请者和被邀请者。因此,我该如何设置才能确保不返回错误?
问题:
我想设置一个可以加入组的用户。这种关系将由 UserGroup 管理,因为用户可以是多个组的成员。一个群组也将有一个所有者用户,即群组的创建者和管理员。
用户也可以是邀请者,也可以邀请作为受邀者的用户。为了邀请朋友加入群组,用户在邀请者将向被邀请者发送邀请的情况下。然后受邀者需要接受才能成为该组的成员。
Schema.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:
The error is quite clear. It is saying that there is no user_id column
on the user_groups table, which is true according to your schema. Your
has_many :groups, through: :user_groups is likely what is causing the
error when you call user.groups, since the has_many :user_groups
relation does not specify a foreign key. Rails then implicitly assumes
that the column is called user_id. If you specify a foreign_key on the
has_many :user_groups relation, this should resolve your error. Though
you may need separate through relations for the inviters and invitees.
TLDR:创建用户可以使用邀请功能加入的群组returns 一个明显的错误:
PG::UndefinedColumn: ERROR: column user_groups.user_id does not exist
但我不清楚答案。用户组有邀请者和被邀请者。因此,我该如何设置才能确保不返回错误?
问题: 我想设置一个可以加入组的用户。这种关系将由 UserGroup 管理,因为用户可以是多个组的成员。一个群组也将有一个所有者用户,即群组的创建者和管理员。
用户也可以是邀请者,也可以邀请作为受邀者的用户。为了邀请朋友加入群组,用户在邀请者将向被邀请者发送邀请的情况下。然后受邀者需要接受才能成为该组的成员。
Schema.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:
The error is quite clear. It is saying that there is no user_id column on the user_groups table, which is true according to your schema. Your has_many :groups, through: :user_groups is likely what is causing the error when you call user.groups, since the has_many :user_groups relation does not specify a foreign key. Rails then implicitly assumes that the column is called user_id. If you specify a foreign_key on the has_many :user_groups relation, this should resolve your error. Though you may need separate through relations for the inviters and invitees.