stefankroes / ancestry

Organise ActiveRecord model into a tree structure
MIT License
3.72k stars 459 forks source link

Serialization options to include/except attributes with arrange_serializable #213

Open ArTiSTiX opened 9 years ago

ArTiSTiX commented 9 years ago

I'm currently having some difficulties with arrange_serializable. I eager load some of relations of the hierarchical model... but there seems to be no options to add those fields in serialization...

I'm doing:

MyModel.first.subtree.select(:id,:ancestry,:user_id).includes(:user).arrange_serializable

But user relation is not serialized. I expect something like:

{
  "id": 1, "ancestry": null, "user_id": 1,
  "user": {"id": 34, "name": "John Doe"},
  "children": [
    {
      "id": 2, "ancestry": "1", "user_id": 2,
      "user": {"id": 32, "name": "Chuck Norris"},
      "children": []
    },
    {
      "id": 4, "ancestry": "1", "user_id": 2,
      "user": {"id": 32, "name": "Chuck Norris"},
      "children": []
    }
  ]
}

Any practice to do this with arrange_serializable ?

rikkipitt commented 9 years ago

Hi @ArTiSTiX I'm looking to do something like this too. I normally use https://github.com/rails-api/active_model_serializers with my usual controllers etc, but I'm not yet sure how to integrate these two gems yet...

Can anyone suggest a way to do this?

Cheers,

Rikki

mastfish commented 9 years ago

I've just run into this too - my solution was:

# On the model
  def self.arrange_custom_serializable options={}, nodes=nil, &block
    nodes = arrange(options) if nodes.nil?
    nodes.map do |parent, children|
      yield parent, arrange_custom_serializable(options, children, &block)
    end
  end

On the controller

data = item.subtree.arrange_custom_serializable do |parent, children|
    ModelSerializer.new(parent, children: children)
 end

Inside the serializer

attributes :children
def children
    return @options[:children]
end

This gives a nice serializer tree with the a root node of item. It wouldn't be difficult to turn this into a PR if there's interest?

stefankroes commented 9 years ago

I don't think Ancestry should be concerned with serialization. If you want to arrange but have access to full models with eager loaded associations, why not use regular #arrange?

mastfish commented 9 years ago

I agree completely with having ancestry not handle serialization; I'm suggesting accepting a block in #arrange_serialization(which already exists, but isn't very easy to use). This would offload serialization concerns onto users, allowing them to use whichever option they prefer.

Something like:

def arrange_serializable options={}, nodes=nil, &block
      nodes = arrange(options) if nodes.nil?
      nodes.map do |parent, children|
        if block_provided?
          yield parent, arrange_serializable(options, children, &block)
       else
          parent.serializable_hash.merge 'children' => arrange_serializable(options, children)
       end
     end
end
stefankroes commented 9 years ago

Great idea! Thx for the explanation. If you provide a pull request with tests and docs I'll merge it.