{"id":17826414,"url":"https://github.com/jguecaimburu/fixture_champagne","last_synced_at":"2025-03-18T23:31:01.605Z","repository":{"id":65742229,"uuid":"592479122","full_name":"jguecaimburu/fixture_champagne","owner":"jguecaimburu","description":"Fixture migrations for Ruby on Rails applications","archived":false,"fork":false,"pushed_at":"2023-05-20T20:08:11.000Z","size":1335,"stargazers_count":11,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-17T04:21:21.122Z","etag":null,"topics":["fixture-generator","fixtures","rails","testing"],"latest_commit_sha":null,"homepage":"","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/jguecaimburu.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","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":"2023-01-23T20:20:18.000Z","updated_at":"2023-05-12T20:03:42.000Z","dependencies_parsed_at":"2023-06-25T21:47:02.821Z","dependency_job_id":null,"html_url":"https://github.com/jguecaimburu/fixture_champagne","commit_stats":{"total_commits":36,"total_committers":1,"mean_commits":36.0,"dds":0.0,"last_synced_commit":"c652970952b3028795f84c4998aeb36a4879947c"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jguecaimburu%2Ffixture_champagne","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jguecaimburu%2Ffixture_champagne/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jguecaimburu%2Ffixture_champagne/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jguecaimburu%2Ffixture_champagne/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jguecaimburu","download_url":"https://codeload.github.com/jguecaimburu/fixture_champagne/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244325262,"owners_count":20435075,"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":["fixture-generator","fixtures","rails","testing"],"created_at":"2024-10-27T18:47:38.812Z","updated_at":"2025-03-18T23:31:01.597Z","avatar_url":"https://github.com/jguecaimburu.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Fixture Champagne :champagne:\n\n### Fixture migrations for your Ruby on Rails applications\n\n[![Build Status](https://github.com/jguecaimburu/fixture_champagne/workflows/Tests/badge.svg)](https://github.com/jguecaimburu/fixture_champagne/actions) [![Gem Version](https://badge.fury.io/rb/fixture_champagne.svg)](https://badge.fury.io/rb/fixture_champagne)\n\n\nFixture Champagne is designed to help you keep your fixtures tidy, applying the data migration pattern to create, update or destroy fixtures.\n\nIt supports label references for `belongs_to` associations, both regular and polymorphic, single table inheritance, enums and all the different data types.\n\n\n## Installation\n\n1. Add `fixture-champagne` to the development group of your Rails app's `Gemfile`:\n\n```ruby\ngroup :development do\n  gem 'fixture-champagne'\nend\n```\n\n2. Then, in your project directory:\n\n```sh\n# Download and install\n$ bundle install\n\n# Generate fixture_migrations folder in your test or spec folder, depending on your test suite\n$ bin/rails generate fixture_champagne:install\n```\n\n\n## Usage\n\n\n### Sync fixtures with schema\n\nIf your schema version changed and you need to add any new column to the current fixtures, simply run:\n\n```sh\nbin/rails fixture_champagne:migrate\n```\n\nThe migration process will regenarate your `fixtures` folder.\n\n\n### Add, update or destroy fixtures\n\nIf you need specific values for the any new columns or you want to populate a newly created table, you might find it useful to create a fixture migration. This can be done using the generator:\n\n```sh\nbin/rails generate fixture_champagne:migration new_migration_name\n```\n\nA new versioned migration file will be created in the `fixture_migrations` folder. If this is your first migration, make sure that folder exists or run the installation command.\n\n`ActiveRecord` queries and fixture accessors can be used inside the migrations. For example, let's suppose you've just added the `Enemy` model and you need to create a new enemy fixture having the following files:\n\n```ruby\n# models/level.rb\n\nclass Level \u003c ApplicationRecord\n  has_many :enemies\nend\n\n# models/enemy.rb\n\nclass Enemy \u003c ApplicationRecord\n  belongs_to :level\nend\n```\n\n```yaml\n# test/fixtures/levels.yml\n\nfirst_level:\n  name: Initial\n```\n\nYou can then generate a new migration:\n\n```sh\nbin/rails generate fixture_champagne:migration create_initial_enemy\n```\n\nThe generator automatically adds a version number to the new migration file, which is important to keep track of executed migrations. Also, the migration filename must correspond with the migration class inside the file. All this should feel similar to the way schema migrations are handled by Rails.\n\nAdd the `up` and `down` logic to the new migration:\n\n```ruby\n# 20230126153650_create_initial_enemy.rb\n\nclass CreateInitialEnemy \u003c FixtureChampagne::Migration::Base\n  def up\n    unless Enemy.find_by(name: \"Initial Enemy\").present?\n      Enemy.create!(name: \"Initial Enemy\", level: levels(:first_level))\n    end\n  end\n\n  def down\n    Enemy.find_by(name: \"Initial Enemy\").destroy!\n  end\nend\n```\n\nRunning `bin/rails fixture_champagne:migrate` will execute the `up` method of all pending migrations in ascending version order to update the test database. The `fixtures` folder is regenerated at the end of the process only if all the migrations were successfully executed. In this case, it would generate the following file:\n\n```yaml\n# test/fixtures/enemies.yml\n\nenemies_12345678:\n  level: first_level\n  name: Initial Enemy\n```\n\nIf the migration is successful, the migrator will take the max version all available migrations and the current schema version and save both numbers in `test/.fixture_champagne_versions.yml` (or `spec/` if using Rspec) to identify future pending migrations.\n\nThe default label for a new fixture is a unique identifier composed of the table name and the record id. However, this label can be [configured](#fixture-labels).\n\nYou can also customize your fixture migrations by overriding the default template. Just place yours in `lib/templates/fixture_champagne/migration/migration.rb.tt`. This can be useful for example if you use [FactoryBot](#extending-your-migrations).\n\n### Rollback\n\nYou can optionally complete the `down` method in the migration to allow rollback. Running the following command will rollback the last executed migration:\n\n```sh\nbin/rails fixture_champagne:rollback\n```\n\nNew max version will be set to the next one in descending order. Schema version won't change. Any changes in the configuration apply to both `migrate` or `rollback`.\n\n\n### Configuration\n\nYou can better control fixture migrations by creating a config YAML file: `test/fixture_champagne.yml` (or, again, `spec/`).\n\n#### Overwrite current fixtures\n\nSetting the `overwrite` key to `false` will leave your current fixtures untouched. The generated fixtures will go to `tmp/fixtures`. Default value is set to `true`.\n\nThis feature has partial support for multiple fixture paths (Rails \u003e 7.1). If your fixtures are divided across multiple paths (for example `test/fixtures_a` and `test/fixtues_b`), the fixture migration will fail unless you set `overwrite` to `false`. However, if you set multiple folders but only use one (all your files are in `test/fixtures_a`) then the migration can overwrite that folder.\n\n\n```yaml\n# test/fixture_champagne.yml\n\noverwrite: false\n```\n\n#### Fixture labels\n\nSetting the `label` key will allow you to control the names your fixtures get. It accepts a hash, where keys are table names and values are label templates: strings interpolated with a I18n style syntax. Interpolated keywords must be instance methods or attributes.\n\nIn the previous example, you can configure:\n\n```yaml\n# test/fixture_champagne.yml\n\nlabel:\n  enemy: \"%{name}\"\n```\n\nTo generate:\n\n```yaml\n# test/fixtures/enemies.yml\n\ninitial_enemy:\n  level: first_level\n  name: Initial Enemy\n```\n\n#### Rename current fixtures\n\nSetting the `rename` key to `true` will force every fixture label to follow the templates in the configuration. Default value is `false`. If any table is not configured, the default label will be used (something like `%{table_name}_%{id}` if `table_name` was an instance method).\n\n```yaml\n# test/fixture_champagne.yml\n\nrename: true\n```\n\nIf `rename` is set to `true`, every time you run `migrate` or `rollback` all fixtures will be regenerated in the corresponding folder (depending on `overwrite`), even if there's no pending migrations or schema version is up to date. Keep in mind that a renaming might break the fixture accessors in your tests or previous migrations. It could also break unsupported attachment fixtures.\n\n#### Ignore tables\n\nSetting the `ignore` key will allow you to control which tables get saved as fixtures. It accepts an array, where items are table names. Any table ignored by this configuration will disappear from the corresponding fixture folder (depending on `overwrite`).\n\nLet's say for example that each time a new `Enemy` gets created, it creates an associated `Event` in a callback that runs some processing in the background. If that event belongs to a polymorphic `eventable`, for every single one of those, a new event will be added to your fixtures, making the `events.yml` a big but not very useful file. Or maybe events get incinerated a couple of days after execution and it makes no sense to have fixtures for them. In any of those situations, you could ignore them from fixtures like this:\n\n```yaml\n# test/fixture_champagne.yml\n\nignore:\n  - events\n```\n\nThis configuration does not change the shape of the database after the migrations as the database transactions are left untouched (for example, events will be created anyway) but next time fixtures get loaded, no item from ignored tables will be present. This could break the integrity of your database, so make sure everything is working afterwards.\n\n\n### Manually adding or editing fixtures\n\nNothing prevents you from manually editing your fixture files. Take into account that the next time that you run migrations, what's on your fixtures will define the initial state of your migration database, which could break previous migrations or rollbacks (in the rare case that you need to run them again). The next time you run `migrate`, the migrator will tidy the information you added manually.\n\n\n### Generated fixtures folder structure\n\nOn namespaced models, the migrator will create a folder for each level and a `.yml` file for the last one. For example, `Level::Enemy` fixtures will be saved in `fixtures/level/enemies.yml`.\n\nIf you use single table inheritance, then the file will correspond with the parent model, the owner of the table. For example, `class Weapon::Rocket \u003c Weapon; end` will be saved in `fixtures/weapons.yml`.\n\nAll fixtures files that correspond to attachments will be copied as they are. Those are the ones located in `fixtures/files`, `fixtures/active_storage` and `fixtures/action_text`.\n\n\n### Extending your migrations\n\nYou can customize your fixture migrations by overriding the default template. Just place yours in `lib/templates/fixture_champagne/migration/migration.rb.tt`. Let's say you use [FactoryBot](https://github.com/thoughtbot/factory_bot_rails). It could be really helpful to use your existing factories to create new fixtures.\n\nYou could replace the default template with:\n```ruby\nrequire \"factory_bot_rails\"\n\nclass \u003c%= class_name %\u003e \u003c FixtureChampagne::Migration::Base\n  include FactoryBot::Syntax::Methods\n\n  def up\n    # Create, update or destroy records here\n  end\n\n  def down\n    # Optionally, reverse changes made by the :up method\n  end\nend\n```\n\nAnd all your migrations will now have access to your existing factories. If you have an enemy factory, the new migration could look like:\n```ruby\n# 20230126153650_create_initial_enemy.rb\n\nclass CreateInitialEnemy \u003c FixtureChampagne::Migration::Base\n  def up\n    unless Enemy.find_by(name: \"Initial Enemy\").present?\n      create(:enemy, name: \"Initial Enemy\", level: levels(:first_level))\n    end\n  end\n\n  def down\n    Enemy.find_by(name: \"Initial Enemy\").destroy!\n  end\nend\n```\n\n\n## Features currently not supported\n\nThe following fixture features are not supported:\n- More than one test suite in the same application\n- Dynamic ERB fixtures (considered a code smell in the [Rails documentation](https://edgeapi.rubyonrails.org/classes/ActiveRecord/FixtureSet.html))\n- Explicit `created_at` or `updated_at` timestamps (favoured autofilled ones)\n- Explicit `id` (favoured label references)\n- Fixture label interpolation (favoured configuration)\n- HABTM (`have_and_belong_to_many`) associations as inline lists\n- Support for YAML defaults (this could be nice)\n- Overwriting multiple fixture paths\n\nAs stated before, at least for now, fixtures files that correspond to attachments will be copied as they are. This means:\n- This fixtures must be generated manually\n- This fixtures must be updated manually if other fixtures labels change\n- All this files will be left untouched\n\n##  A few soft recommendations\n\n\n#### Don't have too many fixtures\n\nThe goal of this gem is to make it easier to keep fixtures tidy and up to date as things start to get complicated, so that factories aren't your only option. But no gem can replace good ol' discipline. If a new fixture gets added for every single small feature or bugfix, maintenance will be hard no matter the tool.\n\nReduce repetition, reuse fixtures using helpers to modify them in the tests or use factories for some of your tests.\n\n#### Make your migrations idempotent\n\nVersions saved in `.fixture_champagne_versions.yml` are there to ensure that your migrations are only executed once, but it would be a good idea to design your migrations to be idempotent, meaning that executing them more than once does not change the results.\n\n#### Raise errors\n\nRaise errors to stop the migration if there are invalid objects. A good way to do that is using `ActiveRecord` bang methods `create!`, `update!` and `destroy!`.\n\n#### Review changes before git commits\n\nThe safest way to rollback a migration is to revert any changes made to your `fixtures` folder and versions file using git. After migrating, inspect the changes made to the fixture folder and run the whole test suite.\n\n\n## Contributing\n\nFeel free to open an issue if you have any doubt, suggestion or find buggy behaviour. If it's a bug, it's always great if you can provide a minimum Rails app that reproduces the issue.\n\nThis project uses [Rubocop](https://github.com/rubocop/rubocop) to format Ruby code. Please make sure to run `rubocop` on your branch before submitting pull requests. You can do that by running `bundle exec rubocop -A`.\n\nAlso run the tests for each supported Rails version with:\n```sh\nbundle exec appraisal rake test\n```\n\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).\n\n\n## Code of Conduct\n\nEveryone interacting in the FixtureChampagne project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/fixture_champagne/blob/master/CODE_OF_CONDUCT.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjguecaimburu%2Ffixture_champagne","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjguecaimburu%2Ffixture_champagne","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjguecaimburu%2Ffixture_champagne/lists"}