เจออะไรใน Rails 3: เพิ่มพลัง ActiveRecord#find (ตอนที่ 2)
February 12th, 2010 Posted in Ruby, Ruby on Railsเจออะไรใน Rails 3 เป็นสกู๊ปพิเศษสำหรับนำเสนอสิ่งใหม่ๆ ที่จะมีเพิ่มขึ้นมาใน Ruby on Rails 3.0
หลังจากที่ผมนำเสนอเรื่องของการ deprecate options ทั้งหมดของ ActiveRecord#find แล้วเปลี่ยนเป็นเมธอดที่ทำหน้าที่คล้ายๆ กับ named_scope กันไปแล้ว ตอนนี้ผมไปเจอข้อมูลจาก @lifo ซึ่งพูดเพิ่มเติมในเรื่องของเมธอดที่จะถูก deprecated และเมธอดที่ให้ใช้แทนครับ
สิ่งที่จะถูกถอดออกไป
การเรียกใช้ #find โดยมี option hash นั้นจะ deprecated ออกไป
User.find(:first, :where => {:status => "suspended"})
แต่อย่างไรก็ตาม #find method จะยังคงอยู่ โดยคุณสามารถใช้มันเพื่อหา record ตาม ID ได้แทน เช่น
User.find(1) User.find(3,4,5) # ให้ argument เป็น array ได้แล้ว
การใช้ #find(:first), #find(:all) จะถูกแทนที่ด้วยเมธอด #first, #all
User.find(:first) # => deprecated User.first # use this
และการใช้เมธอดสำหรับการคำนวณทุกอันนั้น ก็จะไม่รับ argument ที่เป็น hash แล้วเช่นกัน
User.count(:id, :conditions => {:status => "suspended"}) # => deprecated User.where({:status => "suspended"}).count # use this
แต่ยังคงยกเว้น #count ที่ยังคงรับตัวเลือก :distinct อยู่
นอกจากนั้นการกำหนดค่า named_scope โดยใช้ option hash และเมธอด #scoped_by_xxx และ #default_scope ก็ถูกถอดออกเช่นกัน
# all lines here are deprecated named_scope :suspended, :conditions => { :status => "suspended" } default_scope :conditions => "status != 'deleted'" User.scoped_by_status("suspended")
เมธอดใหม่ทั้งหมด
ActiveRecord ใน Rails 3 นั้น จะมีการเพิ่มเมธอดเหล่านี้
- where
- having
- select
- group
- order
- limit
- offset
- joins
- includes
- lock
- readonly
- from
เมธอดทุกอย่างนั้นสามารถ chain เข้าหากันได้ เพราะฉะนั้นคุณก็จะสามารถทำอย่างนี้ได้
User.where(:status => "suspended").includes(:event_log).limit(15).order(:name) User.where(:name => "john_doe").joins(:profile)
และเนื่องจาก result ของมันเป็น lazy-loading หมด ทำให้คุณสามารถนำมันไปเก็บในตัวแปร หรือว่าเพิ่ม condition เข้าไปทีหลังได้ โดย SQL จะถูกส่งไปยัง server เมื่อคุณเรียกใช้ #each, #first, #all เท่านั้น
suspended_users = User.where(:status => "suspended") latest_suspended_users = suspended_users.order("id DESC").limit(5) User.where(:status => "suspended") # ยังไม่ query User.where(:status => "suspended").all # query แล้ว!
เพราะฉะนั้นถ้าคุณไม่สนใจในเรื่องของการ lazy loading และต้องการจะโหลดข้อมูลลงมาเก็บไว้ใน array ก่อน คุณก็เพียงแค่ใช้ #all ตามหลัง query ของคุณเท่านั้นเอง
suspended_users = User.where(:status => "suspended").all # ข้อมูลถูกเก็บใน suspended_users
named_scope ยังเปลี่ยนไปเป็น scope อีก
นอกจากที่กล่าวมาข้างต้นนั้น ยังมีการเปลี่ยนชื่อเมธอดของ named_scope ให้เป็น scope และรองรับการใช้เมธอดใหม่ของ finder เพราะฉะนั้นจากโค้ด
named_scope :suspended, :conditions => { :status => "suspended" }
ก็ต้องเปลี่ยนไปเป็น
scope :suspended, where({ :status => "suspended"})
นอกจากนั้นยังมีการเพิ่มเติม with_scope และ with_exclusive_scope ซึ่งโค้ดในบล็อกที่ให้มานั้นจะมี scope ตามที่ระบุไว้แทน
with_scope(where( :status => 'suspended')) do ... end
with_exclusive_scope(User.online) do ... end
แล้วเมื่อไรจะต้องเปลี่ยนละเนี่ย …
คุณไม่จำเป็นต้องรีบเปลี่ยนโค้ดในส่วนของการใช้ finder เพราะใน Rails 3.0 นั้น ทุกอย่างยังคงจะใช้ได้ตามปกติ โดยที่มีกำหนดการว่าเมธอดเก่าๆ นั้นจะถูกนำออกไปใน Rails 3.2 ครับ เพราะฉะนั้นคุณก็ยังคงสามารถใช้โค้ดเก่าๆ ในการ query ข้อมูลมาได้ แต่ผมแนะนำว่าค่อยๆ ไล่เปลี่ยนไป ก็จะทำให้โค้ดของคุณพร้อมสำหรับการ upgrade ไปยัง version ใหม่ๆ ครับ


