【问题标题】:Creating User Groups on Rails在 Rails 上创建用户组
【发布时间】:2020-06-23 00:55:21
【问题描述】:

我正在创建一个 Rails 应用程序,用户可以在其中创建组、添加联系人、将联系人添加到该组,然后将信息广播给用户到他们创建的组。

我正处于第三阶段,我现在正尝试允许登录用户向组中添加联系人。

我为多对多关系提供了三种模型:

class UserGroups < ApplicationRecord
  belongs_to :user
  belongs_to :group
end
class Group < ApplicationRecord

  belongs_to :user

  has_many: :user_groups
  has_many: :users, through: :user_groups

  validates :title, presence: true

end
class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  has_one_attached :avatar

  has_many :groups, dependent: :destroy
  has_many :posts, dependent: :destroy

  has_many :user_groups
  has_many :users, through: :user_groups

  before_create :set_circleid
  has_many :contactships, dependent: :destroy
  has_many :contacts, -> { where contactships: { status: :accepted }}, through: :contactships
  has_many :requested_contacts, -> { where contactships: { status: :requested }}, through: :contactships, source: :contact
  has_many :pending_contacts, -> { where contactships: { status: :pending }}, through: :contactships, source: :contact
  has_many :blocked_contacts, -> { where contactships: { status: :blocked }}, through: :contactships, source: :contact

  has_many :contactships_inverse, class_name: 'Contactship', foreign_key: :contact_id
  has_many :contacts_inverse, through: :contactships_inverse, source: :user

  def all_contacts
    contacts + contacts_inverse
  end

  def has_contactship?(contact)
      #return true if the user is a contact
      return true if self == contact
      contactships.map(&:contact_id).include?(contact.id)
  end

  def requested_contacts_with?(contact)
      return false if self == contact
      #we are going to map requested contacts with list of users to see if they include contact_id
      requested_contacts.map(&:id).include?(contact.id)
  end

  def pending_contacts_with?(contact)
      return false if self == contact
      pending_contacts.map(&:id).include?(contact.id)
  end

  def contacts_with?(contact)
      return false if self == contact
      contacts.map(&:id).include?(contact.id)
  end

  def contact_request(contact)
    #unless the contact is not equal to self and contactship does not already exist
    unless self == contact || Contactship.where(user: self, contact: contact).exists?
        #transaction means that if one fails they both are rolled back
        transaction do
            #for user to another user (sent request)
            Contactship.create(user: self, contact: contact, status: :pending)
            #from another user to user (recieve request)
            Contactship.create(user: contact, contact: self, status: :requested)
        end
     end

  def accept_request(contact)
      transaction do
        Contactship.find_by(user: self, contact: contact, status: [:requested])&.accepted!
        Contactship.find_by(user: contact, contact: self, status: [:pending])&.accepted!
      end
  end

  def reject_request(contact)
      transaction do
        Contactship.find_by(user: self, contact: contact)&.destroy!
        Contactship.find_by(user: contact, contact: self)&.destroy!
      end
  end
end

我的组控制器中的一个方法(不知道在这里做什么):

    #for adding a user to a group?
    def add_user
        #search for the group?
        @group = Group.find(params[:id])
        #add a user to that group via user_groups? How?
    end

schema.rb:

ActiveRecord::Schema.define(version: 2020_06_22_142356) do

  # These are extensions that must be enabled in order to support this database
  enable_extension "plpgsql"

  create_table "active_storage_attachments", force: :cascade do |t|
    t.string "name", null: false
    t.string "record_type", null: false
    t.bigint "record_id", null: false
    t.bigint "blob_id", null: false
    t.datetime "created_at", null: false
    t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id"
    t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true
  end

  create_table "active_storage_blobs", force: :cascade do |t|
    t.string "key", null: false
    t.string "filename", null: false
    t.string "content_type"
    t.text "metadata"
    t.bigint "byte_size", null: false
    t.string "checksum", null: false
    t.datetime "created_at", null: false
    t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true
  end

  create_table "groups", force: :cascade do |t|
    t.string "title"
    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_groups_on_user_id"
  end

  create_table "contactships", force: :cascade do |t|
    t.bigint "user_id"
    t.bigint "contact_id"
    t.integer "status", limit: 2, default: 0
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["contact_id"], name: "index_contactships_on_contact_id"
    t.index ["user_id"], name: "index_contactships_on_user_id"
  end

  create_table "posts", force: :cascade do |t|
    t.string "description"
    t.integer "user_id"
    t.string "thought"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
  end

  create_table "user_groups", force: :cascade do |t|
    t.bigint "user_id", null: false
    t.bigint "group_id", null: false
    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 ["user_id"], name: "index_user_groups_on_user_id"
  end

  create_table "users", force: :cascade do |t|
    t.string "email", default: "", null: false
    t.string "encrypted_password", default: "", null: false
    t.string "first_name"
    t.string "last_name"
    t.string "groupid"
    t.text "bio"
    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.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 "active_storage_attachments", "active_storage_blobs", column: "blob_id"
  add_foreign_key "groups", "users"
  add_foreign_key "comments", "users"
  add_foreign_key "user_groups", "groups"
  add_foreign_key "user_groups", "users"
end

我将如何着手开发该方法,以便可以成功地将联系人添加到控制台中的组?我对实现这一点的方法特别感到困惑,尤其是因为联系人不是他们自己的模型,而是用户模型的一部分。

谢谢!

【问题讨论】:

  • 能否请您也分享一下您的 schema.rb / 数据库架构。
  • 当然 - 把它放在上面!

标签: ruby-on-rails


【解决方案1】:

你可以的

group = Group.find(params[:id])
contact = User.find(params[:user_id])
UserGroups.create(user: contact, group: group)

命名

您已经在问题中提到了contacts 一词,也许可以考虑这样命名您的协会。如果模型类的名称与关联名称不匹配,您可以指定 class_name 属性让 Rails 知道它的名称。

  belongs_to :owner, class_name: "User"

  has_many: :user_groups
  has_many: :contacts, through: :user_groups, class_name: "User"

  validates :title, presence: true

https://guides.rubyonrails.org/association_basics.html#options-for-belongs-to

has_many 通过 vs. has_and_belongs_to

如果您真的需要 UserGroups 模型或使用 has_and_belongs_to 关联,您也应该考虑一下,请参阅 Rails 指南

最简单的经验法则是,如果您需要将关系模型作为独立实体使用,您应该设置一个 has_many :through 关系。如果您不需要对关系模型进行任何操作,那么设置 has_and_belongs_to_many 关系可能会更简单(尽管您需要记住在数据库中创建连接表)。

https://guides.rubyonrails.org/association_basics.html#choosing-between-has-many-through-and-has-and-belongs-to-many

【讨论】:

  • 对这段关系很感兴趣。因此,如果该组仅对用户可见 - 我猜它不需要第三个实体?
  • 可见是什么意思?如报价中所述,主要区别在于您是否需要将逻辑放入 UserGroups 模型中。如果它只是一个连接模型/表,则不需要创建它,可以使用has_and_belongs_to 关系并删除UserGroups 模型。不过你仍然需要这张桌子。
  • 意味着该组对用户来说是个人的,它包含联系人但不与其他联系人共享。虽然我认为你说的没错,但UserGroups 中不需要任何逻辑
  • 如果一个群组有很多联系人并且在用户之间共享,那么您的belongs_to :user 也需要是has_and_belongs_to 关系。
猜你喜欢
  • 2014-11-09
  • 1970-01-01
  • 1970-01-01
  • 2016-12-30
  • 1970-01-01
  • 2011-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多