ฉันพยายามหาวิธีที่ดีที่สุดในการตั้งค่าเริ่มต้นสำหรับวัตถุใน Rails
สิ่งที่ดีที่สุดที่ฉันคิดได้คือการตั้งค่าเริ่มต้นในnew
วิธีการในคอนโทรลเลอร์
ใครมีข้อมูลเข้าบ้างไหมว่าสิ่งนี้ยอมรับได้หรือมีวิธีที่ดีกว่านี้ไหม
ฉันพยายามหาวิธีที่ดีที่สุดในการตั้งค่าเริ่มต้นสำหรับวัตถุใน Rails
สิ่งที่ดีที่สุดที่ฉันคิดได้คือการตั้งค่าเริ่มต้นในnew
วิธีการในคอนโทรลเลอร์
ใครมีข้อมูลเข้าบ้างไหมว่าสิ่งนี้ยอมรับได้หรือมีวิธีที่ดีกว่านี้ไหม
คำตอบ:
"ถูกต้อง" เป็นคำอันตรายใน Ruby โดยปกติจะมีวิธีทำอะไรได้มากกว่าหนึ่งวิธี ถ้าคุณรู้ว่าคุณจะเสมอต้องการค่าเริ่มต้นที่สำหรับคอลัมน์ที่บนโต๊ะที่ตั้งค่าไว้ในแฟ้มการโยกย้ายฐานข้อมูลเป็นวิธีที่ง่ายที่สุด:
class SetDefault < ActiveRecord::Migration
def self.up
change_column :people, :last_name, :type, :default => "Doe"
end
def self.down
# You can't currently remove default values in Rails
raise ActiveRecord::IrreversibleMigration, "Can't remove the default"
end
end
เนื่องจาก ActiveRecord จะค้นหาคุณสมบัติตารางและคอลัมน์ของคุณโดยอัตโนมัติสิ่งนี้จะทำให้ค่าเริ่มต้นเดียวกันถูกตั้งค่าในโมเดลใด ๆ โดยใช้ในแอป Rails มาตรฐานใด ๆ
อย่างไรก็ตามหากคุณต้องการเฉพาะค่าเริ่มต้นที่กำหนดในบางกรณีเช่นเป็นโมเดลที่สืบทอดมาซึ่งแชร์ตารางกับคนอื่น ๆ จากนั้นอีกวิธีหนึ่งที่สวยงามคือทำโดยตรงในรหัส Rails ของคุณเมื่อสร้างวัตถุโมเดล:
class GenericPerson < Person
def initialize(attributes=nil)
attr_with_defaults = {:last_name => "Doe"}.merge(attributes)
super(attr_with_defaults)
end
end
จากนั้นเมื่อคุณทำ a GenericPerson.new()
มันจะปล่อยแอตทริบิวต์ "Doe" ขึ้นมาเสมอPerson.new()
เว้นแต่คุณจะแทนที่ด้วยอย่างอื่น
.new
เมธอดคลาส การสนทนาของโพสต์ในบล็อกเกี่ยวกับการเรียกใช้ ActiveRecord โดยตรง.allocate
นั้นเกี่ยวกับวัตถุโมเดลที่โหลดด้วยข้อมูลที่มีอยู่จากฐานข้อมูล ( และเป็นความคิดที่แย่มากสำหรับ ActiveRecord ที่จะทำงานแบบนั้น IMO แต่นั่นก็อยู่ข้างประเด็นนี้)
change_column_default :people, :last_name, nil
stackoverflow.com/a/1746246/483520
change_column :people, :last_name, :string, default: "Doe"
จากคำตอบของ SFEley นี่คือการปรับปรุง / แก้ไขสำหรับ Rails เวอร์ชันใหม่:
class SetDefault < ActiveRecord::Migration
def change
change_column :table_name, :column_name, :type, default: "Your value"
end
end
change_column
สามารถ "จัดโครงสร้าง" ได้ค่อนข้างมากการดำเนินการย้อนกลับไม่สามารถอนุมานได้ หากคุณไม่แน่ใจให้ทดสอบโดยการเรียกใช้db:migrate
และdb:rollback
ทันทีหลังจากนั้น คำตอบที่ได้รับการยอมรับว่าเป็นผลลัพธ์เดียวกัน แต่อย่างน้อยก็ถือว่า!
up
และdown
เหมือนที่อธิบายไว้ข้างต้นจาก @GoBusto
ก่อนอื่นคุณไม่สามารถโอเวอร์โหลดได้initialize(*args)
เนื่องจากไม่ได้เรียกใช้ในทุกกรณี
ตัวเลือกที่ดีที่สุดคือใส่ค่าเริ่มต้นในการย้ายข้อมูลของคุณ:
add_column :accounts, :max_users, :integer, :default => 10
ประการที่สองที่ดีที่สุดคือการวางค่าเริ่มต้นลงในโมเดลของคุณ แต่จะใช้ได้เฉพาะกับแอตทริบิวต์ที่เป็นศูนย์เริ่มต้นเท่านั้น คุณอาจมีปัญหาเหมือนกับที่ฉันทำกับboolean
คอลัมน์:
def after_initialize
if new_record?
max_users ||= 10
end
end
คุณต้องใช้new_record?
ค่าเริ่มต้นจึงไม่แทนที่ค่าที่โหลดจากฐานข้อมูล
คุณต้อง||=
หยุด Rails จากการแทนที่พารามิเตอร์ที่ส่งผ่านไปยังวิธีการเริ่มต้น
after_initiation :your_method_name
.... 2 ใช้self.max_users ||= 10
after_initialize do
แทนที่จะเป็นdef after_initialize
คุณยังสามารถลองchange_column_default
ในการย้ายข้อมูลของคุณ (ทดสอบใน Rails 3.2.8):
class SetDefault < ActiveRecord::Migration
def up
# Set default value
change_column_default :people, :last_name, "Smith"
end
def down
# Remove default
change_column_default :people, :last_name, nil
end
end
หากคุณอ้างถึงวัตถุ ActiveRecord คุณมี (มากกว่า) สองวิธีในการดำเนินการนี้:
เช่น
class AddSsl < ActiveRecord::Migration
def self.up
add_column :accounts, :ssl_enabled, :boolean, :default => true
end
def self.down
remove_column :accounts, :ssl_enabled
end
end
ข้อมูลเพิ่มเติมที่นี่: http://api.rubyonrails.org/classes/ActiveRecord/Migration.html
เช่น before_validation_on_create
ข้อมูลเพิ่มเติมที่นี่: http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html#M002147
ใน Ruby on Rails v3.2.8 โดยใช้การafter_initialize
เรียกกลับ ActiveRecord คุณสามารถเรียกใช้เมธอดในโมเดลของคุณที่จะกำหนดค่าเริ่มต้นสำหรับอ็อบเจ็กต์ใหม่
after_initialize callback ถูกทริกเกอร์สำหรับแต่ละอ็อบเจ็กต์ที่พบและสร้างอินสแตนซ์โดย finder โดย after_initialize จะถูกทริกเกอร์หลังจากอ็อบเจ็กต์ใหม่ถูกสร้างอินสแตนซ์เช่นกัน ( ดูการเรียกกลับ ActiveRecord )
ดังนั้น IMO ควรมีลักษณะดังนี้:
class Foo < ActiveRecord::Base
after_initialize :assign_defaults_on_new_Foo
...
attr_accessible :bar
...
private
def assign_defaults_on_new_Foo
# required to check an attribute for existence to weed out existing records
self.bar = default_value unless self.attribute_whose_presence_has_been_validated
end
end
Foo.bar = default_value
สำหรับอินสแตนซ์นี้เว้นแต่อินสแตนซ์จะมีการattribute_whose_presence_has_been_validated
บันทึก / อัปเดตก่อนหน้านี้ default_value
จะถูกใช้ร่วมกับมุมมองของคุณจะทำให้รูปแบบโดยใช้default_value
สำหรับbar
แอตทริบิวต์
ที่ดีที่สุดคือแฮ็ค ...
แทนที่จะตรวจสอบค่าแอตทริบิวต์ให้ใช้new_record?
วิธีการในตัวกับราง ดังนั้นตัวอย่างข้างต้นควรมีลักษณะดังนี้:
class Foo < ActiveRecord::Base
after_initialize :assign_defaults_on_new_Foo, if: 'new_record?'
...
attr_accessible :bar
...
private
def assign_defaults_on_new_Foo
self.bar = default_value
end
end
นี่สะอาดกว่ามาก อาวิเศษของ Rails - ฉลาดกว่าฉัน
after_initialize
โทรกลับที่นี่ เอกสารเกี่ยวกับการโทรกลับมีตัวอย่างการตั้งค่าเริ่มต้นbefore_create
โดยไม่ต้องตรวจสอบเงื่อนไขเพิ่มเติม
Subscription
after_initialize
แทนการbefore_create
เรียกกลับคือเราต้องการตั้งค่าเริ่มต้นสำหรับผู้ใช้ (สำหรับใช้ในมุมมอง) เมื่อพวกเขากำลังสร้างวัตถุใหม่ การbefore_create
เรียกกลับจะถูกเรียกหลังจากที่ผู้ใช้ได้รับอ็อบเจ็กต์ใหม่จัดเตรียมอินพุตของพวกเขาและส่งอ็อบเจ็กต์เพื่อสร้างไปยังคอนโทรลเลอร์ จากนั้นคอนโทรลเลอร์จะตรวจสอบการbefore_create
โทรกลับใด ๆ ดูเหมือนจะสวนทางกับสัญชาตญาณ แต่มันเป็นระบบการตั้งชื่อ - before_create
หมายถึงการcreate
กระทำ การสร้างอินสแตนซ์วัตถุใหม่ไม่ใช่create
วัตถุ
สำหรับฟิลด์บูลีนใน Rails 3.2.6 อย่างน้อยสิ่งนี้จะใช้ได้ในการย้ายข้อมูลของคุณ
def change
add_column :users, :eula_accepted, :boolean, default: false
end
การใส่1
หรือ0
เป็นค่าเริ่มต้นจะไม่ทำงานที่นี่เนื่องจากเป็นฟิลด์บูลีน ต้องเป็น a true
หรือfalse
ค่า
ในกรณีที่คุณกำลังจัดการกับ Model คุณสามารถใช้ Attriutes API ใน Rails 5+ http://api.rubyonrails.org/classes/ActiveRecord/Attributes/ClassMethods.html#method-i-attribute
เพียงเพิ่มการย้ายข้อมูลด้วยชื่อคอลัมน์ที่เหมาะสมจากนั้นในโมเดลตั้งค่าด้วย:
class StoreListing < ActiveRecord::Base
attribute :country, :string, default: 'PT'
end
สร้างการโยกย้ายและการใช้งานที่change_column_default
รวบรัดและย้อนกลับได้:
class SetDefaultAgeInPeople < ActiveRecord::Migration[5.2]
def change
change_column_default :people, :age, { from: nil, to: 0 }
end
end
หากคุณเพิ่งตั้งค่าเริ่มต้นสำหรับแอตทริบิวต์บางอย่างของโมเดลที่ได้รับการสนับสนุนฐานข้อมูลฉันจะพิจารณาใช้ค่าคอลัมน์เริ่มต้นของ sql - คุณสามารถอธิบายได้ไหมว่าคุณใช้ค่าเริ่มต้นประเภทใด
มีหลายวิธีในการจัดการปลั๊กอินนี้ดูเหมือนเป็นตัวเลือกที่น่าสนใจ
คำแนะนำในการแทนที่ new / initialize อาจจะไม่สมบูรณ์ Rails จะ (บ่อยครั้ง) เรียกการจัดสรรสำหรับวัตถุ ActiveRecord และการเรียกเพื่อจัดสรรจะไม่ส่งผลให้มีการเรียกเพื่อเริ่มต้น
หากคุณกำลังพูดถึงวัตถุ ActiveRecord ให้ดูที่การแทนที่ after_initialize
โพสต์บล็อกเหล่านี้ (ไม่ใช่ของฉัน) มีประโยชน์:
ค่า ดีฟอลต์ตัวสร้างเริ่มต้นไม่ถูกเรียก
[แก้ไข: SFEley ชี้ให้เห็นว่าจริง ๆ แล้ว Rails ดูที่ค่าเริ่มต้นในฐานข้อมูลเมื่อสร้างอินสแตนซ์วัตถุใหม่ในหน่วยความจำ - ฉันไม่ได้ตระหนักถึงสิ่งนั้น]
ฉันต้องการตั้งค่าเริ่มต้นเหมือนกับที่ระบุเป็นค่าคอลัมน์เริ่มต้นใน DB มันก็เป็นแบบนี้
a = Item.new
a.published_at # => my default value
a = Item.new(:published_at => nil)
a.published_at # => nil
เนื่องจาก after_initialize เรียกกลับหลังจากตั้งค่าแอตทริบิวต์จากอาร์กิวเมนต์จึงไม่มีทางทราบได้ว่าแอตทริบิวต์เป็นศูนย์เนื่องจากไม่เคยตั้งค่าหรือเนื่องจากตั้งใจตั้งค่าเป็นศูนย์ ดังนั้นฉันต้องโผล่เข้าไปข้างในเล็กน้อยและมาพร้อมกับวิธีง่ายๆนี้
class Item < ActiveRecord::Base
def self.column_defaults
super.merge('published_at' => Time.now)
end
end
ใช้งานได้ดีสำหรับฉัน (ราง 3.2.x)
วิธีที่อาจดีกว่า / สะอาดกว่าคำตอบที่เสนอไว้คือการเขียนทับ accessor เช่นนี้:
def status
self['name_of_var'] || 'desired_default_value'
end
โปรดดูที่ "การเขียนทับ accessors เริ่มต้น" ในเอกสาร ActiveRecord :: ฐานและอื่น ๆ จาก StackOverflow เกี่ยวกับการใช้ตัวเอง
ฉันตอบคำถามที่คล้ายกันที่นี่ .. วิธีง่ายๆในการทำสิ่งนี้คือการใช้ Rails attr_accessor_with_default
class SOF
attr_accessor_with_default :is_awesome,true
end
sof = SOF.new
sof.is_awesome
=> true
อัปเดต
attr_accessor_with_defaultเลิกใช้แล้วใน Rails 3.2 .. คุณสามารถทำสิ่งนี้แทนด้วย Ruby แท้
class SOF
attr_writer :is_awesome
def is_awesome
@is_awesome ||= true
end
end
sof = SOF.new
sof.is_awesome
#=> true
attr_accessor_with_default
เลิกใช้แล้วเมื่อราง> 3.1.0
หากคุณกำลังพูดถึงวัตถุ ActiveRecord ฉันใช้อัญมณี "แอตทริบิวต์ - ค่าเริ่มต้น"
เอกสารและดาวน์โหลด: https://github.com/bsm/attribute-defaults
คุณสามารถใช้อัญมณี rail_default_value เช่น:
class Foo < ActiveRecord::Base
# ...
default :bar => 'some default value'
# ...
end
คุณสามารถแทนที่ตัวสร้างสำหรับโมเดล ActiveRecord
แบบนี้:
def initialize(*args)
super(*args)
self.attribute_that_needs_default_value ||= default_value
self.attribute_that_needs_another_default_value ||= another_default_value
#ad nauseum
end