Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def self.
from_json(string_or_io : String | IO, trusted : Bool =
false) :
self
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def self.
from_json(string_or_io : String | IO, root : String, trusted : Bool =
false) :
self
#
Deserializes the given JSON in string_or_io into
an instance of self, assuming the JSON consists
of an JSON object with key root, and whose value is
the value to deserialize. Will not deserialise from
fields with mass_assign: false
class User < ActiveModel::Model
attribute name : String
attribute google_id : UUID, mass_assign: false
end
User.from_json(%({"main": {"name": "Jason", "google_id": "f6f70bfb-c882-446d-8758-7ce47db39620"}}), root: "main") # => #<User:0x103131b20 @name="Jason">
def self.
from_trusted_json(string_or_io : String | IO, root : String) :
self
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def self.
from_trusted_json(string_or_io : String | IO) :
self
#
Serialize from a trusted JSON source
def self.
from_trusted_yaml(string_or_io : String | IO) :
self
#
Serialize from a trusted YAML source
def self.
from_yaml(string_or_io : String | IO, trusted : Bool =
false) :
self
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def self.
new(ctx : YAML::ParseContext, node : YAML::Nodes::Node)
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def self.
new(pull : JSON::PullParser)
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def self.
new(rs : DB::ResultSet)
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def self.
new(created_at : Time | ActiveModel::Model::None =
::ActiveModel::Model::None.new, updated_at : Time | ActiveModel::Model::None =
::ActiveModel::Model::None.new, group_id : UUID | ActiveModel::Model::None =
::ActiveModel::Model::None.new, signage_template_id : UUID | ActiveModel::Model::None =
::ActiveModel::Model::None.new)
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def self.
new(params : HTTP::Params | Hash(String, String) | Tuple(String, String))
#
Initialize PlaceOS::Model::GroupSignageTemplate from HTTP::Params.
def self.
attributes : Array(Symbol)
#
Returns all attribute keys.
def self.
changes(id : Tuple(UUID, UUID) | Nil =
nil) :
ChangeFeed
#
Changefeed at row (if #id passed) or whole table level.
Returns a ChangeFeed instance which can be used to invoke async callbacks via on or
use blocking Iterator via each method.
def self.
from_rs(__temp_2572 : DB::ResultSet)
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def self.
on_error(err : Exception | IO::Error)
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def
after_initialize(trusted : Bool)
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
Generate code to apply default values
def
assign_attributes(created_at : Time | Missing =
Missing, updated_at : Time | Missing =
Missing, group_id : UUID | Missing =
Missing, signage_template_id : UUID | Missing =
Missing)
#
Assign to multiple attributes.
def
assign_attributes(params : HTTP::Params | Hash(String, String) | Tuple(String, String))
#
Assign to multiple attributes via HTTP::Params.
Assign to multiple attributes from a model object
def
assign_attributes_from_json(json, root : String)
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def
assign_attributes_from_json(json)
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def
assign_attributes_from_trusted_json(json, root : String)
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def
assign_attributes_from_trusted_json(json)
#
Assign each field from JSON if field exists in JSON and has changed in model
def
assign_attributes_from_trusted_yaml(yaml)
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def
assign_attributes_from_yaml(yaml)
#
Uses the YAML parser as JSON is valid YAML
Returns a Hash of all attribute values
Returns a NamedTuple of all attribute values.
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
Check if any attributes have changed.
Returns a Hash with all changed attributes.
def
changed_json(io : IO) : Nil
#
Serialize the set of changed attributes to JSON.
def
changed_json : String
#
Serialize the set of changed attributes to JSON.
def
changed_persist_attributes
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def
changed_yaml(io : IO) : Nil
#
Serialize the set of changed attributes to YAML.
def
changed_yaml : String
#
Serialize the set of changed attributes to YAML.
def
created_at=(value : Time)
#
def
created_at? : Time | Nil
#
NOTE use getter / getter! (not property / property!) so that the
setter defined later in __create_initializer__ is the only setter on
the field. Crystal's overload resolution silently fails to replace a
property-defined setter with one of identical signature for generic
types (e.g. Set(String)?, Array(String)?, String | Array(String)),
although it does work for non-generic ones like String?. Defining the
setter only once via __create_initializer__ ensures change tracking,
sanitization, and custom setter blocks run uniformly across all types.
def
created_at_assigned? : Bool
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def
created_at_change : Tuple(Time | Nil, Time | Nil) | Nil
#
Returns a Tuple of the previous and the current
value of an instance variable if it has changed
def
created_at_changed? : Bool
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def
created_at_default : Time
#
def
created_at_removed? : Bool
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def
created_at_was : Time | Nil
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def
created_at_will_change! : Nil
#
Include #created_at in the set of changed attributes, whether it has changed or not.
def
group_id? : UUID | Nil
#
NOTE use getter / getter! (not property / property!) so that the
setter defined later in __create_initializer__ is the only setter on
the field. Crystal's overload resolution silently fails to replace a
property-defined setter with one of identical signature for generic
types (e.g. Set(String)?, Array(String)?, String | Array(String)),
although it does work for non-generic ones like String?. Defining the
setter only once via __create_initializer__ ensures change tracking,
sanitization, and custom setter blocks run uniformly across all types.
def
group_id_assigned? : Bool
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def
group_id_change : Tuple(UUID | Nil, UUID | Nil) | Nil
#
Returns a Tuple of the previous and the current
value of an instance variable if it has changed
def
group_id_changed? : Bool
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def
group_id_default : UUID
#
def
group_id_removed? : Bool
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def
group_id_was : UUID | Nil
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def
group_id_will_change! : Nil
#
Include #group_id in the set of changed attributes, whether it has changed or not.
Always returns this record's primary key value, even when the primary key
isn't named #id
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def
persistent_attributes
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
Reset each attribute to their previous values and clears all changes.
def
signage_template_id : UUID
#
def
signage_template_id=(value : UUID)
#
def
signage_template_id? : UUID | Nil
#
NOTE use getter / getter! (not property / property!) so that the
setter defined later in __create_initializer__ is the only setter on
the field. Crystal's overload resolution silently fails to replace a
property-defined setter with one of identical signature for generic
types (e.g. Set(String)?, Array(String)?, String | Array(String)),
although it does work for non-generic ones like String?. Defining the
setter only once via __create_initializer__ ensures change tracking,
sanitization, and custom setter blocks run uniformly across all types.
def
signage_template_id_assigned? : Bool
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def
signage_template_id_change : Tuple(UUID | Nil, UUID | Nil) | Nil
#
Returns a Tuple of the previous and the current
value of an instance variable if it has changed
def
signage_template_id_changed? : Bool
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def
signage_template_id_default : UUID
#
def
signage_template_id_removed? : Bool
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def
signage_template_id_was : UUID | Nil
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def
signage_template_id_will_change! : Nil
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def
updated_at? : Time | Nil
#
NOTE use getter / getter! (not property / property!) so that the
setter defined later in __create_initializer__ is the only setter on
the field. Crystal's overload resolution silently fails to replace a
property-defined setter with one of identical signature for generic
types (e.g. Set(String)?, Array(String)?, String | Array(String)),
although it does work for non-generic ones like String?. Defining the
setter only once via __create_initializer__ ensures change tracking,
sanitization, and custom setter blocks run uniformly across all types.
def
updated_at_assigned? : Bool
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def
updated_at_change : Tuple(Time | Nil, Time | Nil) | Nil
#
Returns a Tuple of the previous and the current
value of an instance variable if it has changed
def
updated_at_changed? : Bool
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def
updated_at_default : Time
#
def
updated_at_removed? : Bool
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def
updated_at_was : Time | Nil
#
Junction between Group and SignageTemplate (both authority-scoped,
UUID). Same M:N shape as GroupPlaylistItem — allows templates to be
shared with groups so they can manage their own templates.
Presence-only — no per-row permission bitmask, no GroupHistory audit.
A user's capability on a linked template comes from their
GroupUser.permissions within the group.
Both sides must share an authority — enforced here at the model layer
(no single FK can express it).
def
updated_at_will_change! : Nil
#
Include #updated_at in the set of changed attributes, whether it has changed or not.
def
validate_nilability
#
Validate that all non-nillable fields have values.