Funkcje Rails 6: Co nowego i dlaczego ma to znaczenie

Opublikowany: 2022-03-11

Jak większość fanów Ruby on Rails może być świadoma, Rails 6 nadejdzie wkrótce i przyniesie wiele niecierpliwie oczekiwanych funkcji i zmian. Celem tego artykułu jest zapoznanie Cię z kluczowymi funkcjami, które zostały dodane do Rails 6 i nakreślenie, w jaki sposób mogą one pomóc ulepszyć Twoje aplikacje, oszczędzając w ten sposób cenny czas programowania.

Na początek pamiętaj, że Railsy 6 wymagają Ruby 2.5+ i zaktualizowanych baz danych. Upewnij się więc, że masz plan odpowiedniej aktualizacji systemów, na wypadek, gdyby jeszcze tego nie zrobiłeś.

Więc jakie są te nowe funkcje? Oto krótkie podsumowanie kluczowych funkcji Rails 6, z których prawdopodobnie będziesz korzystać w przyszłości:

Testowanie w Rails 6

Jako profesjonalni programiści Ruby on Rails, staramy się zapewnić maksymalne pokrycie naszego kodu. Jednak testowanie staje się żmudną czynnością, gdy nasze przypadki testowe stają się „ciężkie” i musimy czekać kilka minut, a nawet godzin, aby je wykonać.

Testowanie równoległe

Cóż, Rails 6 ma tutaj odpowiedź. Dodano metodę parallelize do ActiveSupport::TestCase , która pozwala na zrównoleglenie zestawu testów z procesami rozwidlonymi.

Więc to, co musisz zrobić, aby zrównoleglić procesy dla swoich testów, to dodać to do swojego test_helper.rb :

 parallelize(workers: 2)

Alternatywnie możemy zastąpić nasze poprzednio używane polecenia do uruchamiania testów. Na przykład, bin/rails test OR bin/rspec spec można teraz zastąpić przez PARALLEL_WORKERS=15 rails test OR PARALLEL_WORKERS=15 rspec spec .

W związku z tym możesz zmienić polecenia uruchamiania zestawów testowych na różnych platformach CI, takich jak Travis, Gitlab, CircleCI i inne.

Istnieją również haki, gdy każdy proces jest tworzony/niszczony, których można użyć w następujący sposób:

 class ActiveSupport::TestCase parallelize_setup do |worker| # setup databases end parallelize_teardown do |worker| # cleanup databases end parallelize(workers: :number_of_processors) end

Uwaga: Jeśli chcesz dowiedzieć się więcej, możesz zapoznać się z Przewodnikami po Rails, aby uzyskać dodatkowe informacje.

Testowanie kabli akcji

Skoro mówiliśmy o wydajnym testowaniu, zrozummy również, jak poprawił się Action Cable, jedna z najważniejszych cech Railsów 5. Teraz możliwe jest testowanie Action Cable na dowolnym poziomie: połączeń , kanałów i emisji .

Testy połączeń mają na celu sprawdzenie, czy identyfikatory połączeń są przypisane prawidłowo lub czy wszelkie nieprawidłowe żądania połączenia są odrzucane:

 class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase test "connects with params" do connect params: { user_id: 42 } OR cookies.signed[:user_id] = "42" connect assert_equal connection.user_id, "42" end test "rejects connection without params" do assert_reject_connection { connect } end end

Testy kanałów można napisać, aby sprawdzić, czy użytkownicy mogą subskrybować kanały, a kanał ma strumień:

 class ChatChannelTest < ActionCable::Channel::TestCase test "subscribes and stream for room" do # Simulate a subscription creation by calling `subscribe` subscribe room: "15" # You can access the Channel object via `subscription` in tests assert subscription.confirmed? assert_has_stream "chat_15" end end

Transmisję do kanałów można przetestować w następujący sposób:

 # app/jobs/chat_relay_job.rb class ChatRelayJob < ApplicationJob def perform_later(room, message) ChatChannel.broadcast_to room, text: message end end # test/jobs/chat_relay_job_test.rb require 'test_helper' class ChatRelayJobTest < ActiveJob::TestCase include ActionCable::TestHelper test "broadcast message to room" do room = rooms(:all) assert_broadcast_on(ChatChannel.broadcasting_for(room), text: "Hi!") do ChatRelayJob.perform_now(room, "Hi!") end end end

Uwaga: Więcej wskazówek dotyczących testowania można znaleźć tutaj.

Wstawianie i wkładanie zbiorcze

W pewnym momencie wszyscy musimy wstawić wiele rekordów za jednym razem i znaleźliśmy wiele obejścia tego problemu. Cóż, Railsy 6 mają nową metodę po wyjęciu z pudełka — insert_all , podobną do update_all .

Nie uruchomi żadnych wywołań zwrotnych i wykona pojedyncze zapytanie SQL. Istnieje dodatkowa metoda upsert_all , która pozwala na użycie operacji upsert, która jest widoczna w wielu nowoczesnych bazach danych, takich jak Postgres. Teraz możesz zmniejszyć liczbę zapytań o wstawianie i zoptymalizować swój kod. Pożegnaj się także z wcześniej używanymi perełkami, takimi jak activerecord-import .

Za pomocą tych metod jest przygotowywane pojedyncze zapytanie INSERT SQL, a pojedyncza instrukcja SQL jest wysyłana do bazy danych bez tworzenia instancji modelu lub wywoływania wywołań zwrotnych i walidacji Active Record. Możliwe jest również zdefiniowanie kryteriów, gdy klucz podstawowy — unikatowe indeksy lub unikatowe ograniczenia są naruszane z opcją pominięcia lub uruchomienia zapytań upsert.

Oto kilka przykładów:

 result = Article.insert_all( [ { id: 1, title: 'Handling 1M Requests Per Second', author: 'John', slug: '1m-req-per-second' }, #...snip... ], returning: %w[ id title ], unique_by: :index_articles_on_title_and_author ) result = Article.upsert_all( [ { id: 1, title: 'Handling 1M Requests Per Second', author: 'John', slug: '1m-req-per-second' }, { id: 1, .... }, # duplicate 'id' here { id: 2, .... }, { id: 3, .... }, # duplicate 'title' and 'author' here { id: 4, .... }, { id: 5, .... }, # duplicate 'slug' here { id: 6, .... } ] )

Metody insert , insert! a upsert to otoki wokół insert_all , insert_all! i upsert_all , odpowiednio.

Uwaga: istnieje bardzo dobry artykuł, który omawia zapytania zbiorcze w odniesieniu do różnych baz danych. Jeśli potrzebujesz dodatkowych informacji, koniecznie sprawdź to.

Przełączanie między wieloma bazami danych

Jedną z głównych cech, które doceni wiele dużych aplikacji, jest ta: Railsy 6 w końcu dodały obsługę wielu baz danych dla Twojej aplikacji, wbudowaną i gotową do działania, po wyjęciu z pudełka!

Schemat przełączania między bazami danych

Oczywiście wybór projektu nadal należy do Ciebie, niezależnie od tego, czy chcesz podzielić swoją aplikację na wiele mikrousług, z których każda ma osobną bazę danych, czy też wybrać trasę monolityczną lub dodać kilka replik do odczytu dla swojej aplikacji.

Jednak możliwość zrobienia tego w tak łatwy sposób może zaoszczędzić dużo czasu na froncie programistycznym.

A więc tak będzie wyglądał twój nowy plik database.yml :

 development: primary: database: my_primary_db user: root primary_replica: database: my_primary_db user: ro_user replica: true animals: database: my_animals_db user: root animals_replica database: my_animals_db user: ro_user replica: true

Oto ciekawe sposoby określania sposobu przełączania się do różnych baz danych:

 class AnimalsModel < ApplicationRecord self.abstract_class = true connects_to database: { writing: :animals_primary, reading: :animals_replica } end class Dog < AnimalsModel # connected to both the animals_primary db for writing and the animals_replica for reading end

Oto oficjalna strona GitHub, która jest również dobrze udokumentowana. Osobiście nie mogę się doczekać możliwości shardingu bazy danych w przyszłych aktualizacjach Railsów (coś w tym rodzaju).

Skrzynka pocztowa akcji

Kolejną interesującą cechą Rails 6 jest dodanie Action Mailbox, która dodaje możliwość kierowania przychodzących wiadomości e-mail do kontrolera, takich jak skrzynki pocztowe do przetwarzania w Rails.

Skrzynka Action Mailbox zawiera ingress dla Mailgun, Mandrill, Postmark i SendGrid. Możesz także obsługiwać przychodzące wiadomości e-mail bezpośrednio przez wbudowane wejścia Exim, Postfix i Qmail. Teraz prawdopodobnie możesz sobie wyobrazić potencjalne korzyści bez wchodzenia w szczegóły. Może bezpośrednio przetwarzać wiadomości e-mail z działu pomocy lub automatyzować zgłoszenia pomocy technicznej — Rails 6 umożliwia klientom odpowiadanie bezpośrednio przez e-mail i wiele, wiele więcej. Zapraszamy do zapoznania się z tą funkcją i wymyślenia podejścia, które będzie idealne dla Twojej aplikacji.

Oto mały przykład, aby zrozumieć, jak korzystać ze skrzynki Action Mailbox:

 COMMENTS_REGEX = /^comment\+(.+)@example\.com/i # app/mailboxes/application_mailbox.rb class ApplicationMailbox < ActionMailbox::Base routing COMMENTS_REGEX => :comments end # app/mailboxes/comments_mailbox.rb class CommentsMailbox < ApplicationMailbox def process user = User.find_by(email: mail.from) post_uuid = COMMENTS_REGEX.match(mail.to)[1] post = Post.find_by(uuid: post_uuid) post.comments.create(user: user, content: mail.body) end end

Ponadto nowy sposób konfiguracji e-maili wygląda następująco (na przykładzie Sendgrid):

 # config/environments/production.rb config.action_mailbox.ingress = :sendgrid

Użyj rails credentials:edit , aby dodać hasło do zaszyfrowanych poświadczeń aplikacji w obszarze action_mailbox.ingress_password , gdzie Action Mailbox automatycznie je znajdzie:

 action_mailbox: ingress_password: …

Skonfiguruj funkcję SendGrid Inbound Parse, aby przesyłać przychodzące wiadomości e-mail do /rails/action_mailbox/sendgrid/inbound_emails z nazwą użytkownika actionmailbox i wcześniej wygenerowanym hasłem. Jeśli Twoja aplikacja znajduje się pod https://example.com , skonfiguruj SendGrid z następującym adresem URL:

 https://actionmailbox:[email protected]/rails/action_mailbox/sendgrid/i

Jeśli chcesz dalej to zbadać, Railsy mają już przewodnik na ten temat tutaj.

Zeitwerk

Zeitwerk to nowy program ładujący kod dla Rubiego. Biorąc pod uwagę konwencjonalną strukturę plików, Zeitwerk ładuje klasy i moduły projektu na żądanie, co oznacza, że ​​nie musisz pisać wymaganych wywołań dla własnych plików. Aby włączyć to w Rails 6, możesz wykonać następujące czynności:

 config.autoloader = :zeitwerk

Więcej o Zeitwerk przeczytasz tutaj.

Wskazówki dotyczące optymalizacji

Obawiasz się, że wykonanie niektórych zapytań trwa zbyt długo? Cóż, teraz masz również sposób na zdefiniowanie limitów czasu dla swoich zapytań.

Poniższa instrukcja wywoła wyjątek StatementTimeout , jeśli wykonanie zapytania trwa dłużej niż zwykle:

 User.optimizer_hints("MAX_EXECUTION_TIME(5000)").all

Jest obsługiwany przez MySQL i musisz sprawdzić, czy Twoja baza danych go obsługuje.

Obetnij bazę danych

A co z danymi siewu? Poniższa instrukcja obetnie wszystkie tabele bazy danych, a następnie będziesz mógł przystąpić do umieszczania danych:

 rails db:truncate_all

Koniec z usuwaniem baz danych do seed. Prawdopodobnie zgodzisz się, że to eleganckie i szybkie rozwiązanie.

Tekst akcji

Być może kolejną godną uwagi funkcją wielu aplikacji, które współpracują z edytorami WYSIWYG, jest dodanie obsługi edytora Trix natywnie w aplikacjach Rails 6. To z pewnością będzie dobrym ulepszeniem/dodatkiem dla wielu projektów.

Większość edytorów HTML WYSIWYG ma ogromny zakres — każda implementacja przeglądarki ma swój własny zestaw błędów i dziwactw, a programiści JavaScript muszą rozwiązać te niespójności. Trix omija te niespójności, traktując zawartość contenteditable jako urządzenie we/wy: Kiedy dane wejściowe trafiają do edytora, Trix konwertuje je do operacji edycji na swoim wewnętrznym modelu dokumentu, a następnie ponownie renderuje ten dokument z powrotem do edytora. Daje to Trix pełną kontrolę nad tym, co dzieje się po każdym naciśnięciu klawisza.

Instalacja:

 rails action_text:install # app/models/message.rb class Message < ApplicationRecord has_rich_text :content end

Możesz zapoznać się z tekstem akcji bardziej szczegółowo w oficjalnej dokumentacji, tutaj.

Bezpieczeństwo

Żadna poważna aktualizacja nie jest kompletna bez kilku ulepszeń bezpieczeństwa. Rails 6 nie rozczarowuje również pod względem bezpieczeństwa. Pierwszą godną uwagi aktualizacją zabezpieczeń jest dodanie obsługi autoryzacji hosta .

Autoryzacja hosta to nowe oprogramowanie pośredniczące, które chroni przed atakami związanymi z ponownym wiązaniem DNS, jawnie zezwalając na hosty, do których można wysłać żądanie. Oznacza to, że możesz zdefiniować hosty, które mają dostęp do twoich aplikacji.

Kolejna aktualizacja zabezpieczeń ma na celu udaremnienie ataków, które próbują skopiować podpisaną/zaszyfrowaną wartość pliku cookie i wykorzystać ją jako wartość innego pliku cookie. Robi to, przechowując nazwę pliku cookie w polu celu, które jest następnie podpisywane/szyfrowane wraz z wartością pliku cookie. Następnie podczas odczytu po stronie serwera weryfikujemy nazwy plików cookie i odrzucamy zaatakowane pliki cookie. Włącz action_dispatch.use_cookies_with_metadata , aby korzystać z tej funkcji, która zapisuje pliki cookie z osadzonym nowym celem i metadanymi wygaśnięcia.

Webpack jako domyślny pakiet

Jako de facto standard w wielu nowoczesnych frameworkach JavaScript do programowania front-end, Railsy 6 dodały Webpack jako domyślny pakiet JavaScript poprzez webpacker gem, zastępując potok zasobów Rails. Jest to stosunkowo prosty dodatek i nie będziemy wchodzić w szczegóły. Dość powiedzieć, że Webpack przyniesie ulgę przepracowanym front-end developerom.

Zapobieganie warunkom wyścigowym

Railsy 6 mają nową metodę, która służy do zapobiegania wyścigom SELECT/INSERT w naszym kodzie (jestem pewien, że wielu czytelników miało nieszczęście napotkać wyścigi podczas skalowania swojego projektu). Oto wątek GitHub na wypadek, gdybyś potrzebował dodatkowych informacji.

Tabela podstawowa musi mieć odpowiednie kolumny zdefiniowane z ograniczeniami przez unikalność. Chociaż unikamy sytuacji wyścigu między SELECT → INSERT od #find_or_create_by , w rzeczywistości mamy inny wyścig między INSERT → SELECT, który może zostać wywołany, jeśli DELETE między tymi dwoma instrukcjami zostanie uruchomiony przez innego klienta. Ale w przypadku większości zastosowań jest to warunek, w który jest znacznie mniej prawdopodobne.

Poświadczenia w Rails 6

Od czasów Rails 5.2 poświadczenia zostały nazwane nowym „sposobem Rails” do radzenia sobie z poufnymi informacjami z obietnicą pozbycia się niesławnych plików .env raz na zawsze. Dzięki poświadczeniom zaszyfrowane klucze usług innych firm można sprawdzić bezpośrednio w kontroli źródła.

Jednak do tej pory Railsy używały tego samego zaszyfrowanego pliku we wszystkich środowiskach, co sprawiało, że radzenie sobie z różnymi kluczami w rozwoju i produkcji było trochę trudne, zwłaszcza w przypadku dużych projektów i starszego kodu.

W Rails 6 zostało to ostatecznie rozwiązane dzięki obsłudze poświadczeń dla poszczególnych środowisk. Ponownie, dalsze szczegóły można znaleźć w oficjalnym wątku GitHub.

Czy Railsy 6 to dobra aktualizacja?

Tak, i faktycznie Railsy 6 można by opisać jako dużą aktualizację, choć niewielu nazwałoby to zmianą gry. Ponieważ Ruby on Rails istnieje od lat, niewiele osób spodziewa się rewolucyjnych zmian, ale jego szóste wcielenie wnosi wiele do stołu.

Niektóre funkcje wprowadzone w Rails 6 wydają się drobnymi ulepszeniami, podczas gdy inne mogą zaoszczędzić dużo czasu na opracowywanie, poprawić bezpieczeństwo, niezawodność i tak dalej. Konkluzja: Railsy są dojrzałe, wielu programistów podchodzi entuzjastycznie do ich przyszłości, a wraz z wydaniem Rails 6 stało się jeszcze lepsze.

Oczywiście ta lista funkcji Rails 6 jest niekompletna i aby zobaczyć pełny zestaw zmian, musisz zajrzeć do changeloga. Ponadto istnieje wiele wad, które należy wziąć pod uwagę. Na koniec, jeśli nalegasz na przeglądanie każdej zmiany i aktualizowanie się, przeczytaj pełne informacje o wydaniu.