Stel virtuele attributen in met behulp van echte attributen

Ik heb een model met een virtueel attribuut voor een tijdsinterval:

attr_accessible :description, :time_end, :time_start, :duration
belongs_to :timesheet

def duration
  if attribute_present?("time_start") and attribute_present?("time_end")
    ChronicDuration.output(self.time_end - self.time_start) 
  else
    ChronicDuration.output(0)
  end
end

def duration=(d)
  self.time_end = self.time_start + d
end

Bij het maken van een nieuw object probeert Rails echter de duur van de start in te stellen, wat tot een fout leidt. Hoe kan ik ervoor zorgen dat de duur is ingesteld op na start?

fout:

undefined method `+' for nil:NilClass

params:

{"utf8"=>"✓",
 "authenticity_token"=>"dg+CysIxZORyV3cwvD+LdWckFdHgecGDFDBNOip+iKo=",
 "entry"=>{"time_start"=>"now",
 "duration"=>"2h",
 "description"=>""},
 "commit"=>"Create Entry"}
0

2 antwoord

1.) Het is niet slim om een ​​attribuut end een naam te geven omdat dat een sleutelwoord is en het kan wat problemen veroorzaken.

2.) Plaats alstublieft uw params-hash

1
toegevoegd
1.) Ik ben het ermee eens. De werkelijke naam is time_end
toegevoegd de auteur Axel Magnuson, de bron

Een paar dingen

  • Worth reading about: and vs && in ruby - http://devblog.avdi.org/2010/08/02/using-and-and-or-in-ruby/
  • some alternates to using attribute_present? method

    # opposite of blank? - http://api.rubyonrails.org/classes/Object.html#method-i-present-3F
    if time_start.present? && time_end.present?
    
    # short hand syntax for present?
    if time_start? && time_end?
    

Ik denk niet dat het probleem is dat de duur wordt ingesteld vóór time_start, ervan uitgaande dat time_start een datum- of tijddatabase is probeer dit in de rails console

entry = Entry.new
entry.time_start = "now" 
# => "now"
entry.time_start
# => nil

je geeft strings door in tijdobjecten en rails/robijn stelt de waarde gewoon op nul. Als time_end en time_start strings waren, denk ik nog steeds niet dat je code je het gewenste resultaat zou geven?

def duration=(d)
  self.time_end = self.time_start + d
end

# params: time_start = "now"
# params: duration = "2h"
# time_end would be: now2h

als ik het verkeerd heb over duration = running voordat time_start is ingesteld, zou een alternatief ongeveer zoiets zijn met een call-call before_save

class Entry < ActiveRecord::Base
  before_save :set_time_end

  attr_accessor :duration
  attr_accessible :description, :time_end, :time_start, :duration

  belongs_to :timesheet

  def duration
    if time_start? && time_end?
      ChronicDuration.output(self.time_end - self.time_start) 
    else
      ChronicDuration.output(0)
    end
  end

  def set_time_end
    return nil if time_start.blank?
    self.time_end = self.time_start + self.duration
  end
end
1
toegevoegd