AnonymousActiveRecord

[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT) [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fpboling%2Fanonymous_active_record.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fpboling%2Fanonymous_active_record?ref=badge_shield) [![Version](https://img.shields.io/gem/v/anonymous_active_record.svg)](https://rubygems.org/gems/anonymous_active_record) [![Downloads Today](https://img.shields.io/gem/rd/anonymous_active_record.svg)](https://github.com/pboling/anonymous_active_record) [![Depfu](https://badges.depfu.com/badges/272ce0df3bc6df5cbea9354e2c3b65af/overview.svg)](https://depfu.com/github/pboling/anonymous_active_record?project_id=5614) [![CodeCov][🖇codecov-img♻️]][🖇codecov] [![Test Coverage](https://api.codeclimate.com/v1/badges/fe504d4ab2fb77cecf7d/test_coverage)](https://codeclimate.com/github/pboling/anonymous_active_record/test_coverage) [![Maintainability](https://api.codeclimate.com/v1/badges/fe504d4ab2fb77cecf7d/maintainability)](https://codeclimate.com/github/pboling/anonymous_active_record/maintainability) [![CI Supported Build][🚎s-wfi]][🚎s-wf] [![CI Unsupported Build][🚎us-wfi]][🚎us-wf] [![CI Style Build][🚎st-wfi]][🚎st-wf] [![CI Coverage Build][🚎cov-wfi]][🚎cov-wf] [![CI Heads Build][🚎hd-wfi]][🚎hd-wf] [![CI Ancient Build][🚎an-wfi]][🚎an-wf] [![CI Dead Build][🚎ded-wfi]][🚎ded-wf]

[![Liberapay Patrons][⛳liberapay-img]][⛳liberapay] [![Sponsor Me on Github][🖇sponsor-img]][🖇sponsor] [![Polar Shield][🖇polar-img]][🖇polar] [![Donate to my FLOSS or refugee efforts at ko-fi.com][🖇kofi-img]][🖇kofi] [![Donate to my FLOSS or refugee efforts using Patreon][🖇patreon-img]][🖇patreon]

This library was 🎩 inspired by 🎩, the Wolverine project, which implemented a clever workaround to the official non-support of anonymous classes by ActiveRecord.

Warning: Use of this gem is a security risk, due to the use of Ruby's eval. It is intended for use in a test suite, or other non-critical environment.

Project AnonymousActiveRecord
gem name anonymous_active_record
documentation on Github.com, on RDoc.info, on Railsbling.com
code triage Open Source Helpers
expert support Get help on Codementor
... 💖 Liberapay Patrons Sponsor Me Follow Me on LinkedIn Find Me on WellFound: Find Me on CrunchBase My LinkTree Follow Me on Ruby.Social Tweet @ Peter 💻 🌏

Installation

Install the gem and add to the application's Gemfile by executing, adding the --group test on the end if you will only use it for testing (which is the only way it should be used):

$ bundle add anonymous_active_record --group test

If bundler is not being used to manage dependencies, install the gem by executing:

$ gem install anonymous_active_record

Compatibility

This gem is compatible with, as of Sep 2024: • Ruby 2.4, 2.5, 2.6, 2.7, 3.0, 3.1, 3.2, 3.3, ruby-head, truffleruby-head

Usage

Require the library in your spec_helper or other test suite boot file.

require "anonymous_active_record"

Let's say you want to write specs for a module, HasBalloon, which provides a method has_balloon?, and will be mixed into ActiveRecord classes.

module HasBalloon
  def has_balloon?
    name == "Spot" # only Spot has a balloon
  end
end

This won't work (really!):

let(:ar_with_balloon) do
  Class.new(ActiveRecord::Base) do
    attr_accessor :name

    include HasBalloon
    def flowery_name
      "#{b_f}#{name}#{b_f}"
    end
    def b_f
      has_balloon? ? "🎈" : "🌸"
    end
  end
end

So do this instead:

let(:ar_with_balloon) do
  AnonymousActiveRecord.generate(columns: ["name"]) do
    include HasBalloon
    def flowery_name
      "#{b_f}#{name}#{b_f}"
    end
    def b_f
      has_balloon? ? "🎈" : "🌸"
    end
  end
end
it "can test the module" do
  expect(ar_with_balloon.new(name: "Spot").flowery_name).to(eq("🎈Spot🎈"))
  expect(ar_with_balloon.new(name: "Not Spot").flowery_name).to(eq("🌸Not Spot🌸"))
end

Generate Options

AnonymousActiveRecord.generate(
  table_name: "a_table_name",
      # if table_name is not set klass_basename will be used to derive a unique random table_name
      # default is a unique random table name
  klass_basename: "anons", # is default
  columns: ["name"],
      # columns default is [],
      # meaning class will have ['id', 'created_at', 'updated_at'], as the AR defaults
      # Optionally provide an array of hashes and thereby designate column type:
      # [{name: 'name', type: 'string'}, {name: 'baked_at', type: 'time'}]
  timestamps: true, # is default
  indexes: [{columns: ["name"], unique: true}],
      # indexes default is [],
      # meaning class will have no indexes, as the AR defaults
      # Optionally provide an array of hashes of index options (similar to those used in Rails migrations):
      # [{columns: ['name'], unique: true}, {columns: ['baked_at']}]
  connection_params: {adapter: "sqlite3", encoding: "utf8", database: ":memory:"}, # is default
) do
   # code which becomes part of the class definition
end

The block is optional.

Factory Options

AnonymousActiveRecord.factory(
  source_data: [{name: "Phil"}, {name: "Vickie"}],
        # Array of hashes, where each hash represents a record that will be created
    # ... The rest of the options are the same as for generate, see above.
) do
  # same as for generate, see above.
end

The block is optional.

There is also a factory! method that will raise if the create fails, accomplished by calling create! instead of create.

🤝 Contributing

See CONTRIBUTING.md

Code Coverage

If you need some ideas of where to help, you could work on adding more code coverage.

Coverage Graph

🌈 Contributors

Contributors

Made with contributors-img.

Star History

Star History Chart

🪇 Code of Conduct

Everyone interacting in this project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.

📌 Versioning

This Library adheres to Semantic Versioning 2.0.0. Violations of this scheme should be reported as bugs. Specifically, if a minor or patch version is released that breaks backward compatibility, a new version should be immediately released that restores compatibility. Breaking changes to the public API will only be introduced with new major versions.

To get a better understanding of how SemVer is intended to work over a project's lifetime, read this article from the creator of SemVer:

As a result of this policy, you can (and should) specify a dependency on these libraries using the Pessimistic Version Constraint with two digits of precision.

For example:

spec.add_dependency("anonymous_active_record", "~> 1.0")

See CHANGELOG.md for list of releases.

[comment]: <> ( 📌 VERSIONING LINKS )

📄 License

The gem is available as open source under the terms of the MIT License License: MIT. See LICENSE.txt for the official Copyright Notice.

FOSSA Status

[comment]: <> ( 📄 LEGAL LINKS )