Rails выбирает случайную запись
Я не знаю, могу ли я просто искать здесь неправильные места или что, но имеет ли активная запись метод для извлечения случайного объекта?
Что-то вроде?
@user = User.random
Или... ну, так как этот метод не существует, есть какой-то удивительный "Rails Way" для этого, мне всегда кажется многословным. Я также использую mysql.
Ответы
Ответ 1
В Rails 4 я бы протянул ActiveRecord::Relation
:
class ActiveRecord::Relation
def random
offset(rand(count))
end
end
Таким образом вы можете использовать области видимости:
SomeModel.all.random.first # Return one random record
SomeModel.some_scope.another_scope.random.first
Ответ 2
Большинство примеров, которые я видел, в конечном итоге подсчитывают строки в таблице, а затем генерируют случайное число, чтобы выбрать один. Это связано с тем, что альтернативы, такие как RAND()
, неэффективны в том, что они фактически получают каждую строку и присваивают им случайное число, или я читал (и, по-моему, я имею в виду базу данных).
Вы можете добавить метод, подобный тому, который я нашел здесь.
module ActiveRecord
class Base
def self.random
if (c = count) != 0
find(:first, :offset =>rand(c))
end
end
end
end
Это приведет к тому, что любая используемая вами модель имеет метод под названием random
, который работает так, как я описал выше: генерирует случайное число в подсчете строк в таблице, а затем выбирает строку, связанную с этим случайным номер. Таким образом, в основном, вы делаете только одну выборку, что вы, вероятно, предпочитаете:)
Вы также можете посмотреть этот плагин rails.
Ответ 3
Мы обнаружили, что смещения очень медленно выполнялись на MySql для большой таблицы. Вместо использования offset, например:
model.find(:first, :offset =>rand(c))
... мы обнаружили, что следующая техника работает более чем в 10 раз быстрее (фиксируется на 1):
max_id = Model.maximum("id")
min_id = Model.minimum("id")
id_range = max_id - min_id + 1
random_id = min_id + rand(id_range).to_i
Model.find(:first, :conditions => "id >= #{random_id}", :limit => 1, :order => "id")
Ответ 4
Попробуйте использовать Array sample метод:
@user = User.all.sample(1)
Ответ 5
Я бы использовал именованный scope. Просто бросьте это в свою модель пользователя.
named_scope :random, :order=>'RAND()', :limit=>1
Однако в каждой базе данных случайная функция не является одинаковой. SQLite и другие используют RANDOM()
, но вам нужно использовать RAND()
для MySQL.
Если вы хотите захватить несколько случайных строк, вы можете попробовать это.
named_scope :random, lambda { |*args| { :order=>'RAND()', :limit=>args[0] || 1 } }
Если вы вызываете User.random
, по умолчанию будет 1, но вы также можете вызвать User.random(3)
, если хотите больше одного.
Ответ 6
Если вам нужна случайная запись, но только в определенных критериях вы можете использовать "random_where" из этого кода:
module ActiveRecord
class Base
def self.random
if (c = count) != 0
find(:first, :offset =>rand(c))
end
end
def self.random_where(*params)
if (c = where(*params).count) != 0
where(*params).find(:first, :offset =>rand(c))
end
end
end
end
Например,
@user = User.random_where("active = 1")
Эта функция очень полезна для отображения случайных продуктов на основе некоторых дополнительных критериев
Ответ 7
Вот лучшее решение для получения случайных записей из базы данных.
RoR обеспечивает все в простоте использования.
Для получения случайных записей из БД используйте образец, ниже приведено описание этого примера.
Образец Backport of Array # на основе Marc-Andre Lafortunes github.com/marcandre/backports/Возвращает случайный элемент или n случайных элементов из массива. Если массив пуст, а n - nil, возвращает nil. Если n передано и его значение меньше 0, оно вызывает исключение ArgumentError. Если значение n равно или больше 0, оно возвращает [].
[1,2,3,4,5,6].sample # => 4
[1,2,3,4,5,6].sample(3) # => [2, 4, 5]
[1,2,3,4,5,6].sample(-3) # => ArgumentError: negative array size
[].sample # => nil
[].sample(3) # => []
Вы можете использовать условие в соответствии с вашим требованием, как показано ниже.
User.where(active: true).sample(5)
он будет беспорядочно возвращать 5 активных пользователей из таблицы пользователя
За дополнительной информацией обращайтесь: http://apidock.com/rails/Array/sample