下面的查询根据该问题的状态向我提供用户的下一个问题。它获取该特定部分的所有问题,然后范围对属于该用户的状态执行LEFT JOIN
。
我的问题是,这似乎不是一种非常Railsy的方式 - 是否有更好的方法来过滤我的表而不是这个笨拙的AND
和.to_s
业务。我的问题是,显然,如果有任何用户回答了这个问题,那么左连接将填满该用户的答案,而我要求它为空。
基本上查询有效,但很难看,我无法弄清楚它是否是最有效的方式!
scope :next_for_user, lambda { |user|
joins("LEFT JOIN user_question_statuses ON user_question_statuses.question_id = questions.id AND user_question_statuses.user_id = ", user.id.to_s).
reorder("user_question_statuses.answered ASC NULLS FIRST").
order("user_question_statuses.updated_at ASC NULLS FIRST").
limit(1)
}
修改
我意识到这种方法特别容易受到SQL注入攻击,所以我用查询替换了查询中的主线:
joins(sanitize_sql_array(["LEFT JOIN user_question_statuses ON user_question_statuses.question_id = questions.id AND user_question_statuses.user_id = %d", user.id]))
似乎有效,并强制输入只是一个整数。
编辑2:
我的另一个选择是使用find_each
然后用户first_or_create
为当前用户的特定问题部分创建空问题状态。这可能发生在他们需要之前寻找问题时。这将允许我从这些状态的问题中做RIGHT JOIN
,知道它们存在,但如果第一种方法是有效和安全的(并且尽可能像Railsy那样),那么就没有理由改变它。
编辑3:
我已经用这种方式构建了这个查询,因为 - 来自section
模型has_many
questions
- 我希望找到应该传递给它的下一个question
user
。
要找到这个,我需要将所有user_question_statuses
加入所有section
模型的问题。这可以做到的唯一方法是question.id
。但是,对于不同的用户,有许多user_question_statuses
具有该问题ID。因此,在加入时,我需要使用AND
子句在加入发生之前将user_question_statuses
过滤为只有user
的{{1}}。用户嘿显然每个question
只有一个状态。
我使用LEFT JOIN
,这样如果状态尚不存在(它们只在用户第一次尝试问题后才会创建),那么仍然存在NULL
s的状态,以便他们创建了一行,然后从那里移动到顶部(因此NULLS FIRST
)并可能服务于user
。
这可能都非常不清楚!
答案 0 :(得分:-2)
您所做的是跳过Active Record提供的ORM层并自行构建查询。你觉得这种方法有很多限制,并且不适合轨道跟随的MVC模型。我建议阅读Active Record Query Interface以获取以rails / oop方式执行此操作的概念