在测试我的友谊模型时,我遇到了错误:
ActiveRecord::StatementInvalid:
SQLite3::SQLException: no such column: users.user_id: SELECT 1 AS one FROM "users" INNER JOIN "friendships" ON "users"."id" = "friendships"."friend_id" WHERE "friendships"."user_id" = ? AND "users"."user_id" IN (SELECT "friendships"."id" FROM "friendships" WHERE "friendships"."status" = ?) AND "users"."id" = ? LIMIT 1
在创建友谊后尝试在rspec测试中访问用户pending_friends时。我有以下代码来定义友谊:
class Friendship < ActiveRecord::Base
belongs_to :user
belongs_to :friend, :class_name => "User"
enum status: [:pending, :accepted]
scope :accepted, -> { where(status: :accepted) }
scope :pending, -> { where(status: :pending) }
validates :user, uniqueness: { scope: :friend, message: "This user is already your friend" }
def decline
self.destroy
end
def accept
self.update status: :accepted
end
end
下面的代码定义了pending_friends在我的用户模型中应该是什么:
has_many :friendships
has_many :pending_friends, -> { where(friendships: Friendship.pending) },
through: :friendships, class_name: "User", source: :friend
我不确定为什么它会尝试访问users.user_id ...如果有人知道如何解决这个问题,我们将非常感谢任何帮助,我一直在深入研究联接的工作原理但我似乎无法找到任何有用的东西。
仅供参考:这就是我创造友谊的方式:
friendship1 = Friendship.build(user: current_user, friend: other_user)
friendship2 = Friendship.build(user: other_user, friend: current_user)
(然后进行保存和错误检查)
这是我的友谊迁移:
class CreateFriendships < ActiveRecord::Migration
def change
create_table :friendships do |t|
t.integer :status, :null => false, :default => 0
t.integer :user_id
t.integer :friend_id
t.timestamps null: false
end
end
end
答案 0 :(得分:1)
让我们深入探讨这个问题。 注意:在关键字上缩进SQL可以更容易地发现正在发生的事情:
SELECT 1 AS one
FROM "users"
INNER JOIN "friendships" ON "users"."id" = "friendships"."friend_id"
WHERE "friendships"."user_id" = ? AND
"users"."user_id" IN (
SELECT "friendships"."id"
FROM "friendships"
WHERE "friendships"."status" = ?) AND
"users"."id" = ?
LIMIT 1
所以......问题显然是这句话:"users"."user_id" IN
用户没有user_id
,用户有id
友谊有user_id
。所以...有些东西导致你的SQL认为你应该通过user_id获取用户,而不应该以这种方式取出友谊。
has_many :pending_friends, -> { where(friendships: Friendship.pending) },
through: :friendships, class_name: "User", source: :friend
显然是产生此权利的代码?
如何将挂起的部分从pending-friends部分拆分出来,看看它们是否分开工作:
has_many :friendships
has_many :pending_friendships, -> { friendships.merge(Friendship.pending) }
看看那部分是否有效?如果没有让它工作(它更简单) (注意:我没有测试过这段代码,你可能需要以不同的方式做这个部分...尝试一下)
然后你可以添加:
has_many :pending_friends, through: :pending_friendships, class_name: "User", source: :friend
答案 1 :(得分:0)
这就是为我做的,感谢max关于如何格式化procs的提示
class CreateFriendships < ActiveRecord::Migration
def change
create_table :friendships do |t|
t.integer :status, :null => false, :default => 0
t.integer :user_id
t.integer :friend_id
t.timestamps null: false
end
end
end
has_many :friendships, :foreign_key => :user_id, dependent: :destroy
has_many :inverse_friendships, :foreign_key => :friend_id, dependent: :destroy,
class_name: :Friendship
has_many :pending_incoming_friendships,
-> { where(friendships: { status: 0 }) },
:class_name => :Friendship,
:foreign_key => :friend_id, :dependent => :destroy
has_many :pending_outgoing_friendships,
-> { where(friendships: { status: 0 }) },
:class_name => :Friendship,
:foreign_key => :user_id, :dependent => :destroy
然后我只检查状态:1获得已接受的友谊!不确定为什么检查符号或使用Friendship.accepted或Friendship.pending范围无法正常工作。看起来这个值最初被设置为&#34; pending&#34;,一个字符串,但是在我调用我的accept函数后,它明确地将它设置为一个符号,然后它就是一个符号。我选择使用整数,因为它们只有2个,并且看起来更安全,具有明显的不可预测性。