【问题标题】:Model Attribute Won't Update, Validation Error Called On Separate Attribute Not Being Updated?模型属性不会更新,在未更新的单独属性上调用验证错误?
【发布时间】:2013-01-04 18:30:06
【问题描述】:

我有以下半高级数据库查询,它查看过去 10 年的每小时价格并返回过去 7 天的每日平均价格:

averages = Trade.where('date >= ?', 7.days.ago).average(:price, :group => "DATE_TRUNC('day', date - INTERVAL '1 hour')")

这会返回date(当天)和averageprice,如下所示:

"2012-12-29 00:00:00"=>#<BigDecimal:7f97932be328,'0.2513458333 33333333E2',27(27)>

然后我遍历每个响应并将它们保存为 TradeDailyAverage 模型中的新记录。

    # Loops through each daily average produced above 
    averages.each do |date, avg|

     # Converts the BigDecimal to Floating Point(?)
     averagefloat = avg.to_f

     # Rounds the Daily Average to only two decimal points
     dailyaverage = number_with_precision(averagefloat, :precision => 2)

     # Creates a new Object in the PpDailyAverage table  
     TradeDailyAverage.create(date: date, averageprice: dailyaverage)

这可行,但由于这将是一个每小时 抽成任务,每小时都会有新价格出现,我该如何更改它以首先找到 date 的 TradeDailyAverage,如果它存在,更新averageprice 属性,如果不存在则创建新记录。

Validate_uniqueness 在 TradeDailyAverage 模型上设置。

更新

当我这样做时,会出现 7 个具有准确平均值的项目。但他们就是不会保存。当我添加 newaverage.save! 时,我收到 “验证错误:日期已被占用!”

 newaverage = TradeDailyAverage.find_or_initialize_by_date(date: date)
          newaverage.averageprice = dailyaverage
          puts newaverage.date
          puts newaverage.averageprice

另外,如果我做 newaverage.new_record?曾经平均回报 TRUE

【问题讨论】:

    标签: ruby-on-rails postgresql activerecord


    【解决方案1】:

    我想你会想要这样的:

    tda = TradeDailyAverage.first_or_initialize(date: date)
    tda.averageprice = dailyaverage
    tda.save
    

    【讨论】:

    • 为了测试这一点,我清空了我的 TradeDailyAverage 表,看看这是否会创建新记录。但是,结果是它只创建了一条记录(而不是过去 7 天的每一天的记录)。
    • 我的这三行代码替代了代码最后一行的create 语句。因此,如果您没有获得预期数量的 TradeDailyAverage 条目,则可能是您生成 averages 数组的方式存在问题。你确定它正在生产七件商品吗?
    • 我已经更新了帖子。平均值是无缝生成的,但我无法保存,因为我得到了上面的数据验证。
    • 我知道那是多么令人沮丧。对我来说,一个候选问题是date(如averages.each 中定义)实际上与数据库中存储的值不匹配(因此,您会获得一条新记录)。但是当需要保存时,ActiveRecord 会将其转换为 确实 匹配数据库中已有内容的值,然后验证失败。 pp_daily_averages.date 列是定义为日期还是日期时间?
    • pp_daily_averages.date 被定义为日期时间,而不是日期。我应该怎么做? P.s.感谢您一直以来的帮助:)
    【解决方案2】:

    问题(感谢 Alex 的帮助)是由于日期时间不同造成的。保存到 PG 数据库后,小时会在日期时间发生变化。这可能是由于数据库中的时区问题。因此,上面的代码找不到现有记录,因为它包含的每小时时间与数据库中保存的时间不同。

    由于我生成的是每日平均值,因此我不需要时间,只需要日期列中的日期。因此,我将日期转换为日期以避免时差问题。我还用 Case 稍微更改了代码,以便我可以报告错误。我认为这不是很有效,但它现在正在工作。我相信只要将日期时间值转换为带有.to_date 的日期,Alex 的上述解决方案也可能有效:

    # Loops through each daily average produced above 
        averages.each do |datetime, avg|
    
        # Converts the BigDecimal to Floating Point(?)
        avgfloat = avg.to_f
    
        # Rounds the Daily Average to only two decimal points
        avgprice = number_with_precision(avgfloat, :precision => 2)
    
        # Converts datetime to date since this will not work with datetime (PostgreSQL is time-zoned challenged)    
        avgdate  = datetime.to_date
    
            # These are printed to use for testing. 
          puts avgdate
          puts avgprice
    
          # Starts Case to either report an error, update an existing record, or create new.
          case
    
            when avgdate.blank? || avgprice.blank?
                puts "Something went terribly wrong with your seven day averages producing algorithm."
    
            when TradeDailyAverage.exists?(:date=>avgdate)
                updateavg = TradeDailyAverage.find_by_date(avgdate)
                updateavg.averageprice = avgprice
                updateavg.save
    
            else
                TradeDailyAverage.create(:date=>avgdate, :averageprice=>avgprice)
    
            end # Ends Case  
    
        end # Ends Loop for each Daily Average 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-03-07
      • 1970-01-01
      • 1970-01-01
      • 2013-11-02
      • 1970-01-01
      • 2012-01-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多