class Attio::Note
Represents a note attached to a record in Attio
def self.resource_path
-
(String)
- The API path
def self.resource_path "notes" end
def content
def content case format when "plaintext" content_plaintext when "html", "markdown" content_markdown else content_plaintext end end
def create(**kwargs)
def create(**kwargs) # Extract options from kwargs opts = {} opts[:api_key] = kwargs.delete(:api_key) if kwargs.key?(:api_key) # Map object/record_id to parent_object/parent_record_id normalized_params = { parent_object: kwargs[:object] || kwargs[:parent_object], parent_record_id: kwargs[:record_id] || kwargs[:parent_record_id], title: kwargs[:title] || kwargs[:content] || "Note", content: kwargs[:content], format: kwargs[:format] } prepared_params = prepare_params_for_create(normalized_params) response = execute_request(:POST, resource_path, prepared_params, opts) new(response["data"] || response, opts) end
def destroy(**opts)
def destroy(**opts) raise InvalidRequestError, "Cannot destroy a note without an ID" unless persisted? note_id = id.is_a?(Hash) ? (id[:note_id] || id["note_id"]) : id self.class.delete(note_id, **opts) freeze true end
def for_record(params = {}, object:, record_id:, **)
def for_record(params = {}, object:, record_id:, **) list( params.merge( parent_object: object, parent_record_id: record_id ), ** ) end
def html?
def html? format == "html" end
def initialize(attributes = {}, opts = {})
def initialize(attributes = {}, opts = {}) super normalized_attrs = normalize_attributes(attributes) @parent_object = normalized_attrs[:parent_object] @parent_record_id = normalized_attrs[:parent_record_id] @title = normalized_attrs[:title] @content_plaintext = normalized_attrs[:content_plaintext] @content_markdown = normalized_attrs[:content_markdown] @tags = normalized_attrs[:tags] || [] @metadata = normalized_attrs[:metadata] || {} @format = normalized_attrs[:format] || "plaintext" @created_by_actor = normalized_attrs[:created_by_actor] end
def parent_record(**)
def parent_record(**) return nil unless parent_object && parent_record_id Internal::Record.retrieve( object: parent_object, record_id: parent_record_id, ** ) end
def plaintext?
def plaintext? format == "plaintext" end
def prepare_params_for_create(params)
def prepare_params_for_create(params) validate_parent!(params[:parent_object], params[:parent_record_id]) validate_content!(params[:content]) validate_format!(params[:format]) if params[:format] { data: { title: params[:title], parent_object: params[:parent_object], parent_record_id: params[:parent_record_id], content: params[:content], format: params[:format] || "plaintext" } } end
def resource_path
def resource_path raise InvalidRequestError, "Cannot generate path without an ID" unless persisted? note_id = id.is_a?(Hash) ? (id[:note_id] || id["note_id"]) : id "#{self.class.resource_path}/#{note_id}" end
def retrieve(id, **opts)
def retrieve(id, **opts) note_id = id.is_a?(Hash) ? (id[:note_id] || id["note_id"]) : id validate_id!(note_id) response = execute_request(:GET, "#{resource_path}/#{note_id}", {}, opts) new(response["data"] || response, opts) end
def save(*)
def save(*) raise NotImplementedError, "Notes cannot be updated. Create a new note instead." end
def strip_html(html)
def strip_html(html) return html unless html.is_a?(String) # Basic HTML stripping (production apps should use a proper HTML parser) html.gsub(/<[^>]+>/, " ") .gsub(/\s+/, " ") .strip end
def to_h
-
(Hash)
- Note data as a hash
def to_h super.merge( parent_object: parent_object, parent_record_id: parent_record_id, content: content, format: format, created_by_actor: created_by_actor, content_plaintext: content_plaintext ).compact end
def to_plaintext
def to_plaintext return content_plaintext if content_plaintext # If no plaintext, try to get markdown/html content and strip HTML html_content = content_markdown || content return nil unless html_content strip_html(html_content) end
def update(*)
def update(*) raise NotImplementedError, "Notes cannot be updated. Create a new note instead." end
def validate_content!(content)
def validate_content!(content) if content.nil? || content.to_s.strip.empty? raise ArgumentError, "content cannot be empty" end end
def validate_format!(format)
def validate_format!(format) valid_formats = %w[plaintext html] unless valid_formats.include?(format.to_s) raise ArgumentError, "Invalid format: #{format}. Valid formats: #{valid_formats.join(", ")}" end end
def validate_parent!(parent_object, parent_record_id)
def validate_parent!(parent_object, parent_record_id) if parent_object.nil? || parent_object.to_s.empty? raise ArgumentError, "parent_object is required" end if parent_record_id.nil? || parent_record_id.to_s.empty? raise ArgumentError, "parent_record_id is required" end end