2013-03-20 12 views
7

jestem chętny ładowanie modelu obiektu z jego zrzeszonychSzyny zachłanne ładowanie i gdzie klauzula

user= User.includes(:posts).find(1) 

ale w niektórych punktach w kodzie chciałbym zrobić coś takiego:

user.posts.where(:topic => "x") 

Ale to tylko ponownie uruchamia kwerendę ponownie. Zamiast tego pomyślałem, że zrobię to:

user.posts.select{|post| post.topic == "x" } 

To nie powoduje ponownego uruchomienia zapytania. Ale mam kilka pytań.

Po pierwsze, czy jest to właściwy sposób na zrobienie tego?

Po drugie, jestem nieco zdezorientowany tym, co wybiera w tym przypadku. Ponieważ po uruchomieniu ostatniej linii, nawet gdy nie korzystałem z funkcji include, po raz pierwszy uruchamia ona zapytanie, a następnie, jeśli uruchomię ją ponownie, to nie jest. Czy jest tam coś w rodzaju buforowania? Ponieważ, gdy używam klauzuli where, uruchamia ona zapytanie za każdym razem.

Dziękuję.

Odpowiedz

14

select to metoda Rubinowa na Enumerable. Przy pierwszym uruchomieniu

user.posts.select{|post| post.topic == "x" } 

wszystkie Post instancje dla user „s :posts stowarzyszenie zostanie załadowany z bazy danych do pamięci; konkretnie do obiektu kolekcji ActiveRecord. select jest wywoływana w tej kolekcji, odfiltrowując wszystkie instancje Post w kolekcji za pomocą atrybutu :topic, który jest inny niż "x".

Ponowne uruchomienie powyższej linii nie spowoduje ponownego wysłania zapytania do bazy danych, ponieważ już załadowano do pamięci posts.


Kiedy zrobić includes jak poniżej

user= User.includes(:posts).find(1) 

to będzie chętny obciążeniu :posts relacja dla każdej instancji User zwrócony (w tym przypadku, pojedyncza User gdzie :id jest 1). Masz teraz wszystkie instancje Post załadowane do pamięci zgodnie z opisem w poprzedniej sekcji powyżej.

Jeśli następnie zrobić coś

user.posts.where(:topic => "x") 

jesteś teraz mówienie szyny do prowadzenia nowy zapytanie przeciwko Post, tym razem znalezienie wszystkich Post przypadki :topic jest "x" i gdzie :user_id jest :id z user. where nie działa jak "filtr" w kolekcji ARel w pamięci.


  • Jeśli chcesz uniknąć kolejnego maila, że ​​złe, select jest dobrym sposobem, aby filtrować zestaw wyników w pamięci.
  • Można uruchomić odniesienia dowiedzieć się, jakie jest szybsze:
    1. zapytań db i odbudową populacji inną kolekcję AREL do pamięci
    2. iteracji nad enumberable w pamięci i działa filtr z Ruby
  • Jeśli nie musisz wszystkie związane :posts dla user, można łatwo to ten w pierwotnym zapytaniu

    user.includes(:posts).where("posts.topic = ?", 'x') 
    
+0

To jest idealne, dzięki! – user1069624