Решение
Подход DRY находится внутри ваших моделей, вы можете определить метод attributes
и вернуть ему форму объекта, которую вы хотите использовать функцией рендеринга.
# thing.rb
def attributes
# Return the shape of the object
# You can use symbols if you like instead of string keys
{
'id' => id, # id of the current thing
'other_fields' => other_fields, # add other fields you want in the serialized result
'object_a' => object_a, # explicitly add the associations
'object_b' => object_b
}
end
Ассоциации object_a
и object_b
должны быть сериализованы как обычно. Вы можете повторить тот же подход для них, добавив метод attributes
в их соответствующие классы, если вы хотите ограничить / настроить их сериализованный результат.
То есть, когда render json:
вызывается для одного или коллекции из этой (ой) модели (ов) вещей, форма возвращаемых объектов json будет такой, как определено в методе выше.
Примечание:
Одно предостережение - ваши ключевые имена в ха sh, возвращаемое в attributes
, должно соответствовать названию метода (или имени ассоциации). Я не слишком уверен, почему. Но обходной путь, который я использовал, когда мне нужно было добавить ключ с именем, отличным от соответствующего столбца, - это создать метод в модели имени ключа, который я хочу использовать.
Например, скажем, ваш Модель Thing
имеет столбец name
, но в результате json вы хотите, чтобы имя ключа, соответствующее этому столбцу, было названо name_of_thing
. Вы должны сделать следующее:
def name_of_thing
name
end
def attributes
{
'name_of_thing' => name_of_thing,
# other fields follow
# ...
}
end
Условные логики c
Условия, зависящие от полей / ассоциаций в модели
Метод attributes
может поддерживать условные на основе полей в модели.
# thing.rb
def attributes
result = {}
result['id'] = id
# add other fields
# For example, if association to object_a exists
if object_a
result.merge!({
'object_a' => object_a
})
end
# return result
result
end
Условия, зависящие от ввода извне модели
Если вы хотите, чтобы ваш метод отображал разные поля в разных местах, вы можете переопределить метод as_json
, который может работать лучше в этих случаях, потому что этот метод принимает параметры в параметре.
# thing.rb
def as_json(options = {})
result = {}
result['id'] = id
# add other fields to result
if(options[:show_only_ids])
result.merge!({
'object_a_id' => object_a_id,
'object_b_id' => object_b_id
})
else
result.merge!({
'object_a' => object_a,
'object_b' => object_b
})
end
# return result
result
end
Затем вам нужно изменить контроллер (или везде, где вы вызываете сериализацию модели Thing
) для передачи в соответствующем параметре при необходимости.
# thing_controller.rb
render json: Thing.all.as_json({ show_only_ids: true })
При рендеринге не всегда нужно явно указывать as_json
. Функция рендера будет вызывать его в любом случае по умолчанию. Вам нужно явно сделать этот вызов, когда вы хотите передать параметры.