mirror of
https://github.com/thoughtbot/factory_bot.git
synced 2022-11-09 11:43:51 -05:00
![Daniel Colson](/assets/img/avatar_default.png)
Fixes #1305
Before Rails 6 when the build_stubbed strategy assigned an id on a
record without a primary key column, the `id=` method would no-op, and
the record would end up looking like a new_record (i.e. `new_record?`
would return true because the id was nil).
This problem surfaced because of a [change in Rails 6][rails], which
caused `id=` to raise a potentially confusing
`ActiveModel::MissingAttributeError: can't write unknown attribute ''`
for records without a primary key column.
Since build_stubbed stubbed was calling `id=` for all instances,
regardless of whether they had primary keys, it was raising the above
error.
To avoid this error, we check whether the instance has a primary_key
defined before setting the id.
We also changed `persisted?` and `new_record?` to be less dependent on
the id. That way those methods will work as expected for records without
primary keys.
[rails]: b6828fc915
Co-authored-by: Jesse Bailey <jbailey117@gmail.com>
67 lines
1.5 KiB
Ruby
67 lines
1.5 KiB
Ruby
require "active_record"
|
|
|
|
module DefineConstantMacros
|
|
def define_class(path, base = Object, &block)
|
|
const = stub_const(path, Class.new(base))
|
|
const.class_eval(&block) if block_given?
|
|
const
|
|
end
|
|
|
|
def define_model(name, columns = {}, &block)
|
|
model = define_class(name, ActiveRecord::Base, &block)
|
|
create_table(model.table_name) do |table|
|
|
columns.each do |column_name, type|
|
|
table.column column_name, type
|
|
end
|
|
end
|
|
model
|
|
end
|
|
|
|
def create_table(table_name, &block)
|
|
connection = ActiveRecord::Base.connection
|
|
|
|
begin
|
|
connection.execute("DROP TABLE IF EXISTS #{table_name}")
|
|
connection.create_table(table_name, &block)
|
|
created_tables << table_name
|
|
connection
|
|
rescue Exception => exception # rubocop:disable Lint/RescueException
|
|
connection.execute("DROP TABLE IF EXISTS #{table_name}")
|
|
raise exception
|
|
end
|
|
end
|
|
|
|
def clear_generated_tables
|
|
created_tables.each do |table_name|
|
|
clear_generated_table(table_name)
|
|
end
|
|
created_tables.clear
|
|
end
|
|
|
|
def clear_generated_table(table_name)
|
|
ActiveRecord::Base.
|
|
connection.
|
|
execute("DROP TABLE IF EXISTS #{table_name}")
|
|
end
|
|
|
|
private
|
|
|
|
def created_tables
|
|
@created_tables ||= []
|
|
end
|
|
end
|
|
|
|
RSpec.configure do |config|
|
|
config.include DefineConstantMacros
|
|
|
|
config.before(:all) do
|
|
ActiveRecord::Base.establish_connection(
|
|
adapter: "sqlite3",
|
|
database: File.join(File.dirname(__FILE__), "test.db"),
|
|
)
|
|
end
|
|
|
|
config.after do
|
|
clear_generated_tables
|
|
end
|
|
end
|