cortex-cms/cortex

View on GitHub
app/models/cortex/content_item.rb

Summary

Maintainability
A
0 mins
Test Coverage
module Cortex
  class ContentItem < Cortex::ApplicationRecord
    include ActiveModel::Transitions

    include Cortex::SearchableContentItem
    include Cortex::BelongsToTenant

    scope :last_updated_at, -> { order(updated_at: :desc).select('updated_at').first.updated_at }

    belongs_to :creator, class_name: 'User'
    belongs_to :updated_by, class_name: 'User', optional: true
    belongs_to :content_type
    has_many :field_items, dependent: :destroy, autosave: true

    accepts_nested_attributes_for :field_items

    default_scope { order(created_at: :desc) }

    validates :creator, :content_type, presence: true

    state_machine do
      state :draft
      state :scheduled

      event :schedule do
        transitions :to => :scheduled, :from => [:draft]
      end

      event :draft do
        transitions :to => :draft, :from => [:scheduled]
      end
    end

    def publish_state
      GetPublishStateTransaction.new.call(self).value!
    end

    # FieldItem and State Convenience Methods. TODO: move to concern? transactions?
    def method_missing(method_name, *arguments, &block)
      super unless dynamic_method?(method_name)

      if dynamic_state_check?(method_name)
        # Used to check state - allows for methods such as #published? and #expired?
        # Will return true if the active_state corresponds to the name of the method
        "#{publish_state.downcase}?" == method_name.to_s
      else
        # Used to query for any field on the relevant ContentType and return data from the content_item
        field_items.find { |field_item| field_item.field.name.parameterize(separator: '_') == method_name.to_s }.data.values.first
      end
    end

    def respond_to_missing?(method_name, include_private = false)
      dynamic_method?(method_name) || super
    end

    private

    def dynamic_method?(method_name)
      dynamic_state_check?(method_name) || has_field_item?(method_name)
    end

    def dynamic_state_check?(method_name)
      method_name.to_s.include? '?'
    end

    # TODO: this logic effectively gets called multiple times (slow?) - how do we optimize or cache the result?
    def has_field_item?(method_name)
      field_items.any? { |field_item| field_item.field.name.parameterize(separator: '_') == method_name.to_s }
    end
  end
end