# ActiveHash for read-only ActiveRecord-style Ruby models

> ActiveHash provides an in-memory, read-only data model backed by a Ruby hash, YAML file, or custom file source. It suits fixed lookup data and database-free tests, but it does not replace ActiveRecord for mutable, persisted application data.

**active-hash/active_hash** — A readonly ActiveRecord-esque base class that lets you use a hash, a Yaml file or a custom file as the datasource

- Repository: https://github.com/active-hash/active_hash
- Stars: 1,358 · Forks: 185
- Language: Ruby
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/active-hash-active-hash

## Why ActiveHash exists for fixed Ruby lookup data

ActiveHash addresses a specific Rails modeling problem: some data behaves like a database table but is small, fixed, and read-only. Countries, status lists, configuration records, and similar values are common examples. The project presents this data through an ActiveRecord-style class so code can call familiar methods such as `all`, `find`, and `where`, and Rails forms can consume model objects instead of raw arrays.

The intended users are Ruby and Rails developers who want model-shaped data without creating a database table, migration, or database connection. The README also identifies developers testing plugins and gems as a use case. Their tests can use simple ActiveRecord behavior without adding database setup or migrations to the spec suite.

This is a narrow role rather than a general replacement for ActiveRecord. The README says the majority of ActiveHash uses define data at boot time and never modify it at runtime. The package is therefore a poor fit when records need user-facing creation, editing, deletion, transactions, or durable storage. Its value comes from presenting stable data through a familiar interface, not from implementing database persistence.

Each source hash must contain an `:id` key. That requirement gives records database-like identifiers and supports the project's stated goal of moving from ActiveHash objects to full ActiveRecord objects without changing application code or existing foreign keys. A data set that lacks meaningful identifiers would not fit this model.

## How ActiveHash converts hashes into model objects

The central mechanism is `ActiveHash::Base`, which accepts an array of hashes as `self.data`. When a class such as `Country` is defined, calling class-level query methods returns `Country` instances with attributes populated from the source data. The project also generates instance accessors for fields found in those hashes. A declared field remains authoritative: the README states that automatically defined fields do not override fields defined on the class or an instance.

Queries operate over the in-memory collection. The documented class methods include `count`, `first`, `last`, `find`, `find_by`, `where`, and `order`. Equality conditions and regular expressions are supported by `where`, while dynamic finders can address declared fields. Scopes can wrap those queries, for example filtering by `language` and optionally accepting that value as an argument.

The return value changed in version 3.0.0 and is chainable rather than being only an `Array` instance. This matters during upgrades because applications that depend on exact collection behavior may need review. The README directs affected users to report a problem and gives `2.3.0` as the older dependency line they can select. It does not document a rollback procedure beyond that version choice.

ActiveHash also states that it supports `has_many` and `belongs_to` through `belongs_to_active_hash`.

## Installing ActiveHash in a Ruby or Rails application

For a Bundler-managed application, add the gem to the Gemfile. The README gives the dependency without a version constraint:

```ruby
gem 'active_hash'
```

For installation outside Bundler, use RubyGems:

```bash
gem install active_hash
```

The compatibility table states that ActiveHash 4.x requires Ruby 3.0 or later and Rails 6.1 or later. Version 2.x and 3.x require Ruby 2.4 or later and Rails 5 or later. An older constraint shown in the README is available when an application remains on the v1 line:

```ruby
gem 'active_hash', '~> 1.5.3'
```

Do not select that older line merely to avoid reading the current requirements. Version choice should follow the Ruby and Rails versions used by the application. The repository lists v4.1.0 as the most recent release shown, while the default branch is `master`. Its last push was on 2026-07-21, and the repository is not archived.

## Defining a Country model and querying its first records

A first model can be defined directly in a Rails model file. This example supplies the required identifiers and a display name:

```ruby
class Country < ActiveHash::Base
  self.data = [
    {:id => 1, :name => "US"},
    {:id => 2, :name => "Canada"}
  ]
end
```

A Rails form can then treat the records as a collection and use their `id` and `name` attributes:

```erb
<%= collection_select :person, :country_id, Country.all, :id, :name %>
```

The model supports normal-looking lookups, including an array of identifiers and attribute filters. These calls document the in-memory query surface:

```ruby
Country.all
Country.find 1
Country.find [1,2]
Country.where(name: 'US')
Country.order(name: :desc)
```

Fields can also be initialized through `create` or `add`. These methods are shown in the usage section, while the broader README description characterizes ActiveHash as a read-only datasource. Code intending to keep the datasource immutable should prefer `self.data` and treat mutation-oriented examples cautiously.

New unsaved instances can still be constructed in the documented model API. This does not make ActiveHash an ActiveRecord replacement. The distinction is the source of truth: ActiveHash reads records from configured in-memory or file-backed data rather than from an application database.

## ActiveFile and ActiveYaml data-source choices

ActiveHash includes two source-specific base classes. `ActiveYaml` turns YAML into a hash and loads the result into an ActiveHash object. `ActiveFile` provides a base class for creating file data sources. These abstractions matter when the records should not be embedded as Ruby literals in a model class.

The README does not include a complete `ActiveYaml` declaration, YAML file layout, `ActiveFile` example, reload behavior, encoding policy, or error handling guidance. It would therefore be unsafe to infer a particular path, schema, or reload configuration from the short description. The YAML structure still needs to produce records compatible with ActiveHash's `:id` requirement.

For data that is convenient to define in code, `self.data` is the clearest documented route. Data can also be assigned outside the class through a Rails initialization block. The following example illustrates that separation:

```ruby
Rails.application.config.to_prepare do
  Country.data = [
      {:id => 1, :name => "US"},
      {:id => 2, :name => "Canada"}
  ]
end
```

This arrangement keeps the model definition separate from data loading in `config/initializers/data.rb`. The example uses `to_prepare`, but the README does not state what happens when the underlying file changes at runtime or how YAML files are watched. Such reload semantics are a key item to verify before editing source data in development.

## ActiveHash limits, upgrade work, and the ActiveRecord alternative

The primary limitation is intentional immutability of the application domain. ActiveHash is designed for reference data that is set up at boot time and not changed through normal application workflows. It does not provide the persistence or transactional behavior expected from ActiveRecord. A record catalog, order, invoice, or other frequently updated entity belongs in an ActiveRecord model backed by a database.

The difference in approach is concrete. ActiveRecord stores records in a database and supplies persistence as part of the model. ActiveHash wraps an array of hashes, YAML, or a custom file as a read-only datasource and evaluates ActiveRecord-style queries in memory. This reduces database setup for fixed data and tests, but it also removes database storage from the feature set.

Upgrading from ActiveHash 2.x to 3.0.0 or later deserves attention because returned collections became chainable and are no longer described as plain `Array` instances. A project pinned to the older behavior can use the documented dependency line `~> 2.3.0`, although adopting an old major version also means accepting its compatibility requirements and missing later fixes.

The project uses the MIT license. That means the source is distributed under permissive MIT terms, subject to the actual `LICENSE` file and applicable law. The repository also includes `CHANGELOG.md`, release tags, specs, and a Rakefile, but the README excerpt does not describe their complete maintenance or upgrade policy.

## Conclusion

Application developers should consider ActiveHash for stable reference values, form collections, and tests that need ActiveRecord-style behavior without a database. Projects requiring runtime updates, persistence, or database-backed relationships should use ActiveRecord instead. Before adoption, verify that Ruby 3.0 or later and Rails 6.1 or later match the application, then confirm that every source record includes `:id` and remains effectively read-only.

## FAQ

### How do I install ActiveHash?

Add `gem 'active_hash'` to the Gemfile for Bundler, or run `gem install active_hash` outside Bundler. ActiveHash 4.x requires Ruby 3.0 or later and Rails 6.1 or later.

### Does every ActiveHash record need an id?

Yes. The README states that ActiveHash assumes every hash has an `:id` key. This identifier supports lookup and the stated migration path to ActiveRecord.

### Can ActiveHash load data from YAML or a custom file?

Yes. `ActiveYaml` turns YAML into a hash and loads it into an ActiveHash object, while `ActiveFile` provides a base class for custom file data sources.

## Sources

- [active-hash/active_hash on GitHub](https://github.com/active-hash/active_hash)
- [Issues](https://github.com/active-hash/active_hash/issues)
- [License: MIT](https://github.com/active-hash/active_hash/blob/master/LICENSE)
- [README](https://github.com/active-hash/active_hash/blob/master/README.md)
- [Releases](https://github.com/active-hash/active_hash/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/active-hash-active-hash
