Skip to content

Commit

Permalink
Add global defaults support (#82)
Browse files Browse the repository at this point in the history
* Add global defaults support

You can now set up default attributes that's applied to created/inserted records, like this:

```ruby
Oaken.prepare do
  # Assign broad global defaults for every type.
  defaults name: -> { Faker::Name.name }, public_key: -> { SecureRandom.hex }

  # Assign a more specific default on one type, which overrides the global default above.
  accounts.defaults name: -> { Faker::Business.name }
end
```

* Fix Ruby 3.0 support
  • Loading branch information
kaspth authored Jun 30, 2024
1 parent 5691526 commit 8b760ff
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 2 deletions.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,22 @@ Oaken has some chosen directory conventions to help strengthen your understandin
- `db/seeds/data` for any data tables, like the plans a SaaS app has.
- `db/seeds/tests/cases` for any specific cases that are only used in some tests, like `pagination.rb`.

### Using default attributes

You can set up default attributes that's applied to created/inserted records at different levels, like this:

```ruby
Oaken.prepare do
# Assign broad global defaults for every type.
defaults name: -> { Faker::Name.name }, public_key: -> { SecureRandom.hex }

# Assign a more specific default on one type, which overrides the global default above.
accounts.defaults name: -> { Faker::Business.name }
end
```

[!TIP] `defaults` are particularly well suited for assigning generated data with [Faker](https://github.com/faker-ruby/faker).

### Reusing data in tests

With the setup above, Oaken can reuse the same data in tests like this:
Expand Down
5 changes: 5 additions & 0 deletions lib/oaken/seeds.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
module Oaken::Seeds
extend self

# Allow assigning defaults across different types.
def self.defaults(**defaults) = attributes.merge!(**defaults)
def self.defaults_for(*keys) = attributes.slice(*keys)
def self.attributes = @attributes ||= {}.with_indifferent_access

def self.method_missing(name, ...)
if type = name.to_s.classify.safe_constantize
register type
Expand Down
2 changes: 1 addition & 1 deletion lib/oaken/stored/active_record.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
class Oaken::Stored::ActiveRecord
def initialize(type)
@type, @key = type, type.table_name
@attributes = {}
@attributes = Oaken::Seeds.defaults_for(*type.column_names)
end
attr_reader :type, :key
delegate :transaction, to: :type # For multi-db setups to help open a transaction on secondary connections.
Expand Down
2 changes: 2 additions & 0 deletions test/dummy/db/seeds.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
Oaken.prepare do
defaults name: -> { "Shouldn't be used for users.name" }, title: -> { "Global Default Title" }

section :registrations
register Menu::Item

Expand Down
8 changes: 7 additions & 1 deletion test/dummy/test/models/oaken_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,13 @@ class OakenTest < ActiveSupport::TestCase
assert menus.basic
end

test "default attributes" do
test "global attributes" do
plan = plans.upsert price_cents: 10_00

assert_equal "Global Default Title", plan.reload.title
end

test "per-type default attributes" do
names = users.pluck(:name)

(1..10).each do
Expand Down

0 comments on commit 8b760ff

Please sign in to comment.