使用Postgres在Rails中设置外键

use*_*553 5 ruby ruby-on-rails

我试图跟踪用户喜欢喜欢它们的用户的相互喜欢.为了检查是否是相互的,我在创建之后调用一个方法.如果那个骗子是一个喜欢它而不是它被认为是相互的.

但问题是,我遇到了一些奇怪的错误,我认为这些错误与外键的设置方式有关.我在Rails中设置了很多关联,但是每当我尝试访问它时,我都会收到PG::InFailedSqlTransaction: ERROR: current transaction is aborted, commands ignored until end of transaction block : RELEASE SAVEPOINT active_record_1错误.

用户:

class User < ApplicationRecord
  has_many :likes
end
Run Code Online (Sandbox Code Playgroud)

喜欢:

class Like < ApplicationRecord
  belongs_to :likee, class_name: 'User', foreign_key: 'likee_id'
  belongs_to :liker, class_name: 'User', foreign_key: 'liker_id'
  belongs_to :connection, optional: true

  after_save :mutual_like?

  private

  def mutual_like?

    if liker.likes.where(likee: liker)
      # fails
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

我已经尝试将钩子更改为保存等,但这也不起作用.

此外,我甚至不能打电话给Like.first别人我得到同样的错误.

我试着打印出liker.likes.where(likee: liker)和我得到PG::UndefinedColumn: ERROR: column likes.user_id does not exist我认为这是问题.

但是,我可以像这样访问liker:self.likee在钩子内部但是如果self.likee.likes没有它返回我就不能打电话#<Like::ActiveRecord_Associations_CollectionProxy:0x3fd91ca5ca78>

架构:

  create_table "likes", force: :cascade do |t|
    t.integer  "liker_id",      null: false
    t.integer  "likee_id",      null: false
    t.integer  "connection_id"
    t.datetime "created_at",    null: false
    t.datetime "updated_at",    null: false
    t.index ["likee_id"], name: "index_likes_on_likee_id", using: :btree
    t.index ["liker_id"], name: "index_likes_on_liker_id", using: :btree
  end





create_table "users", force: :cascade do |t|
    t.string   "email"
    t.string   "username"
    t.string   "password_digest"
    t.boolean  "admin",                default: false
    t.index ["email"], name: "index_users_on_email", using: :btree
    t.index ["username"], name: "index_users_on_username", using: :btree
  end
Run Code Online (Sandbox Code Playgroud)

测试:

RSpec.describe Like, type: :model do
  let(:liker) { Fabricate(:user) }
  let(:likee) { Fabricate(:user) }
  let(:like) { Fabricate(:like, liker: liker, likee: likee) }
  let(:pending_like) { Fabricate.build(:like, liker: liker, likee: likee)}

  context 'relations' do
    it { should belong_to :likee }
    it { should belong_to :liker }

    describe 'liking another user' do

      it '#liker references first user' do
        expect(like.likee).to eq likee
      end

      it '#likee references second user' do
        expect(like.liker).to eq liker
      end

    end
  end
  ...

RSpec.describe User, type: :model do
  context 'relations' do
    it { should have_many :likes }
  end
 ...
Run Code Online (Sandbox Code Playgroud)

这是因为我试图查找正在保存的记录吗?

slo*_*k2k 2

liker.likes.where(likee: liker)仅返回一个关系。你必须像这样执行你的查询liker.likes.where(likee: liker).exists?

has_many :likes在您的模型中需要表中的User一列。根据给出的代码,我认为你必须将其更改为user_idlikes

class User < ApplicationRecord
  has_many :other_likes, foreign_key: :liker_id 
  has_many :likes, foreign_key: :likee_id 
end
Run Code Online (Sandbox Code Playgroud)

belongs_to :connection在我看来这是一个坏名字。ActiveRecord::Base有一个同名的类方法。也许有一天您会遇到这样的协会名称的问题。