better_model 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+ require "rails/generators/active_record"
5
+
6
+ module BetterModel
7
+ module Generators
8
+ module Stateable
9
+ # Generator per creare la tabella state_transitions
10
+ #
11
+ # Usage:
12
+ # rails generate better_model:stateable:install
13
+ # rails generate better_model:stateable:install --table-name=order_transitions
14
+ #
15
+ class InstallGenerator < Rails::Generators::Base
16
+ include ActiveRecord::Generators::Migration
17
+
18
+ source_root File.expand_path("templates", __dir__)
19
+
20
+ class_option :table_name, type: :string, default: "state_transitions",
21
+ desc: "Custom table name for state transitions (default: state_transitions)"
22
+
23
+ desc "Creates the state_transitions table for Stateable history tracking"
24
+
25
+ def create_migration_file
26
+ migration_template "install_migration.rb.tt", "db/migrate/create_#{transitions_table_name}.rb"
27
+ end
28
+
29
+ private
30
+
31
+ def transitions_table_name
32
+ options[:table_name]
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+ require "rails/generators/active_record"
5
+
6
+ module BetterModel
7
+ module Generators
8
+ # Generator per aggiungere Stateable a un modello esistente
9
+ #
10
+ # Usage:
11
+ # rails generate better_model:stateable MODEL_NAME [options]
12
+ #
13
+ # Examples:
14
+ # rails generate better_model:stateable Order
15
+ # rails generate better_model:stateable Article --initial-state=draft
16
+ #
17
+ class StateableGenerator < Rails::Generators::NamedBase
18
+ include ActiveRecord::Generators::Migration
19
+
20
+ source_root File.expand_path("templates", __dir__)
21
+
22
+ class_option :initial_state, type: :string, default: nil,
23
+ desc: "Initial state name (default: first state defined)"
24
+
25
+ desc "Adds Stateable support to an existing model by adding a 'state' column"
26
+
27
+ def create_migration_file
28
+ migration_template "migration.rb.tt", "db/migrate/add_stateable_to_#{table_name}.rb"
29
+ end
30
+
31
+ def show_readme
32
+ readme "README" if behavior == :invoke
33
+ end
34
+
35
+ private
36
+
37
+ def table_name
38
+ name.tableize
39
+ end
40
+
41
+ def model_name
42
+ name.camelize
43
+ end
44
+
45
+ def initial_state_value
46
+ options[:initial_state] || "pending"
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,38 @@
1
+ ===============================================================================
2
+
3
+ Stateable column has been added to your model!
4
+
5
+ Next steps:
6
+
7
+ 1. Run the migration:
8
+ $ bin/rails db:migrate
9
+
10
+ 2. Add Stateable configuration to your model:
11
+
12
+ class <%= model_name %> < ApplicationRecord
13
+ include BetterModel
14
+
15
+ stateable do
16
+ # Define states
17
+ state :<%= initial_state_value %>, initial: true
18
+ state :confirmed
19
+ state :completed
20
+
21
+ # Define transitions
22
+ transition :confirm, from: :<%= initial_state_value %>, to: :confirmed do
23
+ guard { valid? }
24
+ before { prepare_confirmation }
25
+ after { send_notification }
26
+ end
27
+
28
+ transition :complete, from: :confirmed, to: :completed
29
+ end
30
+ end
31
+
32
+ 3. Don't forget to create the state_transitions table (once per app):
33
+ $ bin/rails generate better_model:stateable:install
34
+ $ bin/rails db:migrate
35
+
36
+ For more information, see: docs/stateable.md
37
+
38
+ ===============================================================================
@@ -0,0 +1,20 @@
1
+ class Create<%= transitions_table_name.camelize %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
+ def change
3
+ create_table :<%= transitions_table_name %> do |t|
4
+ t.string :transitionable_type, null: false
5
+ t.integer :transitionable_id, null: false
6
+ t.string :event, null: false
7
+ t.string :from_state, null: false
8
+ t.string :to_state, null: false
9
+ t.json :metadata
10
+
11
+ t.datetime :created_at, null: false
12
+ end
13
+
14
+ add_index :<%= transitions_table_name %>, [:transitionable_type, :transitionable_id], name: "index_<%= transitions_table_name %>_on_transitionable"
15
+ add_index :<%= transitions_table_name %>, :event
16
+ add_index :<%= transitions_table_name %>, :from_state
17
+ add_index :<%= transitions_table_name %>, :to_state
18
+ add_index :<%= transitions_table_name %>, :created_at
19
+ end
20
+ end
@@ -0,0 +1,9 @@
1
+ class AddStateableTo<%= table_name.camelize %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
+ def change
3
+ change_table :<%= table_name %> do |t|
4
+ t.string :state, null: false, default: "<%= initial_state_value %>"
5
+ end
6
+
7
+ add_index :<%= table_name %>, :state
8
+ end
9
+ end
@@ -0,0 +1,28 @@
1
+ class Create<%= versions_table_name.camelize %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
+ def change
3
+ create_table :<%= versions_table_name %> do |t|
4
+ # Polymorphic association to tracked models
5
+ t.string :item_type, null: false
6
+ t.integer :item_id, null: false
7
+
8
+ # Event type: created, updated, destroyed
9
+ t.string :event, null: false
10
+
11
+ # Changes stored as JSON (before/after values)
12
+ # SQLite uses json, PostgreSQL can use jsonb
13
+ t.json :object_changes
14
+
15
+ # Optional tracking fields
16
+ t.integer :updated_by_id
17
+ t.string :updated_reason
18
+
19
+ t.datetime :created_at, null: false
20
+ end
21
+
22
+ # Indexes for performance
23
+ add_index :<%= versions_table_name %>, [ :item_type, :item_id ], name: "index_<%= versions_table_name %>_on_item"
24
+ add_index :<%= versions_table_name %>, :created_at
25
+ add_index :<%= versions_table_name %>, :updated_by_id
26
+ add_index :<%= versions_table_name %>, :event
27
+ end
28
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+
5
+ module BetterModel
6
+ module Generators
7
+ class TraceableGenerator < Rails::Generators::Base
8
+ source_root File.expand_path("templates", __dir__)
9
+
10
+ argument :name, type: :string, default: "model", desc: "Model name (optional, used for default table name)"
11
+
12
+ class_option :create_table, type: :boolean, default: false,
13
+ desc: "Create the versions table (only needed once per table)"
14
+
15
+ class_option :table_name, type: :string, default: nil,
16
+ desc: "Custom table name for versions (default: {model}_versions)"
17
+
18
+ def create_migration_file
19
+ if options[:create_table]
20
+ template "create_table_migration.rb.tt",
21
+ "db/migrate/#{timestamp}_create_#{versions_table_name}.rb"
22
+
23
+ say "Created migration for '#{versions_table_name}' table", :green
24
+ say "Run 'rails db:migrate' to create the table", :green
25
+ else
26
+ say "Traceable will use the '#{versions_table_name}' table", :yellow
27
+ say "If the table doesn't exist yet, run:", :yellow
28
+ say " rails g better_model:traceable #{name} --create-table#{table_name_option_hint}", :green
29
+ say " rails db:migrate", :green
30
+ end
31
+ end
32
+
33
+ def show_usage_instructions
34
+ say "\nTo enable Traceable in your model:", :yellow
35
+ say " class #{class_name} < ApplicationRecord", :white
36
+ say " include BetterModel", :white
37
+ say " ", :white
38
+ say " traceable do", :white
39
+ say " track :field1, :field2, :field3", :white
40
+ if custom_table_name?
41
+ say " table_name '#{versions_table_name}'", :white
42
+ else
43
+ say " # table_name '#{versions_table_name}' (default)", :white
44
+ end
45
+ say " end", :white
46
+ say " end", :white
47
+ say "\nSee documentation for more options and usage examples", :yellow
48
+ end
49
+
50
+ private
51
+
52
+ def timestamp
53
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
54
+ end
55
+
56
+ def class_name
57
+ name.camelize
58
+ end
59
+
60
+ def model_name
61
+ name.underscore
62
+ end
63
+
64
+ def versions_table_name
65
+ @versions_table_name ||= options[:table_name] || "#{model_name}_versions"
66
+ end
67
+
68
+ def custom_table_name?
69
+ options[:table_name].present?
70
+ end
71
+
72
+ def table_name_option_hint
73
+ custom_table_name? ? " --table-name=#{versions_table_name}" : ""
74
+ end
75
+ end
76
+ end
77
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: better_model
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - alessiobussolari
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-10-29 00:00:00.000000000 Z
11
+ date: 2025-10-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -33,7 +33,7 @@ dependencies:
33
33
  description: BetterModel is a Rails engine gem (Rails 8.1+) that provides powerful
34
34
  extensions for ActiveRecord models including declarative status management and more.
35
35
  email:
36
- - alessio@cosmic.tech
36
+ - alessio.bussolari@pandev.it
37
37
  executables: []
38
38
  extensions: []
39
39
  extra_rdoc_files: []
@@ -48,10 +48,29 @@ files:
48
48
  - lib/better_model/railtie.rb
49
49
  - lib/better_model/searchable.rb
50
50
  - lib/better_model/sortable.rb
51
+ - lib/better_model/state_transition.rb
52
+ - lib/better_model/stateable.rb
53
+ - lib/better_model/stateable/configurator.rb
54
+ - lib/better_model/stateable/errors.rb
55
+ - lib/better_model/stateable/guard.rb
56
+ - lib/better_model/stateable/transition.rb
51
57
  - lib/better_model/statusable.rb
58
+ - lib/better_model/traceable.rb
59
+ - lib/better_model/validatable.rb
60
+ - lib/better_model/validatable/business_rule_validator.rb
61
+ - lib/better_model/validatable/configurator.rb
62
+ - lib/better_model/validatable/order_validator.rb
52
63
  - lib/better_model/version.rb
64
+ - lib/better_model/version_record.rb
53
65
  - lib/generators/better_model/archivable/archivable_generator.rb
54
66
  - lib/generators/better_model/archivable/templates/migration.rb.tt
67
+ - lib/generators/better_model/stateable/install_generator.rb
68
+ - lib/generators/better_model/stateable/stateable_generator.rb
69
+ - lib/generators/better_model/stateable/templates/README
70
+ - lib/generators/better_model/stateable/templates/install_migration.rb.tt
71
+ - lib/generators/better_model/stateable/templates/migration.rb.tt
72
+ - lib/generators/better_model/traceable/templates/create_table_migration.rb.tt
73
+ - lib/generators/better_model/traceable/traceable_generator.rb
55
74
  - lib/tasks/better_model_tasks.rake
56
75
  homepage: https://github.com/alessiobussolari/better_model
57
76
  licenses: