2016-01-06 15 views
5

Mam pewien kod, który generuje problem z bazą danych N + 1.Rails 4: mały problem N + 1 dla strony bez zawartości

Problem pojawia się tylko wtedy, gdy strona jest w pamięci podręcznej. Gdy strona zostanie zapisana w pamięci podręcznej, dodanie wartości .includes spowoduje niepotrzebne wywołanie bazy danych. Zastanawiam się, jak obejść ten problem.

mój applicaiton_helper.rb zawiera następujące elementy:

module ApplicationHelper 
    def by(article) 
    "By #{article.username} on #{article.created_at.strftime('%B %e, %Y')}" 
    end 
end 

mój article.rb zawiera:

class Article < ActiveRecord::Base 
    belongs_to :user 

    def username 
    user.username 
    end 
end 

i mój articles_controller.rb zawiera:

class ArticlesController < ApplicationController 
    def index 
    @articles = user_signed_in? ? Article.all : Article.all.published.limit(13) 
    end 
end 

Metodą, o której mowa, jest metoda username, która wywołuje model użytkownika. Jak wspomniano powyżej, gdy strona nie została jeszcze buforowana, powoduje to, że metoda pomocnika by(article) wywołuje ciągłe wywołania do modelu użytkownika bez nadmiernego ładowania. Ponieważ jednak buforuję swoje opinie, ta nieefektywność występuje tylko raz. Jeśli zmienię mojego articles_controller.rb na następujące kwestie:

class ArticlesController < ApplicationController 
    def index 
    @articles = user_signed_in? ? Article.all.includes(:user) : Article.all.published.limit(13).includes(:user) 
    end 
end 

N + 1 problem znika na pierwszej stronie obciążenia, ale potem pojawia się niepotrzebnego .includes na przeładowania strony.

Każdy pomysł, jak mogę naprawić ten mały błąd?

Dzięki!

+0

To nie pasuje do zmysłu. 'includes' powinno użyć jednego zapytania, aby załadować użytkowników. Coś innego prawdopodobnie się dzieje. Czy włączenie testowania pamięci podręcznej umożliwia testowanie tego? – Mohamad

+0

Mam wrażenie, że jest to wywołanie 'article.username', powodujące to wyszukiwanie w modelu za pomocą dodatkowego żądania. – jbehrens94

+0

@Mohamad Właśnie wyłączyłem buforowanie w rozwoju. Teraz ciągle otrzymuję wiadomość od Bulleta mówiąc: '' 'Zapytanie N + 1 wykryte Artykuł => [: użytkownik] Dodaj do wyszukiwarki:: zawiera => [: użytkownik] N + 1 Stos wywołań metod zapytania ~ /mojapp/app/models/article.rb:64:in 'username''''' – DaniG2k

Odpowiedz

0

jakoś to rozwiązał mój problem:

class Article < ActiveRecord::Base 
    belongs_to :user 
    delegate :username, to: :user 
end 

Więc ja po prostu delegowania połączenia nazwy użytkownika na artykuł do modelu użytkownika. Piękne, czyste i psikus: bullet już nie narzeka.

0

Właśnie doszedłem do szalonego rozwiązania: mógłbyś sprawdzić, czy fragment w pamięci podręcznej istnieje w kontrolerze. Problem polega jednak na tym, że Railsy automatycznie dodają plik skrótu do klucza pamięci podręcznej. Więc moje „rozwiązanie”: zmiana buforowanie sposób czymś jak to

# in your view: 
<% cache 'foo', skip_digest: true do %> 
    contents 
<% end %> 

A następnie w kontrolerze można sprawdzić, czy fragment jest już w pamięci podręcznej:

def index 
    if fragment_exist?('asd') 
    @articles = user_signed_in? ? Article.all : Article.published.limit(13) 
    else 
    @articles = user_signed_in? ? Article.all.includes(:user) : Article.published.limit(13).includes(:user) 
    end 
end 

Oczywiście wyłączenie digest nie jest bardzo dobre rozwiązanie: rozwiązując bieżący problem, dodaje nowy. Ale działa :)

Nie mogłem znaleźć sposobu na uzyskanie podsumowania w kontrolerze, ale w każdym razie myślę, że byłoby to przesadą dla tak małego problemu, jak jednorazowy N + 1. A jeśli przeszkadza Ci tylko ostrzeżenie bullet, możesz turn them off dla konkretnej akcji.

+0

Dzięki za to. Naprawdę myślę, że problem może dotyczyć Bullet, a nie z użyciem '.includes (: user)'. Poinformuję o tym i zobaczę, co myślą. – DaniG2k

+0

Co do mnie, 'bullet' ma w tym przypadku rację, ponieważ kiedy strona jest zbuforowana,' zawiera 'jest niepotrzebne. Ale skoro już wiesz o tym i jest to pożądane zachowanie, możesz wyłączyć ostrzeżenie. – hedgesky

Powiązane problemy