【问题标题】:How do I create groups users can be invited to, invite to and own?如何创建可以邀请、邀请和拥有用户的群组?
【发布时间】:2020-10-24 00:51:17
【问题描述】:

TLDR:创建用户可以使用邀请功能加入的群组会返回明显错误:

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 表上没有user_id 列,根据您的架构,这是正确的。当您调用user.groups 时,您的has_many :groups, through: :user_groups 可能是导致错误的原因,因为has_many :user_groups 关系没有指定外键。然后 Rails 隐式假定该列名为 user_id。如果您在has_many :user_groups 关系上指定foreign_key,这应该可以解决您的错误。尽管您可能需要为邀请者和被邀请者提供单独的 through 关系。
  • @james00794,你确实是对的,好地方。这导致我有一个新问题,所以我会更新这个问题。谢谢你。 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'

标签: ruby-on-rails ruby ruby-on-rails-5


【解决方案1】:

通过编辑 User 模型以包含 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, through: :user_groups 可能是导致 调用 user.groups 时出错,因为 has_many :user_groups 关系没有指定外键。 Rails 然后隐式假设 该列称为 user_id。如果您在 has_many :user_groups 关系,这应该可以解决您的错误。尽管 您可能需要将邀请者和被邀请者的关系分开。

【讨论】:

    猜你喜欢
    • 2012-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多