11

Jak mogę podać nazwę aliasu dla np. includes()? Obserwowany jest podana:Szyny 4 - jak nadać nazwy aliasom włączeń() i sprzężeń() w zapytaniach aktywnych rekordów

  • użytkownika: aktywny modelu rekord
  • Student: aktywny modelu rekord, dziedziczy z Użytkownikiem (STI)
  • Nauczyciel: aktywny modelu rekord, dziedziczy z Użytkownikiem (STI)
  • Projektu : Active record modelowe

Oto kilka przykładów:

Pierwszy przypadek (więcej stowarzyszenia STI)

Project.all.includes(:students, :teachers).order('teachers_projects.name ASC') # order on teachers 
Project.all.includes(:students, :teachers).order('users.name ASC') # order on students 

Rails używa automatycznie alias nazwy teachers_projects dla :teachers w SQL. Jak mogę to zastąpić, aby móc używać w języku SQL nazwy aliasu teachers zamiast teachers_projects? :students otrzymuje nazwę aliasu users.

Przykłady te nie:

Project.all.includes(:students, :teachers).order('teachers.name ASC') 
Project.all.includes(:students, :teachers).order('students.name ASC') 
Project.all.includes(:students, :teachers).order('students_projects.name ASC') 

drugim przypadku (jedno stowarzyszenie STI)

Jeśli użyć tylko :students (bez :teachers) w metodzie includes(), szyn wykorzystuje alias STI nazwa klasy podstawowej users (bez dołączonej _projects) dla :students:

Project.all.includes(:students).order('users.name ASC') # order on students 

Przykład ten nie powiedzie się:

Project.all.includes(:students).order('students.name ASC') 
Project.all.includes(:students).order('students_projects.name ASC') 

PYTANIE

może istnieć coś takiego:

Project.all.includes(:students).alias(students: :my_alias) 

SZYNY alias Tracker

https://github.com/rails/rails/blob/v4.2.0/activerecord/lib/active_record/associations/alias_tracker.rb#L59

BADANIE APP

https://gist.github.com/phlegx/add77d24ebc57f211e8b

https://github.com/phlegx/rails_query_alias_names

+0

Czy wypróbowałeś coś w stylu Project.joins (: nauczyciele). Gdzie ...... – Leon

+0

Jeśli otrzymasz odpowiedź, proszę _notify_ me, abym mógł zobaczyć odpowiedź. –

+0

Czy możesz również podać Gist, aby pokazać definicje modeli, migracje i niektóre dane. Czy mogę skonfigurować i spróbować zrobić? –

Odpowiedz

1

mam zamiar zrobić kolejne podejście do tej kwestii: zamiast próbować kontrolować nazwy alias o zapytaniach z .alias metoda, dam Railsom/Arelowi to zająć i po prostu wyglądam na poprawną nazwę tabeli (aliasowaną lub nie) podnosząc ją, gdy jest ona potrzebna w danym zakresie.

Dodaj tę metodę pomocniczą do swojego modelu, z której będzie można nawiązać połączenie z zakresu, aby sprawdzić, czy zakres jest używany w ramach JOIN, który ma alias tabeli (wiele złączeń w tym samym stole), lub jeśli z drugiej strony zakres nie ma aliasu dla nazwy tabeli.

def self.current_table_name 
    current_table = current_scope.arel.source.left 

    case current_table 
    when Arel::Table 
    current_table.name 
    when Arel::Nodes::TableAlias 
    current_table.right 
    else 
    fail 
    end 
end 

Wykorzystuje obiekt current_scope jako obiekt podstawowy do wyszukiwania tablicy arel. Dzwonię pod numer source na ten obiekt, aby uzyskać Arel::SelectManager, który z kolei da ci bieżącą tabelę na #left. Dostępne są dwie opcje: albo masz tam Arel::Table (bez aliasu, nazwa tabeli jest na #name) lub masz Arel::Nodes::TableAlias z aliasem na jego #right.

Teraz trzeba tylko użyć tego na swoim order sprawozdania (nietestowane):

Project.all.includes(:students, :teachers).order("#{current_table_name}.name ASC") 
Project.all.includes(:students, :teachers).order("#{current_table_name}.name ASC") 
Project.all.includes(:students, :teachers).order("#{current_table_name}.name ASC") 

Podobne pytania:

+0

Podałem odpowiedź w jednym z pytań, które polecasz. Możesz to nieco uprościć. 'current_scope.table' jest takie samo jak' current_scope.arel.source.left' (być może nie w Railsach <4.2.2?). A jeśli użyjesz składni "Arel", "nie musisz uzyskiwać nazwy gołego stołu. Na przykład. użyj go w ten sposób: 'at = current_scope.table', a następnie' at [: the_column_name] .asc' i 'Arel' zrob wszystko dla ciebie. (być może musisz dodać '.to_sql', ale myślę, że Rails sobie z tym poradzi) – 244an

2

Arel nie mamy metodę aliasu.

student_alias = Student.arel_table.alias(:my_student_table_alias) 

Zastrzeżenie: będzie to wymagało użycia jeszcze bardziej ręcznie wykonanego Arel i ręcznego łączenia. A łączenie się w Arel może trochę skomplikować, jeśli nie jesteś do nich przyzwyczajony.

student_alias_join = student_alias.create_on(
    Project.arel_table[:primary_key].eq(student_alias[:project_id]) 
) 

Project.joins(
    Project.arel_table.create_join(
    student_alias, student_alias_join, Arel::Nodes::OuterJoin 
) 
).order(...) 

Coś takiego powinno wystarczyć. Oczywiście umieszczenie tego w pewnej metodzie Class z :my_student_table_alias jako parametrem sprawiłoby, że byłby on bardziej uporządkowany i wielokrotnego użytku, ponieważ wyglądałoby to trochę niechlujnie w kontrolerze.