使用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查询字符串参数作为过滤依据,这个控制器操作将变得非常复杂。
发布于 2011-04-28 23:18:42
这样如何:
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)之后,才会执行该查询。
发布于 2011-04-28 22:38:39
嗯,你想要使用的最好的方法可以是在两个动作中传播它。
def index
@post = Post.all
end
def get
@post = Post.where("author=?", params[:author_id])
end
如果你考虑一个RESTful应用程序接口,索引就更有意义了,索引意味着列出所有内容,然后获取(或显示)请求的接口并显示它!
发布于 2019-02-15 16:33:16
这个问题已经很老了,但它在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在保证一切安全方面做得很好。
https://stackoverflow.com/questions/5820277
复制相似问题