Module: AgentCode::HidableColumns

Extended by:
ActiveSupport::Concern
Included in:
AgentCodeModel
Defined in:
lib/agentcode/concerns/hidable_columns.rb

Overview

Column-level visibility control concern. Mirrors the Laravel HidableColumns trait.

Base hidden columns: password, remember_token, created_at, updated_at, deleted_at, discarded_at, email_verified_at

Usage: class User < ApplicationRecord include AgentCode::HidableColumns

agentcode_additional_hidden :secret_field, :internal_notes
end

Adding computed attributes to JSON responses: class Comment < AgentCode::AgentCodeModel def author_name user&.name || 'Anonymous' end

def agentcode_computed_attributes
  {
    'author_name' => author_name
  }
end
end

Policy-based hiding: class UserPolicy < AgentCode::ResourcePolicy def hidden_attributes_for_show(user) has_role?(user, 'admin') ? [] : ['email', 'phone'] end

def permitted_attributes_for_show(user)
  has_role?(user, 'admin') ? ['*'] : ['id', 'name', 'avatar']
end
end

Constant Summary collapse

BASE_HIDDEN_COLUMNS =
%w[
  password
  password_digest
  remember_token
  created_at
  updated_at
  deleted_at
  discarded_at
  email_verified_at
].freeze

Instance Method Summary collapse

Instance Method Details

#agentcode_computed_attributesHash

Override this method in your model to add computed/virtual attributes to the JSON response. These attributes are subject to policy-level blacklist (+hidden_attributes_for_show+) and whitelist (+permitted_attributes_for_show+) just like database columns.

Examples:

def agentcode_computed_attributes
  {
    'full_name' => "#{first_name} #{last_name}",
    'is_overdue' => due_date&.past?,
    'days_until_expiry' => expiry_date ? (expiry_date - Date.current).to_i : nil
  }
end

Returns:

  • (Hash)

    key-value pairs to merge into the JSON response



127
128
129
# File 'lib/agentcode/concerns/hidable_columns.rb', line 127

def agentcode_computed_attributes
  {}
end

#as_agentcode_jsonHash

Serialize to JSON excluding hidden columns and respecting policy whitelist.

The current user is resolved automatically from RequestStore. Policy filtering (blacklist + whitelist) is applied AFTER computed attributes are merged, so computed attributes are always subject to policy control.

Do NOT override this method. Override agentcode_computed_attributes instead to add computed/virtual attributes to the JSON response.

Returns:

  • (Hash)


87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/agentcode/concerns/hidable_columns.rb', line 87

def as_agentcode_json
  user = agentcode_current_user
  hidden = hidden_columns_for(user)
  result = as_json(except: hidden)

  # Merge computed attributes from model BEFORE applying policy filtering
  computed = agentcode_computed_attributes
  result.merge!(computed) if computed.is_a?(Hash) && computed.any?

  # Apply blacklist to the final hash (covers DB columns from as_json
  # overrides AND computed attributes from agentcode_computed_attributes)
  hidden_set = Set.new(hidden)
  result.reject! { |key, _| hidden_set.include?(key) }

  # Apply whitelist to the final hash (covers computed attributes too)
  permitted = policy_permitted_attributes(user)
  if permitted && permitted != ['*']
    permitted_set = Set.new(permitted.map(&:to_s))
    permitted_set.add('id') # id is always allowed
    result.select! { |key, _| permitted_set.include?(key) }
  end

  result
end

#hidden_columns_for(user = nil) ⇒ Array<String>

Get the list of columns to hide for the current user. Merges base + static + policy-defined hidden columns. Resolves the user from RequestStore automatically.

Returns:

  • (Array<String>)

    Column names to hide



69
70
71
72
73
74
75
# File 'lib/agentcode/concerns/hidable_columns.rb', line 69

def hidden_columns_for(user = nil)
  user ||= agentcode_current_user
  columns = BASE_HIDDEN_COLUMNS.dup
  columns.concat(additional_hidden_columns)
  columns.concat(policy_hidden_columns(user))
  columns.uniq
end