Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions docs/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,15 @@ end
- Duplicate exposed names raise `FixtureKit::DuplicateNameError`.
- Records are captured as class/id pairs at the moment `expose` is called, not
at the end of the definition. The record objects themselves are not retained.
- Exposing a record that is not persisted raises
`FixtureKit::UnpersistedRecordError`. This applies to records inside an
exposed collection as well, and to records that have been destroyed.
- Exposing a record with no id raises `FixtureKit::UnpersistedRecordError`.
This applies to records inside an exposed collection as well.
- Only the class and the id are stored, so an unsaved instance carrying the id
of a real row is a valid way to expose that row under a different model class
than the one that created it:

```ruby
expose(address: Addresses::Db::Address.new(id: company_address.id))
```

Because capture happens when `expose` is called, expose a record only once it
has been saved:
Expand Down
4 changes: 2 additions & 2 deletions lib/fixture_kit/definition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ def serialize(name, record)
end

def reference(name, record)
unless record.persisted?
if record.id.nil?
raise FixtureKit::UnpersistedRecordError,
"cannot expose #{name.inspect}: the #{record.class} is not persisted. " \
"cannot expose #{name.inspect}: the #{record.class} has no id. " \
"Exposed records are captured as class/id pairs when `expose` is called, " \
"so save the record before exposing it."
end
Expand Down
21 changes: 12 additions & 9 deletions spec/unit/definition_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,17 +101,17 @@
expect(definition.exposed).to eq({ sedan: { Car => sedan.id } })
end

it "raises when the record is not persisted" do
it "raises when the record has no id" do
unsaved = User.new(name: "Alice", email: "alice-unsaved@example.com")
definition = described_class.new { expose(alice: unsaved) }

expect { definition.evaluate(Object.new) }.to raise_error(
FixtureKit::UnpersistedRecordError,
/cannot expose :alice: the User is not persisted/
/cannot expose :alice: the User has no id/
)
end

it "raises when a record inside a collection is not persisted" do
it "raises when a record inside a collection has no id" do
saved = User.create!(name: "Alice", email: "alice-mixed@example.com")
unsaved = User.new(name: "Bob", email: "bob-mixed@example.com")
definition = described_class.new { expose(users: [saved, unsaved]) }
Expand All @@ -122,13 +122,16 @@
)
end

it "raises when the record has been destroyed" do
destroyed = User.create!(name: "Alice", email: "alice-destroyed@example.com")
destroyed.destroy!
definition = described_class.new { expose(alice: destroyed) }
# Only the class and the id are stored, so an unsaved instance carrying the
# id of a real row is a valid way to expose that row under a different
# model class than the one that created it.
it "accepts an unsaved instance that carries the id of a real row" do
alice = User.create!(name: "Alice", email: "alice-reference@example.com")
definition = described_class.new { expose(alice: User.new(id: alice.id)) }

expect { definition.evaluate(Object.new) }
.to raise_error(FixtureKit::UnpersistedRecordError)
definition.evaluate(Object.new)

expect(definition.exposed).to eq({ alice: { User => alice.id } })
end

it "allows an empty collection" do
Expand Down
Loading