Upgrade to Pro — share decks privately, control downloads, hide ads and more …

What's new in Rails?

Miha Rekar
October 24, 2023

What's new in Rails?

A talk I gave at Ruby Zagreb October meetup

Summary of all the important new stuff in Rails 7.1 and a bit about Kamal (formerly known as MRSK).

Miha Rekar

October 24, 2023
Tweet

More Decks by Miha Rekar

Other Decks in Technology

Transcript

  1. What is Kamal? • Capistrano for Containers • imperative: step-by-step

    commands are more straightforward and less abstract • a simpler alternative to Kubernetes or Docker Swarm • deploy anywhere, from bare metal to cloud VMs • compress the complexity of going to production • SSHKit + Traefik + Docker
  2. Why Kamal? • Cloud !!! • Kubernetes, Nomad, Mesos,… are

    complicated AF • Ansible, Chef,Puppet,… are configuration management tools, not made for deployment • Docker Swarm is declerative and can get finnicky • Dokku is like Linux: free only if your time has no value
  3. Benefits • simple and readable Ruby gem • YAML configuration

    • Includes server set up, zero-downtime deploys, rolling restarts, easy rollback, deploy locks, logs grep,… • Deploy across multiple clouds or on personal hardware • Support for accessories like Redis, memcached, Postgres, MySql,… via their own Dockerfile in a designated or same server
  4. Why would you use it? • Heroku is " •

    Try Fly.io or Render • Get away from Big Cloud™ • Hetzner, DigitalOcean, Linode,… Raspberry Pi? • Stop dealing with k8s, Dokku,… • Fun to try out and learn something new
  5. Async queries • async_count • async_sum • async_minimum • async_maximum

    • async_average • async_pluck • async_pick • async_ids • async_find_by_sql • async_count_by_sql
  6. Async queries • async_count • async_sum • async_minimum • async_maximum

    • async_average • async_pluck • async_pick • async_ids • async_find_by_sql • async_count_by_sql https://radanskoric.com/articles/understand-rails-async-db-queries
  7. Unused routes $ bin/rails routes --unused Found 2 unused routes:

    Prefix Verb URI Pattern Controller#Action one GET /one(.:format) action#one two GET /two(.:format) action#two
  8. Common Table Expressions Post.with( posts_with_comments: Post.where("comments_count > ?", 0), posts_with_tags:

    Post.where("tags_count > ?", 0) ) # Replaces posts_with_comments_table = Arel::Table.new(:posts_with_comments) posts_with_comments_expression = Post.arel_table.where(posts_with_comments_table[:comments_count].gt(0)) posts_with_tags_table = Arel::Table.new(:posts_with_tags) posts_with_tags_expression = Post.arel_table.where(posts_with_tags_table[:tags_count].gt(0)) Post.all.arel.with([ Arel::Nodes::As.new(posts_with_comments_table, posts_with_comments_expression), Arel::Nodes::As.new(posts_with_tags_table, posts_with_tags_expression) ]) # WITH posts_with_comments AS ( # SELECT * FROM posts WHERE (comments_count > 0) # ), posts_with_tags AS ( # SELECT * FROM posts WHERE (tags_count > 0) # ) # SELECT * FROM posts
  9. ActiveRecord::Relation#explain • now accepts options • query.explain(“ANALYZE, COSTS, VERBOSE, BUFFERS,

    FORMAT JSON") • query.explain("ANALYZE", "COSTS", "VERBOSE", "BUFFERS", "FORMAT JSON”) • https://explain.dalibo.com/
  10. #select Accepts a Hash # You can now write selects

    like this: Post.joins(:comments).select( posts: { id: :post_id, title: :post_title }, comments: { id: :comment_id, body: :comment_body} ) # In place of this: Post.joins(:comments).select( "posts.id as post_id, posts.title as post_title, comments.id as comment_id, comments.body as comment_body" )
  11. ActiveRecord::Base.normalizes class User < ApplicationRecord normalizes :email, with: -> email

    { email.strip.downcase } normalizes :phone, with: -> phone { phone.delete("^0-9").delete_prefix("1") } end # Normalize email address before creating a user user = User.create(email: " [email protected]\n") user.email # => "[email protected]"
  12. Composite keys • both at the database and at application

    level • derived from schema • mainly for many-to-many relationships • virtual primary key via query_constraints • composite foreign key on association
  13. BYO Authentication • Devise is " • User.authenticate_by( email: “[email protected]",

    password: “rails4ever” ) • lazaronixon/authentication-zero • passkeys (WebAuthn) class User < ApplicationRecord has_secure_password generates_token_for :password_reset, expires_in: 15.minutes do # Last 10 characters of password salt, changes when password is updated: password_salt&.last(10) end end user = User.first token = user.generate_token_for(:password_reset) User.find_by_token_for(:password_reset, token) # => user # 16 minutes later... User.find_by_token_for(:password_reset, token) # => nil
  14. ActiveSupport::MessagePack • new serializer that integrates with the msgpack gem

    • can reduce payload size and improve performance compared to JSON and Marshal
  15. ActiveJob.perform_all_later • single redis/pg call # Enqueueing individual jobs ActiveJob.perform_all_later(

    MyJob.new("hello", 42), MyJob.new("world", 0) ) # Enqueueing an array of jobs user_jobs = User.pluck(:id).map { |id| UserJob.new(user_id: id) } ActiveJob.perform_all_later(user_jobs)
  16. Allow templates to set strict locals • By default, templates

    will accept any locals as keyword arguments • Now you can define what locals a template should accept via locals magic comment <%# locals: (message:) -%> <%= message %> You can also set default values for these locals: <%# locals: (message: "Hello, world!") -%> <%= message %> If you want to disable the use of locals entirely, you can do so like this: <%# locals: () %>
  17. Support Bun • all-in-one JS/TS runtime & toolkit designed for

    speed, complete with a bundler, test runner, and Node.js-compatible package manager. • I know nothing about this • other people are excited
  18. ICYMI • Ruby 3.3's YJIT is amazing • New register

    allocator • More code now gets JIT compiled • For Shopify: • 13% faster than 3.2 YJIT • 15% faster than 3.3 without YJIT • For Basecamp: • +24% faster on the median, +12% on the average
  19. • https://www.youtube.com/@railsofficial • My favs: • Zeitwerk Internals • Tailwind

    CSS: It looks awful, and it works • Applying Shape Up in the Real World • Tenderlove (Aaron Patterson)