Running with Ruby

Tag: random ID

ActiveRecord – pobieranie losowego elementu (rekordu) z modelu

Kolejna krótka notka.

Tym razem nt tego jak pobierać losowy element (rekord) z modelu.

Najprościej jest skorzystać z kodu który krąży po necie od dawien dawna:

      def self.random
        find(:first, :order => "RAND()")
      end

Ma on jednak jedną wadę. Cachowanie Railsowego go psuje. Tzn że jeśli Railsy cachują zapytania i wykonamy dwa razy tę metodę, w obrębie jednego żądania – to wylosuje nam ten sam element. Rozwiązaniem tego jest wykorzystanie parametry created_at w taki oto sposób:

      def self.random
        find(:first, :order => "RAND()", :conditions => "created_at < '#{Time.now.to_s(:db)}'")
      end

co wymusi każdorazowo wykonanie nowego zapytania, ponieważ znacznik czasu będzie inny.

Acts As Random – plugin do generowania losowych ID zamiast autoincrement

O tym dlaczego ważne jest generowanie losowych ID, pisałem już w innym poście. Tutaj opiszę jak działa najważniejsza część mojego pluginu. Do pobrania jest tutaj.

Jak go dodać do klasy:

class CoolClass < ActiveRecord::Base
    acts_as_random
end

I od tego momentu generuje nam losowe wartości naszych id. W każdej klasie dziedziczącej po ActiveRecord, dodając acts_as_random, otrzymamy pseudolosowe id.

A działa to tak:

      def before_create
        range = 2147483647
        id = rand(range)
        while self.class.exists?(id) do
          id = rand(range)
        end
        self.id = id
      end

Malutko prawda? :)
Najpierw mamy deklarację zakresu INT(11) w (nawiasem mówiąc, taka sama jest w Postgresie. Wynika to z rozmiaru INTa a nie specyfikacji danego systemu bazodanowego). Następnie losujemy id z naszego zakresu, czyli od 0 do range. Sprawdzamy czy taki wpis istnieje i jeśli tak, to dopóki wpisy o ID takim jak losujemy istnieją, to musimy losować inne ID. Kiedy już mamy ID to po prostu je przydzielamy do naszego obiektu.

Proste, w miarę czytelne, niewielkie, ale swoje robi. Plusem tego pluginu jest to, że można go podpinać pod już istniejące projekty mające autoincrement. Stare elementy będą inkrementowane, ale nowe już nie.

Copyright © 2018 Running with Ruby

Theme by Anders NorenUp ↑