OpenStruct and ActiveRecord Combo

 2017-10-31 00:00  |   Norly Canarias

What is OpenStruct?

An OpenStruct is a data structure, similar to a Hash, that allows the definition of arbitrary attributes with their
accompanying values. This is accomplished by using Ruby’s metaprogramming to define methods on the class itself. — from ruby-doc

Here is it's basic usage

```ruby require 'ostruct' dog = OpenStruct.new

dog.name = 'Snoop' dog.age = 1

puts dog.name # => 'Snoop' puts dog.age # => 1 ```

You can also inherit from it

```ruby require 'ostruct'

class Dog < OpenStruct end

dog = Dog.new({name: 'Brownie', age: 2}) puts dog.name # => 'Snoop' puts dog.age # => 2 ```

Rails ActiveRecord

You probably know what is Rails ActiveRecord so we will move to the interesting part which is querying using raw sql statements. Yes, ActiveRecord provides find_by_sql but something deeper lies the exec_query. exec_query is a method you can call on ActiveRecord's connection adapter:

ruby ActiveRecord::Base.connection.class => ActiveRecord::ConnectionAdapters::Mysql2Adapter

So, the ActiveRecord::Base.connection returns an instance of ActiveRecord::ConnectionAdapters::Mysql2Adapter and it can change depending on what database you will be using. That adapter has the exec_query method which can be used to perform raw queries like this:

ruby results = ActiveRecord::Base.connection.exec_query('Select * from users limit 2') puts results.class # => ActiveRecord::Result ActiveRecord::Result.ancestors # [... Enumerable ...]

exec_query takes in the query which is a string then returns an instance of ActiveRecord::Result. ActiveRecord::Result inherits from a number of classes and modules including the Enumerable module which means it behaves like an array and enumerates row results which are represented by Hash.

Here we print out each of the hash contained in the result ```ruby results = ActiveRecord::Base.connection.exec_query('Select id, name from users limit 2') results.each do |result| puts result end

=> {'id'=>1, 'name'=>'user1'}

# => {'id'=>2, 'name'=>"user2'} ```

Finally, the combo

```ruby class PersonnelSalesReport < OpenStruct def self.initialize_collection(attributes_list) attributes_list.map do |attributes| PersonnelSalesReport.new(attributes) end end

def foo # … end

def bar # … end end ```

ruby class PersonnelSalesReportsController < ApplicationController def show query = build_complex_query results = ActiveRecord::Base.connection.exec_query('Select * from users limit 2') @personnel_sales_report = PersonnelSalesReport.initialize_collection(results) end end

Tags: