在我的Rails 4应用程序中,我想在文本字段中接受一年作为字符串,但将其作为日期存储在数据库中,以防我决定接受完整日期。但是,当我尝试这样做时,我会一直得到一个零日期值。我已经验证控制器正确地将参数传递给模型,但在验证发生之前的某个时刻,日期已设置为nil。
我正在尝试做什么?如果是这样,我错过了什么关键步骤?谢谢!
这是表格的相关部分:
<p>
<%= f.label :publication_date %><br>
<%= f.text_field :publication_date, :size => 4 %>
</p>
架构:
create_table "books", force: true do |t|
t.string "title"
t.datetime "created_at"
t.datetime "updated_at"
t.date "publication_date"
...
end
模型验证:
validates :publication_date, length: { is: 4 }, numericality: true
before_validation :check_pub_date
def check_pub_date
# this prints nil
logger.debug "Publication date: #{self.publication_date}"
end
before_save :convert_pub_year
def convert_pub_year
# Never gets here because validation never passes
logger.debug "Publication year: #{self.publication_date}"
if self.publication_date
self.publication_date = DateTime.strptime(self.publication_date, "%Y")
end
end
答案 0 :(得分:1)
鉴于你的模型期待完整的约会,当你只从表单中传递一个字符串时,你会遇到一个问题 - 我会创建一个简单的text_field来捕获年份并从那里开始... < / p>
在你看来
<%= text_field_tag :pub_year %>
在您的控制器中
publication_year = params[:pub_year]
@book.publication_date = DateTime.strptime(publication_year, "%Y")
或当然,将年份解析为模型的完整日期。
编辑 - 对此进行扩展,如果您愿意,也可以在模型中创建一个不会保存到数据库的属性,因此在您的模型中,您将拥有:
attr_accessor :pub_year
然后,在convert_pub_year
中,替换pub_year而不是publication_date
def convert_pub_year
if self.pub_year
self.publication_date = DateTime.strptime(self.pub_year, "%Y")
end
end
除了你想要的任何其他参数外,你的控制器还需要允许pub_year参数 - 所以在私有方法中 - 如下所示:
def book_params
params.require(:book).permit(:title, :pub_year)
end
最后在您看来,删除publication_date' and include
pub_year`:
<%= f.label :pub_year %><br>
<%= f.text_field :pub_year %>
希望有所帮助
答案 1 :(得分:0)
问题的存在是因为验证发生在从控制器传递的字符串的赋值之后,即您验证的不是字符串,而是在类型转换为日期之后的属性。如果失败(因为 - 在您的情况下 - 日期不完整且仅包含一年),该属性为零。 对于像你这样的情况,您可能需要查看attribute_before_type_cast函数/变量,这些函数/变量将允许您在将其类型转换为nil之前访问原始日期字符串。