Подтвердить что ты не робот

Rails выбирает случайную запись

Я не знаю, могу ли я просто искать здесь неправильные места или что, но имеет ли активная запись метод для извлечения случайного объекта?

Что-то вроде?

@user = User.random

Или... ну, так как этот метод не существует, есть какой-то удивительный "Rails Way" для этого, мне всегда кажется многословным. Я также использую mysql.

4b9b3361

Ответ 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