Rails ActiveRecord Arels:不支持的参数类型:字符串。改为构建 Arel 节点

Rails ActiveRecord Arels: Unsupported argument type: String. Construct an Arel node instead

我正在使用 Arels 创建查询。在此查询中,我使用 generate_series 函数。这是我的代码:

    def generate_series
      Arel::Nodes::NamedFunction.new('GENERATE_SERIES', [start_date, end_day, '1 day'])
    end

def start_date
      Arel::Nodes::SqlLiteral.new(<<-SQL
         CASE WHEN DATE_PART('hour', NOW() AT TIME ZONE 'ICT') < #{Time.now - 3days} THEN (CURRENT_DATE - INTERVAL '14 days') ELSE (CURRENT_DATE - INTERVAL '13 days') END
      SQL
      )
    end

    def end_date
      Arel::Nodes::SqlLiteral.new(<<-SQL
         CASE WHEN DATE_PART('hour', NOW() AT TIME ZONE 'ICT') < #{Time.now} THEN (CURRENT_DATE - INTERVAL '1 day') ELSE CURRENT_DATE END
      SQL
      )
    end

当我尝试通过 generate_series.to_sql 进行测试时。我遇到异常:

Arel::Visitors::UnsupportedVisitError: Unsupported argument type: String. Construct an Arel node instead.

我尝试缩短测试代码:

def generate_series
      Arel::Nodes::NamedFunction.new('GENERATE_SERIES', ['19/11/2012', '20/11/2012', '1 day'])
 end

问题是一样的。请告诉我如何解决这个问题。

你的最后一个参数应该是 Arel::Nodes。所以你应该把 1 day 包装成 Arel::Nodes:SqlLiteral。这是更新的代码:

def generate_series
      Arel::Nodes::NamedFunction.new('GENERATE_SERIES', 
             [start_date, end_date, Arel::Nodes::SqlLiteral.new('\'1 day\'')]
      )
end

请注意,您还必须将 1 day 括在(单)引号内,即:'1 day'。因为如果你不这样做,生成的查询将是:

GENERATE_SERIES(start, stop, 1 day) 

但真正的查询应该是:

GENERATE_SERIES(start, stop, '1 day') 

您可以使用 Arel::Nodes.build_quoted 来引用文字:

def generate_series
      Arel::Nodes::NamedFunction.new('GENERATE_SERIES', 
             [start_date, end_date, Arel::Nodes.build_quoted('1 day')]
      )
end

这样做的好处是您不必像使用 Arel::Nodes::SqlLiteral 那样记住包含和手动转义引号。