嵌套和递归JSON输入处理

时间:2013-07-19 19:57:24

标签: ruby-on-rails rest

我正在使用rails构建REST API,并且我有一些接受嵌套和递归JSON的控制器,例如,在/taxonomies/:id.json上执行PUT时,您可以传递类似的内容:

{
  "names":[
    "brands",
    "secondary_brands"
  ],
  "taxonomy_data":{
    "some":"data"
  },
  "terms":[
    {
      "slug":"apple",
      "data":{
        "value":"Apple California"
      },
      "overridable_data":{
        "weight":0.5
      },
      "term_data":{
        "description":{
          "en":"Apple makes the iPhone"
        }
      }
    },
    {
      "slug":"microsoft",
      "data":{
        "value":"Microsoft Inc"
      },
      "overridable_data":{
        "weight":0.5
      },
      "term_data":{
        "description":{
          "en":"Microsoft makes windows"
        }
      },
      "children":[
        {
          "data":{
            "value":"Xbox"
          },
          "overridable_data":{
            "weight":0.5
          },
          "term_data":{
            "description":{
              "en":"Xbox one is bad"
            }
          }
        }
      ]
    },
    {
      "slug":"hp",
      "data":{
        "value":"HP Inc"
      },
      "overridable_data":{
        "weight":0.5
      },
      "term_data":{
        "description":{
          "en":"HP makes atomic clocks"
        }
      }
    }
  ]
}

现在,我在我的模型中添加了以下代码:

class Taxonomy < ActiveRecord::Base

  has_many                            :terms,
                                      -> {order(:id)}


  def update_terms(params)

    existing_term_ids = terms.map &:id

    create_term = lambda do |term_params, parent=nil|
      t = terms.find_by(:id => term_params[:id]) if term_params[:id]
      t ||= terms.build
      t.attributes = term_params.slice(:slug, :data, :overridable_data, :term_data)
      t.parent = parent
      t.save
      existing_term_ids.delete(t.id)

      if term_params.has_key?(:children)
        term_params[:children].each do |child_params|
          create_term.call(child_params, t)
        end
      end

    end

    params.each do |term_params|
      create_term.call(term_params)
    end

    terms.where(:id => existing_term_ids).destroy_all
    save
  end
end

此版本(快速写入测试轨道4)使用切片来过滤参数,因为attr_accessible已消失。

这让我想知道这种代码是应该在模型中还是在控制器中。

1 个答案:

答案 0 :(得分:1)

阅读这篇文章:http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/

我的意见是,你应该在这种情况下提供服务,例如:

# app/services/recursive_update.rb
class RecursiveUpdate
  def initalize(source)
    @source = source
  end

  def update(params)
    # your code here
  end

  def create_term(term_params, parent=nil)
    #....
  end

  def permitted_params
    #....
  end

  def save
    @source.save
  end
end

在控制器中:

updater = RecurciveUpdate.new @model
updater.update params
update.save