Mongoid ใส่ค่าทศนิยมลงในฟิลด์เมื่อได้รับสตริง

ฉันใช้ Ruby 1.9.3-p448 และ Rails 3.2.13 ฉันมีโมเดลง่าย ๆ นี้พร้อมการตรวจสอบความถูกต้องของรูปแบบทศนิยม:

class User
  include Mongoid::Document
  include Mongoid::Timestamps

  field :height, type: Float
  field :weight, type: Float

  validates :height, presence: true, format: { with: /[-+]?[0-9]*\.?[0-9]+/ }
  validates :weight, presence: true, format: { with: /[-+]?[0-9]*\.?[0-9]+/ }

end

ถ้าฉันเรียกใช้รหัสนี้:

test = User.new(height:"hi", weight:"try")

มันให้ผลลัพธ์ต่อไปนี้แก่ฉัน:

#<User _id: 51f67b49781018056b000008, created_at: nil, updated_at: nil, height: 0.0,width: 0.0> 

เหตุใด mongoid จึงใส่ค่า 0.0 ถ้าฉันใส่สตริง ฉันคาดว่าจะมีข้อผิดพลาดในการตรวจสอบความถูกต้อง


person Alberto Pellizzon    schedule 29.07.2013    source แหล่งที่มา
comment
คุณคาดหวังข้อผิดพลาดอะไร?   -  person toro2k    schedule 29.07.2013
comment
ฉันคาดว่าจะเกิดข้อผิดพลาดในการตรวจสอบความถูกต้องของรูปแบบ   -  person Alberto Pellizzon    schedule 29.07.2013
comment
นอกจากนี้เมื่อฉันเรียกใช้ User.validators บนคอนโซล มันจะพิมพ์ [#‹Mongoid::Validations::PresenceValidator:0xa7e51d0 @attributes=[:height], @options={}›, # ‹Mongoid::Validations::PresenceValidator:0xa7e38d0 @ คุณลักษณะ=[:น้ำหนัก], @options={}›, #‹Mongoid::Validations::PresenceValidator:0xa907824 @attributes=[:chest], @options={}›]   -  person Alberto Pellizzon    schedule 29.07.2013


คำตอบ (2)


คุณไม่ได้รับข้อผิดพลาดในการตรวจสอบความถูกต้องเนื่องจากวิธีการ new ไม่ทำให้เกิดการตรวจสอบ คุณควรดำเนินการเพื่อดู:

User.create!(height:"hi", weight:"try")
# .../mongoid-3.1.0/lib/mongoid/persistence.rb:335:in `fail_validate!': (Mongoid::Errors::Validations)
# Problem:
#   Validation of User failed.
# Summary:
#   The following errors were found: Height is invalid, Weight is invalid
# ...

เนื่องจากฟิลด์ height และ weight จะถูกเติมด้วย 0.0 เนื่องจาก Strings จะถูกแปลงเป็น Float โดยใช้เมธอด to_f ซึ่งมีการทำงานดังนี้:

'foo'.to_f
# => 0.0

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

1.2 =~ /any_regexp/
# => nil


อัปเดต หากต้องการตรวจสอบว่าฟิลด์เป็นตัวเลขที่ถูกต้อง คุณสามารถใช้ตัวเลือก numericality ได้:

class User
  # ...
  validates :height, presence: true, numericality: true
  # ...
end

User.create!(height: '0.0')
# => #<User ... >

User.create!(height: 'foo')
# Problem:
#  Validation of User failed.
# ...
person toro2k    schedule 29.07.2013
comment
นั่นเป็นปัญหาของฉัน ขอบคุณ! ฉันต้องตรวจสอบรูปแบบในฝั่งไคลเอ็นต์หรือจะตรวจสอบในฝั่งเซิร์ฟเวอร์ด้วยวิธีอื่นได้หรือไม่? - person Alberto Pellizzon; 29.07.2013

MongoDB จัดเก็บข้อมูลในรูปแบบไบนารีที่เรียกว่า BSON ซึ่งรองรับประเภทข้อมูลตัวเลขเหล่านี้:

  • int32 - 4 ไบต์ (จำนวนเต็มที่ลงนาม 32 บิต)
  • int64 - 8 ไบต์ (จำนวนเต็มลงนาม 64 บิต)
  • double - 8 ไบต์ (จุดลอยตัว IEEE 754 64 บิต)

ไม่มีจุดคงที่ที่แน่นอนเทียบเท่ากับประเภททศนิยมของ mySQL ใน MongoDB แต่คุณสามารถจัดเก็บตัวเลขทศนิยม 64 บิตใน Mongo ให้เป็นสองเท่าได้

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

อย่างไรก็ตาม ไดรเวอร์ภาษา MongoDB ส่วนใหญ่สร้างความแตกต่างระหว่างประเภทจำนวนเต็มและจำนวนจุดลอยตัว

จาก -> MongoDB รองรับประเภทจุดลอยตัวหรือไม่

person Mini John    schedule 29.07.2013
comment
ฉันใช้ mongoid และฉันไม่สามารถระบุ Double เป็นประเภทข้อมูลได้ ฉันมีเพียง Flaot two.mongoid org/docs/documents/fields.html - person Alberto Pellizzon; 29.07.2013
comment
โหวตลง เนื่องจากเป็นสำเนาของคำตอบนี้ทุกประการ หากคำตอบควรเหมือนกัน ให้ลิงก์ไปยังคำถามอื่น - person Jon Cairns; 29.07.2013