미리 사과 드리겠습니다. 긴 질문이 될 것입니다.레일 : 컨트롤러가 모델을 올바르게 업데이트하지 않습니다.
짧은 버전 :
은 내가 date
, start_time
및 end_time
을 가지고 회의 모델을 가지고있다. 이것들은 시간 객체입니다. 물론 사용자가 입력해야하는 고통이 있습니다. 따라서 저장하기 전에 Chronic으로 구문 분석되는 문자열을 허용하기 위해 가상 속성을 사용하고 있습니다.
나는 폼에서 이러한 가상 속성을 받아 모델에 전달하는 일반 바닐라 레일 컨트롤러를 사용합니다. 내가 예상대로 설정 예를 params[:meeting][:date_string]
를 들어, 컨트롤러가 양식에서 올바른 매개 변수를 수신하는 것을 확인했습니다
def create
@meeting = @member.meetings.build(params[:meeting])
if @meeting.save
redirect_to member_meetings_path(@member), :notice => "Meeting Added"
else
render :new
end
end
def update
@meeting = @member.meetings.find(params[:id])
if @meeting.update_attributes(params[:meeting])
redirect_to member_meetings_path(@member), :notice => "Meeting Updated"
else
render :new
end
end
다음은 컨트롤러입니다.
문제 :이
에 생성은 날짜가 올바르게 설정됩니다,하지만 시간은 UTC에서 설정 한 2000 년에 할당되며, 프론트 엔드에 현지 시간으로 표시되지 않습니다.
업데이트시 날짜가 업데이트되지 않습니다. 시간은 2000-01-01 동안 UTC로 업데이트되지만 유지됩니다. 버전 제가이 모든 것을 나타내는 괜찮은 테스트 커버리지 모델 계층에서 작동이되는이 슈퍼 기괴한하게 무엇
긴. 여기
# DEPENDENCIES require 'chronic' class Meeting < ActiveRecord::Base # MASS ASSIGNMENT PROTECTION attr_accessible :name, :location, :description, :contact_id, :member_id, :time_zone, :date, :start_time, :end_time, :date_string, :start_time_string, :end_time_string # RELATIONSHIPS belongs_to :member belongs_to :contact # CALLBACKS before_save :parse_time # Time IO Formatting attr_writer :date_string, :start_time_string, :end_time_string # Display time as string, year optional def date_string(year=true) if date str = "%B %e" str += ", %Y" if year date.strftime(str).gsub(' ',' ') else "" end end # Display time as string, AM/PM optional def start_time_string(meridian=true) if start_time str = "%l:%M" str += " %p" if meridian start_time.strftime(str).lstrip else "" end end # Display time as string, AM/PM optional def end_time_string(meridian=true) if end_time str = "%l:%M" str += " %p" if meridian end_time.strftime(str).lstrip else "" end end # Display Date and Time for Front-End def time date.year == Date.today.year ? y = false : y = true start_time.meridian != end_time.meridian ? m = true : m = false [date_string(y),'; ',start_time_string(m),' - ',end_time_string].join end private # Time Input Processing, called in `before_save` def parse_time set_time_zone self.date ||= @date_string ? Chronic.parse(@date_string).to_date : Date.today self.start_time = Chronic.parse @start_time_string, :now => self.date self.end_time = Chronic.parse @end_time_string, :now => self.date end def set_time_zone if time_zone Time.zone = time_zone elsif member && member.time_zone Time.zone = member.time_zone end Chronic.time_class = Time.zone end end
은 사양입니다 : 여기 모델이다. 독점적으로 parse_time
콜백을 테스트하려면 실제로 레코드를 만들거나 업데이트하지 않을 때마다이 테스트에서 @meeting.send(:parse_time)
을 호출합니다. require "minitest_helper"
describe Meeting do
before do
@meeting = Meeting.new
end
describe "accepting dates in natural language" do
it "should recognize months and days" do
@meeting.date_string = 'December 17'
@meeting.send(:parse_time)
@meeting.date.must_equal Date.new(Time.now.year,12,17)
end
it "should assume a start time is today" do
@meeting.start_time_string = '1pm'
@meeting.send(:parse_time)
@meeting.start_time.must_equal Time.zone.local(Date.today.year,Date.today.month,Date.today.day, 13,0,0)
end
it "should assume an end time is today" do
@meeting.end_time_string = '3:30'
@meeting.send(:parse_time)
@meeting.end_time.must_equal Time.zone.local(Date.today.year,Date.today.month,Date.today.day, 15,30,0)
end
it "should set start time to the given date" do
@meeting.date = Date.new(Time.now.year,12,1)
@meeting.start_time_string = '4:30 pm'
@meeting.send(:parse_time)
@meeting.start_time.must_equal Time.zone.local(Time.now.year,12,1,16,30)
end
it "should set end time to the given date" do
@meeting.date = Date.new(Time.now.year,12,1)
@meeting.end_time_string = '6pm'
@meeting.send(:parse_time)
@meeting.end_time.must_equal Time.zone.local(Time.now.year,12,1,18,0)
end
end
describe "displaying time" do
before do
@meeting.date = Date.new(Date.today.year,12,1)
@meeting.start_time = Time.new(Date.today.year,12,1,16,30)
@meeting.end_time = Time.new(Date.today.year,12,1,18,0)
end
it "should print a friendly time" do
@meeting.time.must_equal "December 1; 4:30 - 6:00 PM"
end
end
describe "displaying if nil" do
it "should handle nil date" do
@meeting.date_string.must_equal ""
end
it "should handle nil start_time" do
@meeting.start_time_string.must_equal ""
end
it "should handle nil end_time" do
@meeting.end_time_string.must_equal ""
end
end
describe "time zones" do
before do
@meeting.assign_attributes(
time_zone: 'Central Time (US & Canada)',
date_string: "December 1, #{Time.now.year}",
start_time_string: "4:30 PM",
end_time_string: "6:00 PM"
)
@meeting.save
end
it "should set meeting start times in the given time zone" do
Time.zone = 'Central Time (US & Canada)'
@meeting.start_time.must_equal Time.zone.local(Time.now.year,12,1,16,30)
end
it "should set the correct UTC offset" do
@meeting.start_time.utc_offset.must_equal -(6*60*60)
end
after do
@meeting.destroy
end
end
describe "updating" do
before do
@m = Meeting.create(
time_zone: 'Central Time (US & Canada)',
date_string: "December 1, #{Time.now.year}",
start_time_string: "4:30 PM",
end_time_string: "6:00 PM"
)
@m.update_attributes start_time_string: '2pm', end_time_string: '3pm'
Time.zone = 'Central Time (US & Canada)'
end
it "should update start time via mass assignment" do
@m.start_time.must_equal Time.zone.local(Time.now.year,12,1,14,00)
end
it "should update end time via mass assignment" do
@m.end_time.must_equal Time.zone.local(Time.now.year,12,1,15,00)
end
after do
@m.destroy
end
end
end
나중에 테스트 방법에서 대량 할당을 통해 레코드를 만들고 업데이트하는 작업을 특별히 혼합하여 예상대로 작동하는지 확인했습니다. 모든 테스트가 통과합니다.
나는 다음에 어떤 통찰력을 주셔서 감사합니다 :하지 않는 이유는 컨트롤러 # 업데이트 작업의 날짜 업데이트?
왜 설정 한 날짜로부터 시간을 얻지 못하는 걸까요? 이것은 모델 및 스펙에서 작동하지만 컨트롤러를 통해 양식을 통해 제출 된 경우에는 작동하지 않습니다.
시간대가 양식에서 전달되는 시간대로 설정되지 않는 이유는 무엇입니까? 다시 말하지만,이 스펙은 통과합니다. 컨트롤러의 문제점은 무엇입니까?
시간대가 프런트 엔드의 시간대에 표시되지 않는 이유는 무엇입니까?
도움을 주셔서 감사합니다. 나는 몇 시간 동안이 나무에서 숲을 잃어 가고있는 것 같습니다.
하는 업데이트 : AJcodez의 도움을
감사합니다, 나는 몇 가지 문제 보았다
하는 것은 잘못된 날짜, 감사 AJ를 할당했다! 현재 사용 : 내가 제대로 만성를 사용했다
if @date_string.present? self.date = Chronic.parse(@date_string).to_date elsif self.date.nil? self.date = Date.today end
, 내 실수는 데이터베이스 계층에 있었다! 데이터베이스의 필드를
time
대신datetime
으로 설정 했으므로 모든 것이 손상됩니다. 이 책을 읽는 모든 이들에게 교훈 : 데이터베이스 필드로time
을 절대 사용하지 마십시오 (정확히 무엇을하는지, 왜 datetime 대신 사용하는지 이해하지 않는 한).동일한 문제가 발생하여
datetime
으로 필드를 변경하면 문제가 해결됩니다.여기에서 문제는 모델에서보기와 시간에 액세스하는 것과 관련이 있습니다. 이 시간 형식 지정 메소드를 도우미로 이동하면 현재 요청 범위에서 호출되므로 올바르게 작동합니다.
감사합니다. AJ! 당신의 제안은 저의 사각 지대를 넘어 섰습니다.
고맙습니다.이 질문은 100 % 답변이 아니었지만 디버깅 할 수있는 몇 가지 새로운 방법을 발견하게 도와주었습니다. 어떻게 해결했는지에 대한 몇 가지 노트로 답변을 업데이트했습니다. – Andrew