Module: Rhino::HidableColumns
- Extended by:
- ActiveSupport::Concern
- Included in:
- RhinoModel
- Defined in:
- lib/rhino/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 Rhino::HidableColumns
rhino_additional_hidden :secret_field, :internal_notes
end
Adding computed attributes to JSON responses:
class Comment < Rhino::RhinoModel
def
user&.name || 'Anonymous'
end
def rhino_computed_attributes
{
'author_name' =>
}
end
end
Policy-based hiding:
class UserPolicy < Rhino::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
-
#as_rhino_json(computed_attributes: []) ⇒ Hash
Serialize to JSON excluding hidden columns and respecting policy whitelist.
-
#hidden_columns_for(user = nil) ⇒ Array<String>
Get the list of columns to hide for the current user.
-
#rhino_computed_attributes ⇒ Hash
Override this method in your model to add computed/virtual attributes to the JSON response.
-
#rhino_record_computed_attributes ⇒ Hash{String => #call}
Override this method to declare OPT-IN record-level computed attributes.
Instance Method Details
#as_rhino_json(computed_attributes: []) ⇒ Hash
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 rhino_computed_attributes instead
to add computed/virtual attributes to the JSON response.
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/rhino/concerns/hidable_columns.rb', line 112 def as_rhino_json(computed_attributes: []) user = rhino_current_user hidden = hidden_columns_for(user) result = as_json(except: hidden) # Merge computed attributes from model BEFORE applying policy filtering computed = rhino_computed_attributes result.merge!(computed) if computed.is_a?(Hash) && computed.any? # Merge the OPT-IN record-level computed attributes the client selected via # ?computed_attributes=. Nothing here is evaluated unless it was asked for # by name, so declaring an expensive attribute costs nothing on requests # that don't want it. Merged before policy filtering, so the blacklist and # whitelist below still govern them. result.merge!(rhino_resolve_record_computed_attributes(computed_attributes, user)) # Apply blacklist to the final hash (covers DB columns from as_json # overrides AND computed attributes from rhino_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 # The route key column is always allowed too — responses must stay # routable even when a policy whitelist omits it. route_key = self.class.try(:rhino_resolved_route_key) permitted_set.add(route_key.to_s) if route_key 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.
94 95 96 97 98 99 100 |
# File 'lib/rhino/concerns/hidable_columns.rb', line 94 def hidden_columns_for(user = nil) user ||= rhino_current_user columns = BASE_HIDDEN_COLUMNS.dup columns.concat(additional_hidden_columns) columns.concat(policy_hidden_columns(user)) columns.uniq end |
#rhino_computed_attributes ⇒ Hash
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.
163 164 165 |
# File 'lib/rhino/concerns/hidable_columns.rb', line 163 def rhino_computed_attributes {} end |
#rhino_record_computed_attributes ⇒ Hash{String => #call}
Override this method to declare OPT-IN record-level computed attributes.
Unlike rhino_computed_attributes, nothing here is evaluated unless the
client names it in ?computed_attributes=a,b on index/show/trashed
— so expensive per-row work is only paid for when it is actually wanted.
Return a hash of attribute name => callable. The callable may accept zero, one (record) or two (record, user) arguments.
185 186 187 |
# File 'lib/rhino/concerns/hidable_columns.rb', line 185 def rhino_record_computed_attributes {} end |