构造一个Rails ActiveRecord where子句

时间:2011-04-28 14:33:39

标签: ruby-on-rails activerecord

使用Rails ActiveRecord构造where子句的最佳方法是什么?例如,假设我有一个控制器动作,它返回一个博客帖子列表:

def index
  @posts = Post.all
end

现在,假设我希望能够传入一个url参数,以便此控制器操作仅返回特定作者的帖子:

def index
  author_id = params[:author_id]

  if author_id.nil?
    @posts = Post.all
  else
    @posts = Post.where("author = ?", author_id)
  end
end

这对我来说感觉不太干。如果我要添加排序或分页或更糟糕的是,更多可选的URL查询字符串参数进行过滤,此控制器操作将变得非常复杂。

5 个答案:

答案 0 :(得分:24)

怎么样:

def index
  author_id = params[:author_id]

  @posts = Post.scoped

  @post = @post.where(:author_id => author_id) if author_id.present?

  @post = @post.where(:some_other_condition => some_other_value) if some_other_value.present?
end

Post.scoped本质上是一个延迟加载等效于Post.all(因为Post.all返回一个数组 立即,而Post.scoped只返回一个关系对象)。直到此查询才会执行 你实际上试图在视图中迭代它(通过调用.each)。

答案 1 :(得分:2)

嗯,你想要使用的最佳方法是将其传播到2个动作中

def index
   @post = Post.all
end

def get
  @post = Post.where("author=?", params[:author_id])
end

恕我直言,如果你考虑一个RESTful API更有意义,索引意味着列出所有并获取(或显示)来获取所请求的并显示它!

答案 2 :(得分:0)

这样的事情会起作用吗?

def get
  raise "Bad parameters...why are you doing this?" unless params[:filter].is_a?(Hash)
  @post = Post.where(params[:filter])
end

然后你可以这样做:  ?filter [author_id] = 1& filter [post_date] = ... etc。

答案 3 :(得分:0)

您应该使用嵌套资源建模网址。预期的网址是/ authors / 1 / posts。将作者视为资源。阅读本指南中的嵌套资源:http://guides.rubyonrails.org/routing.html(滚动到2.7 - 嵌套资源)。

答案 4 :(得分:0)

这个问题已经很老了,但在2019年google中仍然很高,而且已经弃用了一些较早的答案,所以我想我会分享一个可能的解决方案。

在模型中介绍一些范围,并测试传递的参数是否存在:

class Post
    scope :where_author_ids, ->(ids){ where(author_id: ids.split(‘,’)) if ids }
    scope :where_topic_ids,  ->(ids){ where(topic_id:  ids.split(‘,’)) if ids }

然后,您可以在控制器中随意放置多个过滤器,例如:

def list
    @posts = Post.where_author_ids(params[:author_ids])
                 .where_topic_ids(params[:topic_ids])                                  
                 .where_other_condition_ids(params[:other_condition_ids])
                 .order(:created_at)

该参数可以是单个值,也可以是逗号分隔的值列表,两者都可以正常工作。

如果不存在参数,则仅跳过该where子句,并且不针对该特定条件进行过滤。如果参数存在,但其值为空字符串,则它将“过滤”所有内容。

此解决方案当然不能适合所有情况。如果您有一个带有多个过滤器的视图页面,但是在第一次打开时,您想显示所有数据而不是没有数据,直到您按下“提交”按钮或类似按钮(如此控制器一样),那么您就必须对其进行一些微调。

我已经尝试过SQL注入,并且Rails似乎可以很好地保持一切安全。