2011-07-31 24 views
48

比方說,我有一個應用程序處理TODO列表。該清單已完成並未完成項目。現在我想將兩個虛擬屬性添加到列表對象;列表中已完成和未完成項目的計數。我也需要這些顯示在json輸出中。將虛擬屬性添加到json輸出

我有兩種方法在我的模型,獲取了毛坯件/成品項目:

def unfinished_items 
    self.items.where("status = ?", false) 
end 

def finished_items 
    self.items.where("status = ?", true) 
end 

所以,我怎樣才能得到我的JSON輸出這兩種方法的計數?

我使用Rails 3.1

+0

:也許你需要做的就是添加一個attr_reader:finished_items? – mkro

回答

95

對象的序列化Rails有兩個步驟:

  • 首先,as_json被稱爲對象轉換爲一個簡單的哈希值。
  • 然後,在as_json返回值上調用to_json以獲取最終的JSON字符串。

通常你想獨自離開to_json因此,所有你需要做的就是添加your own as_json implementation排序是這樣的:

def as_json(options = { }) 
    # just in case someone says as_json(nil) and bypasses 
    # our default... 
    super((options || { }).merge({ 
     :methods => [:finished_items, :unfinished_items] 
    })) 
end 

你也可以做這樣的:

def as_json(options = { }) 
    h = super(options) 
    h[:finished] = finished_items 
    h[:unfinished] = unfinished_items 
    h 
end 

如果您想爲方法支持的值使用不同的名稱。

如果你關心XML和JSON,看看serializable_hash

+3

我得到了這個錯誤的頂部: 未定義的方法'合併'爲零:NilClass 所以我用'(options || {})。merge'替換'options.merge'。 – Turadg

+0

@Turadg:除非有人在某處傳遞一個明確的'nil',否則第一個應該由於默認的'options = {}'而工作,爲了安全起見,我會補充額外的偏執狂。對不起,您的評論在日常混亂中迷失了,所以我有點遲到回到你身邊。 –

13

另一種方式做,這是添加到您的模型:

def attributes 
    super.merge({'unfinished' => unfinished_items, 'finished' => finished_items}) 
end 

這也將自動爲XML序列化工作。 http://api.rubyonrails.org/classes/ActiveModel/Serialization.html 但請注意,您可能希望使用字符串作爲鍵,因爲當在軌道3中對鍵進行排序時,該方法無法處理符號。但它並未在軌道4中排序,因此應該不再有問題了。

22

使用Rails 4,你可以做以下 -

render json: @my_object.to_json(:methods => [:finished_items, :unfinished_items]) 

希望這有助於別人誰是後來的/最新版本

+0

thx,這是一個非常酷的捷徑,特別是對於與BSON ObjectIds結合使用的javascript響應。 – RunsnbunsN

0

我只是想我會像我這樣的人提供這個答案,誰試圖此集成到現有as_json塊:

def as_json(options={}) 
    super(:only => [:id, :longitude, :latitude], 
      :include => { 
      :users => {:only => [:id]} 
      } 
    ).merge({:premium => premium?}) 

只是粘性.merge({})到你的super()

2

剛剛結束關閉所有的數據的爲一個哈希,像

render json: {items: items, finished: finished, unfinished: unfinished}

0

這樣做,而不必做一些醜陋overridings。如果你有一個模型List例如,你可以把這個在你的控制器:

render json: list.attributes.merge({ 
             finished_items: list.finished_items, 
             unfinished_items: list.unfinished_items 
            }) 
0

上面列出Aswin:methods將使你返回一個特定的模型的方法/函數作爲一個JSON屬性,如果你有複雜assosiations這將這樣的伎倆,因爲這將函數添加到現有的模型/ assossiations:D,將工作就像一個魅力,如果你不想重新定義as_json

檢查這個代碼,並請注意如何我使用:methods以及:include [N +查詢甚至不是一個選項;]]

render json: @YOUR_MODEL.to_json(:methods => [:method_1, :method_2], :include => [:company, :surveys, :customer => {:include => [:user]}])

Overwritting as_json功能將在此情況下(特別是因爲你必須手動添加:include assossiations方式更難:我還沒有嘗試過這種/ def as_json(options = { }) end