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

What's new in Rails?

Avatar for Miha Rekar 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).

Avatar for Miha Rekar

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)