Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/headmandev/passive_columns
ActiveRecord module that allows you to skip selecting specific columns by default and retrieve only on-demand
https://github.com/headmandev/passive_columns
Last synced: 3 months ago
JSON representation
ActiveRecord module that allows you to skip selecting specific columns by default and retrieve only on-demand
- Host: GitHub
- URL: https://github.com/headmandev/passive_columns
- Owner: headmandev
- License: mit
- Created: 2024-06-08T17:22:18.000Z (7 months ago)
- Default Branch: main
- Last Pushed: 2024-08-11T15:43:03.000Z (5 months ago)
- Last Synced: 2024-08-11T16:58:59.990Z (5 months ago)
- Language: Ruby
- Homepage: https://rubygems.org/gems/passive_columns
- Size: 67.4 KB
- Stars: 41
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: MIT-LICENSE
Awesome Lists containing this project
- trackawesomelist - passive\_columns (⭐38) - A gem that extends Active Record to retrieve specific columns from DB on demand. [:red\_circle:](https://rubygems.org/gems/passive_columns) (Recently Updated / [Jul 15, 2024](/content/2024/07/15/README.md))
README
# Passive Columns
A gem that extends `Active Record` to retrieve columns from DB on demand.
Works with `Rails` >= 6.1 and `Ruby` >= 2.7## Usage
```ruby
class Page < ApplicationRecord
include PassiveColumns
passive_columns :huge_article
end
````ActiveRecord::Relation` now retrieves all the columns except the passive ones by default.
```ruby
article = Page.where(status: :active).to_a
# => SELECT "pages"."id", "pages"."status", "pages"."title" FROM "pages" WHERE "pages"."status" = 'active'
```If you specify the columns via select it retrieves only the specified columns and nothing more.
```ruby
page = Page.select(:id, :title).take # => #
page.to_json # => {"id": 1, "title": "Some title"}```
But you still has an ability to retrieve the passive column on demand
```ruby
page.huge_article
# => SELECT "pages"."huge_article" WHERE "pages"."id" = 1 LIMIT 1
'Some huge article...'page.to_json # => {"id": 1, "title": "Some title", "huge_article": "Some huge article..."}
# The next time you call the passive column it won't hit the database as it is already loaded.
page.huge_article # => 'Some huge article...'
```---
Another way to get columns on demand is to use the `load_column` method.
This method loads a column value, if not already loaded, from the database
regardless of whether the column is added to `passive_columns` or not.```ruby
class User < ActiveRecord::Base
include PassiveColumns
end
```
```ruby
user = User.select('id').take!
user.name # missing attribute 'name' for User (ActiveModel::MissingAttributeError)user.load_column(:name) # => SELECT "name" FROM "users" WHERE "id" = ? LIMIT ?
'John'
user.load_column(:name) # no additional query. It's already loaded
'John'user.name
'John'
```By the way, it uses the Rails' `.pick` method to get the value of the column under the hood
### Important
If you want `passive_columns` to skip validation rules specific to the columns you exclude.
(in case they were not retrieved / modified)
```ruby
validates :huge_article, presence: true
# Will be transformed into:
# validates :huge_article, presence: true, if: -> { attributes.key?('huge_article') }
```You must declare validation rules for `passive_columns` separately
```ruby
class Page < ActiveRecord::Base
include PassiveColumns
passive_columns :huge_article # Declare columns above the validation rules.validates :name, presence: true
# Validation rules transformation will work
validates :huge_article, presence: true # It works for a separate rule.
# -> the rule is transformed into:
# -> validates :huge_article, presence: true, if: -> { attributes.key?('huge_article') }
end
``````ruby
class Page < ActiveRecord::Base
include PassiveColumns
passive_columns :huge_article # Declare columns above the validation rules.# Validation rules transformation WON'T work
validates :name, :huge_article, presence: true # It doesn't work for combined rules.
# -> the rule remains the same:
# -> validates :name, :huge_article, presence: true
end
```## Installation
Add this line to your Gemfile:```ruby
gem "passive_columns"
```And then execute:
```bash
$ bundle install
```Or install it yourself as:
```bash
$ gem install passive_columns
```# Motivation
There are situations when you have an `Active Record` model with columns
that you don't want to fetch from a DB every time you manipulate the model.What options do you have?
```ruby
# You can declare a scope to exclude columns dynamically from the select settings.
scope :skip_retrieving, ->(*v) { select(column_names.map(&:to_sym) - Array.wrap(v)) }
# or you can select only the columns you need
scope :only_main_columns, -> { select(%w[id name description uuid]) }# When it's really important to skip unnecessary columns, you can use the default scope.
default_scope { :only_main_columns }
```At first glance, it seems like a good solution.
Until you realize that you cannot manipulate the model without the columns you skipped, as there are validation rules related to them.```ruby
class Project < ActiveRecord::Base
scope :only_main_columns, -> { select(%w[id name description uuid]) }validates :id, :name, presence: true
validates :settings, presence: true
endp = Project.only_required_columns.take
p.update!(name: 'New name') # missing attribute 'settings' for Project (ActiveModel::MissingAttributeError)```
One way to avoid this is to check for the presence of the attribute before validating it.```ruby
validates :huge_article, presence: true, if: -> { attributes.key?('huge_article') }
```Unfortunately, boilerplate code is needed for such a simple task.
But the only thing you wanted was to exclude some columns and be able to manipulate a model without extra steps.By the way, after doing those steps, you still cannot retrieve the column when you need it after loading the scoped model...
So, `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.
---
#### Inspiration
There are similar gems that were relatively popular but are no longer supported. Let's give them the honor they deserve:
- [lazy_columns](https://github.com/jorgemanrubia/lazy_columns)
- [columns_on_demand](https://github.com/willbryant/columns_on_demand)## License
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).