การเข้าถึงความสัมพันธ์ในเครื่องมือเริ่มต้น mongoid

ฉันกำลังย้ายโครงการจาก MongoMapper ไปยัง Mongoid ฉันมีสองโมเดล Graph และ Point ที่มีความสัมพันธ์ 1-N อ้างอิง ดังนั้นจุด belongs_to :graph และแต่ละกราฟ has_many :points ฉันได้แทนที่ตัวเริ่มต้นในโมเดล Point เนื่องจากฉันต้องอ้างอิงสถานะบางอย่างจากอินสแตนซ์กราฟที่เป็นของจุดนั้นเพื่อให้สามารถเริ่มต้นจุดได้อย่างถูกต้อง

อย่างไรก็ตาม ดูเหมือนว่าความสัมพันธ์จะไม่ได้รับการเตรียมใช้งานแม้ว่าจะเรียก super ในเครื่องมือเริ่มต้นแล้วก็ตาม ฉันจะตั้งค่าสถานะของคะแนนได้อย่างถูกต้องได้อย่างไร?

นี่คือเวอร์ชันที่เรียบง่ายของสองคลาสของฉันและเครื่องมือเริ่มต้น:

class Graph
  include Mongoid::Document

  has_many :points,  dependent: :delete

  field :type,       type: String
  field :timezone,   type: String

  # ...etc...
end

class Point
  include Mongoid::Document

  belongs_to :graph

  field :date,    type: Date
  field :value,   type: Float
  field :urtext,  type: String  # as originally entered by user
  field :nextday, type: Date

  attr_accessible :urtext

  validates :value, presence: true
  validates :date,  presence: true

  def initialize(params, options={})
    super(params, options)
    parse_urtext
  end

  def parse_urtext(ur)
    # for the sake of argument, imagine this is doing some critical calculation
    # that requires info derived from current state of the graph at creation
    # and which is related to parsing the urtext

    self.date, self.value = urtext.split(",")
    self.nextday = Time.use_zone(self.graph.timezone){ Time.zone.now.to_date + 1 }
  end
end

เมื่อฉันพยายามสร้างจุดใหม่ที่เกี่ยวข้องกับกราฟ ฉันได้รับข้อผิดพลาดศูนย์จากเครื่องมือเริ่มต้น

# in a console:
> g = Graph.first
> p = g.points.build( urtext: "2015-11-30,1" )
  NoMethodError: undefined method `timezone' for nil:NilClass
      from /rails_root/app/models/point.rb:34:in `parse_urtext'
      from /rails_root/app/models/point.rb:22:in `initialize'
      from /.../.rvm/gems/ruby-2.2.0/gems/mongoid-3.1.7/lib/mongoid/factory.rb:23:in `new'
      ...

ใครสามารถอธิบายได้ว่าทำไมสิ่งนี้ถึงไม่ทำงาน ฉันสามารถเขียนเมธอด build_point บนโมเดล Graph และสร้าง Points แบบนั้นได้เสมอ แต่แล้วฉันก็สูญเสียประโยชน์ของการปฏิบัติตามแบบแผนของ Rails ดูเหมือนว่าการโทรกลับจะไม่ทำให้ฉันเข้าใจพฤติกรรมที่ฉันต้องการเช่นกัน (การตรวจสอบความถูกต้องเป็นสิ่งแรกที่จะดำเนินการ และฉันต้องการเริ่มต้นสถานะให้เสร็จสิ้นก่อนการตรวจสอบความถูกต้อง)

Rails 3.2.22, Mongoid 3.1.7


person Bee    schedule 30.11.2015    source แหล่งที่มา


คำตอบ (1)


คุณกำลังทำเรื่องนี้ผิด การเอาชนะ initialize เมื่อใช้ O[RD]M แทบจะเป็นความคิดที่ไม่ดีเสมอไป

วิธีการทั่วไปที่ใช้กันทั่วไปคือการใช้ hooks วงจรชีวิตมาตรฐานเพื่อแยกวิเคราะห์สิ่งต่างๆ ตัวอย่างเช่น คุณสามารถใช้ before_validation:

class Point
  include Mongoid::Document

  belongs_to :graph

  field :date,    type: Date
  field :value,   type: Float
  field :urtext,  type: String
  field :nextday, type: Date

  before_validation :parse_urtext, :if => :urtext_changed?

  validates :value, presence: true
  validates :date,  presence: true

private

  def parse_urtext
    self.date, self.value = self.urtext.split(",")
    self.nextday = Time.use_zone(self.graph.timezone){ Time.zone.now.to_date + 1 }
  end

end

ในบางกรณี คุณสามารถแทนที่เมธอด urtext mutator ได้:

def urtext=(v)
  ...
end

แต่นั่นจะใช้ไม่ได้ผลที่นี่ การพูดว่า g.points.build( urtext: "2015-11-30,1" ) จะเป็นการโทร #urtext= แต่ไม่จำเป็นก่อนที่ #graph_id= จะถูกเรียก ดังนั้นคุณจึงสามารถ (และในกรณีนี้จะโทร) มี self.graph.nil? เมื่อ #urtext= ถูกเรียกระหว่าง g.points.build(...)

ฉันมักจะใช้ before_validation hooks สำหรับสิ่งนี้ และจากนั้น validates hooks เพื่อให้แน่ใจว่าการโทร before_validation ทำสิ่งที่ถูกต้อง

person mu is too short    schedule 02.12.2015
comment
ฉันเริ่มลองใช้การเรียกกลับวงจรชีวิต แต่โดยพื้นฐานแล้วมีสภาวะการแข่งขันเพราะฉันใส่รหัสของฉันในการเรียกกลับ after_create โดยให้เหตุผลว่าสถานะกราฟ/ความสัมพันธ์หวังว่าจะเริ่มต้นได้ในตอนนั้น ฉันไม่เคยทำการเรียกกลับสำหรับการสร้างเลย เพราะเป้าหมายไม่ถูกต้อง และเป้าหมายนั้นไม่ถูกต้องเพราะฉันไม่เคยสร้างมันขึ้นมาเลย... ฉันจะต้องคิดให้ละเอียดอีกสักหน่อยจึงจะเห็น ถ้าฉันสามารถใช้ before_validation hooks เพื่อทำสิ่งนี้ได้ - person Bee; 03.12.2015