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.
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.
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.
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.
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.
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.
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') 
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With