我想为我的模型编写一个类函数,它返回一个满足我的条件的随机记录并排除一些记录。我的想法是,我将制作一个“随机文章部分”。
我希望我的函数看起来像这样
Article.randomArticle([1, 5, 10]) # array of article ids to exclude
一些伪代码:
ids_to_exclude = [1,2,3]
loop do
returned_article = Article.where(published: true).sample
break unless ids_to_exclude.include?(returned_article.id)
do
让我们看一下数据库特定选项。
class Article
# ...
def self.random(limit: 10)
scope = Article.where(published: true)
# postgres, sqlite
scope.limit(limit).order('RANDOM()')
# mysql
scope.limit(limit).order('RAND()')
end
end
Article.random
要求数据库为我们获取10条随机记录。
那么让我们看看如何添加一个选项来排除某些记录:
class Article
# ...
def self.random(limit: 10, except: nil)
scope = Article.where(published: true)
if except
scope = scope.where.not(id: except)
end
scope.limit(limit).order('RANDOM()')
end
end
现在
Article.random(except: [1,2,3])
将获得 10 条 id 不是 [1,2,3]
的记录。
这是因为 Rails 中的
.where
返回一个可链接的范围。例如:
> User.where(email: '[email protected]').where.not(id: 1)
User Load (0.7ms) SELECT "users".* FROM "users" WHERE "users"."email" = $1 AND ("users"."id" != $2) [["email", "[email protected]"], ["id", 1]]
=> #<ActiveRecord::Relation []>
我们甚至可以在这里传递范围:
# cause everyone hates Bob
Article.random(except: Article.where(author: 'Bob'))
请参阅 Rails 快速提示 - 随机记录,了解为什么数据库特定解决方案是一个不错的选择。
你可以使用这样的:
ids_to_exclude = [1,2,3,4]
Article.where("published = ? AND id NOT IN (?)", true , ids_to_exclude ).order( "RANDOM()" ).first