Nadchodzące w ActiveRecord zmiany zwiastują niemałą rewolucje. Oczywiście zanim rewolucja nastąpi czeka nas jeszcze wydanie Rails 3.1 gdzie pojawią się wszystkie ostrzeżenia dotyczące metod które wylecą (a wylatuje ich naprawde dużo). Myśle ze w Rails 3.2 przestanie działać 99 % obecnych pluginów. Nowy system relacji mi sie podoba, przypomina to co prezentował Sequel ale wydaje sie być jeszcze bardziej niskopoziomowy (Sequel zawierał już wiele uproszczeń, tutaj tych uproszczeń nie ma).
Arel::Table.engine = Arel::Sql::Engine.new(ActiveRecord::Base)[/code]
Osobiście bardzo podoba mi się nowy system budowania zapytań. Oto prosty przykład budowania relacji tabeli users z tabelą locations i prostego warunku OR:
users = Table(:users)
locations = Table(:locations)
query = users.join(locations).on(users[:location_id].eq(locations[:id])).where(users[:name].eq('pkondzior').or(users[:name].eq('rgrabowski')))
Okres przejściowy będzie naprawde trudny dla wielu aplikacji, ale myśle ze nowy system usprawni mocno pisanie złożonych zapytań i warunków. Każde takie zapytanie można bez problemu enumerować, dobudowywać kolejne jego części lub po porstu zamienić na sql metodą #to_sql. Jest też możliwość dopiywania opcji poprzez Hash #apply_finder_options jeśli ktoś już naprawde będzie musiał
[quote=PaK]Jeszcze w temacie… przykład użycia nowego API w Model’ach wygląda jak narazie troche topornie:
Location.where(Location.arel_table[:name].eq("Washington")).to_sql
=> SELECT `locations`.* FROM `locations` WHERE (`locations`.`name` = 'Washington')
[/quote]
Ja cały czas właśnie czekam na jakąś sensowną propozycję conditions zrobione w ActiveRecord (tzn. bez instalowania pluginów i ze wsparciem rails core team), które pozwolą na OR bez uciekania do stringów.
Czekam na to samo… i zapowiada sie obiecująco. Perspektywa Arel wygląda to przejrzyście:
users = Table(:users)
users.project(users[:id]).where(users[:name].eq("pkondzior").or(users[:name].matches("%grabowski%")).and(users[:active].eq(true))).to_sql
=> "SELECT `users`.`id` FROM `users` WHERE ((`users`.`name` = 'pkondzior' OR `users`.`name` LIKE '%grabowski%') AND `users`.`active` = 1)"
Ale ActiveRecord ma to troche dziwnie obudowane:
User.where(User.arel_table[:name].eq("pkondzior").or(User.arel_table[:name].matches("%grabowski%")).and(User.arel_table[:active].eq(true))).to_sql
=> "SELECT `users`.* FROM `users` WHERE (((`users`.`name` = 'pkondzior' OR `users`.`name` LIKE '%grabowski%') AND `users`.`active` = 1))"
Natomiast naprawde topornie jest obecnie przepisywany Hash na Arel:
User.where(:name => 'pkondzior')
Przechodzi w:
User.where(Arel::Attribute.new(User.unscoped, :name).eq("pkondzior")).to_sql
=> "SELECT `users`.* FROM `users` WHERE (`users`.`name` = 'pkondzior')"
Nie mam pojęcia dlaczego obecnie jest to generowane właśnie w taki sposób. Chyba aktualnie nie mają jeszcze pomysłu jak udostępnić nowe API Arel w ActiveRecord
[quote=PaK]User.where(:name => 'pkondzior')
Przechodzi w:
User.where(Arel::Attribute.new(User.unscoped, :name).eq("pkondzior")).to_sql
=> "SELECT `users`.* FROM `users` WHERE (`users`.`name` = 'pkondzior')"
Nie mam pojęcia dlaczego obecnie jest to generowane właśnie w taki sposób. Chyba aktualnie nie mają jeszcze pomysłu jak udostępnić nowe API Arel w ActiveRecord[/quote]
Ale syf. Przypominają mi się czasy php i propela. Jeśli coś takiego miałoby zostać to… nie wiem co powiedzieć. Zaczynam wierzyć w koniec świata w 2012 roku ;).
[quote=radarek][quote=PaK]User.where(:name => 'pkondzior')
Przechodzi w:
User.where(Arel::Attribute.new(User.unscoped, :name).eq("pkondzior")).to_sql
=> "SELECT `users`.* FROM `users` WHERE (`users`.`name` = 'pkondzior')"
Nie mam pojęcia dlaczego obecnie jest to generowane właśnie w taki sposób. Chyba aktualnie nie mają jeszcze pomysłu jak udostępnić nowe API Arel w ActiveRecord[/quote]
Ale syf. Przypominają mi się czasy php i propela. Jeśli coś takiego miałoby zostać to… nie wiem co powiedzieć. Zaczynam wierzyć w koniec świata w 2012 roku ;).[/quote]
Warto chyba nadmienić, że ten kod to “niskopoziomowy” framework Arel z którego ma korzystać ActiveRecord więc użytkownik Rails’ów nieczęsto będzie musiał bezpośrednio z niego korzystać (w domyśle tak często jak teraz korzysta z find_by_sql np.) IMO chodzi o wyeliminowanie budowania zapytań sklejając ze sobą stringi, które jest obecnie w kodzie AR opierając framework AR na frameworku Arel - czy coś pomieszałem ? Wg. mnie będzie lepiej o ile jakimś dziwnym trafem nie zostaniemy zmuszeni do korzystania z API przypominającego JPA (patrząc na to co się dzieje z Rails 3 i w którą stronę wszystko zmierza jestem przekonany, że nie zostaniemy zmuszeni )
Dokładnie tak. Wszystko co do tej pory można było robic z find() będzie nadal dostępne pod postacią where() z tą różnicą że będzie to tłumaczone na zapytanie dopiero w bibliotece ARel a nie tak jak do tej pory w ActiveRecord. Już teraz kod AR jest w owiele lepszym staniem IMHO po podłączeniu tego ARel, AR 3.2 będzie już zupełnie innym ActiveRecord.
Te przykłady które podałem to nie jest ZALECANE stosowanie, to jest coś co ja wyciągnołem z kodu żeby pokazać jak to mniejwięcej teraz działa. Ja osobiście mam nadzieje ze nowe API podniesie troche jakość złożonych zapytań i edge cases przestaną wyratać jak grzyby po deszczu No ale pewnie jestem tutaj zbyt dużym optymistą…
[quote=radarek][quote=PaK]User.where(:name => 'pkondzior')
Przechodzi w:
User.where(Arel::Attribute.new(User.unscoped, :name).eq("pkondzior")).to_sql
=> "SELECT `users`.* FROM `users` WHERE (`users`.`name` = 'pkondzior')"
Nie mam pojęcia dlaczego obecnie jest to generowane właśnie w taki sposób. Chyba aktualnie nie mają jeszcze pomysłu jak udostępnić nowe API Arel w ActiveRecord[/quote]
Ale syf. Przypominają mi się czasy php i propela. Jeśli coś takiego miałoby zostać to… nie wiem co powiedzieć. Zaczynam wierzyć w koniec świata w 2012 roku ;).[/quote]
Dramatyzujesz pokazałem tylko jak obecnie AR składa zapytania Jeśli tylko znajdą sposób na łatwiejsze przedstawianie tych atrybutów ARel w kodzie AR to nie będzie tak źle. Jeśli byś wzioł teraz Ruby TreeParser to napisanie zajebiste DSL’a na bazie czegoś takiego staje sie 100x prostrze To samo tyczy sie każdej innej biblioteki typu Squirrel, Searchlogic które zazwyczaj wymyślały swoje mechanizmy łączenia kodu SQL od nowa.
Przykład użycia nowego API Arel z poziomu Modelu
Model#arel_table, Model#arel_engine nie należa jeszcze do oficjalnego API ActiveRecord, to samo tyczy sie chyba Model#unscoped. Natomiast Arel::Attribute.new(Model#unscoped, :column_name) to już API ARel z wykorzystaniem ActiveRecord, faktycznie troche nieprecyzyjny byłem wcześniej moja wina.
Zaraz będe testował - sama idea AREL wydaje się trafiona w 10 - trzeba bedzie tylko pewnie poczekać aż dograją na tip -top składnie no i troche się pomęczyć przy przestawieniu na nowy zapis
Nie wiem czym tu się jarać. Znacznie większe możliwości ma Sequel. M.in. ma ładniejszy i potężniejszy DSL (sumy logiczne to żaden tam problem), ma prepared statement (znacznie przyśpiesza niektóre operacje i automatycznie znika możliwość SQL injection), ma bardzo wygodną metodę .sql którą można dokleić w dowolnym etapie budowania zapytania aby wyświetlić jaki ostateczny SQL zostanie stworzony (i to się wyświetli bez jakiegokolwiek łączenia się z bazą!). Ma też eager preloading, transakcje, sharding i inne zaawansowane mechanizmy bazy relacyjnej itp. itd.
Jarek, ale wszyscy śledzący blog Yehudy i komentarze nań już wiedzą, że jesteś niezbyt pozytywnie nastawiony do Rails 3 od strony nawet samej idei, nie wspominając o poszczególnych rozwiązaniach
Prawdopodobnie tym, że jedna z najpopularniejszych (żeby nie było flame’u: najpopularniejsza != najlepsza) bibliotek do obsługi bazy danych w Ruby dostanie genialne API i jest gruntownie zrefaktoryzowana. Większość osób tutaj po prostu już używa ActiveRecorda i przesiadka na innego ORMa będzie trudniejsza niż na kolejną wersję AR. W pierwszym przypadku musisz od razu przepisać cały kod, w drugim powoli poprawiać wszystkie deprecation warnings.