使用 ActiveRecord 创建子选择字符串(Rails 教程第 2 版,清单 11.45)



在 The Rails Tutorial 第 2 版第 11 章的清单 11.45 中,Micropost类的 from_users_followed_by 类方法定义如下:

class Micropost < ActiveRecord::Base
...
  def self.from_users_followed_by(user)
    followed_user_ids = "SELECT followed_id FROM relationships
                         WHERE follower_id = :user_id"
    where("user_id IN (#{followed_user_ids}) OR user_id = :user_id", 
          user_id: user.id)
  end
end

在本章的脚注 13 中,有一个指向此博客文章的链接,其中指出,如果要创建子选择字符串,可以使用 ActiveRecord 内部方法construct_finder_sql send方法。 因此,我尝试将followed_user_ids字符串替换为:

followed_user_ids = Relationship.send(:construct_finder_sql,
                                      select: "followed_id",
                                      conditions: { follower_id: :user_id })

唯一的问题是construct_finder_sql在 Rails 3 中被折旧了,所以除了不知道我写的内容是否正确之外,我无论如何都不能使用它。 那么,是否有一种 Rails 3 方法可以使用 ActiveRecord(最好仍使用 :user_id 参数)创建子选择字符串,可以在这种情况下工作?

您可以将 seb-select 构建为单独的查询,然后使用 to_sql 获取 SQL:

def self.from_users_followed_by(user)
  followed = Relationship.select(:followed_id)
                         .where(:follower_id => user.id)
                         .to_sql
  where("user_id in (#{followed}) or user_id = :user_id", :user_id => user.id)
end

M.select(...).where(...)只是构建ActiveRecord::Relation实例之类的东西,而那些实例则逐个构建查询,在您请求一些结果(以某种方式)之前,不会将任何内容发送到数据库。因此,您可以使用 AREL 的东西来构建查询,然后to_sql它以获取 SQL 版本。

相关内容