has_dynamic_columns

This plugin gives ActiveRecord models the ability to dynamically define collectable data based on has_many and belongs_to relationships.

Installation

gem "has_dynamic_columns"

The Active Record migration is required to create the has_dynamic_columns table. You can create that table by running the following command:

rails generate has_dynamic_columns:active_record
rake db:migrate

Usage

has_dynamic_columns

  • as:
    • the setter/getter method
  • field_scope:
    • belongs_to or has_many relationship

belongs_to relationship

Our example is a data model where an account has_many customers and each customer has_many customer_addresses

Each customers collectable info is uniquely defined by the associated account.

Each customer addresses collectable info is defined by the associated customers account.

Models

class  < ActiveRecord::Base
    has_many :customers
    has_dynamic_columns
end

class Customer < ActiveRecord::Base
    belongs_to :account
    has_dynamic_columns field_scope: "account", as: "customer_fields"
end

class CustomerAddress < ActiveRecord::Base
    belongs_to :customer
    has_dynamic_columns field_scope: "customer.account"
end

Setup

# ------------------------------------------------
# Create our first account
# ------------------------------------------------
 = .new(:name => "Account #1")

# Define a first_name field
.activerecord_dynamic_columns.build(:dynamic_type => "Customer", :key => "first_name", :data_type => "string")
# Define a last_name field
.activerecord_dynamic_columns.build(:dynamic_type => "Customer", :key => "last_name", :data_type => "string")
# Define a company field
.activerecord_dynamic_columns.build(:dynamic_type => "Customer", :key => "company", :data_type => "string")

# save
.save

# ------------------------------------------------
# Create our second account
# ------------------------------------------------
 = .new(:name => "Account #2")

# Define a first_name field
.activerecord_dynamic_columns.build(:dynamic_type => "Customer", :key => "first_name", :data_type => "string")
# Define a last_name field
.activerecord_dynamic_columns.build(:dynamic_type => "Customer", :key => "last_name", :data_type => "string")
# Define a country field
.activerecord_dynamic_columns.build(:dynamic_type => "Customer", :key => "country", :data_type => "string")

# save
.save

Data

# Add a customer to our first account
 = .find(1)
customer = Customer.new(:account => )
customer.customer_fields = {
    "first_name" => "Butch",
    "last_Name" => "Marshall",
    "company" => "Aperture Science"
}
customer.save

# as_json
customer.as_json
# == { "id": 1, "account_id": 1, "customer_fields" => { "first_name" => "Butch", "last_Name" => "Marshall", "company" => "Aperture Science" } }

# Add a customer to our first account
 = .find(1)
customer = Customer.new(:account => )
customer.customer_fields = {
    "first_name" => "John",
    "last_Name" => "Paterson",
    "company" => "Aperture Science"
}
customer.save

# Add a customer to our second account
 = .find(2)
customer = Customer.new(:account => )
customer.customer_fields = {
    "first_name" => "Butch",
    "last_Name" => "Marshall",
    "country" => "Canada"
}
customer.save

# as_json
puts customer.as_json
# == { "id": 2, "account_id": 2, "customer_fields" => { "first_name" => "Butch", "last_Name" => "Marshall", "country" => "Canada" } }

Searching


# ------------------------------------------------
# with_scope
# ------------------------------------------------

# ------------------------------------------------
# Find customers under the first account
# ------------------------------------------------
 = .find(1)

# 1 result
Customer.where.has_dynamic_scope({ :first_name => "Butch" }).with_scope()

# 1 result
Customer.where.has_dynamic_scope({ :first_name => "Butch", :company => "Aperture Science" }).with_scope()

# 0 results
Customer.where.has_dynamic_scope({ :first_name => "Butch", :company => "Blaaaaa" }).with_scope()

# 2 results
Customer.where.has_dynamic_scope({ :company => "Aperture Science" }).with_scope()

# ------------------------------------------------
# Find customers under the second account
# ------------------------------------------------
 = .find(2)
# 1 result
Customer.where.has_dynamic_scope({ :first_name => "Butch" }).with_scope()

# 1 result
Customer.where.has_dynamic_scope({ :first_name => "Butch", :country => "Canada" }).with_scope()

# 0 results
Customer.where.has_dynamic_scope({ :first_name => "Butch", :country => "Japan" }).with_scope()

------------------------------------------------

without_scope

------------------------------------------------

6 results

finds everyone named butch, no matter what account they're apart of

Customer.where.has_dynamic_scope({ :first_name => "Butch" }).without_scope

------------------------------------------------

with Arel

WARNING: compound conditionals such as Customer.arel_table[:first_Name].matches("B%").and(Customer.arel_table[:first_Name].eq("Canada")) are NOT currently supported

------------------------------------------------

6 matches

Customer.where.has_dynamic_scope(Customer.arel_table[:first_Name].matches("B%")).without_scope

1 match

Customer.where.has_dynamic_scope(Customer.arel_table[:first_Name].eq("Canada")).with_scope(Account.find(1))

has_many relationship

TODO example.