Ответ 1
Вместо этого вы захотите использовать методы order
и limit
. Вы можете избавиться от all
.
Для PostgreSQL и SQLite:
User.order("RANDOM()").limit(10)
Или для MySQL:
User.order("RAND()").limit(10)
User.find(:all, :order => "RANDOM()", :limit => 10)
был тем, как я это делал в Rails 3.
User.all(:order => "RANDOM()", :limit => 10)
- это то, как я думал, что Rails 4 сделает это, но это все еще дает мне предупреждение об отказе:
DEPRECATION WARNING: Relation#all is deprecated. If you want to eager-load a relation, you can call #load (e.g. `Post.where(published: true).load`). If you want to get an array of records from a relation, you can call #to_a (e.g. `Post.where(published: true).to_a`).
Вместо этого вы захотите использовать методы order
и limit
. Вы можете избавиться от all
.
Для PostgreSQL и SQLite:
User.order("RANDOM()").limit(10)
Или для MySQL:
User.order("RAND()").limit(10)
Поскольку случайная функция может меняться для разных баз данных, я бы рекомендовал использовать следующий код:
User.offset(rand(User.count)).first
Конечно, это полезно, только если вы ищете только одну запись.
Если вы хотите получить больше этого, вы можете сделать что-то вроде:
User.offset(rand(User.count) - 10).limit(10)
- 10
должен гарантировать, что вы получите 10 записей в случае, когда rand возвращает число больше, чем count - 10.
Помните, что вы всегда будете получать 10 последовательных записей.
Я думаю, что лучшее решение действительно упорядочивается случайным образом в базе данных.
Но если вам нужно избегать конкретной случайной функции из базы данных, вы можете использовать подход pluck
и shuffle
.
Для одной записи:
User.find(User.pluck(:id).shuffle.first)
Для более чем одной записи:
User.where(id: User.pluck(:id).sample(10))
Я бы предложил сделать эту область видимости, как вы можете ее потом:
class User < ActiveRecord::Base
scope :random, -> { order(Arel::Nodes::NamedFunction.new('RANDOM', [])) }
end
User.random.limit(10)
User.active.random.limit(10)
Хотя это не самое быстрое решение, мне нравится краткость:
User.ids.sample(10)
Метод .ids
дает массив идентификаторов пользователя, а .sample(10)
выбирает 10 случайных значений из этого массива.
Для MYSQL это сработало для меня:
User.order("RAND()").limit(10)
Здесь быстрое решение. В настоящее время он использует его с более чем 1,5 миллионами записей и получает достойную производительность. Лучшим решением было бы кэшировать один или несколько наборов случайных записей, а затем обновлять их с помощью рабочего стола в нужном интервале.
Создан random_records_helper.rb
файл:
module RandomRecordsHelper
def random_user_ids(n)
user_ids = []
user_count = User.count
n.times{user_ids << rand(1..user_count)}
return user_ids
end
в контроллере:
@users = User.where(id: random_user_ids(10))
Это намного быстрее, чем метод .order("RANDOM()").limit(10)
- я перешел с 13-секундного времени загрузки до 500 мс.