Mam mniej wiecej taki kawalek kodu, ktory wybiera wydarzenia wraz z typami uzytkownika:
Event.joins(“left join bets on bets.event_id = events.id and bets.user_id = #{current_user.id}”)
Moj problem polega na tym, ze pozniej w widoku odwolujac sie do event.bets idzie ponownie zapytanie do bazy danych, oczywiscie nie uwzgledniajac tez uzytkownika.
Jak tego uniknac i rozwiazac to w ladny sposob?
Dzieki za wszelka pomoc!
Do załadowania relacji do obiektu służy includes (które technicznie zrobi dwa zapytania), albo dostępne w rails 4 preload / eager_load. joins służy tylko i wyłącznie do tworzenia warunków (w select nie zostanie uwzględnione).
Includes decyduje czy zostanie zrobiony left join czy wywolane drugie zapytanie, jesli chcemy jasno okreslic zachowanie wtedy uzywamy preload lub eager_load.
Zalozmy jednak, ze uzyje polecanego includes. W tym przypadku zbudowane zostanie zapytanie z left joinem, ktore pobierze WSZYSTKIE bets dla eventu.
Ja chce ta asocjacje ograniczyc do konkretnego uzytkownika, a zatem dokladajac warunek where(“bets.user_id = ?”, current_user) spowoduje, ze tylko events, ktore maja juz swoj typ zostana pobrane.
to zapytanie bedzie wygladac tak:
select * from events left join bets on bets.event_id = events.id where bets.user_id = ?
mi bardziej chodzi o cos takiego:
select * from events left join bets on bets.event_id = events.id and bets.user_id = ?
mam nadzieje, ze teraz jest to bardziej zrozumiale
to i tak bede mial takie samo zapytanie, tzn. bets.user_id znajdzie sie w WHERE, co ogranicza mi Events, do tych ktore uzytkownik juz wytypowal. porownaj prosze moje dwa zapytania z posta wyzej i zobacz czym sie roznia.
Tak na pierwszy rzut oka wydaje mi sie, ze problem bedzie jesli current_user nie typowal eventu, a typowali inni (w bets beda typy innych uzytkownikow) lub ani current user ani nikt inny nie typowal (wtedy event w ogole sie nie pokaze)
Ale dlaczego? Przecież jest or, a to co po or w ogóle się nie odnosi do żadnego user. Nie mam struktury twojej bazy, więc najprościej będzie jak sam sobie to przetestujesz.
select * from events left join bets on bets.event_id = events.id WHERE bets.user_id = ? OR bets.event_id = events.id;
i taki przyklad, co sie stanie jesli w bets nie ma zadnych wpisow, a masz kilka eventow?
zwrocne zostana tylko te ktore juz maja jakis wpis w tabeli bets
Czyli ty chcesz wszystkie events oraz wszystkie bets które mają bets.event_id = events.id and bets.user_id = ?
To tak się chyba w railsach nie da tego zrobić, nie wiem czy jest jakiś ORM który na to pozwala Bo ORM’y są sprytne ale chyba nie na tyle by każde dowolne pytanie SQL przerobić na obiekty. Sam przerabiałem inny problem ale też o optymalizację ilości pytań chodziło i albo robisz jedno zapytanie którego wynik zajmie dużo pamięci i podczas iteracji po rekordach sprawdzasz warunki, albo dostajesz dokładnie te obiekty które chcesz bez zbędnego narzutu pamięci, tylko wtedy więcej razy trzeba odpytać bazę danych.
Może czas przemyśleć samą logikę. Zastanowić się po co Ci Events.all oraz Bets.where(bets.user_id = current_user.id) w jednym zapytaniu. Najprościej chyba wyjść od tego jakie obiekty potrzebujesz do pracy. Różnica pomiędzy jednym pytaniem a dwoma, nie jest jeszcze taka straszna.