通过关联使用named_scope

时间:2013-11-19 08:43:23

标签: mysql sql ruby-on-rails ruby ruby-on-rails-2

我尝试优化一些查询(Rails 2.3.18)

这是我的测试用例:

class Post
  belongs_to :category
  belongs_to :user
  named_scope :public, :conditions => ["#{Post.table_name}.public = ?", true]
  named_scope :of_user, lambda {|u|
    { :conditions => ["#{Post.table_name}.user_id = ?", u] }
  }
end

class Category
  has_many :posts
end

class User
  has_many :posts
end

我的查询很简单:获取所有具有用户公开信息的类别。

def categories
  Post.of_user(u).public.map(&:category)
end

SELECT * FROM posts WHERE posts.user_id = 123 AND posts.public = 1
SELECT * FROM categories WHERE category_id = 4
SELECT * FROM categories WHERE category_id = 5
SELECT * FROM categories WHERE category_id = 6

我们现在有1个帖子查询,每个类别有n个查询。 使用:include

可以提高效率
def categories
  Post.of_user(u).public.find(:all, :include => :category).map(&:category)
end

SELECT * FROM posts WHERE posts.user_id = 123 AND posts.public = 1
SELECT * FROM categories WHERE category_id IN (4,5,6)

现在,我们只有2个查询:一个用于帖子,一个用于类别。 使用proxy_options

可以提高效率
def categories
  proxy_options = Post.of_user(u).public.proxy_options
  # Returns { :conditions => "posts.user_id = 123 AND posts.public = 1" }
  proxy_options[:joins] = "INNER JOIN #{Post.table_name}
      ON #{Post.table_name}.category_id = #{Category.table_name}.id"
  return Category.find(:all, proxy_options)
end

SELECT * FROM categories INNER JOIN posts ON posts.category_id = category.id
  WHERE posts.user_id = 123 AND posts.public = 1

它有效,我只有1个查询,但我发现这个方法“难看”。

你有“通过关联使用named_scope”的任何其他方法吗?

2 个答案:

答案 0 :(得分:0)

在这种情况下,我可能会使用

class User
  has_many :posts
  has_many :categories, :through => :posts
end

并且您不需要任何named_scope来获取用户的类别。

答案 1 :(得分:0)

您可以创建另一个关联,让Rails为您处理SQL查询。

class User < ActiveRecord::Base
  has_many :posts
  has_many :public_posts, :class_name => 'Post', :conditions => { :public => true }
  has_many :public_post_categories, :through => :public_posts, :source => :category
end

使用此功能,您只需拨打User.public_post_categories

即可