Rails update_attributes โดยไม่บันทึก?


386

มีทางเลือกอื่นสำหรับ update_attributes ที่ไม่ได้บันทึกบันทึกหรือไม่?

ดังนั้นฉันสามารถทำสิ่งที่ชอบ:

@car = Car.new(:make => 'GMC')
#other processing
@car.update_attributes(:model => 'Sierra', :year => "2012", :looks => "Super Sexy, wanna make love to it")
#other processing
@car.save

BTW ฉันรู้ว่าฉันทำได้@car.model = 'Sierra'แต่ฉันต้องการอัปเดตพวกเขาทั้งหมดในบรรทัดเดียว


คุณหมายถึง "ไม่บันทึกข้อมูล" หรือไม่
Anatoly

update_attributes บันทึกรูปแบบฐานข้อมูล ฉันสงสัยว่ามีวิธีการที่คล้ายกันหรือไม่
tybro0103

3
คุณลักษณะวิธีการไม่ทำลาย ดูAPIสำหรับรายละเอียด
Anatoly

3
คุณสามารถใช้ update_column (ชื่อ, ค่า) อัปเดตแอตทริบิวต์เดียวของวัตถุโดยไม่ต้องโทรบันทึก 1. การตรวจสอบถูกข้ามไป 2. การโทรกลับถูกข้ามไป 3. คอลัมน์ updated_at / updated_on จะไม่ได้รับการอัปเดตหากมีคอลัมน์นั้น apidock.com/rails/ActiveRecord/Persistence/update_column
แอนทอน

10
สำหรับ 3.1+ ให้ใช้assign_attributes apidock.com/rails/ActiveRecord/Base/assign_attributes
elado

คำตอบ:


597

assign_attributesผมเชื่อว่าสิ่งที่คุณกำลังมองหาอยู่

โดยพื้นฐานแล้วมันเหมือนกับ update_attributes แต่มันไม่ได้บันทึกเร็กคอร์ด:

class User < ActiveRecord::Base
  attr_accessible :name
  attr_accessible :name, :is_admin, :as => :admin
end

user = User.new
user.assign_attributes({ :name => 'Josh', :is_admin => true }) # Raises an ActiveModel::MassAssignmentSecurity::Error
user.assign_attributes({ :name => 'Bob'})
user.name        # => "Bob"
user.is_admin?   # => false
user.new_record? # => true

ตัวอย่างของคุณทำให้เข้าใจผิดเล็กน้อยเนื่องจากคุณไม่ได้วางบรรทัดนี้จากโมเดล: attr_accessible :is_admin, :as => :admin;)
Robin

@Robin attr_protected :is_adminหรือเพียงแค่: หรือ: attr_accessible :nameจุดที่เป็นในตัวอย่างนี้: is_admin ได้รับการคุ้มครอง ฉันควรทราบด้วยว่าการพยายามกำหนดแอตทริบิวต์ที่ได้รับการป้องกันโดยรวม.assign_attributesจะเพิ่มขึ้นอย่างแน่นอนActiveModel::MassAssignmentSecurity::Errorแม้ว่าจะไม่ได้แสดงในตัวอย่าง
Ajedi32

ใช่ แต่บรรทัดของฉันมาจากเอกสารที่คุณเชื่อมโยง ฉันแค่บอกว่าคุณควรคัดลอก / วางตัวอย่างทั้งหมด แต่ใช่คุณสามารถพูดได้ว่ามันได้รับการคุ้มครอง
Robin

@ Robin ฉันจะอัปเดตตัวอย่างให้ชัดเจนยิ่งขึ้น ตัวอย่างในเอกสารยังทำให้เข้าใจผิดเล็กน้อยเนื่องจากไม่ได้กล่าวถึงuser.assign_attributes({ :name => 'Josh', :is_admin => true })ข้อความแจ้งข้อผิดพลาดและไม่ได้ตั้งค่าคุณสมบัติชื่อของผู้ใช้
Ajedi32

7
assign_attributes สามารถใช้ได้จาก Rails 3.1 เป็นต้นไปดังนั้นคุณจะไม่สามารถใช้งานได้หากคุณยังคงใช้ Rails เวอร์ชันเก่าอยู่
Haegin

173

คุณสามารถใช้assign_attributesหรือattributes=(พวกเขาเหมือนกัน)

อัพเดทวิธีโกงสูตร (สำหรับ Rails 6):

  • update= assign_attributes+save
  • attributes= = นามแฝงของ assign_attributes
  • update_attributes = เลิกใช้แล้วนามแฝงของ update

ที่มา:
https://github.com/rails/rails/blob/master/activerecord/lib/active_record/persistence.rb
https://github.com/rails/rails/blob/master/activerecord/lib/active_record/attribute_assignment .rb

อีกแผ่นโกง:
http://www.davidverhasselt.com/set-attributes-in-activerecord/#cheat-sheet


1
ชัดเจนและสั้น ขอบคุณ
freemanoid

1
ในกรณีของ. attributes = val หากโมเดลของคุณมี__oneและยอมรับ s_nested_attributes_ สำหรับโมเดลอื่นการส่งผ่านนั่นคือโมเดล แต่ assign_attributes ไม่ทำงานเช่นนั้น
ClassyPimp

65

คุณสามารถใช้วิธีการ 'แอตทริบิวต์':

@car.attributes = {:model => 'Sierra', :years => '1990', :looks => 'Sexy'}

ที่มา: http://api.rubyonrails.org/classes/ActiveRecord/Base.html

attribute = (new_attributes, guard_protected_attributes = true) ให้คุณตั้งค่าคุณลักษณะทั้งหมดในครั้งเดียวโดยส่งแฮชที่มีคีย์ที่ตรงกับชื่อแอตทริบิวต์ (ซึ่งตรงกับชื่อคอลัมน์อีกครั้ง)

หาก guard_protected_attributes เป็นจริง (ค่าเริ่มต้น) แล้วแอตทริบิวต์ที่ละเอียดอ่อนสามารถได้รับการปกป้องจากรูปแบบการมอบหมายจำนวนมากโดยใช้แมโคร attr_protected หรือคุณสามารถระบุแอตทริบิวต์ที่สามารถเข้าถึงได้ด้วยแมโคร attr_accessible จากนั้นแอตทริบิวต์ทั้งหมดที่ไม่รวมอยู่ในนั้นจะไม่ได้รับอนุญาตให้มีการมอบหมายจำนวนมาก

class User < ActiveRecord::Base
  attr_protected :is_admin
end

user = User.new
user.attributes = { :username => 'Phusion', :is_admin => true }
user.username   # => "Phusion"
user.is_admin?  # => false

user.send(:attributes=, { :username => 'Phusion', :is_admin => true }, false)
user.is_admin?  # => true

7

สำหรับการกำหนดค่าจำนวนมากให้กับโมเดล ActiveRecord โดยไม่บันทึกให้ใช้วิธีassign_attributesหรือ attributes=วิธีการเหล่านี้มีอยู่ใน Rails 3 และใหม่กว่า อย่างไรก็ตามมีความแตกต่างเล็กน้อยและ gotchas ที่เกี่ยวข้องกับเวอร์ชันที่ต้องระวัง

ทั้งสองวิธีปฏิบัติตามการใช้งานนี้:

@user.assign_attributes{ model: "Sierra", year: "2012", looks: "Sexy" }

@user.attributes = { model: "Sierra", year: "2012", looks: "Sexy" }

โปรดทราบว่าไม่มีวิธีใดที่จะทำการตรวจสอบหรือดำเนินการเรียกกลับ การเรียกกลับและการตรวจสอบจะเกิดขึ้นเมื่อsaveมีการโทร

ราง 3

attributes=แตกต่างจากassign_attributesใน Rails เล็กน้อย3 attributes=จะตรวจสอบว่าข้อโต้แย้งที่ส่งผ่านไปนั้นคือแฮชและส่งกลับทันทีถ้าไม่ใช่ assign_attributesไม่มีการตรวจสอบแฮช ดูเอกสาร API ActiveRecord attributes=การกำหนดแอตทริบิวต์สำหรับ

รหัสที่ไม่ถูกต้องต่อไปนี้จะล้มเหลวโดยไม่ส่งคืนโดยไม่ต้องตั้งค่าแอตทริบิวต์:

@user.attributes = [ { model: "Sierra" }, { year: "2012" }, { looks: "Sexy" } ]

attributes= จะทำงานอย่างเงียบ ๆ ราวกับว่าได้รับมอบหมายสำเร็จเมื่อพวกเขาไม่ได้ทำ

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

@user.assign_attributes([ { model: "Sierra" }, { year: "2012" }, { looks: "Sexy" } ])

assign_attributesจะเพิ่มNoMethodErrorข้อยกเว้นสำหรับการstringify_keysระบุว่าอาร์กิวเมนต์แรกไม่ใช่แฮช ข้อยกเว้นนั้นไม่ได้ให้ข้อมูลมากนักเกี่ยวกับสาเหตุที่แท้จริง แต่ความจริงที่ว่าข้อยกเว้นนั้นเกิดขึ้นเป็นอย่างมากความสำคัญ

ความแตกต่างเพียงอย่างเดียวระหว่างกรณีเหล่านี้คือวิธีที่ใช้สำหรับการมอบหมายจำนวนมาก: attributes=ประสบความสำเร็จอย่างเงียบ ๆ และassign_attributesยกข้อยกเว้นเพื่อแจ้งว่ามีข้อผิดพลาดเกิดขึ้น

ตัวอย่างเหล่านี้อาจดูเหมือน contrived และพวกเขามีในระดับหนึ่ง แต่ประเภทของข้อผิดพลาดนี้สามารถเกิดขึ้นได้เมื่อมีการแปลงข้อมูลจาก API หรือแม้กระทั่งเพียงแค่ใช้ชุดของการแปลงข้อมูลและลืมที่จะผลการสุดท้ายHash[] .mapรักษารหัส 50 บรรทัดด้านบนและ 3 ฟังก์ชันออกจากการกำหนดคุณสมบัติของคุณและคุณมีสูตรสำหรับความล้มเหลว

บทเรียนที่มีทางรถไฟ 3 คือ: เสมอใช้แทนassign_attributesattributes=

ราง 4

ในรางที่ 4 เป็นเพียงนามแฝงที่จะattributes= assign_attributesดูเอกสาร API ActiveRecord attributes=การกำหนดแอตทริบิวต์สำหรับ

ด้วย Rails 4 วิธีใดวิธีหนึ่งอาจถูกใช้แทนกันได้ ความล้มเหลวในการส่งแฮชเป็นอาร์กิวเมนต์แรกจะทำให้เกิดข้อยกเว้นที่มีประโยชน์มาก:ArgumentError: When assigning attributes, you must pass a hash as an argument.

การตรวจสอบ

หากคุณกำลังเตรียมการบินล่วงหน้าเพื่อเตรียม a saveคุณอาจสนใจตรวจสอบก่อนบันทึกเช่นกัน คุณสามารถใช้valid?และinvalid?วิธีการนี้ ทั้งสองคืนค่าบูลีน valid?ผลตอบแทนจริงถ้ารุ่นที่ไม่ได้บันทึกผ่านการตรวจสอบทั้งหมดหรือเท็จถ้ามันไม่ได้ invalid?เป็นเพียงสิ่งที่ตรงกันข้ามvalid?

valid? สามารถใช้ดังนี้:

@user.assign_attributes{ model: "Sierra", year: "2012", looks: "Sexy" }.valid?

นี้จะช่วยให้คุณสามารถที่จะจัดการกับปัญหาการตรวจสอบใด ๆ saveล่วงหน้าของการโทร

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