Class: Attio::Attribute

Inherits:
APIResource show all
Defined in:
lib/attio/resources/attribute.rb

Overview

Represents a custom attribute on an Attio object Attributes define the schema for data stored on records

Constant Summary collapse

TYPES =

Attribute types

%w[
  text
  number
  checkbox
  date
  timestamp
  rating
  currency
  status
  select
  multiselect
  email
  phone
  url
  user
  record_reference
  location
].freeze
TYPE_CONFIGS =

Type configurations

{
  "text" => {supports_default: true, supports_required: true},
  "number" => {supports_default: true, supports_required: true, supports_unique: true},
  "checkbox" => {supports_default: true},
  "date" => {supports_default: true, supports_required: true},
  "timestamp" => {supports_default: true, supports_required: true},
  "rating" => {supports_default: true, max_value: 5},
  "currency" => {supports_default: true, supports_required: true},
  "status" => {requires_options: true},
  "select" => {requires_options: true, supports_default: true},
  "multiselect" => {requires_options: true},
  "email" => {supports_unique: true, supports_required: true},
  "phone" => {supports_required: true},
  "url" => {supports_required: true},
  "user" => {supports_required: true},
  "record_reference" => {requires_target_object: true, supports_required: true},
  "location" => {supports_required: true}
}.freeze

Constants inherited from APIResource

Attio::APIResource::SKIP_KEYS

Instance Attribute Summary collapse

Attributes inherited from APIResource

#created_at, #id, #metadata

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from APIResource

#==, #[], #[]=, api_operations, attr_attio, #changed, #changed?, #changed_attributes, #changes, #destroy, #each, execute_request, #fetch, #hash, id_param_name, #inspect, #key?, #keys, #persisted?, #reset_changes!, resource_name, #revert!, #to_json, #update_attributes, #update_from, validate_id!, #values

Constructor Details

#initialize(attributes = {}, opts = {}) ⇒ Attribute

Returns a new instance of Attribute.



66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/attio/resources/attribute.rb', line 66

def initialize(attributes = {}, opts = {})
  super
  normalized_attrs = normalize_attributes(attributes)
  @api_slug = normalized_attrs[:api_slug]
  @type = normalized_attrs[:type]
  @attio_object_id = normalized_attrs[:object_id]
  @object_api_slug = normalized_attrs[:object_api_slug]
  @parent_object_id = normalized_attrs[:parent_object_id]
  @created_by_actor = normalized_attrs[:created_by_actor]
  @is_archived = normalized_attrs[:is_archived] || false
  @archived_at = parse_timestamp(normalized_attrs[:archived_at])
  @title = normalized_attrs[:title]
end

Instance Attribute Details

#api_slugObject (readonly)

Read-only attributes



62
63
64
# File 'lib/attio/resources/attribute.rb', line 62

def api_slug
  @api_slug
end

#archived_atObject (readonly)

Read-only attributes



62
63
64
# File 'lib/attio/resources/attribute.rb', line 62

def archived_at
  @archived_at
end

#attio_object_idObject (readonly)

Read-only attributes



62
63
64
# File 'lib/attio/resources/attribute.rb', line 62

def attio_object_id
  @attio_object_id
end

#created_by_actorObject (readonly)

Read-only attributes



62
63
64
# File 'lib/attio/resources/attribute.rb', line 62

def created_by_actor
  @created_by_actor
end

#is_archivedObject (readonly)

Read-only attributes



62
63
64
# File 'lib/attio/resources/attribute.rb', line 62

def is_archived
  @is_archived
end

#object_api_slugObject (readonly)

Read-only attributes



62
63
64
# File 'lib/attio/resources/attribute.rb', line 62

def object_api_slug
  @object_api_slug
end

#parent_object_idObject (readonly)

Read-only attributes



62
63
64
# File 'lib/attio/resources/attribute.rb', line 62

def parent_object_id
  @parent_object_id
end

#titleObject (readonly)

Read-only attributes



62
63
64
# File 'lib/attio/resources/attribute.rb', line 62

def title
  @title
end

#typeObject (readonly)

Read-only attributes



62
63
64
# File 'lib/attio/resources/attribute.rb', line 62

def type
  @type
end

Class Method Details

.create(params = {}, **opts) ⇒ Object

Override create to handle object-specific attributes



249
250
251
252
253
254
255
256
# File 'lib/attio/resources/attribute.rb', line 249

def create(params = {}, **opts)
  object = params[:object]
  validate_object_identifier!(object)

  prepared_params = prepare_params_for_create(params)
  response = execute_request(:POST, "objects/#{object}/attributes", prepared_params, opts)
  new(response["data"] || response, opts)
end

.for_object(object, params = {}) ⇒ Object

List attributes for a specific object



259
260
261
# File 'lib/attio/resources/attribute.rb', line 259

def for_object(object, params = {}, **)
  list(params.merge(object: object), **)
end

.list(params = {}, **opts) ⇒ Object

Override list to handle object-specific attributes



236
237
238
239
240
241
242
243
244
245
246
# File 'lib/attio/resources/attribute.rb', line 236

def list(params = {}, **opts)
  if params[:object]
    object = params.delete(:object)
    validate_object_identifier!(object)

    response = execute_request(:GET, "objects/#{object}/attributes", params, opts)
    APIResource::ListObject.new(response, self, params.merge(object: object), opts)
  else
    raise ArgumentError, "Attributes must be listed for a specific object. Use Attribute.for_object(object_slug) or pass object: parameter"
  end
end

.prepare_params_for_create(params) ⇒ Object

Override create to handle validation and object parameter



191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/attio/resources/attribute.rb', line 191

def prepare_params_for_create(params)
  validate_type!(params[:type])
  validate_type_config!(params)

  # Generate api_slug from name if not provided
  api_slug = params[:api_slug] || params[:name].downcase.gsub(/[^a-z0-9]+/, "_")

  {
    data: {
      title: params[:name] || params[:title],
      api_slug: api_slug,
      type: params[:type],
      description: params[:description],
      is_required: params[:is_required] || false,
      is_unique: params[:is_unique] || false,
      is_multiselect: params[:is_multiselect] || false,
      default_value: params[:default_value],
      config: params[:config] || {}
    }.compact
  }
end

.prepare_params_for_update(params) ⇒ Object

Override update params preparation



214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/attio/resources/attribute.rb', line 214

def prepare_params_for_update(params)
  # Only certain fields can be updated
  updateable_fields = i[
    name
    title
    description
    is_required
    is_unique
    default_value
    options
  ]

  update_params = params.slice(*updateable_fields)
  update_params[:options] = prepare_options(update_params[:options]) if update_params[:options]

  # Wrap in data for API
  {
    data: update_params
  }
end

.resource_pathString

API endpoint path for attributes

Returns:

  • (String)

    The API path



53
54
55
# File 'lib/attio/resources/attribute.rb', line 53

def self.resource_path
  "attributes"
end

.retrieve(id, **opts) ⇒ Object

Override retrieve to handle object-scoped attributes



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/attio/resources/attribute.rb', line 153

def retrieve(id, **opts)
  # Extract simple ID if it's a nested hash
  attribute_id = Util::IdExtractor.extract_for_resource(id, :attribute)
  validate_id!(attribute_id)

  # For attributes, we need the object context - check if it's in the nested ID
  if id.is_a?(Hash) && id["object_id"]
    object_id = id["object_id"]
    response = execute_request(:GET, "objects/#{object_id}/attributes/#{attribute_id}", {}, opts)
  else
    # Fall back to regular attributes endpoint
    response = execute_request(:GET, "#{resource_path}/#{attribute_id}", {}, opts)
  end

  new(response["data"] || response, opts)
end

.update(id, params = {}, **opts) ⇒ Object

Override update to handle object-scoped attributes



171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/attio/resources/attribute.rb', line 171

def update(id, params = {}, **opts)
  # Extract simple ID if it's a nested hash
  attribute_id = Util::IdExtractor.extract_for_resource(id, :attribute)
  validate_id!(attribute_id)

  # For attributes, we need the object context
  if id.is_a?(Hash) && id["object_id"]
    object_id = id["object_id"]
    prepared_params = prepare_params_for_update(params)
    response = execute_request(:PATCH, "objects/#{object_id}/attributes/#{attribute_id}", prepared_params, opts)
  else
    # Fall back to regular attributes endpoint
    prepared_params = prepare_params_for_update(params)
    response = execute_request(:PATCH, "#{resource_path}/#{attribute_id}", prepared_params, opts)
  end

  new(response["data"] || response, opts)
end

Instance Method Details

#archive(**opts) ⇒ Object

Archive this attribute



81
82
83
84
85
86
87
# File 'lib/attio/resources/attribute.rb', line 81

def archive(**opts)
  raise InvalidRequestError, "Cannot archive an attribute without an ID" unless persisted?

  response = self.class.send(:execute_request, :POST, "#{resource_path}/archive", {}, opts)
  update_from(response[:data] || response)
  self
end

#archived?Boolean

Returns:

  • (Boolean)


98
99
100
# File 'lib/attio/resources/attribute.rb', line 98

def archived?
  @is_archived == true
end

#has_default?Boolean

Returns:

  • (Boolean)


110
111
112
# File 'lib/attio/resources/attribute.rb', line 110

def has_default?
  is_default_value_enabled == true
end

#required?Boolean

Returns:

  • (Boolean)


102
103
104
# File 'lib/attio/resources/attribute.rb', line 102

def required?
  is_required == true
end

#resource_pathObject



136
137
138
139
140
# File 'lib/attio/resources/attribute.rb', line 136

def resource_path
  raise InvalidRequestError, "Cannot generate path without an ID" unless persisted?
  attribute_id = Util::IdExtractor.extract_for_resource(id, :attribute)
  "#{self.class.resource_path}/#{attribute_id}"
end

#saveObject

Override save to handle nested ID



143
144
145
146
147
148
149
# File 'lib/attio/resources/attribute.rb', line 143

def save(**)
  raise InvalidRequestError, "Cannot save an attribute without an ID" unless persisted?
  return self unless changed?

  # Pass the full ID (including object context) to update method
  self.class.update(id, changed_attributes, **)
end

#to_hHash

Convert attribute to hash representation

Returns:

  • (Hash)

    Attribute data as a hash



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/attio/resources/attribute.rb', line 116

def to_h
  super.merge(
    api_slug: api_slug,
    name: name,
    description: description,
    type: type,
    is_required: is_required,
    is_unique: is_unique,
    is_default_value_enabled: is_default_value_enabled,
    default_value: default_value,
    options: options,
    object_id: attio_object_id,
    object_api_slug: object_api_slug,
    parent_object_id: parent_object_id,
    created_by_actor: created_by_actor,
    is_archived: is_archived,
    archived_at: archived_at&.iso8601
  ).compact
end

#unarchive(**opts) ⇒ Object

Unarchive this attribute



90
91
92
93
94
95
96
# File 'lib/attio/resources/attribute.rb', line 90

def unarchive(**opts)
  raise InvalidRequestError, "Cannot unarchive an attribute without an ID" unless persisted?

  response = self.class.send(:execute_request, :POST, "#{resource_path}/unarchive", {}, opts)
  update_from(response[:data] || response)
  self
end

#unique?Boolean

Returns:

  • (Boolean)


106
107
108
# File 'lib/attio/resources/attribute.rb', line 106

def unique?
  is_unique == true
end