Rails中的随机记录

时间:2015-05-10 06:57:30

标签: ruby-on-rails ruby ruby-on-rails-4

现在我正在制作一个Web应用程序(在线单词学习),允许用户选择单词的正确含义。当他们点击开始时,它将从数据库中随机选择一个单词并显示给用户。用户选择答案后,将转到下一个问题。 请看下面的图片: enter image description here

如果我使用Word.order(“rand()”)。limit(1),我想这个单词是否可以用最后选择的单词重复? 使用上图中的应用程序,有什么更好的想法来解决这个问题吗?

2 个答案:

答案 0 :(得分:1)

我会将以下范围添加到模型中(取决于您使用的数据库):

# in app/models/word.rb
# 'RANDOM' works with postgresql and sqlite, whereas mysql uses 'RAND'
scope :random, -> { order('RAND()') }
scope :without, ->(ids) { where.not(id: ids) }

使用该范围,您可以在控制器中编写以下查询:

@word = Word.random.without(params[:last_ids]).limit(1)

如果要在视图中加载新的随机元素,只需将当前单词的ID添加到请求中即可。这可以确保不会随机选择此ID(params[:last_ids])。

答案 1 :(得分:0)

长话短说,为了不重复自己,你必须把这些话存放在某个地方。要么显示的那些,要么已经显示的那些。如果我是你,我会选择以下路线之一:

  1. 在开始测验之前获取所有单词并随机化它们。这可能是这样的:

    session[:words] = Word.order("RAND()").select(:id).take(10)
    

    甚至可以通过为随机单词定义范围来实现更好:

    class Word < ActiveRecord::Base
      # ...
      scope :random_quiz, -> { order("RAND()").take(10).pluck(:id) }
      # ...
    end
    
    # ... in the controller when the quiz is getting started:
    session[:words] = Word.random_quiz
    # ... in the controller when you want to show the word:
    new_word = Word.find(sessions[:words].pop)
    

    由于ORDER BY RAND()是一项非常昂贵的操作,这可能是有道理的。然后,您只需使用session[:words].pop逐个弹出单词ID,然后提出问题。

    这样可以保证您不会重复测验中的单词并为您提供非常佳的表现。

  2. 在您提出问题并保存您已经询问过的问题时,逐步取词。

    class Word < ActiveRecord::Base
      # ...
      def self.random_word(exclusions)
        eligible = where('id NOT IN (?)', exclusions)
        eligible.offset(rand(0..eligible.count)).take!(1)
      end
      # ..
    end
    
    # ... in the controller when you need a new word:
    session[:words_shown] ||= [ ]
    new_word = Word.random_word(session[:words_shown])
    # mark the word as shown:
    session[:words_shown].push(new_word.id)
    
  3. 您可能已经注意到在第二个示例中获取随机记录的奇怪方式。事实证明它生成以下查询更有效:

    SELECT * FROM words OFFSET _random_number_ LIMIT 1
    

    而不是:

    SELECT * FROM words ORDER BY RAND() LIMIT 1
    

    第一个只是一个普通的选择,而第二个需要通过整个表的RAND()进行无索引排序,然后才能给出随机结果。事实证明,前者几乎比后者快十倍。

    希望有意义!