Reputation: 2504
I'm trying to find a way to get some random record without repetition at least until I take all the records from a table one time.
I have a table with some questions (3000).
I create a quiz selecting some random questions (30). I need to create quiz with all the question so without repetition until I use all the 3000 questions. Then I can begin to us the questions for another cycle.
In a single user environment I can add a field "count" to increase in my Question table every time I use a question, but I have a multiuser environment, so I can't pollute the Question table.
Any idea?
Upvotes: 1
Views: 124
Reputation: 5740
You must create an intermediate table.
Assuming your models are User
and Question
:
rails g migration create_users_questions user_id:integer question_id:integer
rake db:migrate
This will generate a users_questions
table in your database.
Then, in your user.rb
:
has_and_belongs_to_many :questions
and in your question.rb
:
has_and_belongs_to_many :users
Each row of the new table will contain a user_id
and a question_id
So, to get unused questions for user @user
:
Generic Syntax
@unused_questions = Question.where('id not in (?)',@user.questions.map(&:id))
Rails ~> 4.0 Syntax [thanks D-Side]
@unused_questions = Question.where.not(id:@user.question_ids)
And to add a new, used, question (let's say @question) to @user:
@user.questions<<@question
That's it, end of story...
Finally, to reset status of the @user's questions:
if @unused_questions.empty? # we have defined that above
@user.questions.clear
end
And then you go adding once again...
Upvotes: 3
Reputation: 5229
I think you can use cache for store ids of sorted unused questions.
available_question_ids = Rails.cache.read('available_question_ids')
if available_questions_ids.nil? || available_question_ids.empty?
available_question_ids = Question.pluck(:id).to_a.shuffle
end
quiz_questions_ids = available_question_ids.pop(30)
Rails.cache.write('available_question_ids', available_question_ids)
Now you can find your questions with quiz_questions = Question.find(quiz_questions_ids)
.
Upvotes: 0
Reputation: 230
You are going to need to add another model to track user interactions with a specific question.
User Questions:
User:
Then you are going to need to run a limited, randomized query:
user_question = User.user_questions.where(used: false).order("RANDOM()").first
This will get you your next question to use. Once it's been answered you will mark it as used so it's not picked up again.
When you regenerate a quiz you would need to reset to false. Alternatively you can use a count... but if your last quiz didn't use all the questions you will need to reset in some way or your counts will be off.
Upvotes: 0
Reputation: 961
IF you don't want to add any database fields, the best way will be using redis
1- Adding all ure questions ids in redis
$redis.sadd 'set_one', Question.pluck(:id)
2- Hitting on a method which selects a random id and removes it from the list
def get_rand_question
random_id = $redis.spop "set_one"
Question.find random_id
end
Upvotes: 0