模型属性不会更新,在不更新的单独属性上调用验证错误?

时间:2013-01-04 18:30:07

标签: ruby-on-rails postgresql activerecord

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

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属性,或创建新记录(如果它不存在)。

在TradeDailyAverage模型上设置Validate_uniqueness。

更新

当我这样做时,会显示7个项目,并且具有准确的平均值。但他们只是赢了。当我添加newaverage.save!时,我收到&#34;验证错误:已经过了日期!&#34;

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

另外,如果我做newaverage.new_record?平均值返回TRUE

2 个答案:

答案 0 :(得分:2)

我想你想要这样的东西:

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

答案 1 :(得分:0)

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

由于我生成每日平均值,因此我不需要时间,只需要日期列中的日期。因此,我将日期转换为日期以避免时差问题。我还使用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