DmitryTsepelev / store_model

Work with JSON-backed attributes as ActiveRecord-ish models
MIT License
1.06k stars 85 forks source link

Assignment Doesn't work in OneOf case #123

Closed fameoflight closed 2 years ago

fameoflight commented 2 years ago
      pp task_page_element.data

     task_page_element.data.title = 'Updated Task'

      pp task_page_element.data

      task_page_element.save!

      task_page_element.reload

      pp task_page_element.data

Here is the output

#<WorkflowLibrary::PageElementTask kind: task, status: pending, title: nil>
#<WorkflowLibrary::PageElementTask kind: task, status: pending, title: Updated Task>
#<WorkflowLibrary::PageElementTask kind: task, status: pending, title: nil>

Here is the code in my model 

  OneOfPageElement = StoreModel.one_of do |json|
    kind = json[:kind]

    if kind.nil?
      PageElementAbstract
    else
      "WorkflowLibrary::PageElement#{kind.camelize}".constantize
    end
  end

And

    enumerize :kind, in: %i[text task], default: 'text'

    attribute :data, OneOfPageElement.to_type

    validates :data, store_model: { merge_errors: true }

    before_validation :set_data_defaults, on: :create

    def set_data_defaults
      self.data = { kind: kind } if data.kind.nil?

      data.title = 'New Task' if data.kind == 'task'
    end
fameoflight commented 2 years ago

Would appreciate any help of what I might be doing wrong

fameoflight commented 2 years ago

after little more investigation, it seems like this code remove unknown attributes

      def handle_unknown_attribute(value, exception)
        attribute = exception.attribute.to_sym
        value_symbolized = value.symbolize_keys
        value_symbolized = value_symbolized[:attributes] if value_symbolized.key?(:attributes)

        cast_value(value_symbolized.except(attribute)).tap do |configuration|
          configuration.unknown_attributes[attribute.to_s] = value_symbolized[attribute]
        end
      end

which seems pretty dangerous

DmitryTsepelev commented 2 years ago

Hi! Unknown attributes are stored in the separate place and can be acessed via #unknown_attributes (per doc). I guess you need to make sure that all possible values of OneOf have that title attribute.