Module: Randumb::ActiveRecord::Relation

Included in:
ActiveRecord::Relation
Defined in:
lib/randumb/relation.rb

Instance Method Summary collapse

Instance Method Details

#random(max_items = nil, opts = {}) ⇒ Object

If the max_items argument is omitted, one random entity will be returned. If you provide the integer argument, you will get back an array of records.



12
13
14
# File 'lib/randumb/relation.rb', line 12

def random(max_items = nil, opts={})
  random_weighted(nil, max_items, opts)
end

#random_by_id_shuffle(max_items = nil, opts = {}) ⇒ Object

This was my first implementation, adding it as an option for people to use and to fall back on for pesky DB one off situations…

https://github.com/spilliton/randumb/issues/7


49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/randumb/relation.rb', line 49

def random_by_id_shuffle(max_items = nil, opts={})
  return_first_record = max_items.nil? # see return switch at end
  max_items ||= 1
  relation = clone
  ids = fetch_random_ids(relation, max_items, opts)

  # build new scope for final query
  the_scope = klass.includes(includes_values)

  # specifying empty selects caused bug in rails 3.0.0/3.0.1
  the_scope = the_scope.select(select_values) unless select_values.empty?

  # get the records and shuffle since the order of the ids
  # passed to where() isn't retained in the result set
  rng = random_number_generator(opts)
  records = the_scope.where(:id => ids).shuffle!(:random => rng)

  # return first record if method was called without parameters
  return_first_record ? records.first : records
end

#random_weighted(ranking_column, max_items = nil, opts = {}) ⇒ Object

If ranking_column is provided, that named column wil be multiplied by a random number to determine probability of order. The ranking column must be numeric.



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/randumb/relation.rb', line 18

def random_weighted(ranking_column, max_items = nil, opts={})
  relation = clone
  return random_by_id_shuffle(max_items, opts) if is_randumb_postges_case?(relation, ranking_column)
  raise_unless_valid_ranking_column(ranking_column)

  # get clause for current db type
  order_clause = Randumb::Syntax.random_order_clause(ranking_column, opts.merge(connection: connection, table_name: table_name))

  the_scope = if ::ActiveRecord::VERSION::MAJOR == 3 && ::ActiveRecord::VERSION::MINOR < 2
    # AR 3.0.0 support
    relation.order(order_clause)
  else
    # keep prior orders and append random
    all_orders = (relation.orders + [order_clause]).join(", ")
    # override all previous orders
    relation.reorder(all_orders) 
  end
  
  # override the limit if they are requesting multiple records
  if max_items && (!relation.limit_value || relation.limit_value > max_items)
    the_scope = the_scope.limit(max_items)
  end

  # return first record if method was called without parameters
  max_items ? the_scope.to_a : the_scope.first
end