paulelliott / fabrication-site

This project has moved to GitLab! Please check there for the latest updates.
https://gitlab.com/fabrication-gem/docsite
17 stars 14 forks source link

attributes_for doesn't work with complex objects (2.5.0) #8

Closed Darkvater closed 11 years ago

Darkvater commented 11 years ago

When I use attributes_for for a complex object, the complex object is not converted to a hash. For example:

class Order
  attr_accessor productType
  attr_accessor quoteRef
  attr_accessor allocations
  attr_accessor marketPrice
end

class Allocation
  attr_accessor account
  attr_accessor notionalAmount
end

class MarketPrice
  attr_accessor id
  attr_accessor prices
end

Fabricator :order do
  productType "Product"
  quoteRef ""
  allocations(count: 1, fabricator: :allocation)
  marketPrice(fabricator: :market_price)
end

Fabricator :allocation do
  account "10009-1"
  notionalAmount 500000.0
end

Fabricator :market_price do |f|
  f.id ""
  prices [85.7]
end
Fabricator.attributes_for(:order_do, :quoteRef=> 'olalala') = Hash (4 element(s))
  productType -> Product
  quoteRef -> olalala
  allocations = Array(1 element(s))
    [0] = {Allocation} #<Allocation:0x1140ecf2>
  marketPrice_id' ->

It is a bit annoying. Separately, I cannot use the word 'id' as an attribute, code in definition.rb:127 if value && value.respond_to?(:id) hardcodes the :id symbol and the object doesn't get parsed any further.

P.S. I am using fabricator 2.5.0, as 2.5.1 doesn't work. manager.rb [](name) tries to do a name.try(:to_sym) on a symbol, but name is already a symbol and doesn't have the try method... at least in my jruby 1.7

Darkvater commented 11 years ago

I have fixed it locally by implementing a to_hash method in my own code. Obviously it should be different in Fabricator taking into account the Active thingie. Is there any reason that :id is reserved for to_hash in Fabricator?

      def to_hash(object)
        return object.collect { |element| to_hash(element) } if object.is_a?(Array)
        return object if object.instance_variables.empty?

        { }.tap do |hash|
          object.instance_variables.each { |var|
            hash[var.to_s.delete('@')] = to_hash(object.instance_variable_get(var))
          }
        end
      end
paulelliott commented 11 years ago

Thanks for bringing this up. I have wanted to rearchitect the hashing implementation for a while but it hasn't caused me any pain so I have been putting it off. I am working on it now and hope to have something out in the next week or so.

FYI, this is the github project for http://fabricationgem.org, not the gem itself. Please open issues for the gem in the gem's project: https://github.com/paulelliott/fabrication.

paulelliott commented 11 years ago

What are you ultimately wanting to do with these attributes once fabrication gives them to you?

Darkvater commented 11 years ago

We use these attributes to send them as json-data to the server for further processing. As we use cucumber for our testing all these objects are preset with default values which you can override with test-specific data. The 'complicated' object layout represents our pojo that will be deserialised to a Java object.