异常ActiveRecord :: StatementInvalid不起作用

时间:2012-08-21 22:48:35

标签: mysql ruby-on-rails postgresql activerecord exception-handling

我对Rails相对较新,所以我不知道我解决问题的方法是否正确,但是它存在一些问题

我在我的PC上安装了MySQL,但是Heroku使用PostgreSQL,所以我正在设计一个解决方案,以便在某些问题上同时使用DBMS。

我有下一个代码:

begin
   @products_with_valid_offers = Product.joins(:variants).active.discount_valid.discount_date_valid_mySQL

   rescue ActiveRecord::StatementInvalid
      @products_with_valid_offers = Product.joins(:variants).active.discount_valid.discount_date_valid_postgreSQL
end

范围是:

scope :active,  includes([:assets, :store]).where(:active => true, :deleted_at => nil, :stores => { :deleted_at => nil, :active => true }).order("products.created_at DESC")
scope :discount_date_valid_mySQL, where('DATE_FORMAT(NOW(),"%Y-%m-%d 23:59:59") + '" BETWEEN discount_from AND discount_to')
scope :discount_date_valid_postgreSQL, where('now()::date BETWEEN discount_from AND discount_to')

如您所见,我需要两种不同的表单来管理日期格式,每个DBMS一个。 问题是流程永远不会进入异常。如果@products_with_valid_offers是MySQL中的SQL错误,则永远不要进入rescue块执行PostgreSQL行,它会返回错误。

请帮忙吗? :d

1 个答案:

答案 0 :(得分:0)

您的报价在discount_date_valid_mySQL中搞砸了,您想这样说:

scope :discount_date_valid_mySQL, where("DATE_FORMAT(NOW(),'%Y-%m-%d 23:59:59') BETWEEN discount_from AND discount_to")

至少这是有效的Ruby代码。

那就是说,你目前的方法在各方面都很糟糕:

  • 您确保在生产中始终有例外。
  • 您正在一个数据库上进行开发,但在另一个数据库之上进行部署,仅此一项就会导致各种问题。
  • 您应该在MySQL版本中使用date_format(now(), '%Y-%m-%d')

可能存在其他问题,但没有必要花更多时间分开代码:有一种更好的方法。 MySQL和PostgreSQL(甚至是SQLite)都支持current_date,所以你可以只使用一件事:

scope :discount_date_valid, where('current_date between discount_from and discount_to')

当然假设您希望所有内容都采用UTC。如果你想让事情使用其他时区,那么:

  1. 将您的discount_fromdiscount_to存储为日期列,日期在SQL中没有时区。大概你已经这样做了,但我只是想确定一下。
  2. 调整范围以从客户端代码中获取当前日期(可能配置为使用正确的时区):

    def self.discount_date_valid
        where(':current_date between discount_from and discount_to', :current_date => Date.today)
    end
    
  3. 您必须对范围使用类方法,以确保在正确的时间(即使用范围而不是加载类时)评估Date.today

    如果你在PostgreSQL上部署,你真的应该在PostgreSQL之上开发。您甚至应该确保在相同版本的PostgreSQL上开发和部署。在一个堆栈上进行开发并在另一个堆栈上进行部署会导致各种无意义的挫折和混乱。