คุณสมบัติ Rails 6: มีอะไรใหม่และเหตุใดจึงสำคัญ

เผยแพร่แล้ว: 2022-03-11

อย่างที่แฟนๆ Ruby on Rails ส่วนใหญ่ทราบกันดีอยู่แล้วว่า Rails 6 กำลังจะมาในเร็วๆ นี้ และมาพร้อมฟีเจอร์และการเปลี่ยนแปลงที่รอคอยอย่างใจจดใจจ่อ จุดมุ่งหมายของบทความนี้คือการทำความคุ้นเคยกับคุณสมบัติหลักที่เพิ่มเข้ามาใน Rails 6 และสรุปว่าคุณสมบัติเหล่านี้สามารถช่วยทำให้แอปพลิเคชันของคุณดีขึ้นได้อย่างไร ซึ่งช่วยประหยัดเวลาอันมีค่าในการพัฒนา

สำหรับผู้เริ่มต้น โปรดจำไว้ว่า Rails 6 ต้องใช้ Ruby 2.5+ และฐานข้อมูลที่อัปเกรดแล้ว ดังนั้น ตรวจสอบให้แน่ใจว่าคุณมีแผนที่จะอัพเกรดระบบของคุณตามนั้น ในกรณีที่คุณยังไม่ได้ดำเนินการดังกล่าว

แล้วคุณสมบัติใหม่เหล่านี้คืออะไร? นี่คือบทสรุปโดยย่อของคุณสมบัติหลักของ Rails 6 ที่คุณน่าจะใช้ในอนาคต:

การทดสอบใน Rails 6

ในฐานะนักพัฒนา Ruby on Rails มืออาชีพ เรามุ่งมั่นที่จะสร้างความครอบคลุมสูงสุดสำหรับโค้ดของเรา อย่างไรก็ตาม การทดสอบกลายเป็นกิจกรรมที่น่าเบื่อหน่ายเมื่อกรณีทดสอบของเรา "หนัก" และเราต้องรอหลายนาทีหรือหลายชั่วโมงเพื่อให้กรณีทดสอบดำเนินการได้

การทดสอบแบบขนาน

Rails 6 มีคำตอบที่นี่ ได้เพิ่มวิธีการ parallelize ใน ActiveSupport::TestCase ซึ่งช่วยให้คุณขนานชุดการทดสอบด้วยกระบวนการแยก

ดังนั้น สิ่งที่คุณต้องทำเพื่อขนานกระบวนการสำหรับการทดสอบของคุณคือเพิ่มสิ่งนี้ใน test_helper.rb ของคุณ:

 parallelize(workers: 2)

อีกทางหนึ่ง เราสามารถแทนที่คำสั่งที่ใช้ก่อนหน้านี้สำหรับการทดสอบรัน ตัวอย่างเช่น bin/rails test OR bin/rspec spec สามารถแทนที่ด้วย PARALLEL_WORKERS=15 rails test OR PARALLEL_WORKERS=15 rspec spec

ดังนั้น คุณสามารถเปลี่ยนคำสั่งสำหรับการรันชุดทดสอบบนแพลตฟอร์ม CI ต่างๆ เช่น Travis, Gitlab, CircleCI และอื่นๆ

นอกจากนี้ยังมี hooks เมื่อมีการสร้าง/ทำลายแต่ละกระบวนการ ซึ่งสามารถใช้ได้ดังนี้:

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

หมายเหตุ: หากต้องการเรียนรู้เพิ่มเติม คุณสามารถดู Rails Guides สำหรับรายละเอียดเพิ่มเติมได้

การทดสอบสายเคเบิลการดำเนินการ

เนื่องจากเรากำลังพูดถึงการทดสอบที่มีประสิทธิภาพ เรามาทำความเข้าใจว่า Action Cable ซึ่งเป็นหนึ่งในคุณสมบัติเด่นที่สุดของ Rails 5 ได้รับการปรับปรุงอย่างไร ตอนนี้คุณสามารถทดสอบ Action Cable ในทุกระดับ: การเชื่อมต่อ ช่อง และ การออกอากาศ

การทดสอบการเชื่อม ต่อมีจุดมุ่งหมายเพื่อตรวจสอบว่าตัวระบุการเชื่อมต่อได้รับมอบหมายอย่างถูกต้องหรือคำขอเชื่อมต่อที่ไม่เหมาะสมถูกปฏิเสธ:

 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

การทดสอบช่อง สามารถเขียนขึ้นเพื่อตรวจสอบว่าผู้ใช้สามารถสมัครรับข้อมูลจากช่องและช่องมีสตรีมหรือไม่:

 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

สามารถทดสอบการ แพร่ภาพไปยังช่อง ต่างๆ ได้ดังนี้:

 # 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

หมายเหตุ: ดูเคล็ดลับเพิ่มเติมเกี่ยวกับวิธีการทดสอบได้ที่นี่

แทรกและอัพจำนวนมาก

เมื่อถึงจุดหนึ่ง เราทุกคนจำเป็นต้องแทรกหลายระเบียนในครั้งเดียว และพบวิธีแก้ไขปัญหาชั่วคราวหลายอย่างเมื่อทำเช่นนั้น Rails 6 มาพร้อมกับวิธีการใหม่แกะกล่อง — insert_all คล้ายกับ update_all

จะไม่เรียกใช้การเรียกกลับใด ๆ และจะดำเนินการแบบสอบถาม SQL เดียว มีวิธีการเพิ่มเติม upsert_all ซึ่งช่วยให้คุณใช้การดำเนินการ upsert ซึ่งถูกเปิดเผยโดยฐานข้อมูลสมัยใหม่มากมาย เช่น Postgres ดังนั้นตอนนี้ คุณสามารถลดการสืบค้นข้อมูลส่วนแทรกและทำให้โค้ดของคุณเหมาะสมยิ่งขึ้น ยังบอกลาอัญมณีที่ใช้ก่อนหน้านี้เช่น activerecord-import

แบบสอบถาม INSERT SQL เดียวถูกจัดเตรียมโดยวิธีการเหล่านี้ และคำสั่ง SQL เดียวจะถูกส่งไปยังฐานข้อมูล โดยไม่ต้องสร้างอินสแตนซ์ของโมเดล หรือเรียกใช้การเรียกกลับของ Active Record และการตรวจสอบความถูกต้อง นอกจากนี้ยังสามารถกำหนดเกณฑ์เมื่อคีย์หลัก—ดัชนีที่ไม่ซ้ำหรือข้อจำกัดที่ไม่ซ้ำถูกละเมิดพร้อมตัวเลือกในการข้ามหรือเรียกใช้การสืบค้นข้อมูลที่สูงกว่า

ตัวอย่างบางส่วนอยู่ด้านล่าง:

 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, .... } ] )

วิธีการ insert , insert! และ upsert เป็น wrappers รอบ ๆ insert_all , insert_all! และ upsert_all ตามลำดับ

หมายเหตุ: มีบทความที่ดีมากที่กล่าวถึงการสืบค้นข้อมูลจำนวนมากเกี่ยวกับฐานข้อมูลต่างๆ หากคุณต้องการข้อมูลเพิ่มเติม อย่าลืมตรวจสอบ

การสลับระหว่างหลายฐานข้อมูล

หนึ่งในคุณสมบัติหลักที่แอปพลิเคชั่นขนาดใหญ่จำนวนมากจะต้องชอบคือสิ่งนี้: ในที่สุด Rails 6 ได้เพิ่มการรองรับฐานข้อมูลหลายตัวสำหรับแอปพลิเคชันของคุณ สร้างขึ้นในและพร้อมใช้งานทันทีที่แกะกล่อง!

ไดอะแกรมของการสลับระหว่างฐานข้อมูล

แน่นอน ตัวเลือกการออกแบบยังคงเป็นของคุณ ไม่ว่าคุณจะต้องการแบ่งแอปพลิเคชันของคุณออกเป็นไมโครเซอร์วิสหลายตัวโดยที่แต่ละรายการมีฐานข้อมูลแยกกัน หรือใช้เส้นทางแบบเสาหิน หรือเพิ่มแบบจำลองการอ่านหลายแบบสำหรับแอปพลิเคชันของคุณ

อย่างไรก็ตาม ความสามารถในการทำในลักษณะง่ายๆ ดังกล่าวมีศักยภาพที่จะช่วยประหยัด เวลาได้มาก ในด้านการพัฒนา

นี่คือลักษณะของไฟล์ 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

ต่อไปนี้คือวิธีที่น่าสนใจในการระบุวิธีสลับไปยังฐานข้อมูลต่างๆ:

 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

นี่คือหน้า GitHub อย่างเป็นทางการซึ่งมีการจัดทำเป็นเอกสารไว้อย่างดีเช่นกัน โดยส่วนตัวแล้ว ฉันตั้งตารอที่จะมีความสามารถในการแบ่งส่วนฐานข้อมูลในการอัปเดต Rails ในอนาคตเช่นกัน (ลักษณะนี้)

แอคชั่นเมลบ็อกซ์

คุณสมบัติ Rails 6 ที่น่าสนใจอีกประการหนึ่งคือการเพิ่ม Action Mailbox ซึ่งเพิ่มความสามารถในการ กำหนดเส้นทางอีเมลขา เข้าไปยังคอนโทรลเลอร์ เช่น กล่องจดหมายสำหรับการประมวลผลใน Rails

ฟีเจอร์ Action Mailbox ขาเข้าสำหรับ Mailgun, Mandrill, Postmark และ SendGrid คุณยังสามารถจัดการอีเมลขาเข้าได้โดยตรงผ่านทางขาเข้า Exim, Postfix และ Qmail ตอนนี้คุณสามารถจินตนาการถึงผลประโยชน์ที่อาจเกิดขึ้นโดยไม่ต้องลงรายละเอียดเพิ่มเติม อาจเป็นการประมวลผลอีเมลโดยตรงจากแหล่งความช่วยเหลือไปจนถึงตั๋วสนับสนุนอัตโนมัติ Rails 6 ช่วยให้ลูกค้าสามารถตอบกลับโดยตรงผ่านอีเมล และอื่นๆ อีกมากมาย ชั้นเปิดให้คุณสำรวจคุณลักษณะนี้และนำเสนอแนวทางที่เหมาะสำหรับแอปพลิเคชันของคุณ

ต่อไปนี้คือตัวอย่างเล็กๆ เพื่อทำความเข้าใจวิธีใช้ 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

นอกจากนี้ วิธีใหม่ในการกำหนดค่าอีเมลมีดังนี้ (ใช้ตัวอย่างของ Sendgrid):

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

ใช้ rails credentials:edit เพื่อเพิ่มรหัสผ่านให้กับข้อมูลประจำตัวที่เข้ารหัสของแอปพลิเคชันของคุณภายใต้ action_mailbox.ingress_password โดยที่ Action Mailbox จะค้นหาโดยอัตโนมัติ:

 action_mailbox: ingress_password: …

กำหนดค่า SendGrid Inbound Parse เพื่อส่งต่ออีเมลขาเข้าไปยัง /rails/action_mailbox/sendgrid/inbound_emails actionmailbox ชื่อผู้ใช้และรหัสผ่านที่คุณสร้างไว้ก่อนหน้านี้ หากแอปพลิเคชันของคุณอยู่ที่ https://example.com คุณจะต้องกำหนดค่า SendGrid ด้วย URL ต่อไปนี้:

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

ในกรณีที่คุณต้องการสำรวจเพิ่มเติม Rails มีคำแนะนำเกี่ยวกับเรื่องนี้แล้วที่นี่

Zeitwerk

Zeitwerk เป็นตัวโหลดโค้ดใหม่สำหรับ Ruby ด้วยโครงสร้างไฟล์แบบเดิม Zeitwerk จะโหลดคลาสและโมดูลของโปรเจ็กต์ตามต้องการ หมายความว่าคุณไม่จำเป็นต้องเขียนไฟล์ที่ต้องใช้การเรียกไฟล์ของคุณเอง ในการเปิดใช้งานใน Rails 6 คุณสามารถทำสิ่งต่อไปนี้:

 config.autoloader = :zeitwerk

คุณสามารถอ่านเพิ่มเติมเกี่ยวกับ Zeitwerk ได้ที่นี่

คำแนะนำเครื่องมือเพิ่มประสิทธิภาพ

คุณกังวลว่าข้อความค้นหาบางรายการของคุณใช้เวลาในการดำเนินการนานเกินไปหรือไม่ ตอนนี้คุณมีวิธีกำหนดระยะหมดเวลาสำหรับข้อความค้นหาของคุณด้วย

คำสั่งต่อไปนี้จะทำให้เกิดข้อยกเว้น StatementTimeout หากการสืบค้นใช้เวลานานกว่าปกติในการดำเนินการ:

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

รองรับโดย MySQL และคุณจะต้องสำรวจว่าฐานข้อมูลของคุณรองรับหรือไม่

ตัดทอนฐานข้อมูล

แล้วการ seed data ล่ะ? คำสั่งต่อไปนี้จะตัดตารางฐานข้อมูลทั้งหมดของคุณ และคุณสามารถดำเนินการเริ่มต้นข้อมูลของคุณได้:

 rails db:truncate_all

ไม่ต้องลบฐานข้อมูลของคุณเพื่อตั้งต้นอีกต่อไป คุณอาจจะเห็นด้วยว่านี่เป็นวิธีแก้ปัญหาที่หรูหราและรวดเร็ว

ข้อความการกระทำ

บางทีคุณสมบัติที่โดดเด่นอีกอย่างสำหรับแอปพลิเคชันจำนวนมากที่เล่นกับโปรแกรมแก้ไขแบบ WYSIWYG ก็คือการเพิ่มการรองรับตัวแก้ไข Trix ในแอปพลิเคชัน Rails 6 โดยกำเนิด นี่จะเป็นการอัปเกรด/เพิ่มเติมที่ดีสำหรับหลาย ๆ โครงการอย่างแน่นอน

โปรแกรมแก้ไข HTML แบบ WYSIWYG ส่วนใหญ่มีขอบเขตมหาศาล—การใช้งานของเบราว์เซอร์แต่ละตัวมีชุดของจุดบกพร่องและลักษณะเฉพาะของตัวเอง และนักพัฒนา JavaScript ถูกปล่อยให้แก้ไขความไม่สอดคล้องกัน Trix หลีกเลี่ยงความไม่สอดคล้องกันเหล่านี้โดยถือว่า contenteditable เป็นอุปกรณ์ I/O: เมื่ออินพุตเข้าถึงตัวแก้ไข Trix จะแปลงอินพุตนั้นเป็นการดำเนินการแก้ไขบนโมเดลเอกสารภายใน จากนั้นจึงแสดงผลเอกสารนั้นกลับเข้าไปในตัวแก้ไข สิ่งนี้ทำให้ Trix ควบคุมสิ่งที่เกิดขึ้นหลังจากการกดแป้นพิมพ์ทุกครั้ง

การติดตั้ง:

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

คุณสามารถสำรวจ Action Text โดยละเอียดในเอกสารประกอบอย่างเป็นทางการได้ที่นี่

ความปลอดภัย

การอัปเกรดที่จริงจังไม่เสร็จสมบูรณ์หากไม่มีการปรับปรุงความปลอดภัยเล็กน้อย Rails 6 ก็ไม่ทำให้ผิดหวังในเรื่องความปลอดภัยเช่นกัน การอัพเกรดการรักษาความปลอดภัยที่โดดเด่นครั้งแรกคือการเพิ่มการรองรับการ อนุญาตโฮสต์

การอนุญาตโฮสต์เป็นมิดเดิลแวร์ใหม่ที่ป้องกันการโจมตี DNS rebinding โดยอนุญาตให้โฮสต์ส่งคำขอได้อย่างชัดเจน สิ่งนี้หมายความว่าคุณสามารถกำหนดโฮสต์ที่สามารถเข้าถึงแอปพลิเคชันของคุณได้

การอัพเกรดการรักษาความปลอดภัยอีกประการหนึ่งมีขึ้นเพื่อป้องกันการโจมตีที่พยายามคัดลอกค่าที่ลงนาม/เข้ารหัสของคุกกี้และใช้เป็นค่าของคุกกี้อื่น ทำได้โดยซ่อนชื่อคุกกี้ในฟิลด์วัตถุประสงค์ จากนั้นลงชื่อ/เข้ารหัสพร้อมกับค่าคุกกี้ จากนั้น เมื่ออ่านฝั่งเซิร์ฟเวอร์ เราจะตรวจสอบชื่อคุกกี้และทิ้งคุกกี้ที่ถูกโจมตี เปิดใช้งาน action_dispatch.use_cookies_with_metadata เพื่อใช้คุณลักษณะนี้ ซึ่งเขียนคุกกี้ด้วยวัตถุประสงค์ใหม่และข้อมูลเมตาการหมดอายุที่ฝังไว้

Webpack เป็น Bundler เริ่มต้น

ในฐานะที่เป็นมาตรฐานโดยพฤตินัยด้วยเฟรมเวิร์ก JavaScript ที่ทันสมัยมากมายสำหรับการพัฒนาส่วนหน้า Rails 6 ได้เพิ่ม Webpack เป็นชุดรวม JavaScript เริ่มต้นผ่าน webpacker gem โดยแทนที่ไปป์ไลน์ Rails Asset นี่เป็นการเพิ่มที่ค่อนข้างตรงไปตรงมา และเราจะไม่ลงรายละเอียดมากนัก พอจะพูดได้ว่า Webpack จะช่วยบรรเทาปัญหาให้กับนักพัฒนา front-end ที่ทำงานหนักเกินไปได้

การป้องกันสภาพการแข่งขัน

Rails 6 มีวิธีการใหม่ที่ใช้ในการป้องกันเงื่อนไขการแข่งขัน SELECT/INSERT ในโค้ดของเรา (ฉันแน่ใจว่าผู้อ่านหลายคนต้องพบกับความโชคร้ายในการเผชิญกับสภาวะการแข่งขันในขณะที่พวกเขาขยายโครงการ) นี่คือเธรด GitHub ในกรณีที่คุณต้องการข้อมูลเพิ่มเติม

ตารางพื้นฐานต้องมีคอลัมน์ที่เกี่ยวข้องซึ่งกำหนดด้วยข้อจำกัดเฉพาะ แม้ว่าเราจะหลีกเลี่ยงสภาวะการแข่งขันระหว่าง SELECT → INSERT จาก #find_or_create_by แต่ที่จริงแล้ว เรามีสภาวะการแข่งขันอื่นระหว่าง INSERT → SELECT ซึ่งสามารถทริกเกอร์ได้หาก DELETE ระหว่างสองคำสั่งนี้เรียกใช้โดยไคลเอ็นต์อื่น แต่สำหรับการใช้งานส่วนใหญ่ นั่นเป็นเงื่อนไขที่เรามีโอกาสโดนน้อยกว่ามาก

ข้อมูลประจำตัวใน Rails 6

นับตั้งแต่ยุคของ Rails 5.2 ข้อมูลประจำตัวได้รับการขนานนามว่าเป็น “วิธีการรถไฟ” แบบใหม่เพื่อจัดการกับข้อมูลที่ละเอียดอ่อนพร้อมสัญญาว่าจะกำจัดไฟล์ .env ที่น่าอับอายออกไปทุกครั้ง ด้วยข้อมูลประจำตัว คีย์ที่เข้ารหัสสำหรับบริการของบุคคลที่สามสามารถตรวจสอบได้โดยตรงในการควบคุมแหล่งที่มา

อย่างไรก็ตาม จนถึงตอนนี้ Rails ใช้ไฟล์ที่เข้ารหัสเดียวกันสำหรับทุกสภาพแวดล้อม ซึ่งทำให้การจัดการกับคีย์ต่างๆ ในการพัฒนาและการผลิตค่อนข้างยุ่งยาก โดยเฉพาะอย่างยิ่งเมื่อต้องจัดการกับโปรเจ็กต์ขนาดใหญ่และโค้ดดั้งเดิม

ใน Rails 6 ในที่สุดสิ่งนี้ก็แก้ไขได้ด้วยการสนับสนุนข้อมูลประจำตัวต่อสภาพแวดล้อม รายละเอียดเพิ่มเติมสามารถสำรวจได้อีกครั้งในเธรด GitHub อย่างเป็นทางการ

Rails 6 เป็นการอัปเดตที่ดีหรือไม่?

ใช่ และที่จริงแล้ว Rails 6 สามารถอธิบายได้ว่าเป็นการอัปเดตครั้งใหญ่ แม้ว่าจะมีเพียงไม่กี่คนที่เรียกมันว่าตัวเปลี่ยนเกม เนื่องจาก Ruby on Rails มีมานานหลายปีแล้ว มีคนเพียงไม่กี่คนที่คาดหวังการเปลี่ยนแปลงที่ปฏิวัติวงการ แต่การกลับชาติมาเกิดครั้งที่ 6 ทำให้เกิดเรื่องมากมาย

ฟีเจอร์บางอย่างที่เปิดตัวใน Rails 6 ดูเหมือนจะมีการปรับปรุงเล็กน้อย ในขณะที่ฟีเจอร์อื่นๆ มีศักยภาพในการประหยัดเวลาในการพัฒนาได้มาก ปรับปรุงความปลอดภัย ความทนทาน และอื่นๆ บรรทัดล่าง: Rails เติบโตเต็มที่แล้ว นักพัฒนาจำนวนมากยังคงกระตือรือร้นเกี่ยวกับอนาคต และด้วยการเปิดตัว Rails 6 ก็ดีขึ้นไปอีก

แน่นอนว่ารายการฟีเจอร์ของ Rails 6 นี้ยังไม่สมบูรณ์ และหากต้องการดูการเปลี่ยนแปลงทั้งหมด คุณจะต้องตรวจสอบบันทึกการเปลี่ยนแปลง นอกจากนี้ยังมีการเลิกใช้งานจำนวนมากที่คุณควรพิจารณา สุดท้ายนี้ หากคุณยืนกรานที่จะทบทวนทุกการเปลี่ยนแปลงและอัปเดตตัวเอง โปรดอ่านบันทึกย่อประจำรุ่นฉบับเต็ม