Как привести тип данных из Rails connection.execute

У меня есть запрос AREL, который я генерировал с большой болью. Для справки (извините):

def self.summarize_user(user)
  c   = Arel::Table.new(:categories)
  s   = Arel::Table.new(:skills)
  cp  = Arel::Table.new(:completions)

  query = c.project(c[:id], c[:name], c[:handle])
    .project(s[:id].count.as("total_skills"))
    .project(cp[:id].count.as("total_completed"))
    .project(cp[:verified_on].count.as("total_verified"))
    .join(s).on(s[:category_id].eq c[:id])
    .join(cp, Arel::Nodes::OuterJoin).on(cp[:skill_id].eq s[:id])
    .where(cp[:user_id].eq(user.id).or(cp[:user_id].eq nil))
    .group(c[:id], c[:name], c[:handle])

  # this is the relevant bit
  connection.execute(query.to_sql)
end

Это выполняет и дает мне правильные результаты из БД, которые выглядят так:

{ "id" => "13",
  "name" => "Category 16",
  "handle" => "category_16",
  "total_skills" => "4",
  "total_completed" => "0",
  "total_verified" => "0"
}

Итак, учитывая, что метод уже монстр, я бы не стал пытаться .inject через результаты, чтобы привести все числа в Fixnum. Есть ли способ, при использовании connection.execute, чтобы привести поля к их соответствующим типам данных?

3 ответа

Решение

Вы можете воспользоваться find_by_sql и to_json

json_records = Arel::Table.find_by_sql(query.to_sql).to_json

Затем вы можете извлечь свои результаты, как

result = JSON.parse json_records

Есть несколько способов конвертировать ActiveRecord возражает против hash, Это всего лишь мое личное предпочтение.

Вы могли бы использовать Virtus

class Summary
  include Virtus.model

  attribute :id, Integer
  attribute :name, String
  attribute :handle, String
  attribute :total_skills, Integer
  attribute :total_completed, Integer
  attribute :total_verified, Integer
end

summary.map { |results| Summary.new(results) }


 hsh = { "id" => "13",
   "name" => "Category 16",
   "handle" => "category_16",
   "total_skills" => "4",
   "total_completed" => "0",
   "total_verified" => "0"
 }

 s = Summary.new(hsh)
 s.total_skills # => 4

Кстати, вот метод, который я предпочел бы не использовать, так как код достаточно сложен, чтобы понять, как он есть.

def self.summarize_user(user)
  # ... sins against nature ...
  result = connection.execute(query.to_sql)
  self.map_summary(result)
end

protected

def self.map_summary(summary)
  summary.map do |result|
    {
      id: result['id'].to_i,
      name: result['name'],
      handle: result['handle'],
      total_skills: result['total_skills'].to_i,
      total_completed: result['total_completed'].to_i,
      total_verified: result['total_verified'].to_i,
    }
  end
end
Другие вопросы по тегам