From c09a4fd23d7d52552132edde7ad155f366c560b8 Mon Sep 17 00:00:00 2001 From: Tongfei Gao Date: Sat, 18 May 2019 20:58:22 +0800 Subject: [PATCH] Allow specify fixtures to be ignored Allow specifying what fixtures can be ignored by setting `ignore` in fixtures YAML file: # users.yml _fixture: ignore: - base base: &base admin: false introduction: "This is a default description" admin: <<: *base admin: true visitor: <<: *base In the above example, "base" fixture will be ignored when creating users fixture. This is helpful when you want to inherit attributes and it makes your fixtures more "DRY". --- activerecord/CHANGELOG.md | 4 ++ .../lib/active_record/fixture_set/file.rb | 6 ++- activerecord/lib/active_record/fixtures.rb | 45 +++++++++++++++++-- activerecord/test/cases/fixtures_test.rb | 27 +++++++++++ activerecord/test/fixtures/other_books.yml | 26 +++++++++++ activerecord/test/fixtures/parrots.yml | 8 +++- 6 files changed, 111 insertions(+), 5 deletions(-) create mode 100644 activerecord/test/fixtures/other_books.yml diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 366032c734..7f2071189b 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,7 @@ +* Allow specifying fixtures to be ignored by setting `ignore` in YAML file's '_fixture' section. + + *Tongfei Gao* + * Make the DATABASE_URL env variable only affect the primary connection. Add new env variables for multiple databases. *John Crepezzi*, *Eileen Uchitelle* diff --git a/activerecord/lib/active_record/fixture_set/file.rb b/activerecord/lib/active_record/fixture_set/file.rb index f1ea0e022f..b2030a5bb9 100644 --- a/activerecord/lib/active_record/fixture_set/file.rb +++ b/activerecord/lib/active_record/fixture_set/file.rb @@ -29,6 +29,10 @@ module ActiveRecord config_row["model_class"] end + def ignored_fixtures + config_row["ignore"] + end + private def rows @rows ||= raw_rows.reject { |fixture_name, _| fixture_name == "_fixture" } @@ -40,7 +44,7 @@ module ActiveRecord if row row.last else - { 'model_class': nil } + { 'model_class': nil, 'ignore': nil } end end end diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index 046ed0e95c..3df4b3c87f 100644 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -420,6 +420,29 @@ module ActiveRecord # # Any fixture labeled "DEFAULTS" is safely ignored. # + # Besides using "DEFAULTS", you can also specify what fixtures will + # be ignored by setting "ignore" in "_fixture" section. + # + # # users.yml + # _fixture: + # ignore: + # - base + # # or use "ignore: base" when there is only one fixture needs to be ignored. + # + # base: &base + # admin: false + # introduction: "This is a default description" + # + # admin: + # <<: *base + # admin: true + # + # visitor: + # <<: *base + # + # In the above example, 'base' will be ignored when creating fixtures. + # This can be used for common attributes inheriting. + # # == Configure the fixture model class # # It's possible to set the fixture's model class directly in the YAML file. @@ -614,7 +637,7 @@ module ActiveRecord end end - attr_reader :table_name, :name, :fixtures, :model_class, :config + attr_reader :table_name, :name, :fixtures, :model_class, :ignored_fixtures, :config def initialize(_, name, class_name, path, config = ActiveRecord::Base) @name = name @@ -647,8 +670,8 @@ module ActiveRecord # Returns a hash of rows to be inserted. The key is the table, the value is # a list of rows to insert to that table. def table_rows - # allow a standard key to be used for doing defaults in YAML - fixtures.delete("DEFAULTS") + # allow specifying fixtures to be ignored by setting `ignore` in `_fixture` section + fixtures.except!(*ignored_fixtures) TableRows.new( table_name, @@ -667,6 +690,21 @@ module ActiveRecord end end + def ignored_fixtures=(base) + @ignored_fixtures = + case base + when Array + base + when String + [base] + else + [] + end + + @ignored_fixtures << "DEFAULTS" unless @ignored_fixtures.include?("DEFAULTS") + @ignored_fixtures.compact + end + # Loads the fixtures from the YAML file at +path+. # If the file sets the +model_class+ and current instance value is not set, # it uses the file value. @@ -678,6 +716,7 @@ module ActiveRecord yaml_files.each_with_object({}) do |file, fixtures| FixtureSet::File.open(file) do |fh| self.model_class ||= fh.model_class if fh.model_class + self.ignored_fixtures ||= fh.ignored_fixtures fh.each do |fixture_name, row| fixtures[fixture_name] = ActiveRecord::Fixture.new(row, model_class) end diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb index a7f01e898e..7ad032a632 100644 --- a/activerecord/test/cases/fixtures_test.rb +++ b/activerecord/test/cases/fixtures_test.rb @@ -1279,6 +1279,33 @@ class CustomNameForFixtureOrModelTest < ActiveRecord::TestCase end end +class IgnoreFixturesTest < ActiveRecord::TestCase + fixtures :other_books, :parrots + + test "ignores books fixtures" do + assert_raise(StandardError) { other_books(:published) } + assert_raise(StandardError) { other_books(:published_paperback) } + assert_raise(StandardError) { other_books(:published_ebook) } + + assert_equal 2, Book.count + assert_equal "Agile Web Development with Rails", other_books(:awdr).name + assert_equal "published", other_books(:awdr).status + assert_equal "paperback", other_books(:awdr).format + assert_equal "english", other_books(:awdr).language + + assert_equal "Ruby for Rails", other_books(:rfr).name + assert_equal "ebook", other_books(:rfr).format + assert_equal "published", other_books(:rfr).status + end + + test "ignores parrots fixtures" do + assert_raise(StandardError) { parrots(:DEFAULT) } + assert_raise(StandardError) { parrots(:DEAD_PARROT) } + + assert_equal "DeadParrot", parrots(:polly).parrot_sti_class + end +end + class FixturesWithDefaultScopeTest < ActiveRecord::TestCase fixtures :bulbs diff --git a/activerecord/test/fixtures/other_books.yml b/activerecord/test/fixtures/other_books.yml new file mode 100644 index 0000000000..62806c03d7 --- /dev/null +++ b/activerecord/test/fixtures/other_books.yml @@ -0,0 +1,26 @@ +_fixture: + model_class: Book + ignore: + - PUBLISHED + - PUBLISHED_PAPERBACK + - PUBLISHED_EBOOK + +PUBLISHED: &PUBLISHED + status: :published + +PUBLISHED_PAPERBACK: &PUBLISHED_PAPERBACK + <<: *PUBLISHED + format: "paperback" + language: :english + +PUBLISHED_EBOOK: &PUBLISHED_EBOOK + <<: *PUBLISHED + format: "ebook" + +awdr: + <<: *PUBLISHED_PAPERBACK + name: "Agile Web Development with Rails" + +rfr: + <<: *PUBLISHED_EBOOK + name: "Ruby for Rails" diff --git a/activerecord/test/fixtures/parrots.yml b/activerecord/test/fixtures/parrots.yml index 8425ef98e0..4f0a090e03 100644 --- a/activerecord/test/fixtures/parrots.yml +++ b/activerecord/test/fixtures/parrots.yml @@ -1,3 +1,9 @@ +_fixture: + ignore: DEAD_PARROT + +DEAD_PARROT: &DEAD_PARROT + parrot_sti_class: DeadParrot + george: name: "Curious George" treasures: diamond, sapphire @@ -17,7 +23,7 @@ polly: name: $LABEL killer: blackbeard treasures: sapphire, ruby - parrot_sti_class: DeadParrot + <<: *DEAD_PARROT DEFAULTS: &DEFAULTS treasures: sapphire, ruby