Skip to content

Commit 6f85e54

Browse files
committed
Support file_fixture in Factory definitions
Related to [factory_bot#1282][] [rails/rails#45606][] has been merged and is likely to be released as part of Rails 7.1. With that addition, the path toward resolving [factory_bot#1282][] becomes more clear. If factories can pass along [Pathname][] instances to attachment attributes, Active Support will handle the rest. Instances of `ActiveSupport::TestCase` provide a [file_fixture][] helper to construct a `Pathname` instance based on the path defined by `ActiveSupport::TestCase.file_fixture_path` (relative to the Rails root directory). [factory_bot#1282]: thoughtbot/factory_bot#1282 (comment) [rails/rails#45606]: rails/rails#45606 [Pathname]: https://docs.ruby-lang.org/en/master/Pathname.html [file_fixture]: https://api.rubyonrails.org/classes/ActiveSupport/Testing/FileFixtures.html#method-i-file_fixture
1 parent 346e3c7 commit 6f85e54

19 files changed

+288
-68
lines changed

Gemfile.lock

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,21 @@ GEM
2424
erubi (~> 1.11)
2525
rails-dom-testing (~> 2.2)
2626
rails-html-sanitizer (~> 1.6)
27+
activejob (7.1.2)
28+
activesupport (= 7.1.2)
29+
globalid (>= 0.3.6)
2730
activemodel (7.1.2)
2831
activesupport (= 7.1.2)
2932
activerecord (7.1.2)
3033
activemodel (= 7.1.2)
3134
activesupport (= 7.1.2)
3235
timeout (>= 0.4.0)
36+
activestorage (7.1.2)
37+
actionpack (= 7.1.2)
38+
activejob (= 7.1.2)
39+
activerecord (= 7.1.2)
40+
activesupport (= 7.1.2)
41+
marcel (~> 1.0)
3342
activesupport (7.1.2)
3443
base64
3544
bigdecimal
@@ -92,6 +101,8 @@ GEM
92101
activesupport (>= 5.0.0)
93102
ffi (1.15.5)
94103
ffi (1.15.5-java)
104+
globalid (1.2.1)
105+
activesupport (>= 6.1)
95106
i18n (1.14.5)
96107
concurrent-ruby (~> 1.0)
97108
io-console (0.7.2)
@@ -107,6 +118,7 @@ GEM
107118
loofah (2.22.0)
108119
crass (~> 1.0.2)
109120
nokogiri (>= 1.12.0)
121+
marcel (1.0.4)
110122
mime-types (3.4.1)
111123
mime-types-data (~> 3.2015)
112124
mime-types-data (3.2023.0218.1)
@@ -228,6 +240,7 @@ PLATFORMS
228240

229241
DEPENDENCIES
230242
activerecord (>= 5.0.0)
243+
activestorage (>= 5.0.0)
231244
appraisal
232245
aruba
233246
cucumber

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,19 @@ using an empty array:
8484
config.factory_bot.definition_file_paths = []
8585
```
8686

87+
### File Fixture Support
88+
89+
Factories have access to [ActiveSupport::Testing::FileFixtures#file_fixture][]
90+
helper to read files from tests.
91+
92+
To disable file fixture support, set `file_fixture_support = false`:
93+
94+
```rb
95+
config.factory_bot.file_fixture_support = false
96+
```
97+
98+
[ActiveSupport::Testing::FileFixtures#file_fixture]: https://api.rubyonrails.org/classes/ActiveSupport/Testing/FileFixtures.html#method-i-file_fixture
99+
87100
### Generators
88101

89102
Including factory\_bot\_rails in the development group of your Gemfile

Rakefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
require "bundler/setup"
22
require "cucumber/rake/task"
33
require "rspec/core/rake_task"
4+
require "minitest/test_task"
45
require "standard/rake"
56

67
Bundler::GemHelper.install_tasks name: "factory_bot_rails"
@@ -12,5 +13,7 @@ end
1213

1314
RSpec::Core::RakeTask.new(:spec)
1415

16+
Minitest::TestTask.create
17+
1518
desc "Run the test suite and standard"
16-
task default: %w[spec cucumber standard]
19+
task default: %w[spec test cucumber standard]

factory_bot_rails.gemspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,5 @@ Gem::Specification.new do |s|
2424

2525
s.add_development_dependency("sqlite3")
2626
s.add_development_dependency("activerecord", ">= 5.0.0")
27+
s.add_development_dependency("activestorage", ">= 5.0.0")
2728
end
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module FactoryBotRails
2+
module FileFixtureSupport
3+
def self.included(klass)
4+
klass.cattr_accessor :file_fixture_support
5+
6+
klass.delegate :file_fixture, to: "self.class.file_fixture_support"
7+
end
8+
end
9+
end

lib/factory_bot_rails/railtie.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@
44
require "factory_bot_rails/generator"
55
require "factory_bot_rails/reloader"
66
require "factory_bot_rails/factory_validator"
7+
require "factory_bot_rails/file_fixture_support"
78
require "rails"
89

910
module FactoryBotRails
1011
class Railtie < Rails::Railtie
1112
config.factory_bot = ActiveSupport::OrderedOptions.new
1213
config.factory_bot.definition_file_paths = FactoryBot.definition_file_paths
1314
config.factory_bot.validator = FactoryBotRails::FactoryValidator.new
15+
config.factory_bot.file_fixture_support = true
1416

1517
initializer "factory_bot.set_fixture_replacement" do
1618
Generator.new(config).run
@@ -20,6 +22,22 @@ class Railtie < Rails::Railtie
2022
FactoryBot.definition_file_paths = definition_file_paths
2123
end
2224

25+
config.after_initialize do
26+
if config.factory_bot.file_fixture_support
27+
FactoryBot::SyntaxRunner.include FactoryBotRails::FileFixtureSupport
28+
29+
ActiveSupport.on_load :active_support_test_case do
30+
setup { FactoryBot::SyntaxRunner.file_fixture_support = self }
31+
end
32+
33+
if defined?(RSpec) && RSpec.respond_to?(:configure)
34+
RSpec.configure do |config|
35+
config.before { FactoryBot::SyntaxRunner.file_fixture_support = self }
36+
end
37+
end
38+
end
39+
end
40+
2341
config.after_initialize do |app|
2442
FactoryBot.find_definitions
2543
Reloader.new(app).run
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
class CreateActiveStorageTables < ActiveRecord::Migration[7.0]
2+
def change
3+
# Use Active Record's configured type for primary and foreign keys
4+
primary_key_type, foreign_key_type = primary_and_foreign_key_types
5+
6+
create_table :active_storage_blobs, id: primary_key_type do |t|
7+
t.string :key, null: false
8+
t.string :filename, null: false
9+
t.string :content_type
10+
t.text :metadata
11+
t.string :service_name, null: false
12+
t.bigint :byte_size, null: false
13+
t.string :checksum
14+
15+
if connection.supports_datetime_with_precision?
16+
t.datetime :created_at, precision: 6, null: false
17+
else
18+
t.datetime :created_at, null: false
19+
end
20+
21+
t.index [:key], unique: true
22+
end
23+
24+
create_table :active_storage_attachments, id: primary_key_type do |t|
25+
t.string :name, null: false
26+
t.references :record, null: false, polymorphic: true, index: false, type: foreign_key_type
27+
t.references :blob, null: false, type: foreign_key_type
28+
29+
if connection.supports_datetime_with_precision?
30+
t.datetime :created_at, precision: 6, null: false
31+
else
32+
t.datetime :created_at, null: false
33+
end
34+
35+
t.index [:record_type, :record_id, :name, :blob_id], name: :index_active_storage_attachments_uniqueness, unique: true
36+
t.foreign_key :active_storage_blobs, column: :blob_id
37+
end
38+
39+
create_table :active_storage_variant_records, id: primary_key_type do |t|
40+
t.belongs_to :blob, null: false, index: false, type: foreign_key_type
41+
t.string :variation_digest, null: false
42+
43+
t.index [:blob_id, :variation_digest], name: :index_active_storage_variant_records_uniqueness, unique: true
44+
t.foreign_key :active_storage_blobs, column: :blob_id
45+
end
46+
end
47+
48+
private
49+
50+
def primary_and_foreign_key_types
51+
config = Rails.configuration.generators
52+
setting = config.options[config.orm][:primary_key_type]
53+
primary_key_type = setting || :primary_key
54+
foreign_key_type = setting || :bigint
55+
[primary_key_type, foreign_key_type]
56+
end
57+
end
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
class AddServiceNameToActiveStorageBlobs < ActiveRecord::Migration[6.0]
2+
def up
3+
return unless table_exists?(:active_storage_blobs)
4+
5+
unless column_exists?(:active_storage_blobs, :service_name)
6+
add_column :active_storage_blobs, :service_name, :string
7+
8+
if (configured_service = ActiveStorage::Blob.service.name)
9+
ActiveStorage::Blob.unscoped.update_all(service_name: configured_service)
10+
end
11+
12+
change_column :active_storage_blobs, :service_name, :string, null: false
13+
end
14+
end
15+
16+
def down
17+
return unless table_exists?(:active_storage_blobs)
18+
19+
remove_column :active_storage_blobs, :service_name
20+
end
21+
end
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
class CreateActiveStorageVariantRecords < ActiveRecord::Migration[6.0]
2+
def change
3+
return unless table_exists?(:active_storage_blobs)
4+
5+
# Use Active Record's configured type for primary key
6+
create_table :active_storage_variant_records, id: primary_key_type, if_not_exists: true do |t|
7+
t.belongs_to :blob, null: false, index: false, type: blobs_primary_key_type
8+
t.string :variation_digest, null: false
9+
10+
t.index %i[blob_id variation_digest], name: "index_active_storage_variant_records_uniqueness", unique: true
11+
t.foreign_key :active_storage_blobs, column: :blob_id
12+
end
13+
end
14+
15+
private
16+
17+
def primary_key_type
18+
config = Rails.configuration.generators
19+
config.options[config.orm][:primary_key_type] || :primary_key
20+
end
21+
22+
def blobs_primary_key_type
23+
pkey_name = connection.primary_key(:active_storage_blobs)
24+
pkey_column = connection.columns(:active_storage_blobs).find { |c| c.name == pkey_name }
25+
pkey_column.bigint? ? :bigint : pkey_column.type
26+
end
27+
end
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class RemoveNotNullOnActiveStorageBlobsChecksum < ActiveRecord::Migration[6.0]
2+
def change
3+
return unless table_exists?(:active_storage_blobs)
4+
5+
change_column_null(:active_storage_blobs, :checksum, true)
6+
end
7+
end

0 commit comments

Comments
 (0)