{"id":13879100,"url":"https://github.com/kenn/active_flag","last_synced_at":"2025-12-24T09:57:27.609Z","repository":{"id":37359199,"uuid":"77180935","full_name":"kenn/active_flag","owner":"kenn","description":"Bit array for ActiveRecord","archived":false,"fork":false,"pushed_at":"2024-12-13T14:28:27.000Z","size":56,"stargazers_count":244,"open_issues_count":2,"forks_count":20,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-06-27T13:15:45.127Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/kenn.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"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":"2016-12-22T22:49:10.000Z","updated_at":"2025-04-17T03:44:48.000Z","dependencies_parsed_at":"2024-11-24T08:30:55.371Z","dependency_job_id":"20d3473c-ea57-4a06-bc4c-37df35335158","html_url":"https://github.com/kenn/active_flag","commit_stats":{"total_commits":44,"total_committers":10,"mean_commits":4.4,"dds":"0.31818181818181823","last_synced_commit":"d5230a1615c3e825c3bff86d786952cf116f7f7f"},"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/kenn/active_flag","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenn%2Factive_flag","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenn%2Factive_flag/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenn%2Factive_flag/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenn%2Factive_flag/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kenn","download_url":"https://codeload.github.com/kenn/active_flag/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenn%2Factive_flag/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265521426,"owners_count":23781500,"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-06T08:02:09.824Z","updated_at":"2025-12-24T09:57:27.601Z","avatar_url":"https://github.com/kenn.png","language":"Ruby","funding_links":[],"categories":["Ruby","ORM/ODM Extensions"],"sub_categories":[],"readme":"# ActiveFlag - Bit array for ActiveRecord\n\n![Build Status](https://github.com/kenn/active_flag/actions/workflows/ci.yml/badge.svg)\n\nStore up to 64 multiple flags ([bit array](https://en.wikipedia.org/wiki/Bit_array)) in a single integer column with ActiveRecord. From a UI standpoint, it can be used as a  multi-select checkbox storage.\n\nPerfect solution to store multiple boolean values such as preferences, notification settings, achievement status, profile options, etc. in a single column.\n\n* **Single column to group multiple boolean values.** You don't need to have many separate columns. You don't even need a migration when you add a new flag item to the list.\n* **Fast bitwise operations.** `WHERE languages \u0026 3 \u003e 0` is faster than `WHERE (english = true) OR (spanish = true) OR ...`\n\nIf you want a simple enum column, take a look at [EnumAccessor](https://github.com/kenn/enum_accessor).\n\nIf you need to work with huge bit arrays, take a look at [Bitwise](https://github.com/kenn/bitwise).\n\n## Usage\n\n```ruby\nclass Profile \u003c ActiveRecord::Base\n  flag :languages, [:english, :spanish, :chinese, :french, :japanese]\nend\n\n# {:english=\u003e1, :spanish=\u003e2, :chinese=\u003e4, :french=\u003e8, :japanese=\u003e16 }\n\n# Instance methods\nprofile.languages                           #=\u003e #\u003cActiveFlag::Value: {:english, :japanese}\u003e\nprofile.languages.english?                  #=\u003e true\nprofile.languages.set?(:english)            #=\u003e true\nprofile.languages.unset?(:english)          #=\u003e false\n\nprofile.languages.set(:spanish)\nprofile.languages.unset(:japanese)\nprofile.languages.raw                       #=\u003e 3\nprofile.languages.to_a                      #=\u003e [:english, :spanish]\n\nprofile.languages = [:spanish, :japanese]   # Direct assignment that works with forms\n\n# Class methods\nProfile.languages.maps                      #=\u003e {:english=\u003e1, :spanish=\u003e2, :chinese=\u003e4, :french=\u003e8, :japanese=\u003e16 }\nProfile.languages.humans                    #=\u003e {:english=\u003e\"English\", :spanish=\u003e\"Spanish\", :chinese=\u003e\"Chinese\", :french=\u003e\"French\", :japanese=\u003e\"Japanese\"}\nProfile.languages.pairs                     #=\u003e {\"English\"=\u003e:english, \"Spanish\"=\u003e:spanish, \"Chinese\"=\u003e:chinese, \"French\"=\u003e:french, \"Japanese\"=\u003e:japanese}\nProfile.languages.to_array(3)               #=\u003e [:english, :spanish]\n\n# Scope methods\nProfile.where_languages(:french, :spanish)  #=\u003e SELECT * FROM profiles WHERE languages \u0026 10 \u003e 0\nProfile.where_all_languages(:french, :spanish)  #=\u003e SELECT * FROM profiles WHERE languages \u0026 10 = 10\nProfile.where_not_languages(:french, :spanish)  #=\u003e SELECT * FROM profiles WHERE languages \u0026 10 = 0\nProfile.where_not_all_languages(:french, :spanish)  #=\u003e SELECT * FROM profiles WHERE languages \u0026 10 \u003c 10\nProfile.languages.set_all!(:chinese)        #=\u003e UPDATE \"profiles\" SET languages = COALESCE(languages, 0) | 4\nProfile.languages.unset_all!(:chinese)      #=\u003e UPDATE \"profiles\" SET languages = COALESCE(languages, 0) \u0026 ~4\n```\n\n## Install\n\n```ruby\ngem 'active_flag'\n```\n\n### Migration\n\nIt is recommended to set `0` by default.\n\n```ruby\nt.integer :languages,                    null: false, default: 0, limit: 8\n# OR\nadd_column :users, :languages, :integer, null: false, default: 0, limit: 8\n```\n\n`limit: 8` is only required if you need more than 32 flags.\n\n## Query\n\nFor a querying purpose, use `where_[column]`, `where_all_[column]`,\n`where_not_[column]` and `where_not_all_[column]` scopes.\n\n```ruby\nProfile.where_languages(:french)            #=\u003e SELECT * FROM profiles WHERE languages \u0026 8 \u003e 0\n```\n\nAlso takes multiple values.\n\n```ruby\nProfile.where_languages(:french, :spanish)  #=\u003e SELECT * FROM profiles WHERE languages \u0026 10 \u003e 0\n```\n\nBy default, it returns profiles that have either French or Spanish.\n\nTo get profiles that have both French and Spanish, use:\n\n```ruby\nProfile.where_all_languages(:french, :spanish) #=\u003e SELECT * FROM profiles WHERE languages \u0026 10 = 10\n```\n\nTo get profiles that do not have either French or Spanish, use:\n\n```ruby\nProfile.where_not_languages(:french, :spanish) #=\u003e SELECT * FROM profiles WHERE languages \u0026 10 = 0\n```\n\nTo get profiles that do not have both French and Spanish, use:\n\n```ruby\nProfile.where_not_all_languages(:french, :spanish) #=\u003e SELECT * FROM profiles WHERE languages \u0026 10 \u003c 10\n```\n\n## Translation\n\n`ActiveFlag` supports [i18n](http://guides.rubyonrails.org/i18n.html) just as ActiveModel does.\n\nFor instance, create a Japanese translation in `config/locales/ja.yml`\n\n```yaml\nja:\n  active_flag:\n    profile:\n      languages:\n        english: 英語\n        spanish: スペイン語\n        chinese: 中国語\n        french: フランス語\n        japanese: 日本語\n```\n\nand now `to_human` method returns a translated string.\n\n```ruby\nI18n.locale = :ja\nprofile.languages.to_human  #=\u003e ['英語', 'スペイン語']\n\nI18n.locale = :en\nprofile.languages.to_human  #=\u003e ['English', 'Spanish']\n```\n\n## Forms\n\nThanks to the translation support, forms just work as you would expect with the `pairs` convenience method.\n\n```ruby\n# With FormBuilder\n\n= form_for(@profile) do |f|\n  = f.collection_check_boxes :languages, Profile.languages.pairs\n\n# With SimpleForm\n\n= simple_form_for(@profile) do |f|\n  = f.input :languages, as: :check_boxes, collection: Profile.languages.pairs\n```\n\n## Other solutions\n\nThere are plenty of gems that share the same goal. However they have messy syntax than necessary in my opinion, and I wanted a better API to achieve that goal.\n\n- [bitfields](https://github.com/grosser/bitfields)\n- [flag_shih_tzu](https://github.com/pboling/flag_shih_tzu)\n\nAlso, `ActiveFlag` has one of the simplest code base that you can easily reason about or hack on.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkenn%2Factive_flag","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkenn%2Factive_flag","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkenn%2Factive_flag/lists"}