0

I have the following JSON:

{
   "ordernumber":"216300001000",
   "datecreated":"2016-11-08T14:23:06.631Z",
   "shippingmethod":"Delivery",
   ...
   "customer":{
      "firstname":"Victoria",
      "lastname":"Validator"
   },
   "products":[
      {
         "sku":"ABC1",
         "price":"9.99"
      },
      ...
   ]
}

With the corresponding Ruby classes including validators:

class Task
  include ActiveModel::Model
  include ActiveModel::Serializers::JSON

  validates ..., presence: true
  ...
end

class Product
  include ActiveModel::Model
  include ActiveModel::Serializers::JSON

  validates ..., presence: true
  ...
end

class Customer
  include ActiveModel::Model
  include ActiveModel::Serializers::JSON

  validates ..., presence: true
  ...
end

What I want to do is serialise the JSON to a Ruby class. The problem is that the Task class get's initialised correctly. But the nested classes like Customer and Product remain hashes. (A Task has one Customer and multiple Products)

Example:

json = %Q{{ "ordernumber":"216300001000", "datecreated":"2016-11-08T14:23:06.631Z", "shippingmethod":"Delivery", "customer":{ "firstname":"Victoria", "lastname":"Validator" }, "products":[ { "sku":"ABC1", "price":"9.99" } ] }}

task = Task.new()
task.from_json(json)

task.class
# => Task

task.products[0].class
# => Hash

How do I do this using ActiveModel and also validate the nested JSON? (I'm not using Rails)

narzero
  • 2,199
  • 5
  • 40
  • 73
  • Are you intending to use [nested attributes](http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html)? – tadman Sep 28 '17 at 22:51

2 Answers2

1

As far as I know, ActiveModel::Model brings validations and other handy stuff, but it does not bring tools to handle association problems like this one. You have to implement his behavior yourself.

First of all, I'd use the builtin initialization system that ActiveModel::Model provides. Then I'd define products= and customer= to take the attributes and initialize instances of the proper classes. And call the validations of the associated records.

class Task
  include ActiveModel::Model

  attr_reader :products, :customer

  # ...

  validate :associated_records_are_valid

  def products=(ary)
    @products = ary.map(&Product.method(:new))
  end

  def customer=(attrs)
    @customer = Customer.new(attrs)
  end

  private

  def associated_records_are_valid
    products.all?(&:valid?) && customer.valid?
  end
end

attributes = JSON.parse(json_str)
task = Task.new(attributes)
ichigolas
  • 7,595
  • 27
  • 50
0

Look at this topic: Is it possible to convert a JSON string to an object?. I am not in front of a computer right now to post a code, but I think that answer solves your problem.