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

ลดความซับซ้อน Models: ใช้ ActiveRecord Enums สำหรับ Attributes ที่ชัดเจน อ่านง่าย

โจทย์ที่อาจเป็น "pending", "approved", หรือ "flagged" หรือเบอร์โทรที่เป็น "home", "office", "mobile", หรือ "fax" (ถ้าเป็นปี 1982)

บาง models ต้องการข้อมูลแบบนี้ Attribute ที่มีค่าได้เพียงค่าหนึ่งจากชุดค่าที่จำกัด และชุดค่านั้นเกือบไม่เปลี่ยน

สถานการณ์ที่ถ้าเป็น plain Ruby คุณจะ用 symbol

คุณอาจสร้าง model PhoneNumberType หรือ QuestionStatus และ belongs_to relationship เพื่อเก็บค่าเหล่านี้ แตไม่คุ้มค่า อาจ stuff ลง yaml file แตตอนนี้ต้องไปดูที่ต่างหากเพื่อรู้ว่า object ทำอะไรได้บ้าง

ใน Rails 4.1 Rails พยายามแก้ปัญหานี้ด้วย ActiveRecord enums

ค่าจำกัดใน Model

ActiveRecord enums ง่ายมาก ให้ model มี column integer:

bin/rails g model phone number:string phone_number_type:integer

ระบุค่าที่ attribute รับได้:

app/models/phone.rb
class Phone < ActiveRecord::Base enum phone_number_type: [:home, :office, :mobile, :fax] end

ตอนนี้จัดการกับ strings แทน numbers

แทนที่จะเป็น:

irb(main):001:0> Phone.first.phone_number_type => 3

จะได้:

irb(main):002:0> Phone.first.phone_number_type => "fax"

เปลี่ยน attribute ได้ด้วย strings หรือ ints:

irb(main):003:0> phone.phone_number_type = 1; phone.phone_number_type => "office" irb(main):004:0> phone.phone_number_type = "mobile"; phone.phone_number_type => "mobile"

หรือ用 bang method:

irb(main):005:0> phone.office! => true irb(main):006:0> phone.phone_number_type => "office"

ได้ methods สำหรับถามว่า attribute มีค่าเฉพาะไหม:

irb(main):007:0> phone.office? => true

และหา ทั้งหมด objects ที่มีค่าที่ต้องการ:

irb(main):008:0> Phone.office Phone Load (0.3ms) SELECT "phones".* FROM "phones" WHERE "phones"."phone_number_type" = ? [["phone_number_type", 1]]

ถ้าอยากดูค่าทั้งหมดพร้อม numbers ที่ map ไป ใช้ class method phone_number_types:

irb(main):009:0> Phone.phone_number_types => {"home"=>0, "office"=>1, "mobile"=>2, "fax"=>3}

ทำให้ใส่ใน HTML form ง่าย:

app/views/phones/_form.html.erb
<div class="field"> <%= f.label :phone_number_type %><br> <%= f.select :phone_number_type, Phone.phone_number_types.keys %> </div>

ลดความซับซ้อน Models: ใช้ ActiveRecord Enums สำหรับ Attributes ที่ชัดเจน อ่านง่าย

สิ่งที่ต้องระวัง

Enums ไม่ได้ไม่มีปัญหา ต้องจดจำบางอย่างไว้ถ้าไม่อยากเจอปัญหาภายหลัง

ตอน define enum ลำดับสำคัญ ถ้ากลับมาเปลี่ยนลำดับเป็น alphabetical:

app/models/phone.rb
class Phone < ActiveRecord::Base enum phone_number_type: [:fax, :home, :mobile, :office] end

Phones จะมี types ผิด แก้ได้โดยบอก enum ว่าเลขไหนไปกับค่าไหน:

app/models/phone.rb
class Phone < ActiveRecord::Base enum phone_number_type: {fax: 3, home: 0, mobile: 2, office: 1} end

แตตัวเลือกดีที่สุดคือเก็บลำดับให้ consistent

ปัญหาใหญ่กว่าคือทำยังไงนอกโลก Rails แม้ Rails เห็น enum values เป็น strings พวกมันแค่ numbers ใน database คนดู raw data จะ ไม่มี ว่าตัวเลขเหล่านี้หมายถึงอะไร ทุก app ที่อ่าน database นั้นจะต้องรู้ enum mapping

อาจ dump enum mapping ลง database หรือ yaml ถ้าจำเป็น แตไม่ DRY เพราะ define enum ในสองที่ ถ้าไปไกลขนาดนั้น อาจดีกว่าสร้าง model แยกและ association ให้ Phone belong_to PhoneNumberType

แตถ้าเก็บง่ายๆ enums เป็นวิธีเริ่มต้นที่ดี

P.S. กรณีพลาด Practicing Rails จะอยู่ใน Ruby Book Bundle launching วันจันทร์ 6 กรกฎาคม รับมันและหนังสือ Ruby อื่นๆ อีก 5 เล่ม ราคาพิเศษ!