ตรวจสอบเอกลักษณ์ของหลายคอลัมน์


193

มีวิธีการทางรถไฟในการตรวจสอบว่าบันทึกจริงไม่ซ้ำกันและไม่เพียงคอลัมน์? ตัวอย่างเช่นโมเดลมิตรภาพ / ตารางไม่ควรมีบันทึกเหมือนกันหลายอย่างเช่น:

user_id: 10 | friend_id: 20
user_id: 10 | friend_id: 20

7
ยกโทษให้ฉันถ้าฉันหนาแน่น แต่จะช่วยได้อย่างไรในสถานการณ์นี้
re5et

2
ลองใช้ "validates_uniqueness_of" ในแบบจำลองของคุณ หากวิธีนี้ใช้ไม่ได้กับความพยายามในการสร้างดัชนีซึ่งคุณสามารถสร้างการย้ายข้อมูลของ feilds ซึ่งมีคำสั่งเช่น add_index: table, [: column_a,: column_b],: unique => true)
Harry Joy

1
@HarryJoy Is there a rails-way wayเขาถาม และคุณให้เขาวิธีที่ไม่ใช่ทางรถไฟ แต่มาตรฐาน The Active Record way claims that intelligence belongs in your models, not in the database.
สีเขียว

2
น่าเสียดายที่validates :field_name, unique: trueมีแนวโน้มที่จะมีสภาพการแข่งขันดังนั้นแม้ว่าจะมีข้อ จำกัด ที่แท้จริง @HarryJoy ฉันจะ upvote คำตอบที่อธิบายถึงข้อ จำกัด
Pooyan Khosravi

1
คำตอบที่ดีกว่าจากนั้นทั้งหมดที่ระบุไว้ด้านล่างคือstackoverflow.com/a/34425284/1612469อันนี้เพราะมันเป็นอีกเลเยอร์ที่ทำให้แน่ใจว่าทุกอย่างจะทำงานได้อย่างถูกต้อง
Aleks

คำตอบ:


319

คุณสามารถกำหนดขอบเขตการvalidates_uniqueness_ofโทรได้ดังนี้

validates_uniqueness_of :user_id, :scope => :friend_id

83
แค่อยากจะเพิ่มว่าคุณสามารถผ่านหลายขอบเขต params ในกรณีที่คุณต้องการตรวจสอบเอกลักษณ์ในมากกว่า 2 ฟิลด์ Ie: scope => [: friend_id,: group_id]
Dave Rapin

27
แปลกที่คุณไม่สามารถพูดvalidates_uniqueness_of [:user_id, :friend_id]ได้ อาจจำเป็นต้องได้รับการแก้ไขหรือไม่
Alexey

12
Alexey, validates_uniqueness_of [: user_id,: friend_id] จะทำการตรวจสอบความถูกต้องสำหรับแต่ละฟิลด์ที่ระบุไว้ - และเป็นเอกสารและพฤติกรรมที่คาดหวัง
Nikita Hismatov

71
ใน Rails 4 สิ่งนี้จะกลายเป็น: ตรวจสอบความถูกต้อง: user_id, ไม่ซ้ำกัน: {scope:: friend_id}
Marina Martin

3
คุณอาจต้องการเพิ่มข้อความแสดงข้อผิดพลาดที่กำหนดเองเช่น: message => 'มีเพื่อนคนนี้แล้ว'
laffuste

137

คุณสามารถใช้validatesเพื่อตรวจสอบความถูกต้องuniquenessในหนึ่งคอลัมน์:

validates :user_id, uniqueness: {scope: :friend_id}

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

validates :attr, uniqueness: {scope: [:attr1, ... , :attrn]}

อย่างไรก็ตามวิธีการตรวจสอบที่แสดงข้างต้นมีเงื่อนไขการแข่งขันและไม่สามารถมั่นใจได้ว่ามีความสอดคล้อง ลองพิจารณาตัวอย่างต่อไปนี้:

  1. บันทึกตารางฐานข้อมูลควรจะไม่ซ้ำกันโดยเขตข้อมูลn ;

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

  3. แต่ละกระบวนการในแบบคู่ขนานจะตรวจสอบว่ามีเร็กคอร์ดที่มีฟิลด์nเดียวกันหรือไม่

  4. การตรวจสอบความถูกต้องสำหรับแต่ละคำร้องขอถูกส่งสำเร็จและแต่ละกระบวนการสร้างเรกคอร์ดในตารางด้วยข้อมูลเดียวกัน

เพื่อหลีกเลี่ยงพฤติกรรมเช่นนี้ควรเพิ่มข้อ จำกัด ที่ไม่ซ้ำกันลงในตาราง db คุณสามารถตั้งค่าด้วยตัวadd_indexช่วยสำหรับหนึ่ง (หรือหลายรายการ) โดยเรียกใช้การโยกย้ายต่อไปนี้:

class AddUniqueConstraints < ActiveRecord::Migration
  def change
   add_index :table_name, [:field1, ... , :fieldn], unique: true
  end
end

ข้อแม้ : แม้หลังจากที่คุณได้ตั้งข้อ จำกัด ที่ไม่ซ้ำกันแล้วคำขอสองคำขอพร้อมกันจะพยายามเขียนข้อมูลเดียวกันไปยัง db แต่แทนที่จะสร้างระเบียนที่ซ้ำกันสิ่งนี้จะทำให้เกิดActiveRecord::RecordNotUniqueข้อยกเว้นซึ่งคุณควรจัดการแยกต่างหาก:

begin
# writing to database
rescue ActiveRecord::RecordNotUnique => e
# handling the case when record already exists
end 

2

สิ่งนี้สามารถทำได้ด้วยข้อ จำกัด ของฐานข้อมูลในสองคอลัมน์:

add_index :friendships, [:user_id, :friend_id], unique: true

คุณสามารถใช้ตัวตรวจสอบความถูกรางได้ แต่โดยทั่วไปฉันแนะนำให้ใช้ข้อ จำกัด ของฐานข้อมูล

อ่านเพิ่มเติม: https : //robots. Thoughtbot.com/validation-database-constraint-or-both

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.