gpt4 book ai didi

ruby-on-rails - Rails 3、will_paginate、随机、重复记录、Postgres、setseed 失败

转载 作者:行者123 更新时间:2023-11-29 11:26:06 27 4
gpt4 key购买 nike

我有一个带有属性的电影数据库。我想以随机顺序将这些电影的查询批处理返回到带有分页的模板。我正在使用 will_paginate。我尝试了以下方法:

## MoviesController

movies = Movie.get_movies(query_string) # a method in Movie model that takes in
# a query_string and fetches movies
# with user-set params

@movies = movies.order('random()').page(params[:page]).per_page(16)

这很好用,除了逐页重复电影。此问题的解决方案已发布herehere .这些链接解释说,因为 random() 种子在页面之间被重置,所以没有一致性并且 OFFSET 变得无用。它们为 MySQL 用户提供了很好的解决方案,因为它的 rand(n) 函数采用种子 n。然而,Postgres 不这样做。在 ORDER 中发出 random() 之前,您必须在 SELECT 中声明 setseed(n)

所以我尝试了 postgres 的方式来设置种子:

@movies = movies.select('setseed(.5)').order('random()').page(params[:page]).per_page(16)

奇怪的是,返回的 Movie 对象完全没有任何属性。以下是从模板中提出的:

ActiveModel::MissingAttributeError in Movies#action

missing attribute: some_movie_attribute

我对此进行了调试,一旦堆栈到达 action_controller/metal,@movies 包含:

[#<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >, #<Movie >]

电影对象的数量 (18) 对应于查询返回的电影数量。

我还尝试了以下方法,通过删除随机排序方法来查看 setseed(n) 是否是问题所在:

@movies = movies.select('setseed(.5)').page(params[:page]).per_page(16)

这返回了与上面布局相同的非属性 Movie 对象。所以看来 setseed(n) 确实是问题所在。

我尝试了一些解决方法,例如:

# MoviesController

movies = Movie.get_movies(query_string)
shuf_movs = movies.shuffle ## effectively turns shuf_movs into an array

@movies = shuf_movs.paginate(:page => params[:page], :per_page => 16)

这也会返回包含重复电影的页面。我认为这是因为分页需要按某物 对对象进行排序,而您不能在 Array#shuffle 中设置种子。因此,我尝试编写自己的随机化代码,该代码将临时存储一个 id 以在 Movie 对象中进行排序。 (请原谅草率的代码):

# Movie model

attr_accessor :rand_id

# MoviesController

movies = get_movies(query_string)
movies_count = movies.count
r = Random.new
nums = []
rand_movs = []
id = 1
while nums.count != movies_count
num = r.rand(0..movies_count - 1)
if !(nums.include?(num))
movie = movies[num]
movie.rand_id = id
rand_movs << movie
nums << num
id += 1
end
end

@movies = rand_movs.sort_by { |a| a.rand_id }.paginate(:page => params[:page], :per_page => 16)

这仍然会在不同的页面中产生重复的电影。在这一点上,我意识到 will_paginate 在调用 paginate 之前不会接受您排序的内容。所以我尝试了这个:

@movies = rand_movs.paginate(:order => 'rand_id', :page => params[:page], :per_page => 16)

那还是重复记录。 :order -> 'rand_id' 被忽略,因为 :order 只在处理 ActiveRecord 对象而不是数组时才重要。

所以 setseed(n) 似乎是我使用 will_paginate 实现随机非重复记录的唯一希望。有什么想法吗?

谢谢!

最佳答案

不是 postgres 的人,但......我会尝试

Movie.connection.execute "select setseed(0.5)"
Movie.where(...).order('random()').page(params[:page]).per_page(15)

关于 Array#shuffle 不采用种子,它使用 Kernel.rand 因此您可以使用 Kernel.srand

关于ruby-on-rails - Rails 3、will_paginate、随机、重复记录、Postgres、setseed 失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10367690/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com