has_many bez bazy danych

Zauważyłem, że czasami jestem w sytuacji, w której potrzebuję korzystać z jakiejś kolekcji połączonej z jakimś modelem, ale niekoniecznie chciałbym, żeby wszystko było zapisane w bazie danych.

Przykład:
Mam zaimplementowaną autoryzację opartą na grupach użytkowników. Grupy są wrzucone na stałe, uprawnienia też.

I teraz teoretycznie najbardziej Rails Way jest zrobienie modelu group, połączenie go z modelem user asocjacją one to many i wszystko działa bardzo fajnie.

Z tym, że jeżeli wiem, że grup będzie 3, to niekoniecznie potrzebuję do tego oddzielnej tabeli.

Zapewne łatwiej byłoby zrobić coś w rodzaju tableless model, gdzieś przy inicjalizacji dodać kod w stylu:

%w/user moderator admin/.each_with_index do |group, index| Group.create(:id => index, :name => group) end
Oczywiście create zapisywałby te 3 grupy do jakiejś zmiennej klasy. Po zdefiniowaniu has_many :groups w user.rb, dostępne byłyby wszystkie metody dostępne przy zwykłych asocjacjach.

Jest jeszcze trzecia opcja - dodanie do klasy User zmiennej klasy w stylu @@groups = [:user, :moderator, :admin] i zapisanie grupy w polu typu string. Zdecydowanie najmniej elastyczne i najbrzydsze, ale z bólem muszę się przyznać, że jakiś czas temu tak to zaimplementowałem - oczywiście do zmiany :wink:

Swoją drogą tutaj wychodzi temat robienia czegoś “the right way” - wydaje się czasami, że zrobienie czegoś tak jak się to powinno zrobić będzie dłuższe, więc pisze się szybkiego hacka, a tutaj wałek - dużo więcej czasu straci się na hacka + późniejsze naprawianie szkód, niż na zrobienie tego od razu solidnie. Zadziwiające jest to, że to stwierdzenie wydaje się oczywiste i zdaję sobie z tego sprawę już od dawna, ale co jakiś czas, przy odpowiednio niskich zasobach czasowych i wysokiej dozie zmęczenia/wkurzenia zdarza mi się coś takiego popełnić.

Wracając do sedna. Jak sobie z tym radzicie? Może jakieś pluginy do bezbolesnego zaimplementowania drugiego scenariusza?

A może bez sensu w ogóle się zastanawiam i od razu powinienem dorzucić jakiś task do rake’a z załadowaniem tych rzeczy do bazy danych i nie zawracać sobie głowy? (im dłużej nad tym postem siedzę tym bardziej zaczynam sądzić, że właściwie nie powinienem go pisać i tak właśnie zrobić, ale skoro już naklepałem się w klawiaturę to wyślę :wink: )

Próbowałeś zrobić model dziedziczący nie z AR:Base, tylko z ActiveResource? Tam ogólnie jest parę klas do tworzenia railsowych modeli niekoniecznie trzymanych w Twojej bazie, tylko np. w Amazon EC2.

Cholera, o tym nawet nie pomyślałem ;]

Pobawię się, aczkolwiek tak jak na końcu napisałem - coraz bardziej się przychylam do tego, że najlepsze wyjście to po prostu tabele w bazie z danymi wrzuconymi jakimś taskiem.

Pewnie fajnie gdyby było to trzymane w pamięci, a jednocześnie zachowane całę API identyczne z tymi dla modeli w bazie, można więc spróbawać kliknąć sobie coś takiego (pisane na poczekaniu. więc nie daję żadnych gwarancji ;))

[code=ruby]class StaticRecord < ActiveRecord::Base
def self.inherited(klass)
klass.class_eval do |s|
s.table_name = s.to_s.tableize
s.establish_connection(
:adapter => ‘sqlite3’,
:dbfile => ‘:memory’
)
end
end

def self.schema(&schema)
connection.drop_table(table_name) rescue nil
connection.create_table(table_name,&schema)
destroy_all
end

def self.data(data)
data.each do |record|
create record
end
end
end[/code]
i model np:

class Blah < StaticRecord

   schema do |t|
      t.string :name
      t.integer :foo
      t.integer :user_id
   end

   data [
      {:name => 'oeau', :foo => 2},
      {:foo => 23},
      {:name => 'aoeu', :user_id => 1}
   ]

end

No i z takim modelem można sobie robić dowolne relacje.

Bardzo dobre rozwiązanie! :slight_smile:

Sprytnie, nie trzeba się skazywać na robienie z modelu wielkiego kaczora, a problem jest rozwiązany.

Dzisiaj chciałem coś takiego zaaplikować w ramach eksperymentu i natrafiłem na coś o czym wcześniej nie pomyślałem. Tym razem relacja to wiele do wielu, czyli i tak trzeba mieć tabelę łączącą. Problem dotyczył reklamy, która może być targetowana na różne województwa. Jak wiadomo liczba województw nie zmienia się zbyt często, a ich liczba nie jest porażająca, więc pasuje całkiem nieźle do scenariusza podanego na początku.

Myślicie, że warto coś takiego zastosować w takiej sytuacji? Może znacie jakieś zupełnie inne podejście do problemu?

Mi sie wydaje troche przekombinowane. Generuje potencjalne problemy - czy da sie wykonac kwerende cross-database (nie wiem, nie sprawdzalem)?

Jezeli chodzi o wojewodztwa to zostalbym przy klasycznym rozwiazaniu.

W sytuacjach typu role/uprawnienia, czy wzglednie malym, niezmiennym zestawie danych (prostych typu id/name) zastosowalbym pole integer (np roles), enum i pobawil sie operatorami bitowymi.