Przykładowe dane

Mam aplikację, która pozwala użytkownikom na samodzielne zakładanie swojego konta (Devise).
Chciałbym, by po zarejestrowaniu się został wyzwolony automat, który wprowadzi kilka przykładowych firm, towarów, faktur, składników faktur, itd.

Jak “elegancko” to oprogramować?
Wyzwolić jakąś funkcję, która tworzy kilka obiektów firm, towarów, itd?
Wywołać: Rails.application.load_seed *?

np:
load(Rails.root.join(“db”, “example.rb”)) ?

Co proponujecie?

  • mam już jakieś tam dane i wtedy musiałbym z jakiegoś innego katalogu

Napisałem już, że nieaktualne, ale jednak …

Poszukałem trochę w necie i zrobiłem tak:

  1. utworzyłem podkatalog i plik:

    db/seeds/other/example.rb

w nim są zapisy jak w zwykłym seeds.rb

  1. utworzyłem plik

    /lib/tasks/custom_seed.rake

i w nim:

namespace :db do
  namespace :seed do
    Dir[File.join(Rails.root, 'db', 'seeds/other/', '*.rb')].each do |filename|
      task_name = File.basename(filename, '.rb').intern    
      task task_name => :environment do
        load(filename) if File.exist?(filename)
      end
    end
  end
end

i teraz jak wywołuję z linii poleceń:

RAILS_ENV=production rake db:seed:example

to mi pięknie ładuje te dane :slight_smile: …ale nie wiem jak to wywołać wewnątrz aplikacji

jak napisałem

def
  Rails.application.load_seed()
end

to mi ładuje z pliku /db/seeds.rb, a jak chcę podać jakikolwiek argument, to dostaję komunikat:

wrong number of arguments (1 for 0)

Ktoś pomoże “zielonemu”?

W jakim celu ma Ci taka funkcjonalność służyć?

Moim zdaniem przekombinowałeś. Ja bym napisał po prostu klasę która by odpowiadała za to zachowanie i odwołał się do niej z kontrolera przy tworzeniu użytkownika.

Gdy rejestruje się nowy człowiek w programie, to jest dziki i nie wie, co ma z tym programem zrobić (ludzie 40-50 lat).
Dlatego postanowiłem załadować mu jakieś przykładowe dane, by mógł się nimi pobawić.
By mógł poćwiczyć edycję, zobaczyć wydruki, etc…

Ogarnąłem już temat. :smile:

do tego folderu /db/seeds/other przeniosłem moje pliki *csv i utworzyłem dev.rb i prod.rb.
Jak chcę załadować bazę do testów, to wywołuję w terminalu

RAILS_ENV=development rake db:seed:dev

…i pięknie mi ładuje dane potrzebne do developerki (userów przykładowych, itd)
a jak wywołam:

RAILS_ENV=production rake db:seed:prod

…to pięknie ładuje mi wszystko, co potrzebuję do zainicjowania bazy produkcyjnej.

(Tak, wiem, że mógłbym posiłkować się zmienną RAILS_ENV i w jednym skrypcie to mieć, ale ponieważ skrypty dev.rb i prod.rb wywołują inne pliki *.rb, więc teraz jest prościej i czytelniej)

W /db/seeds/seeds.rb napisałem moje przykłady, które mogę “doładować” wydając komendę z terminala:

RAILS_ENV=production(lub development) rake db:seed

i które ładują się też po wywołaniu akcji z aplikacji.

Wywołanie zrobiłem prosto
/models/user.rb

 after_commit :load_example_data, on: :create

  def load_example_data
    Rails.application.load_seed
  end

Wszystko gra i buczy. :smiley:
…Ale dzięki za dobre chęci

P.S.

Też o tym myślałem, a chciałem nauczyć się coś z tym wywoływaniem rake db:seed z aplikacji i przy okazji poprawiłem sobie funkcjonalność ładowania różnych rzeczy w wariantach dev/prod

No ale ten ludzik co się zarejestruje to nie powinien miec “swoich” danych do zabawy? Chyba, że każdy może się zarejestrować i grzebać w tym co inni robią.

Dlatego w tym seeds.rb zrobiłem:

@user = User.last

company.create(
asda
dadad
user: @user)

No tak jak mam w aplikacji

user.rb
has_many :companies

company.rb
belongs_to :user

Teraz każdy po zarejestrowaniu się dostaje swój zestaw danych do tej zestaw

Nie podoba mi się twoje rozwiązanie. Ja bym tego w codereview nie przepuścił. Seedy służą do czegoś innego. One mają wypełnić Ci bazę danych po instalacji systemu niezbędnymi danymi (jak np. konto admina, dane słownikowe). Twój use case to kompletnie nie jest przypadek do użycia seedów.

Absolutnie nie upieram się, że to jakieś wspaniale rozwiązanie.
Uczę się RoR i wdzięczny byłbym gdybyś zechciał podać jakieś konkretne argumenty poza “to nie jest przypadek do użycia seedów”.

Po coś jest to:

Rails.application.load_seed

… i sądziłem, że właśnie do takich rzeczy ma być stosowane.

Pewnie Ty masz rację, a to nie jest żadne wymądrzanie się z mojej strony i rzeczywiście chciałbym poznać argumenty przeciwko takiemu rozwiązaniu.

a ja bym przepuscil :slight_smile:

Zgadzam się z @mentero. Ideą seedów jest właśnie to, o czym wspomniałeś. Swoją drogą w ogóle ten mechanizm jest dość prymitywny. Ja osobiście lubię to, co oferuje seed-fu (https://github.com/mbleigh/seed-fu). IMHO bardzo dobry zamiennik.

Słaby punkt, który sam ujawnił @BSorbus to @user = User.last. Jeżeli dwaj użytkownicy zarejestrują się “w tym samym czasie”, to istnieje prawdopodobieństwo, że jeden z nich nie będzie miał tych danych, a dla drugiego wywołamy dwukrotnie ich ładowanie.

Chociażby samo poleganie na User.last jest w mojej opinii Code Smellem. Jestem w stanie wyobrazić sobie scenariusz gdy masz w aplikacji wyścig. Ruby (MRI) posiada coś takiego jak GIL który nie pozwala mu na wykonanie więcej niż jednej instrukcji Rubiego naraz… Oznacza to że kod nie może być wykonywany równolegle… ale może być współbieżnie! Do tego twój serwer może np. odpalić kilka procesów twojej aplikacji które będą zapisywać do tej samej bazy danych dlatego w momencie gdy dojdziesz do linijki User.last nie masz żadnej gwarancji że jest to ten user o którego Ci chodzi!

Cytując http://edgeguides.rubyonrails.org/active_record_migrations.html#migrations-and-seed-data

However, Rails has a ‘seeds’ feature that should be used for seeding a database with initial data.
(…)
This is generally a much cleaner way to set up the database of a blank application.

Ta współbieżność jest to jakiś argument, aczkolwiek spodziewam się rejestracji użytkownika raz na jakieś…2 tygodnie :slight_smile:

Wyjaśnijcie mi jeszcze w jakim celu jest to

Rails.application.load_seed

skoro w dokumentacji mowa o inicjacji bazy?

Przecież chcąc to wykonać użytkownik (np Admin) winien być już zalogowany, tj ma już założone konto, czyli baza nie jest blank. Wymyślili to po to, by wykonać co? Kiedy?

Jaki jest use case tej funkcjonalności?

Skąd taki wniosek? Kod nie jest wykonywany tylko przez kontrolery ale może być też przez różne workery, taski, skrypty.

Słusznie.

Sądzisz, że właśnie do takich celów to wymyślono?

Sam task rake db:seed nie robi nic innego tylko wywołuje tą właśnie metodę: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/tasks/database_tasks.rb#L245

Myślę, że to jest jej główny cel.