{"id":13529337,"url":"https://github.com/headmandev/passive_columns","last_synced_at":"2026-01-02T20:26:23.842Z","repository":{"id":245189602,"uuid":"812366248","full_name":"headmandev/passive_columns","owner":"headmandev","description":"ActiveRecord module that allows you to skip selecting specific columns by default and retrieve only on-demand","archived":false,"fork":false,"pushed_at":"2025-02-05T23:30:32.000Z","size":51,"stargazers_count":44,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-23T07:12:54.313Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://rubygems.org/gems/passive_columns","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/headmandev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"MIT-LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-06-08T17:22:18.000Z","updated_at":"2025-02-05T23:26:40.000Z","dependencies_parsed_at":"2024-06-20T11:38:14.548Z","dependency_job_id":"e8efe462-0725-4321-b178-b9a356be2091","html_url":"https://github.com/headmandev/passive_columns","commit_stats":null,"previous_names":["headmandev/passive_columns"],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/headmandev%2Fpassive_columns","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/headmandev%2Fpassive_columns/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/headmandev%2Fpassive_columns/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/headmandev%2Fpassive_columns/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/headmandev","download_url":"https://codeload.github.com/headmandev/passive_columns/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246662269,"owners_count":20813720,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T07:00:35.496Z","updated_at":"2025-12-15T14:38:47.044Z","avatar_url":"https://github.com/headmandev.png","language":"Ruby","funding_links":[],"categories":["Recently Updated","Gems"],"sub_categories":["[Jul 15, 2024](/content/2024/07/15/README.md)","Performance Optimization","Articles"],"readme":"# Passive Columns\nA gem that extends `Active Record` to retrieve columns from DB on demand.\u003cbr\u003e\nWorks with `Rails` \u003e= 6.1 and `Ruby` \u003e= 2.7\n\n## Usage\n\n```ruby \n  class Page \u003c ApplicationRecord\n    include PassiveColumns\n    passive_columns :huge_article\n  end\n```\n\n`ActiveRecord::Relation` now retrieves all the columns except the passive ones by default.\n```ruby\n  article = Page.where(status: :active).to_a\n  # =\u003e SELECT \"pages\".\"id\", \"pages\".\"status\", \"pages\".\"title\" FROM \"pages\" WHERE \"pages\".\"status\" = 'active'\n```\n\n If you specify the columns via select it retrieves only the specified columns and nothing more.\n```ruby\n  page = Page.select(:id, :title).take # =\u003e #\u003cPage id: 1, title: \"Some title\"\u003e\n  page.to_json # =\u003e {\"id\": 1, \"title\": \"Some title\"}\n\n```\n\nBut you still has an ability to retrieve the passive column on demand\n\n```ruby\n  page.huge_article\n  # =\u003e SELECT \"pages\".\"huge_article\" WHERE \"pages\".\"id\" = 1 LIMIT 1\n  'Some huge article...'\n\n  page.to_json # =\u003e {\"id\": 1, \"title\": \"Some title\", \"huge_article\": \"Some huge article...\"}\n\n  # The next time you call the passive column it won't hit the database as it is already loaded.\n  page.huge_article # =\u003e 'Some huge article...'\n```\n\n---\n\n\nAnother way to get columns on demand is to use the `load_column` method.\n\nThis method loads a column value, if not already loaded, from the database\nregardless of whether the column is added to `passive_columns` or not.\n\n```ruby \n  class User \u003c ActiveRecord::Base\n    include PassiveColumns\n  end\n```\n```ruby\nuser = User.select('id').take!\nuser.name # missing attribute 'name' for User (ActiveModel::MissingAttributeError)\n\nuser.load_column(:name) # =\u003e SELECT \"name\" FROM \"users\" WHERE \"id\" = ? LIMIT ?\n'John'\nuser.load_column(:name) # no additional query. It's already loaded\n'John'\n\nuser.name\n'John'\n```\n\nBy the way, it uses the Rails' `.pick` method to get the value of the column under the hood\n\n\n### Important\n\nIf you want `passive_columns` to skip validation rules specific to the columns you exclude.\u003cbr\u003e\n(in case they were not retrieved / modified)\n```ruby\nvalidates :huge_article, presence: true\n# Will be transformed into:\n# validates :huge_article, presence: true, if: -\u003e { attributes.key?('huge_article') }\n```\n\nYou must declare validation rules for `passive_columns` separately\n```ruby\nclass Page \u003c ActiveRecord::Base\n  include PassiveColumns\n  passive_columns :huge_article # Declare columns above the validation rules.\n\n  validates :name, presence: true\n  # Validation rules transformation will work\n  validates :huge_article, presence: true # It works for a separate rule.\n  # -\u003e the rule is transformed into:\n  # -\u003e validates :huge_article, presence: true, if: -\u003e { attributes.key?('huge_article') }\nend\n```\n\n```ruby\nclass Page \u003c ActiveRecord::Base\n  include PassiveColumns\n  passive_columns :huge_article # Declare columns above the validation rules.\n\n  # Validation rules transformation WON'T work\n  validates :name, :huge_article, presence: true # It doesn't work for combined rules.\n  # -\u003e the rule remains the same:\n  # -\u003e validates :name, :huge_article, presence: true\nend\n```\n\n\n## Installation\nAdd this line to your Gemfile:\n\n```ruby\ngem \"passive_columns\"\n```\n\nAnd then execute:\n```bash\n$ bundle install\n```\n\nOr install it yourself as:\n```bash\n$ gem install passive_columns\n```\n\n# Motivation\n\nThere are situations when you have an `Active Record` model with columns\nthat you don't want to fetch from a DB every time you manipulate the model.\n\nWhat options do you have?\n\n```ruby\n# You can declare a scope to exclude columns dynamically from the select settings.\nscope :skip_retrieving, -\u003e(*v) { select(column_names.map(\u0026:to_sym) - Array.wrap(v)) }\n# or you can select only the columns you need\nscope :only_main_columns, -\u003e { select(%w[id name description uuid]) }\n\n# When it's really important to skip unnecessary columns, you can use the default scope.\ndefault_scope { :only_main_columns }\n```\n\nAt first glance, it seems like a good solution.\nUntil you realize that you cannot manipulate the model without the columns you skipped, as there are validation rules related to them.\n\n```ruby\n\nclass Project \u003c ActiveRecord::Base\n  scope :only_main_columns, -\u003e { select(%w[id name description uuid]) }\n\n  validates :id, :name, presence: true\n  validates :settings, presence: true\nend\n\n\np = Project.only_required_columns.take\np.update!(name: 'New name') # missing attribute 'settings' for Project (ActiveModel::MissingAttributeError)\n\n```\nOne way to avoid this is to check for the presence of the attribute before validating it.\n\n```ruby\nvalidates :huge_article, presence: true, if: -\u003e { attributes.key?('huge_article') }\n```\n\nUnfortunately, boilerplate code is needed for such a simple task. \u003cbr\u003e\nBut the only thing you wanted was to exclude some columns and be able to manipulate a model without extra steps.\n\nBy the way, after doing those steps, you still cannot retrieve the column when you need it after loading the scoped model...\n\nSo, `passive_columns` tries to solve this problem by allowing you to exclude columns from the selection and also allowing you to retrieve them on demand when needed.\n\n---\n\n#### Inspiration\nThere are similar gems that were relatively popular but are no longer supported. Let's give them the honor they deserve:\n- [lazy_columns](https://github.com/jorgemanrubia/lazy_columns)\n- [columns_on_demand](https://github.com/willbryant/columns_on_demand)\n\n## License\nThe gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fheadmandev%2Fpassive_columns","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fheadmandev%2Fpassive_columns","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fheadmandev%2Fpassive_columns/lists"}