2013-06-28 17 views
6

Pracuję nad uaktualnieniem istniejącej aplikacji Rails 3.2 do wersji 4.0. Wpadłem jednak na ceglaną ścianę.Railsy 4 .order() zostają zmanipulowane przy pomocy JOINS

Mam trzy modele: klienta, witryny i kontaktu. Witryny to fizyczne lokalizacje należące do klienta, a klient może mieć wiele witryn. Kontakty to osoby należące do jednej lub wielu witryn. Tak więc klient może mieć wiele kontaktów za pośrednictwem witryn.

Klienci:

class Client < ActiveRecord::Base 

    has_many :sites, -> { where(:sites => {:deleted => false}).order(:name => :asc) }, :dependent => :destroy 
    has_many :contacts, -> { order(:lastname => :asc) }, :through => :sites 

end 

Strony:

class Site < ActiveRecord::Base 

    belongs_to :client 
    has_and_belongs_to_many :contacts 

end 

Kontakt:

class Contact < ActiveRecord::Base 

    has_and_belongs_to_many :sites 

end 

Problem polega na tym, że kiedy u se Client.find(1).contacts, dostaję ActiveRecord::StatementInvalid wyjątek:

Mysql2::Error: Unknown column 'contacts.name' in 'order clause': SELECT contacts .* FROM contacts INNER JOIN contacts_sites ON contacts . id = contacts_sites . contact_id INNER JOIN sites ON contacts_sites . site_id = sites . id WHERE sites . client_id = 5 AND sites . deleted = 0 ORDER BY contacts . lastname ASC, contacts . name ASC

Jest problem: nie mam pojęcia, gdzie ORDER BY ... `contacts`.`name` ASC pochodzi. Tabela kontaktów nie ma kolumny z nazwą, ale Rails próbuje ją posortować i nie wiem, skąd się bierze i jak ją usunąć. ORDER BY `contacts`.`lastname` ASC jest łatwe; pochodzi z modelu klienta.

Te relacje działały bezbłędnie w wersji 3.2, ale teraz wyrzuć ten wyjątek w wersji 4.0.

UPDATE: To zostało podkreślone, że dodatkowy ORDER BY ... `contacts`.`name` ASC pochodzi z pierwszej has_many w modelu Klienci. Jednak intencją było uporządkowanie Stron, a nie Kontaktów. Próbowałem go zmienić na .order('sites.name' => :asc), a SQL skarżył się, że nie ma kolumny o nazwie sites.sites.name. Wygląda więc na to, że przy korzystaniu z :through => z has_many, klauzula zamówienia zostaje zmanipulowana.

Próbowałem usunąć .order() i używając default_scope -> { order(:name => :asc) } w modelu Witryny, ale dostałem dokładnie ten sam błąd, co pierwotnie zgłoszono.

Odpowiedz

9

Rozwiązanie jest proste. Zamiast używać .order(:column_name => :asc), zmieniłem go na .order('column_name ASC'), a błąd zniknął, uzyskując oczekiwany wynik. Pierwotnie miałem to drugie, ale wdrażałem pierwsze w ramach mojej aktualizacji Rails 3 -> 4 i widziałem taką konwencję w RailsCastach i innych dokumentach.

Jest to również konieczne w przypadku korzystania z .joins() i porządkowania według połączonych kolumn tabeli, jak to później stwierdziłem. Ma to sens, ponieważ asocjacja również wykorzystuje sprzężenia.

1

Musisz być zmęczony, właśnie tam w drugiej linii (Client modelu), masz order(:name=> :asc), powinno być:

class Client < ActiveRecord::Base 

    has_many :sites, -> { where(:sites => {:deleted => false}).order(:lastname => :asc) }, :dependent => :destroy 
    has_many :contacts, -> { order(:lastname => :asc) }, :through => :sites 

end 
+0

Nie OP, ale założyłem, że kolejność odnosi się do tabeli stron, która miałaby kolumnę nazwy (ale nie kolumnę nazwiska). –

+0

Święta krowa, masz rację. Wyjąłem '.order()', a zapytanie zadziałało. Ale intencją było uporządkowanie Stron, a nie Kontaktów, jak słusznie ocenił Eric. Jako test zmieniłem go na '.order ('sites.name' =>: asc) 'i został zgłoszony nowy wyjątek, narzekając, że" sites.sites.name "nie istnieje. Tak więc, tak czy inaczej, łamane jest '.order()'. –

+0

Dziwne, masz rację. @EricPalace, założyłem * z serca *, że chodziło o 'Klienta'. Ostatnim razem, gdy musiałem zamówić podobną listę, w końcu użyłem ': conditions => [" joined_table.some_column ... "z tego powodu –

Powiązane problemy