Thanks to visit codestin.com
Credit goes to github.com

Skip to content
/ vial Public

Vial: fixtures, reinvented — compile programmable fixture intent into deterministic Rails fixtures.

License

Notifications You must be signed in to change notification settings

seuros/vial

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Vial: Fixtures, Reinvented

Vial is a Ruby gem for Rails 8.1+ on Ruby 3.4+ that compiles programmable fixture intent into explicit, deterministic fixture files.

Requirements

  • Ruby 3.4+ (Ruby Box optional via RUBY_BOX=1)
  • Rails 8.1+

Support Policy

  • Ruby 3.4+ only
  • Rails 8.1+ only
  • No backward compatibility guarantees for older Ruby/Rails

Features

  • Vial Compiler: Ruby DSL input → explicit YAML fixtures output
  • Fixture Discovery: Automatically finds all YAML fixtures across configured paths
  • Model Mapping Analysis: Determines which models fixtures belong to using Rails conventions
  • Validation: Identifies orphaned fixtures that don't have corresponding models
  • Multiple Detection Methods: Supports all Rails fixture-to-model mapping methods

Installation

Add this gem to your Gemfile in the development/test group:

group :development, :test do
  gem 'vial'
end

Then run:

bundle install

Usage

Compile Vial Sources

Vial reads *.vial.rb files from test/vials and writes YAML fixtures to test/fixtures:

bin/rails vial:compile

If RUBY_BOX=1 is set, Vial evaluates vial sources inside Ruby::Box for isolation.

Compile only specific vials:

bin/rails vial:compile:only[users,posts]

Note: vial:compile:only still validates the full dataset to catch global ID collisions; it only limits which files are written.

Dry run (validate and show output targets without writing files):

bin/rails vial:compile:dry_run

Example test/vials/users.vial.rb:

vial :users do
  base do
    active true
    country "MA"
  end

  variant :admin do
    role "admin"
  end

  variant :guest do
    role "guest"
    active false
  end

  sequence(:email) { |i| "user#{i}@test.local" }

  generate 10, :admin
  generate 50, :guest
end

Output: test/fixtures/users.yml with deterministic IDs and explicit records.

Global Validation

vial:compile validates the entire dataset before writing any fixtures. Any collision or duplicate label fails the compile with a precise error.

Composition

vial :base_users, abstract: true do
  base do
    active true
    country "MA"
  end
end

vial :admin_users do
  include_vial :base_users do
    override :role, "admin"
  end

  generate 2
end

include_vial composes base attributes (and sequences) only; variants are not imported. Abstract Vials are compile-time only and do not emit fixture files.

ID Strategy

Derived IDs are deterministic integers based on the identity tuple:

[vial_name, record_type, label, variants[], index]

You can set a namespace range per Vial:

vial :users, id_base: 100_000, id_range: 90_000 do
  base do
    role "user"
  end

  generate 3
end

Explicit IDs are supported and never rewritten:

vial :users do
  base do
    id 1001
    role "system"
  end

  generate 1
end

Explain a derived ID:

bin/rails vial:explain_id['users.admin.eu[3]']

Determinism & Faker

Vial seeds Ruby's RNG with Vial.config.seed (default: 1). As long as you avoid non-deterministic sources (Time.now, SecureRandom, etc.), recompiles produce identical output.

If you use Faker, seed it explicitly:

Faker::Config.random = Random.new(Vial.config.seed)

Troubleshooting

  • Vial: no vial definitions found → No *.vial.rb files were found under Vial.config.source_paths.
  • Vial: no records generated → All vials are abstract or missing generate calls.
  • Fixture ID standardization skipped for ERB → ERB fixtures are not rewritten to avoid altering dynamic content.
  • Output path looks wrong → Vial.config.output_path defaults to the first ActiveSupport::TestCase.fixture_paths entry.

Configuration

Vial.configure do |config|
  config.source_paths = [Rails.root.join("test/vials")]
  config.output_path = Rails.root.join("test/fixtures")
  config.seed = 1
end

Example Vial sources live in examples/:

  • examples/users.vial.rb
  • examples/company__users.vial.rb
  • examples/base_users.vial.rb
  • examples/admin_users.vial.rb

Use erb("...") inside a Vial file to emit raw ERB (for associations or special IDs).

Vial provides several rake tasks for fixture analysis:

Count Fixtures

Get an overview of all YAML fixtures in your project:

bin/rails vial:count_fixtures

This shows:

  • Total number of fixture files
  • Distribution by directory
  • Configured fixture paths

Note: Vial.config.output_path defaults to the first configured fixture_paths when available.

Clean Stale Vial Fixtures

Remove fixture files previously generated by Vial that no longer have a matching vial definition:

bin/rails vial:clean

Vial tracks generated fixture files in test/fixtures/.vial_manifest.yml and only removes files listed there.

Analyze Fixtures

Get detailed fixture-to-model mapping information:

bin/rails vial:analyze_fixtures

This shows:

  • Mapped fixtures with their corresponding models
  • Detection method used (fixture directive, set_fixture_class, or path inference)
  • Unmapped fixtures that may need attention
  • Any errors encountered during analysis

Validate Fixtures

Check for orphaned fixtures without models:

bin/rails vial:validate_fixtures

This task:

  • Returns success (exit 0) if all fixtures are mapped
  • Returns failure (exit 1) if unmapped fixtures are found
  • Provides suggestions for fixing unmapped fixtures

Analyze Fixture IDs

Check if fixtures use proper ActiveRecord::FixtureSet.identify:

bin/rails vial:analyze_fixture_ids

This shows:

  • Primary key type distribution (UUID, integer, string, etc.)
  • Fixtures that need ID standardization
  • Current vs expected ID values

Standardize Fixture IDs

Convert hardcoded IDs to use ActiveRecord::FixtureSet.identify:

# Preview changes without applying
bin/rails vial:standardize_fixture_ids:dry_run

# Apply changes (with confirmation prompt)
bin/rails vial:standardize_fixture_ids

This will:

  • Replace hardcoded integer IDs with <%= ActiveRecord::FixtureSet.identify(:label) %>
  • Replace hardcoded UUIDs with <%= ActiveRecord::FixtureSet.identify(:label, :uuid) %>
  • Skip string primary keys (often manually managed like slugs)
  • Ensure consistent, deterministic IDs across all fixtures

How Fixture Detection Works

Vial uses three methods to determine which model a fixture belongs to:

  1. _fixture Directive: Checks for _fixture: model_class: in YAML files
  2. set_fixture_class: Uses mappings from ActiveSupport::TestCase.set_fixture_class
  3. Path Inference: Infers models from fixture paths using Rails naming conventions

Example Output

=== Vial Fixture Analysis ===

Total fixtures found: 114
Mapped to models: 93
Unmapped fixtures: 21

=== Mapped Fixtures ===
platform/countries:
  Model: Platform::Country
  Table: platform_countries
  Detection: path_inference

active_llm_llms:
  Model: ActiveLLM::LLM
  Table: active_llm_llms
  Detection: set_fixture_class

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request

License

The gem is available as open source under the terms of the MIT License.

About

Vial: fixtures, reinvented — compile programmable fixture intent into deterministic Rails fixtures.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Languages