Rails3中的JSON

Rails 3.2.12

to_json

#to_json是由gem ‘json’引入的,但是ActiveSupport重写了,和as_json联系起来

[Object, Array, FalseClass, Float,
 Hash, Integer, NilClass, String, TrueClass].each do |klass|
  klass.class_eval do
    def to_json(options = nil)
      ActiveSupport::JSON.encode(self, options)
    end
  end
end

ActiveSupport::JSON#encode

def encode(value, use_options = true)
  check_for_circular_references(value) do
    jsonified = use_options ? value.as_json(options_for(value)) : value.as_json
    jsonified.encode_json(self)
  end
end

#as_json

这个直接看api就知道了,http://api.rubyonrails.org/classes/ActiveModel/Serializers/JSON.html

render :json => @xxx

来看看render :json是如何实现的:

actionpack/lib/action_controller/metal/renderers

add :json do |json, options|
  json = json.to_json(options) unless json.kind_of?(String)
  json = "#{options[:callback]}(#{json})" unless options[:callback].blank?
  self.content_type ||= Mime::JSON
  json
end

可以看到就是调用了to_json,如果是String就直接返回,如果有callback就返回jsonp的格式

另外我们可以添加新的`renderer`:

ActionController::Renderers.add :csv do |obj, options|
  filename = options[:filename] || 'data'
  str = obj.respond_to?(:to_csv) ? obj.to_csv : obj.to_s
  send_data str, :type => Mime::CSV,
   :disposition => "attachment; filename=#{filename}.csv"
end

# 使用

render :csv => @csvable, :filename => @csvable.name

总结:尽量不要在rails3中重写to_json,如果确实需要自己构造json,重写as_json方法。

The InstanceMethods module inside ActiveSupport::Concern will be no longer included automatically

The InstanceMethods module inside ActiveSupport::Concern will be no longer included automatically. Please define instance methods directly in …

今天在一个Rails3.2的项目里发现了这个deprecated,去查看了一下源码,大家可以比较一下:

对比了,发现只是少了这么一句:

base.send :include, const_get("InstanceMethods")

不需要再定义InstanceMethods Module了,直接定义这些方法就行了。#Commit

old

module M
  extend ActiveSupport::Concern

  module ClassMethods
    ...
  end

  module InstanceMethods
    def some_instance_method
      ...
    end
  end
end

new

module M
  extend ActiveSupport::Concern

  module ClassMethods
    ...
  end
 
  # directly define method
  def some_instance_method
    ...
  end

end

Why?

ruby的include行为就是引入instance method,用InstanceMethods确实有点多此一举,不过我想老的版本引入InstanceMethods应该是为了和ClassMethods对应。