Class: TypedEAV::Field::File
- Inherits:
-
Base
- Object
- ActiveRecord::Base
- ApplicationRecord
- Base
- TypedEAV::Field::File
- Defined in:
- app/models/typed_eav/field/file.rb
Overview
Active Storage-backed field type for non-image file attachments. Stores the attached blob’s ‘signed_id` (a String) in `string_value`. Same shape as Field::Image — see image.rb for the full soft-detect rationale, signed_id storage choice, and option semantics.
## Image vs File
Both classes share the same shared ‘:attachment` has_one_attached association on TypedEAV::Value (declared once in engine.rb’s config.after_initialize block; see RESEARCH §Risk 3 for the rationale against per-class associations). The semantic distinction at runtime is ‘value.field.is_a?(TypedEAV::Field::Image)` vs `is_a?(File)`. The blob’s content_type is the source of truth for image-vs-other-file.
The on_image_attached hook (Phase 05) fires ONLY for Field::Image —File has no parallel hook by ROADMAP design. Apps that need a generic file-attached signal use on_value_change (Phase 03) or subscribe to ActiveSupport::Notifications directly.
## Namespace shadowing note
‘TypedEAV::Field::File` shadows Ruby’s top-level ‘::File` constant inside the TypedEAV::Field namespace. Internal code that needs the Ruby File class (none in this file) must reference it as `::File` to avoid ambiguity. This is intentional and matches the gem’s one-class-per-file STI convention; renaming to FileAttachment would diverge from Image (also a single-word noun).
Constant Summary
Constants inherited from Base
Constants included from ColumnMapping
ColumnMapping::DEFAULT_OPERATORS_BY_COLUMN, ColumnMapping::FALLBACK_OPERATORS
Instance Method Summary collapse
-
#cast(raw) ⇒ Object
See TypedEAV::Field::Image#cast for the full contract — File’s cast is identical except for the NotImplementedError message.
-
#validate_typed_value(record, val) ⇒ Object
See TypedEAV::Field::Image#validate_typed_value for the full contract — File’s validation is identical (it accepts the same allowed_content_types / max_size_bytes options).
Methods inherited from Base
#allowed_option_values, #apply_default_to, #array_field?, #backfill_default!, #clear_option_cache!, #default_value, #default_value=, export_schema, #field_type_name, import_schema, #insert_at, #move_higher, #move_lower, #move_to_bottom, #move_to_top, #optionable?, #read_value, #storage_contract, storage_contract_class, #write_value
Instance Method Details
#cast(raw) ⇒ Object
See TypedEAV::Field::Image#cast for the full contract — File’s cast is identical except for the NotImplementedError message.
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'app/models/typed_eav/field/file.rb', line 41 def cast(raw) unless defined?(::ActiveStorage::Blob) raise NotImplementedError, "TypedEAV::Field::File requires Active Storage. " \ "Add `gem 'activestorage'` to your Gemfile (already " \ "included via the `rails` meta-gem in Rails 7.1+) and " \ "run `bin/rails active_storage:install`." end return [nil, false] if raw.nil? || (raw.respond_to?(:empty?) && raw.empty?) return [raw.signed_id, false] if raw.is_a?(::ActiveStorage::Blob) return [raw, false] if raw.is_a?(String) [nil, true] end |
#validate_typed_value(record, val) ⇒ Object
See TypedEAV::Field::Image#validate_typed_value for the full contract — File’s validation is identical (it accepts the same allowed_content_types / max_size_bytes options). Apps that want image-only mime restrictions configure ‘allowed_content_types: [“image/*”]`; otherwise the field is a general-purpose attachment slot.
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
# File 'app/models/typed_eav/field/file.rb', line 63 def validate_typed_value(record, val) return if val.nil? return unless defined?(::ActiveStorage::Blob) blob = ::ActiveStorage::Blob.find_signed(val) if blob.nil? record.errors.add(:value, :invalid) return end if allowed_content_types.present? && !content_type_matches?(blob.content_type) record.errors.add( :value, "must be one of #{Array(allowed_content_types).join(", ")}", ) end return unless max_size_bytes.present? && blob.byte_size > max_size_bytes.to_i record.errors.add(:value, "exceeds max size #{max_size_bytes} bytes") end |