首页 > 解决方案 > ActiveRecord::StatementInvalid (SQLite3::SQLException: no such table: main.contacts) Rails 中的友谊

问题描述

我正在尝试在 Rails 中建立友谊,我将其命名为“连接”,通过用户到用户的关联来创建朋友,我将其命名为“联系人”。我一直在关注一个教程,并且进展顺利,但是当我尝试在 rails 控制台中发送朋友/联系人请求以测试以确保它有效时遇到了麻烦:

2.7.0 :043 > user4.contact_request(user5)
  Connection Exists? (5.7ms)  SELECT 1 AS one FROM "connections" WHERE "connections"."user_id" = ? AND "connections"."contact_id" = ? LIMIT ?  [["user_id", 7], ["contact_id", 8], ["LIMIT", 1]]
  TRANSACTION (0.2ms)  begin transaction
  Connection Create (1.8ms)  INSERT INTO "connections" ("user_id", "contact_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["user_id", 7], ["contact_id", 8], ["created_at", "2021-04-20 00:40:23.578180"], ["updated_at", "2021-04-20 00:40:23.578180"]]
  TRANSACTION (0.1ms)  rollback transaction
Traceback (most recent call last):
        4: from (irb):42
        3: from (irb):43:in `rescue in irb_binding'
        2: from app/models/user.rb:49:in `contact_request'
        1: from app/models/user.rb:50:in `block in contact_request'
ActiveRecord::StatementInvalid (SQLite3::SQLException: no such table: main.contacts)

我不知道我在 PostgresQL 而不是 SQLite 上构建这个 rails 项目是否会有所不同。

连接控制器:

class ConnectionsController < ApplicationController
  before_action :authenticate_user!
  before_action :set_user

  # GET /connections or /connections.json
  def index
    @connections = Connection.all
  end

  # GET /connections/1 or /connections/1.json
  def show
  end

  # GET /connections/new
  def new
    current_user.contact_request(@user)
    current_user.reload
  end

  # GET /connections/1/edit
  def edit
  end

  # POST /connections or /connections.json
  def create
    current_user.accept_request(@user)
    current_user.reload
  end

  # PATCH/PUT /connections/1 or /connections/1.json
  def update
    respond_to do |format|
      if @connection.update(connection_params)
        format.html { redirect_to @connection, notice: "Connection was successfully updated." }
        format.json { render :show, status: :ok, location: @connection }
      else
        format.html { render :edit, status: :unprocessable_entity }
        format.json { render json: @connection.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /connections/1 or /connections/1.json
  def destroy
    current_user.reject_request(@user)
    current_user.reload
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_user
      @user = User.find(params[:id])
    end

    # Only allow a list of trusted parameters through.
    def connection_params
      params.fetch(:connection, {})
    end
end

连接模型:

class Connection < ApplicationRecord
  belongs_to :user
  belongs_to :contact, class_name: 'User'
  enum status: {pending: 0, requested: 1, accepted: 2, blocked: 3}
  # id: 1
  # contact: 2

  # user_id: 1, contact_id: 2, status: :requested
  # user_id: 2, contact_id: 1, status: :pending
end

用户型号:

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable
    has_many :developments, dependent: :destroy
    has_many :connections
    has_many :connections, dependent: :destroy
    has_many :contacts, -> { where connections: { status: :accepted }}, through: :connections
    has_many :requested_contacts, -> { where connections: {status: :requested}}, through: :connections, source: :contact
    has_many :pending_contacts, -> { where connections: { status: :pending }}, through: :connections, source: :contact
    has_many :blocked_contacts, -> { where connections: { status: :blocked }}, through: :connections, source: :contact

# has_many :connections_inverse, class_name: 'Connection', foreign_key: :contact_id
# has_many :contacts_inverse, through: :connections_inverse, source: :user

# def all_contacts
# contacts + contacts_inverse
# end

def has_connection?(contact)
    return true if self == contact
    connections.map(&:contact_id).include?(contact.id)
  end

  def requested_contacts_with?(contact)
    return false if self == contact
    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 reject_request(contact)
    transaction do
      Connection.find_by(user: self, contact: contact)&.destroy!
      Connection.find_by(user: contact, contact: self)&.destroy!
    end
  end

    def contact_request(contact)
        unless self == contact || Connection.where(user: self, contact: contact).exists?
            transaction do
            Connection.create(user: self, contact: contact, status: :pending)
            Connection.create(user: contact, contact: self, status: :requested)
            end
        end
    end

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

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

架构:

ActiveRecord::Schema.define(version: 2021_04_19_034240) do

  create_table "connections", force: :cascade do |t|
    t.integer "user_id", null: false
    t.integer "contact_id", null: false
    t.integer "status", limit: 1, default: 0
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["contact_id"], name: "index_connections_on_contact_id"
    t.index ["user_id"], name: "index_connections_on_user_id"
  end

  create_table "dashboards", force: :cascade do |t|
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
  end

  create_table "developments", force: :cascade do |t|
    t.string "dev_title"
    t.text "dev_description"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
  end

  create_table "lots", force: :cascade do |t|
    t.string "lot_title"
    t.text "lot_description"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.integer "development_id"
  end

  create_table "users", force: :cascade do |t|
    t.string "email", default: "", null: false
    t.string "encrypted_password", default: "", null: false
    t.string "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.boolean "admin", default: 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 "connections", "contacts"
  add_foreign_key "connections", "users"
end

连接迁移:

class CreateConnections < ActiveRecord::Migration[6.1]
  def change
    create_table :connections do |t|
      t.references :user, null: false, foreign_key: { to_table: :users}
      t.references :contact, null: false, foreign_key: {to_table: :users}
      t.integer :status, default: 0, limit: 1

      t.timestamps
    end
  end
end

我对迁移的工作方式有点困惑,所以我直接编辑了迁移文件以添加:

foreign_key: { to_table: :users}
foreign_key: {to_table: :users}

根据建议修复数据库问题,但我的理解是迁移文件总是需要通过在终端中删除、创建和滚动它们来进行编辑,所以我不确定上述修复是否适用于我尝试做的方式它。

编辑:

我不认为这是数据库的问题,但我在网上看到的其他帖子似乎指出这是迁移文件中的问题。如果有人有任何见解,我将不胜感激。

标签: ruby-on-rails

解决方案


推荐阅读