在Rails中使用Postgres设置外键

5
我正在尝试跟踪互相喜欢的情况,即用户喜欢一个也喜欢他们的用户。为了检查喜欢是否互相,我会在创建喜欢后调用一个方法。如果那个点赞者曾经被点赞过,那么就被认为是互相的喜欢。
然而,问题在于我遇到了一些奇怪的错误,我相信这与外键的设置有关。我在Rails中设置了has_many关联,但每当我尝试访问它时,我会收到一个“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

类似:

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

我已经尝试将钩子设置在保存等位置,但也不起作用。

此外,如果我调用Like.first,也会出现同样的错误。

我尝试打印liker.likes.where(likee: liker),结果显示PG::UndefinedColumn: ERROR: column likes.user_id does not exist,我认为这就是问题所在。

然而,在钩子内部,我可以访问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

测试:

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
 ...

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


你能否发布这两个表的相关模式的部分内容。 - Kelsey Hannan
我在用户和点赞表上发布了相关信息。 - user3162553
liker.user.likes 能用吗? - Kelsey Hannan
没有方法错误:未定义的“user”方法。奇怪的是,我有验证关系的测试通过了。 - user3162553
如果我执行self.likee.likes,我会得到一个#< Like :: ActiveRecord_Associations_CollectionProxy: 0x3feaa56865bc>,它无法转换为普通的模型实例/数组。 - user3162553
1个回答

2

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

User 模型中的 has_many :likes 期望在你的 likes 表中有一个 user_id 列。根据给定的代码,我认为你需要将其更改为

class User < ApplicationRecord
  has_many :other_likes, foreign_key: :liker_id 
  has_many :likes, foreign_key: :likee_id 
end

belongs_to :connection 在我看来不是一个好的名称。 ActiveRecord :: Base 有一个同名的类方法。也许你将来会遇到这样一个关联名称的问题。


我认为这是正确的 - 我现在得到了一个关系。只是为了理解,问题是用户关系的一侧没有引用正确的列吗?谢谢,关于“connection”在内部使用的好点子,我不知道。 - user3162553
是的,你的用户端没有引用正确的列。liker.likes.where(likee: liker)的问题是次要的。当你不附加.exists?时,你的if语句在每种情况下都会为true - slowjack2k

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接