Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

Rails 7: Key Features และ Improvements ก่อน Release

Rails 7 ใกล้ release แล้ว ยังไม่มี release date ยืนยัน แต่คาดว่าจะพร้อมก่อนคริสต์มาส ไม่เหลือนาน ฉบับล่าสุดตอนนี้คือ 7.0.0.rc1 (release candidate แรก) Basecamp, HEY, Github, Shopify รัน Rails 7 alpha ใน production แล้ว RC ควรค่อนข้าง stable

ในโพสต์นี้ จะมาดู features และ changes ใหม่ๆ ของ Rails 7

ไม่ต้อง Node และ Webpack แล้ว

อ่านถูกต้อง! JavaScript ใน Rails 7 ไม่ต้อง NodeJS หรือ Webpack อีกต่อไป แต่ยังใช้ npm packages ได้

Transpile ES6 ด้วย Babel และ bundle ด้วย Webpack ต้อง setup เยอะ Rails support ดีผ่าน Webpacker gem แต่พกภาระมาก ยากเข้าใจและแก้ไข โดยเฉพาะตอน maintain upgradability

ตอนนี้ default สำหรับ rails new ใช้ import maps ผ่าน importmaps-rails gem แทน package.json และ npm/yarn ใช้ ./bin/importmap CLI pin/unpin/update dependencies

เช่น ติดตั้ง date-fns:

$ ./bin/importmap pin date-fns

จะเพิ่มบรรทัดใน config/importmap.rb:

pin "date-fns", to: "https://ga.jspm.io/npm:date-fns@2.27.0/esm/index.js"

ใน JavaScript ใช้ได้เหมือนเดิม:

import { formatDistance, subDays } from "date-fns"; formatDistance(subDays(new Date(), 3), new Date(), { addSuffix: true }); //=> "3 days ago"

ข้อควรระวัง: ไม่มี transpiling ระหว่างโค้ดที่เขียนและที่ browser ได้ ส่วนใหญ่โอเค เพราะ browsers สำคัญรองรับ ES6 แล้ว

แต่หมายความว่า ไม่ใช้ TypeScript หรือ JSX ได้ (ต้อง transpile ก่อน)

ถ้าอยาก React กับ JSX ต้อง fallback setup อื่น (webpack/rollup/esbuild)

Rails 7 ทำให้ง่าย คำสั่งเดียวกับ strategy ที่เลือก:

$ ./bin/rails javascript:install:[esbuild|rollup|webpack]

Turbolinks และ UJS ถูกแทนที่ด้วย Turbo และ Stimulus

Apps ที่ generate ด้วย Rails 7 จะได้ Turbo และ Stimulus (จาก Hotwire) โดย default แทน Turbolinks และ UJS Hotwire = approach ใหม่ ส่ง HTML over the wire อัปเดต DOM เร็ว

Encryption ที่ Database Layer

Rails 7 ให้ mark database fields ว่า encrypted ด้วย encrypts method บน ActiveRecord::Base หลัง setup เริ่มต้น เขียนได้แบบนี้:

class Message < ApplicationRecord encrypts :text end

ใช้ encrypted attributes เหมือน attributes ปกติ Rails 7 encrypt/decrypt อัตโนมัติระหว่าง database และ app

แต่มีข้อผูกมัด: query database โดย field นั้นไม่ได้ เว้นแต่ส่ง deterministic: true ให้ encrypts deterministic mode ปลอดภัยน้อยกว่า default ใช้เฉพาะ attributes ที่จำเป็นต้อง query

Asynchronous Querying

มี load_async method ใช้ query data fetch results ใน background สำคัญเมื่อต้อง load หลาย queries ที่ไม่เกี่ยวข้องจาก controller action:

def PostsController def index @posts = Post.load_async @categories = Category.load_async end end

จะยิง queries ทั้งสองพร้อมกันใน background ถ้าแต่ละ query 200ms total time ~200ms แทนที่จะ 400ms ถ้า serial

Zeitwerk Mode สำหรับ Rails 7

Breaking change สำหรับ apps เก่าที่ยังใช้ classic loader Rails 7 apps ต้องใช้ Zeitwerk mode การ switch ง่าย ดู full upgrade guide

Rails 7 Updates อื่นๆ

Retry Jobs Unlimited Times

ActiveJob ส่ง :unlimited เป็น attempts parameter บน retry_on Rails จะ retry job โดยไม่มี max attempts

class MyJob < ActiveJob::Base retry_on(AlwaysRetryException, attempts: :unlimited) def perform raise "KABOOM" end end

Named Variants

ตั้งชื่อ variants บน ActiveStorage แทนระบุ size ทุกครั้ง

class User < ApplicationRecord has_one_attached :avatar do |attachable| attachable.variant :thumb, resize: "100x100" end end # เรียก avatar.variant(:thumb) ได้ thumb variant: <%= image_tag user.avatar.variant(:thumb) %>

Hash to HTML Attributes

มี tag.attributes method ใหม่สำหรับ views แปลง hash เป็น HTML attributes:

<input <%= tag.attributes(type: :text, aria: { label: "Search" }) %>>

ผลลัพธ์:

<input type="text" aria-label="Search" />

Ruby debug

Default debugger เปลี่ยนจาก byebug เป็น debug gem เรียก debugger แทน byebug

Assert Single Record ด้วย sole

Query records เรียก sole หรือ find_sole_by (แทน first/find_by) ต้องการ assert ว่า query ควร match single record เท่านั้น

Product.where(["price = %?", price]).sole # => ActiveRecord::RecordNotFound (ถ้าไม่มี) # => #<Product ...> (ถ้ามี 1) # => ActiveRecord::SoleRecordExceeded (ถ้ามีมากกว่า 1) user.api_keys.find_sole_by(key: key) # เหมือนด้านบน

Check Presence/Absence ของ Association

ใช้ where.associated(:association) check association มีอยู่จริง แทน join และ check id

# Before: account.users.joins(:contact).where.not(contact_id: nil) # After: account.users.where.associated(:contact)

Stream Generated Files จาก Controller Actions

ใช้ send_stream ใน controller action เริ่ม stream file ที่ generate on-the-fly:

send_stream(filename: "subscribers.csv") do |stream| stream.write "email_address,updated_at\n" @subscribers.find_each do |subscriber| stream.write "#{subscriber.email_address},#{subscriber.updated_at}\n" end end

ให้ immediate (partial) response ผู้ใช้รู้ว่ากำลังทำงาน มีประโยชน์บน Heroku

เพราะ file stream ทันที Heroku ไม่ terminate connection ไม่ต้อง background jobs สร้างไฟล์นาน > 30 วินาที

Upgrade ไป Rails 7

เหมือนรุ่นก่อนๆ Upgrade ง่าย แม้ยังไม่มี official guide ขั้นตอนคงเดิม:

  1. เปลี่ยน Rails version ใน Gemfile (7.0.0.rc1 ตอนเผยแพร่) รัน bundle update
  2. รัน bundle exec rails app:update ตาม interactive CLI add/replace/modify files
  3. รัน tests verify ทุกอย่างทำงาน

Wrap Up

ดู bug fixes, features, changes ครบใน Rails 7 release notes ยังไม่ครบถ้วนแต่คาดว่าจะ update เร็วๆ นี้

ถ้ายัง Rails 6 หรือต่ำกว่า: Rails 7 final release → Rails 6.1 เข้า "security issues only" ไม่ได้ bug fixes อีก และ Rails 5.2 EOL ไม่ได้ fixes อีก

Happy coding!

P.S. อยากอ่าน Ruby Magic posts ทันทีเผยแพร่? สมัครรับ Ruby Magic newsletter!