Skip to content

Convient way to optimize rails queries by only loading required columns from db

License

Notifications You must be signed in to change notification settings

nugit/ignorable_columns

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

IgnorableColumns

Motivation is to allow ignoring certain columns both at model level (columns/attributes) as well as database queries level. It works with includes and eager_load as well as simple queries.

Tested on Rails4, should work on Rails3. Not tested on Rails5.

Example Usage

class Topic < ActiveRecord::Base
  ignore_columns :name, :body, :timezone
  ignore_columns_in_sql # optional, recommended for better performance
  ignore_columns_preload_all_subclass # optional, used for preloading subclasses so that constantizing can work
end

ignore_columns

  • This makes the model ignore the attributes stated by default and exposes methods to include them back whenever we want them.

  • ignore_columns must be defined before using ignore_columns_in_sql.

ignore_columns_in_sql

  • This makes the model run optimised sql that only returns those non ignored columns.

ignore_columns_preload_all_subclass

  • This makes the model preload all the different subclasses that is generated by ignore_columns.

  • i.e: if Topic has ignore_columns :name, :body. This preloads the following subclasses: TopicWithName, TopicWithBody, TopicWithNameBody

  • ignore_columns_preload_all_subclass must be defined after everything in your model that affects the default_scope.

To temporarily use the ignored columns:

Topic.including_ignored_columns.where(name: 'Data Rocks')
Topic.including_ignored_columns(:name).where(name: 'Data Rocks')

For use with relations see below example:

Has many

class Topic < ActiveRecord::Base
  ignore_columns :name, :body, :timezone
  ignore_columns_in_sql # optional, recommended for better performance
  ignore_columns_preload_all_subclass # optional, used for preloading subclasses so that constantizing can work

  belongs_to :author
  belongs_to :author_with_location, class_name: Author.including_ignored_columns(:location).name, foreign_key: 'topic_id'
end

class Author < ActiveRecord::Base
  ignore_columns :location, :updated_at
  ignore_columns_in_sql # optional, recommended for better performance
  ignore_columns_preload_all_subclass # optional, used for preloading subclasses so that constantizing can work

  has_many :topics
  has_many :topics_with_body, class_name: Topic.including_ignored_columns(:body).name
  has_many :topics_with_all, class_name: Topic.including_ignored_columns.name
end

Author.last.topics_with_body
Topic.where(name: 'MyTopic').author_with_location
Author.includes(:topics_with_all).last.topics_with_all
Author.eager_load(:topics_with_all).last.topics_with_all

Self Referential

class Topic < ActiveRecord::Base
  ignore_columns :name, :body, :timezone
  ignore_columns_in_sql # optional, recommended for better performance
  ignore_columns_preload_all_subclass # optional, used for preloading subclasses so that constantizing can work

  belongs_to :parent_topic, class_name: Topic.name
  has_many :child_topics, class_name: Topic.name, foreign_key: 'parent_id'

  belongs_to :parent_topic_with_all, class_name: Topic.including_ignored_columns.name
  has_many :child_topics_with_all, class_name: Topic.including_ignored_columns.name, foreign_key: 'parent_id'
end

Topic.where(name: 'MyTopic').child_topics_with_all

Many to many

class Topic < ActiveRecord::Base
  ignore_columns :name, :body, :timezone
  ignore_columns_in_sql # optional, recommended for better performance
  ignore_columns_preload_all_subclass # optional, used for preloading subclasses so that constantizing can work

  has_many :author_topics
  has_many :authors, through: :author_topics
end

class Author < ActiveRecord::Base
  ignore_columns :location, :updated_at
  ignore_columns_in_sql # optional, recommended for better performance
  ignore_columns_preload_all_subclass # optional, used for preloading subclasses so that constantizing can work

  has_many :author_topics
  has_many :topics, through: :author_topics
end

class AuthorTopic < ActiveRecord::Base
  belongs_to :author
  belongs_to :topic

  belongs_to :authors_with_location, class_name: Author.including_ignored_columns(:location).name, foreign_key: 'author_id'
end

Topic.where(name: 'MyTopic').last.authors_with_location

Limitations

  • does not support has and belongs to many relations

  • does not support polymorphic relations

  • because of the ActiveRecord implementation when using count it should be used as count(:all)

(else a middleware could be implemented but it is out of the scope of this gem)

TO DO

  1. specs for relations other than has many

  2. specs for concurrency

  3. support for rails 5

  4. examples (and / or another gem) for use with graphql

Inspired by github.com/nthj/ignorable

About

Convient way to optimize rails queries by only loading required columns from db

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Ruby 100.0%