Class: ActiveRecordCompose::Model

Inherits:
Object
  • Object
show all
Includes:
ActiveModel::Model
Defined in:
lib/active_record_compose/model.rb

Overview

This is the core class of ActiveRecordCompose.

By defining subclasses of this model, you can use ActiveRecordCompose functionality in your application. It has the basic functionality of ActiveModel::Model and ActiveModel::Attributes, and also provides aggregation of multiple models and atomic updates through transaction control.

Examples:

Example of model registration.

class AccountRegistration < ActiveRecordCompose::Model
  def initialize( = Account.new, attributes = {})
    @account = 
    @profile = @account.build_profile
    models <<  << profile
    super(attributes)
  end

  attribute :register_confirmation, :boolean, default: false
  delegate_attribute :name, :email, to: :account
  delegate_attribute :firstname, :lastname, :age, to: :profile

  validates :register_confirmation, presence: true

  private

  attr_reader :account, :profile
end

Multiple model update once.

registration = AccountRegistration.new
registration.assign_attributes(
  name: "alice-in-wonderland",
  email: "alice@example.com",
  firstname: "Alice",
  lastname: "Smith",
  age: 24,
  register_confirmation: true
)

registration.save!      # Register Account and Profile models at the same time.
Account.count           # => (0 ->) 1
Profile.count           # => (0 ->) 1

Attribute delegation.

 = Account.new
.name = "foo"

registration = AccountRegistration.new()
registration.name         # => "foo" (delegated)
registration.name?        # => true  (delegated attribute method + `?`)

registration.name = "bar" # => updates account.name
.name              # => "bar"
.name?             # => true

registration.attributes   # => { "original_attribute" => "qux", "name" => "bar" }

Aggregate errors on invalid.

registration = AccountRegistration.new

registration.name = "alice-in-wonderland"
registration.firstname = "Alice"
registration.age = 18

registration.valid?
#=> false

# The error contents of the objects stored in models are aggregated.
# For example, direct access to errors in Account#email.
registration.errors[:email].to_a  # Account#email
#=> ["can't be blank"]

# Of course, the validation defined for itself is also working.
registration.errors[:register_confirmation].to_a
#=> ["can't be blank"]

registration.errors.to_a
#=> ["Email can't be blank", "Lastname can't be blank", "Register confirmation can't be blank"]

Model Core collapse

Validations collapse

Persistences collapse

Callbacks collapse

Constructor Details

#initialize(attributes = {}) ⇒ Model

Returns a new instance of Model.



356
357
358
# File 'lib/active_record_compose/model.rb', line 356

def initialize(attributes = {})
  super
end

Class Method Details

.after_commit(*args, &block) ⇒ void

Registers a block to be called after the transaction is fully committed.



# File 'lib/active_record_compose/model.rb', line 345

.after_create(*args, &block) ⇒ void

Registers a callback to be called after a model is created.



# File 'lib/active_record_compose/model.rb', line 333

.after_rollback(*args, &block) ⇒ void

Registers a block to be called after the transaction is rolled back.



# File 'lib/active_record_compose/model.rb', line 348

.after_save(*args, &block) ⇒ void

Registers a callback to be called after a model is saved.



# File 'lib/active_record_compose/model.rb', line 324

.after_update(*args, &block) ⇒ void

Registers a callback to be called after a update is updated.



# File 'lib/active_record_compose/model.rb', line 342

.around_create(*args, &block) ⇒ void

Registers a callback to be called around the creation of a model.



# File 'lib/active_record_compose/model.rb', line 330

.around_save(*args, &block) ⇒ void

Registers a callback to be called around the save of a model.



# File 'lib/active_record_compose/model.rb', line 321

.around_update(*args, &block) ⇒ void

Registers a callback to be called around the update of a model.



# File 'lib/active_record_compose/model.rb', line 339

.attribute_namesArray<String>

Returns a array of attribute name. Attributes declared with delegate_attribute are also merged.

Returns:

  • (Array<String>)

    array of attribute name.

See Also:



# File 'lib/active_record_compose/model.rb', line 109

.before_create(*args, &block) ⇒ void

Registers a callback to be called before a model is created.



# File 'lib/active_record_compose/model.rb', line 327

.before_save(*args, &block) ⇒ void

Registers a callback to be called before a model is saved.



# File 'lib/active_record_compose/model.rb', line 318

.before_update(*args, &block) ⇒ void

Registers a callback to be called before a model is updated.



# File 'lib/active_record_compose/model.rb', line 336

.delegate_attribute(*attributes, to: , allow_nil: false) ⇒ void

Provides a method of attribute access to the encapsulated model.

It provides a way to access the attributes of the model it encompasses, allowing transparent access as if it had those attributes itself.

Examples:

Basic usage

delegate_attribute :name, :email, to: :profile

Allowing nil

delegate_attribute :bio, to: :profile, allow_nil: true

Parameters:

  • attributes (Array<Symbol, String>)

    attributes A variable-length list of attribute names to delegate.

  • to (Symbol, String) (defaults to: )

    The target object to which attributes are delegated (keyword argument).

  • allow_nil (Boolean) (defaults to: false)

    allow_nil Whether to allow nil values. Defaults to false.

See Also:

  • for similar behavior in ActiveSupport


# File 'lib/active_record_compose/model.rb', line 91

Instance Method Details

#attribute_namesArray<String>

Returns a array of attribute name. Attributes declared with delegate_attribute are also merged.

class Foo < ActiveRecordCompose::Base
  def initialize(attributes = {})
    @account = Account.new
    super
  end

  attribute :confirmation, :boolean, default: false   # plain attribute
  delegate_attribute :name, to: :account              # delegated attribute

  private

  attr_reader :account
end

Foo.attribute_names                                   # Returns the merged state of plain and delegated attributes
# => ["confirmation" ,"name"]

foo = Foo.new
foo.attribute_names                                   # Similar behavior for instance method version
# => ["confirmation", "name"]

Returns:

  • (Array<String>)

    array of attribute name.

See Also:



# File 'lib/active_record_compose/model.rb', line 116

#attributesHash<String, Object>

Returns a hash with the attribute name as key and the attribute value as value. Attributes declared with delegate_attribute are also merged.

class Foo < ActiveRecordCompose::Base
  def initialize(attributes = {})
    @account = Account.new
    super
  end

  attribute :confirmation, :boolean, default: false   # plain attribute
  delegate_attribute :name, to: :account              # delegated attribute

  private

  attr_reader :account
end

foo = Foo.new
foo.name = "Alice"
foo.confirmation = true

foo.attributes                                        # Returns the merged state of plain and delegated attributes
# => { "confirmation" => true, "name" => "Alice" }

Returns:

  • (Hash<String, Object>)

    hash with the attribute name as key and the attribute value as value.



# File 'lib/active_record_compose/model.rb', line 144

#errorsActiveModel::Errors

Returns the ActiveModel::Errors object that holds all information about attribute error messages.

The ActiveModel::Base implementation itself, but also aggregates error information for objects stored in #models when validation is performed.

class Account < ActiveRecord::Base
  validates :name, :email, presence: true
end

class AccountRegistration < ActiveRecordCompose::Model
  def initialize(attributes = {})
    @account = Account.new
    super(attributes)
    models << 
  end

  attribute :confirmation, :boolean, default: false
  validates :confirmation, presence: true

  private

  attr_reader :account
end

registration = AccountRegistration
registration.valid?
#=> false

# In addition to the model's own validation error information (`confirmation`), also aggregates
# error information for objects stored in `account` (`name`, `email`) when validation is performed.

registration.errors.map { _1.attribute }  #=> [:name, :email, :confirmation]

Returns:

  • (ActiveModel::Errors)


# File 'lib/active_record_compose/model.rb', line 231

#modelsActiveRecordCompose::ComposedCollection (private)

Returns a collection of model elements to encapsulate.

Examples:

Adding models

models << inner_model_a << inner_model_b
models.push(inner_model_c)

#push can have :destroy :if options

models.push(profile, destroy: :blank_profile?)
models.push(profile, destroy: -> { blank_profile? })

Returns:



371
# File 'lib/active_record_compose/model.rb', line 371

def models = @__models ||= ActiveRecordCompose::ComposedCollection.new(self)

#persisted?Boolean

Returns true if model is persisted.

By overriding this definition, you can control the callbacks that are triggered when a save is made. For example, returning false will trigger before_create, around_create and after_create, and returning true will trigger before_update, around_update and after_update.

Examples:

# A model where persistence is always false
class Foo < ActiveRecordCompose::Model
  before_save { puts "before_save called" }
  before_create { puts "before_create called" }
  before_update { puts "before_update called" }
  after_update { puts "after_update called" }
  after_create { puts "after_create called" }
  after_save { puts "after_save called" }

  def persisted? = false
end

# A model where persistence is always true
class Bar < Foo
  def persisted? = true
end

Foo.new.save!
# before_save called
# before_create called
# after_create called
# after_save called

Bar.new.save!
# before_save called
# before_update called
# after_update called
# after_save called

Returns:

  • (Boolean)

    returns true if model is persisted.



# File 'lib/active_record_compose/model.rb', line 171

#save(**options) ⇒ Boolean

Save the models that exist in models. Returns false if any of the targets fail, true if all succeed.

The save is performed within a single transaction.

Only the :validate option takes effect as it is required internally. However, we do not recommend explicitly specifying validate: false to skip validation. Additionally, the :context option is not accepted. The need for such a value indicates that operations from multiple contexts are being processed. If the contexts differ, we recommend separating them into different model definitions.

Options Hash (**options):

  • :validate (Boolean)

    Whether to run validations. This option is intended for internal use only. Users should avoid explicitly passing validate: false, as skipping validations can lead to unexpected behavior.

Returns:

  • (Boolean)

    returns true on success, false on failure.



# File 'lib/active_record_compose/model.rb', line 271

#save!(**options) ⇒ void

Behavior is same to #save, but raises an exception prematurely on failure.

Raises:

  • ActiveRecord::RecordInvalid

  • ActiveRecord::RecordNotSaved

See Also:



# File 'lib/active_record_compose/model.rb', line 290

#update(attributes) ⇒ Boolean

Assign attributes and #save.

Parameters:

  • attributes (Hash<String, Object>)

    new attributes.

Returns:

  • (Boolean)

    returns true on success, false on failure.

See Also:



# File 'lib/active_record_compose/model.rb', line 296

#update!(attributes) ⇒ void

Behavior is same to #update, but raises an exception prematurely on failure.

Parameters:

  • attributes (Hash<String, Object>)

    new attributes.

Raises:

  • ActiveRecord::RecordInvalid

  • ActiveRecord::RecordNotSaved

See Also:



# File 'lib/active_record_compose/model.rb', line 304

#valid?(context = nil) ⇒ Boolean

Runs all the validations and returns the result as true or false.

Parameters:

  • context (defaults to: nil)

    Validation context.

Returns:

  • (Boolean)

    true on success, false on failure.



# File 'lib/active_record_compose/model.rb', line 213

#validate(context = nil) ⇒ Boolean

Alias for #valid?

Parameters:

  • context (defaults to: nil)

Returns:

  • (Boolean)

    true on success, false on failure.

See Also:



# File 'lib/active_record_compose/model.rb', line 218

#validate!(context = nil) ⇒ void

Runs all the validations within the specified context. no errors are found, raises ActiveRecord::RecordInvalid otherwise.

Parameters:

  • context (defaults to: nil)

    Validation context.

Raises:

  • ActiveRecord::RecordInvalid

See Also:



# File 'lib/active_record_compose/model.rb', line 224