2009-05-06 8 views
15

Piszę aplikację szyny, która ze swej natury NIE MOŻE wymagać od użytkowników rejestracji, a zatem nie może używać uwierzytelniania jako zwykłego sposobu ochrony rekordów. (Wiem, wiem ...) Informacje użytkownika tutaj są ograniczone do adresów e-mail. Potrzebuję więc sposobu na nieprzewidywalność identyfikatorów moich modeli, aby inne identyfikatory nie mogły być łatwo odgadnięte. (Wiem, wiem ...)Jak sprawić, by identyfikatory modeli w Railsach były nieprzewidywalne i przypadkowe?

Próbowałem za pomocą wtyczek jak uuidtools do losowo identyfikatory jako rekordy są tworzone, jak w przykładzie:

require 'uuidtools' 
class Post < ActiveRecord::Base 
def before_create() 
    self.id = OpenSSL::Digest.SHA1.hexdigest(UUID.timestamp_create()) 
end 
end 

... To wygląda dobrze na początku, ale zabawny rzeczy się zdarzają. ActiveRecord czasami próbuje wstawić wartość 0 do id i otrzymuję błędy, takie jak "nie mogę znaleźć wpisu z id = 0" itd ...

Skończyły mi się pomysły. Czy ktoś może pomóc? Dzięki.

+0

możesz użyć https://github.com/jashmenn/activeuuid ten klejnot dla twojej potrzeby –

Odpowiedz

5

Jest to plugin, który powinien robić to, co chcesz.

http://codesnipers.com/?q=using-uuid-guid-as-primary-key-in-rails

(wszystkie przeprosiny do tak cenzorów za nie wklejanie w całym artykule w mojej obronie, jest ładowany z linków i formatowania, które Wymaga to sporego wysiłku w celu replikacji. Nie wspominając już o tym, że rabowalibyśmy autora ruchu i potencjalne przychody.)

+0

Nie słyszę, żeby ktoś narzekał na twój link. – drizzle

+0

Z tą wtyczką, co się dzieje, gdy tworzysz model za pomocą zagnieżdżonego formularza modelu? Mam na myśli, jeśli mam utworzyć formularz produktu, w którym można dodawać obrazy jako modele zagnieżdżone, czy obrazy przechowują poprawny product_id? – tybro0103

2

Alternatywą jest wygenerowanie tokena lub sumy kontrolnej lub czegoś podobnego w drugiej kolumnie podczas tworzenia rekordu , a we wszystkich przypadkach kontrolerzy pytają o obiekt, użyj Model.find_by_id_and_token.

Zawsze będziesz generować adresy URL, które zawierają i będą wymagać zarówno identyfikatora, jak i tokena.

+0

Innym powodem, aby to zrobić w ten sposób (dodając token/sumę kontrolną) jest to, że ActiveRecord jest po prostu łatwiejsze, gdy klucze podstawowe są liczbami całkowitymi - w zakresie skojarzeń. –

3

To, co dzieje się nie tak, polega na tym, że self.id wymaga int i OpenSSL :: Digest.SHA1.hexdigest (UUID.timestamp_create()) zwraca ciąg znaków z nieliczbowymi znakami, które prowadzą do wartości " 0' są faktycznie przechowywane w bazie danych

+0

Niekoniecznie można zdefiniować swoją bazę danych tak, aby zawierała ciąg znaków dla kolumny ID.To może nie być idealne, ale jest to możliwe. –

17

w modelu, to zrobić:

before_create :randomize_id 

... 

private 
def randomize_id 
    begin 
    self.id = SecureRandom.random_number(1_000_000) 
    end while Model.where(id: self.id).exists? 
end 
+0

W tej metodzie możliwe jest, aby wiele postów miało ten sam numer losowy? –

+0

@Justin Nie, nie jest, ponieważ pętla while sprawdza, czy obiekt z tym identyfikatorem już istnieje (musisz zastąpić * Model * postem w twoim przypadku) –

+2

, o ile masz mniej niż milion użytkowników: P –

8

Najlepszym sposobem jest użycie SecureRandom.uuid który generuje V4 UUID (unikatowy identyfikator uniwersalny).

Jest praktycznie całkowicie przypadkowy i niepowtarzalny (prawdopodobieństwo kolizji jest coś takiego jak jeden nad dziesiątki bilionów): https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_.28random.29

To powinno załatwić sprawę:

class Post < ActiveRecord::Base 
before_create :generate_random_id 

private 
def generate_random_id 
    self.id = SecureRandom.uuid 
end 
end 

lub jeśli używasz Rails> = 4 i PostgreSQL, możesz je wygenerować dla ciebie:

create_table :posts, id: :uuid do |t| 
    ... 
end 
Powiązane problemy