2014-12-02 32 views
17

我已經使用Rails編寫了一個API,並且需要接受API調用中的一些nested_attributes。如何通過Rails API接受沒有嵌套字段的「_attributes」的JSON

目前我通過

PATCH /api/v1/vintages/1.json發送數據

{ 
    "vintage": { 
    "year": 2014, 
    "name": "Some name", 
    "foo": "bar", 
    "sizes_attributes": [ 
     { 
     "name": "large", 
     "quantity": "12" 
     }, 
     { 
     "name": "medium", 
     "quantity": "2" 
     } 
    ] 
    } 
} 

不過,我想執行以下操作:

PATCH /api/v1/vintages/1.json

{ 
    "vintage": { 
    "year": 2014, 
    "name": "Some name", 
    "foo": "bar", 
    "sizes": [ 
     { 
     "name": "large", 
     "quantity": "12" 
     }, 
     { 
     "name": "medium", 
     "quantity": "2" 
     } 
    ] 
    } 
} 

區別是屬性是領域的關鍵的一部分。我希望能夠accept_nested_attributes_for :sizes而不必使用_attributes成爲JSON對象的一部分。

任何人都知道如何管理這個?

+0

好吧,它會是hackish,但不能只是做一些'params [:vintage] [:sizes_attributes] = params [:vintage] [:sizes]'來重新命名它們。 – Doon 2014-12-05 19:28:31

回答

22

您可以在強參數方法中自由執行一些魔術。根據你想要什麼,你可能在你的控制器,這個方法:

def vintage_params 
    params.require(:vintage).permit(:year, :name, :foo, { sizes: [:name, :quantity] }) 
end 

所有你需要做的是調整該方法中的sizes鍵的名稱。我建議:

def vintage_params 
    vintage_params = params.require(:vintage).permit(:year, :name, :foo, { sizes: [:name, :quantity] }) 
    vintage_params[:sizes_attributes] = vintage_params.delete :sizes 
    vintage_params.permit! 
end 

這將刪除:sizes鍵,把它的預期:sizes_attributes沒有搞亂你漂亮的JSON。沒有什麼可以直接用accepts_nested_attributes_for更改名稱。

+3

「您無法直接使用accept_nested_attributes_for來更改名稱。」這是正確和不幸的。我有這個相同的問題。 – lightswitch05 2014-12-10 15:33:33

+0

它不適合我。參數正確地重命名,但是當我嘗試執行'Model.new(params)'時,我得到'ActiveModel :: ForbiddenAttributesError'。在將屬性分配給模型實例之前,它看起來有一些額外的檢查。 – jmarceli 2016-01-08 15:14:48

+0

您可能需要將'vintage_params.permit!'作爲Rails 4.2及更高版本的最後一行。 – ptd 2016-01-08 20:55:30

5

我也在尋找一種避免使用嵌套屬性cruft污染我的RESTful API的方法。我想我會分享我的解決方案,因爲它對於遇到同樣問題的任何人都是有用的。它從一個簡單的模塊,從你的控制器被利用:

module PrettyApi 
    class << self 
    def with_nested_attributes(params, attrs) 
     return if params.blank? 

     case attrs 
     when Hash 
     with_nested_hash_attributes(params, attrs) 
     when Array 
     with_nested_array_attributes(params, attrs) 
     when String, Symbol 
     unless params[attrs].blank? 
      params["#{attrs}_attributes"] = params.delete attrs 
     end 
     end 
     params 
    end 

    private 

    def with_nested_hash_attributes(params, attrs) 
     attrs.each do |k, v| 
     with_nested_attributes params[k], v 
     with_nested_attributes params, k 
     end 
    end 

    def with_nested_array_attributes(params, attrs) 
     params.each do |np| 
     attrs.each do |v| 
      with_nested_attributes np, v 
     end 
     end 
    end 
    end 
end 

這裏是在控制器中使用這個模塊的一個例子,用於從移動客戶端上傳通訊簿:

class V1::AddressBooksController < V1::BaseController 
    def create 
    @address_book = AddressBook.new address_book_params 
    unless @address_book.save 
     errors = @address_book.errors.to_hash(true) 
     render status: 422, json: { errors: errors } 
    end 
    end 

    private 

    def address_book_params 
    PrettyApi.with_nested_attributes pretty_address_book_params, 
             contacts: [:emails, :phones, :addresses] 
    end 

    def pretty_address_book_params 
    params.permit(
     :device_install_id, 
     contacts: [ 
     :local_id, 
     :first_name, 
     :last_name, 
     :nickname, 
     emails: [ 
      :value, 
      :type 
     ], 
     phones: [ 
      :value, 
      :type 
     ], 
     addresses: [ 
      :type, 
      :street_address, 
      :city, 
      :state, 
      :postal_code, 
      :country 
     ] 
     ] 
    ) 
    end 
end 

注,聲明嵌套屬性的語法反映了在控制器中聲明允許的參數的語法。

Here's the Gist for this example.

我希望有人認爲這很有幫助!

+0

爲我工作,謝謝。希望你已經提出了一些指示,因爲它不是自明的,它是如何工作的。 – Snowman 2016-11-27 23:52:06

相關問題