Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I'm using Arels for creating query. In this query, I use generate_series function. Here is my code:

    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

When I try to test by generate_series.to_sql. I meet exception:

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

I try to shorter my code for testing:

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

The problem is same. Please tell me how can I fix this problem.

like image 296
Trần Kim Dự Avatar asked Dec 20 '16 15:12

Trần Kim Dự


People also ask

What is Arel in rails 6?

Arel is a domain-specific-language allowing to express your queries in relational algebra. In past versions of Rails it was rather common to have to resort to Arel in order to accomplish some rather frequently requested functionalities, though nowadays Rails 6's Active Record already covers most of these use cases.

What is active record in Ruby?

The #activerecord is what binds the model in our ruby application with its respective database table. The Active record object comes with a set of methods to help us query database records so theres no need to use raw SQL. For comparation purposes will present the translation of our activerecord queries to sql queries.

How to create reusable queries in rails?

In older versions of rails, you should use the ActiveRecord::Base#scope class method to create such reusable queries. You are able to attain the same functionality by simply defining class methods: After defining the queries in such fashion, you are able to chain these high level abstractions together.

What is the use of active record in SQL?

The Active record object comes with a set of methods to help us query database records so theres no need to use raw SQL. For comparation purposes will present the translation of our activerecord queries to sql queries.


2 Answers

You can use Arel::Nodes.build_quoted to quote literals:

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

The advantage of this is that you don't have to remember to include and manually escape quotes like you do with Arel::Nodes::SqlLiteral.

like image 102
Tyler Rick Avatar answered Oct 03 '22 00:10

Tyler Rick


Your last parameter should be an Arel::Nodes. So you should wrap 1 day into an Arel::Nodes:SqlLiteral. Here is updated code:

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

Noted that you must also wrap 1 day inside (single) quotes, i.e: '1 day'. Because if you don't do this, the generated query will be:

GENERATE_SERIES(start, stop, 1 day) 

But true query should be:

GENERATE_SERIES(start, stop, '1 day') 
like image 44
hqt Avatar answered Oct 03 '22 02:10

hqt