使用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查询字符串参数进行过滤,此控制器操作将变得非常复杂。
答案 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)
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似乎可以很好地保持一切安全。