1

I'm trying to select a random record, but the only working method seems like a horrible performance liability.

First attempt, using RANDOM function from Postgres - throws "Can't convert Hash into Integer"

   assigned_specialist = User.specialists.legal_for(coach_section).experienced_in(critique.discipline_id).first(:order => "RANDOM()")
   return assigned_specialist.id

Second attempt, using offset method discussed here. Also causes "Can't convert Hash into Integer"

  legal_specialists = User.specialists.legal_for(coach_section).experienced_in(critique.discipline_id)

  offset = rand(legal_specialists.count)
  assigned_specialist = legal_specialists.first(:offset => offset)
  return assigned_specialist.id

Final attempt, using array sample method, which works but seems bad.

  legal_specialists = User.specialists.legal_for(coach_section).experienced_in(critique.discipline_id)
  assigned_specialist = legal_specialists.sample
  return assigned_specialist.id

To be fair, there will only be about 20 specialists in the system, so the array sample method might never cause any issues, but I'd still like to understand what's going on here.

Edit: Here are the scopes I defined:

scope :specialists, where(:role_id => 2)
scope :legal_for, lambda { |coach_section| where("section_id != ?", coach_section) }
scope :experienced_in, lambda { |discipline_id|
  discipline = Discipline.find(discipline_id)
  discipline.users
} 
Community
  • 1
  • 1
Chris Fletcher
  • 2,367
  • 1
  • 16
  • 19

1 Answers1

1

What about :

User.specialists.legal_for(coach_section).experienced_in(critique.discipline_id).sample

It does query all the table, so you just have a shorter version ... wonder if there's a better way to do it!

Edit : Did you try this? It's supposed to work :

assigned_specialist = User.specialists.legal_for(coach_section).experienced_in(critique.discipline_id).order("RANDOM()").first

Take a look at the thread here : Rails 3: Get Random Record. It shows different ways to do it

Also look at this gem : https://github.com/spilliton/randumb Seems to implement what you want to do, in a clean way

Edit : replace with this ?

scope :experienced_in, lambda { |discipline_id| joins(:habtm_models).where(habtm_models: {discipline_id: discipline_id})}

This way your scope will give you back an ActiveRecord::Relation object. I assumed the User model has_many :habtm_models so replace with the real name!

Community
  • 1
  • 1
Anthony Alberto
  • 10,325
  • 3
  • 34
  • 38
  • I saw Zabba's comment on this answer (http://stackoverflow.com/a/10837385/376632), which is what initially made me concerned about the `sample` method. Would love it if a more experienced Rails dev could weigh in on the issue. – Chris Fletcher Nov 02 '12 at 20:16
  • Edited my answer with more info! – Anthony Alberto Nov 02 '12 at 20:18
  • Hmm, I tried your edit and now it's throwing `undefined method 'order' for #` Tried the Randumb gem earlier, but got the same hash|integer conversion problem. Thanks for the ideas though :) – Chris Fletcher Nov 02 '12 at 20:24
  • May be because of the way you implemented your `legal_for` and `experienced_in` methods, are they `scopes` ? – Anthony Alberto Nov 02 '12 at 20:25
  • Good idea, I added my scopes to the question. – Chris Fletcher Nov 02 '12 at 20:29
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/18995/discussion-between-chris-fletcher-and-anthony-alberto) – Chris Fletcher Nov 02 '12 at 20:41
  • As Anthony pointed out, my problem was that my :experienced_in scope was returning an Array instead of an ActiveRecord:Relation object. Thanks :) – Chris Fletcher Nov 13 '12 at 15:41