Rails 4:接受year作为字符串并存储为日期

时间:2014-03-09 17:45:30

标签: ruby-on-rails

在我的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

2 个答案:

答案 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之前访问原始日期字符串。