我正在尝试从用户那里获取日期,并将其作为纯文本发送到电子邮件中,格式如下:“2015年7月30日”。
为了做到这一点,如果我得到的输出是一个字符串,我可以这样做:
Date.parse("2015-07-30").strftime("%m/%d/%Y")
问题是,我得到了一个FixNum。
问题很多:
Date.parse
对其进行解析,则会变为“2001”。Date.parse
...它会抛出'无效日期'。例如:
(2016-02-13).to_s #=> "2001"
(2016-02-13).to_date #=> NoMethodError: undefined method `to_date' for 2001:Fixnum
Date.parse("2001").strftime("%m/%d/%Y") #=> invalid date
因此,如果我可以将2015-07-30
转换为"2015-07-30"
,那么它会起作用:
Date.parse("2015-07-30").strftime("%m/%d/%Y") #=> "07/30/2015"
然后我尝试使用date_select
代替date_field
,但现在消息到达时这些字段为空。
有什么建议吗?
这是我的表格:
= form_for @contact do |f|
= f.text_field :product_name
= f.date_field :purchase_date
= f.submit
这是我的代码:
<%= message.subject %>
<% @resource.mail_form_attributes.each do |attribute, value|
if attribute == "mail_subject"
next
end
%>
<%= "#{@resource.class.human_attribute_name(attribute)}: #{Date.parse(value).class == Date ? Date.parse(value).strftime("%m/%d/%Y") : value}" %>
<% end %>
我的控制器:
class ContactsController < ApplicationController
before_action :send_email, except: [:create]
def create
@contact = Contact.new(params[:contact])
@contact.request = request
if @contact.deliver
@thank = "Thank you for your message!"
@message = "We have received your inquiry and we'll be in touch shortly."
else
@error = "Cannot send message. Please, try again."
end
end
def contact_page
end
def product_complaint
@the_subject = "Product Complaint Form"
end
private
def send_email
@contact = Contact.new
end
end
我的模特:
class Contact < MailForm::Base
# all forms
attribute :mail_subject
attribute :first_name, validate: true
attribute :last_name, validate: true
# product-complaint
attribute :best_by, validate: true, allow_blank: true # date
attribute :bag_code, validate: true, allow_blank: true
attribute :purchase_date, validate: true, allow_blank: true # date
attribute :bag_opened, validate: true, allow_blank: true # date
attribute :problem_noticed, validate: true, allow_blank: true # date
# all forms
attribute :message, validate: true
attribute :nickname, captcha: true
def headers
{
content_type: "text/plain",
subject: %(#{mail_subject}),
to: "xxxxx@xxxxxxx.com",
# from: %("#{first_name.capitalize} #{last_name.capitalize}" <#{email.downcase}>)
from: "xxx@xxxxx.com"
}
end
end
答案 0 :(得分:3)
(2016-02-13).to_date #=> NoMethodError: undefined method `to_date' for 2001:Fixnum
您收到此错误,因为您没有围绕该值的引号。即它不是一个字符串,它是一个应用减法的数字。这被解释为
2016 - 2
2014 - 13
2001.to_date
需要('2016-02-13').to_date
如果您无法将其作为字符串获取,您是否可以发布从用户开始获取它的方式? (日期字段应该向您的控制器发送一个字符串,而不是一系列数字)
答案 1 :(得分:2)
您不了解从表单接收值的内容:您不能接收整数,fixnum或除字符串之外的任何其他内容。所以,你不能收到2016-02-13
。相反,您可以获得"2016-02-13"
或"2016"
,"02"
或"2"
和"13"
,具体取决于表单。如果你在Rails下运行,那么它就得到了字符串,并且通过它的元数据理解你想要一个整数(它实际上应该被定义为一个字符串),然后它将它转换为一个整数。
无论哪种方式,当你写:
(2016-02-13).to_s
(2016-02-13).to_date
你正在将这种误解传播到你的测试中。这就是 MUST 的写法,因为你需要使用字符串:
require 'active_support/core_ext/string/conversions'
("2016-02-13").to_s # => "2016-02-13"
("2016-02-13").to_date # => #<Date: 2016-02-13 ((2457432j,0s,0n),+0s,2299161j)>
您可以创建日期而不使用字符串:Ruby的Date
初始化程序允许我们传递年,月和日值并接收新的Date对象:
year, month, day = 2001, 1, 2
date = Date.new(year, month, day) # => #<Date: 2001-01-02 ((2451912j,0s,0n),+0s,2299161j)>
date.year # => 2001
date.month # => 1
date.day # => 2
继续......
在Ruby中解析日期很快就证明它不是以美国为中心的语言。美国人认为01/01/2001的所有日期都是“MM / DD / YYYY”,但这是一个不好的假设,因为世界其他地方的大部分都使用“DD / MM / YYYY”。不知道这意味着在该假设下编写的代码做错了。考虑一下:
require 'date'
date = Date.parse('01/02/2001')
date.month # => 2
date.day # => 1
显然有些“错误”正在发生,至少对于'mericans来说。这一点非常明显:
date = Date.parse('01/31/2001')
# ~> -:3:in `parse': invalid date (ArgumentError)
这是因为没有月份“31”。在上一个'01/02/2001'
的例子中,这种误解意味着程序员认为它应该是“1月2日”,但是代码认为它是“2月1日”,并且使用它。这可能会对企业系统造成严重破坏,或者涉及财务计算,产品调度,运输或其他任何与日期有关的事情。
因为代码假定为这种字符串的DD / MM / YYYY格式,所以要做的事情是:
强制日期解析器使用明确的日期格式,以便始终做正确的事情:
Date.strptime('01/31/2001', '%m/%d/%Y') # => #<Date: 2001-01-31 ((2451941j,0s,0n),+0s,2299161j)>
Date.strptime('31/01/2001', '%d/%m/%Y') # => #<Date: 2001-01-31 ((2451941j,0s,0n),+0s,2299161j)>
最后一点是编写代码的关键:我们告诉语言该做什么,而不是让自己和我们的雇主接受猜测的代码。给代码一半机会它会做错误的事情,所以你控制它。这就是为什么编程很难的原因。