Rails 4 - 加入AND子句

时间:2015-02-07 15:50:41

标签: ruby-on-rails postgresql join

下面的查询根据该问题的状态向我提供用户的下一个问题。它获取该特定部分的所有问题,然后范围对属于该用户的状态执行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

这可能都非常不清楚!

1 个答案:

答案 0 :(得分:-2)

您所做的是跳过Active Record提供的ORM层并自行构建查询。你觉得这种方法有很多限制,并且不适合轨道跟随的MVC模型。我建议阅读Active Record Query Interface以获取以rails / oop方式执行此操作的概念