Как принять JSON через Rails API без "_трибутов" для вложенных полей
Я написал API с Rails и должен принимать некоторые вложенные_трибуты в вызовах API.
В настоящее время я отправляю данные через
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.
Кто-нибудь знает, как это сделать?
Ответы
Ответ 1
Вы можете использовать магию в своих сильных параметрах. На основе того, что вы хотите, вы, вероятно, имеете этот метод в своем контроллере:
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
, чтобы изменить имя.
Ответ 2
Я тоже искал способ избежать загрязнения моего RESTful API вложенными атрибутами cruft. Я думал, что поделюсь своим решением, поскольку он достаточно общий, чтобы быть полезным для тех, кто работает в одной и той же проблеме. Он начинается с простого модуля, который можно использовать с вашего контроллера:
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
Примечание. Синтаксис объявления вложенных атрибутов отражает то, что объявление допустимых параметров в вашем контроллере.
Здесь Gist для этого примера.
Я надеюсь, что кто-то найдет это полезным!