No commit activity in last 3 years
No release in over 3 years
Adds ability to put dynamic fields into active record models
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

~> 1.7
~> 10.0

Runtime

< 5.0, >= 3.0
 Project Readme

Gem Version Build Status

has_dynamic_columns

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

Release Notes

0.3.5

  • Added model storage type (for storing association with other activerecord objects)

0.3.4

  • Can now store array of data
  • JRuby support

0.3.0

  • Moved to storing data types in separate tables (where/order now correct!)
  • Added order.by_dynamic_columns
  • Improved how joins were built to avoid duplicates
  • Added ActiveRecord 3 and 4 compatibility

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
rails generate has_dynamic_columns:upgrade_0_3_0_active_record
rails generate has_dynamic_columns:upgrade_0_3_4_active_record
rails generate has_dynamic_columns:upgrade_0_3_5_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 Account < 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
# ------------------------------------------------
account = Account.new(:name => "Account #1")

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

# save
account.save

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

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

# save
account.save

Data

# Add a customer to our first account
account = Account.find(1)
customer = Customer.new(:account => 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
account = Account.find(1)
customer = Customer.new(:account => account)
customer.customer_fields = {
	"first_name" => "John",
	"last_Name" => "Paterson",
	"company" => "Aperture Science"
}
customer.save

# Add a customer to our second account
account = Account.find(2)
customer = Customer.new(:account => 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
# ------------------------------------------------
account = Account.find(1)

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

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

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

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

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

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

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

# ------------------------------------------------
# without_scope
# ------------------------------------------------

# 6 results
# finds everyone named butch, no matter what account they're apart of
Customer
	.where
		.has_dynamic_columns({ :first_name => "Butch" })
		.without_scope

# ------------------------------------------------
# with Arel
# ------------------------------------------------

# 6 matches
Customer
	.where.has_dynamic_columns(Customer.arel_table[:first_Name].matches("B%"))
	.without_scope

# 1 match
Customer
	.where
		.has_dynamic_columns(Customer.arel_table[:country].eq("Canada"))
		.with_scope(Account.find(1))

# ------------------------------------------------
# with nested or/and Arel
# ------------------------------------------------

# Anyone with country: Canada or first_name: John
# 2 match
Customer
	.where
		.has_dynamic_columns(
			Customer.arel_table[:country].eq("Canada").or(
				Customer.arel_table[:first_name].eq("John")
			)
		)
		.with_scope(Account.find(1))

has_many relationship

TODO example.

Ordering

# ------------------------------------------------
# by dynamic column
# ------------------------------------------------

Customer
	.order
		.by_dynamic_columns(country: :asc)
		.with_scope(Account.find(1))