1

Примем следующие соотношения:Как высушить Rails/ActiveRecord при использовании as_json?

Blog HAS_MANY Posts has_many Comments has_one Author

Если я хочу, чтобы получить все Blogs со всеми Posts, я мог бы написать:

Blog.all.as_json(:include => :posts) 

Однако это приведет к N + 1 запрос.

Поэтому вместо того, мне нужно написать:

Blog.includes(:posts).all.as_json(:include => :posts) 

Который работает, как ожидалось, но не очень DRY, особенно если у вас есть вложенные включает.

Например:

Blog.includes(
    :posts => { 
     :comments => :author 
    } 
).all.as_json(
    :include => { 
     :posts => { 
      :include => { 
       :comments => { 
        :include => :author 
       } 
      } 
     } 
    } 
) 

Эта проблема становится еще хуже, когда мне нужно запросить для этого же формата JSON в нескольких местах.

Я думал о вводе формата as_json отношений в методе класса, как так:

class Blog < ActiveRecord::base 
... 
    def self.include_all_json_format 
    :include => { 
     :posts => { 
      :include => { 
       :comments => { 
        :include => :author 
       } 
      } 
     } 
    } 
    end 
... 
end 

который решает проблему запросов для этого формата JSON в нескольких местах, потому что я могу затем просто использовать:

Blog.includes(
    :posts => { 
     :comments => :author 
    } 
).all.as_json(
    Blog.include_all_json_format 
) 

Но, конечно же, Blog.includes() принимает другой формат для его хэш отношений, так это:

Blog.includes(
    Blog.include_all_json_format 
).all.as_json(
    Blog.include_all_json_format 
) 

Не сработает.

Я мог бы поставить хэш отношения Blog.includes() во втором методе класса, но наличие двух методов, объявляющих то же самое, включает структуру не DRY.


Единственная идея, которую я могу думать прямо сейчас, используя Blog.include_all_json_format метод, упомянутый выше, а затем писать метод преобразователя, который может превратить что отношения хэш в формат, ожидаемый Blog.includes() (по сути просто зачистки из :include ключей), так что можно было бы назвать:

Blog.includes(
    MyConverter(Blog.include_all_json_format) 
).all.as_json(
    Blog.include_all_json_format 
) 

Но тогда это становится сложнее, когда я хочу использовать :only или :except в моем формате as_json.


Как я могу сушить, они включают в себя, желательно только объявление формата отношений один раз?

Возможно, есть какой-то способ использования названных областей или некоторых драгоценных камней?

Любая помощь очень ценится.

+0

Вы можете попробовать [deep_pluck] (https://github.com/khiav223577/deep_pluck), чтобы высушить его. –

ответ

0

Вы можете переопределить метод as_json в модели

Например

class Blog < ActiveRecord::Base 

    def as_json 
    super(:include => :posts) 
    end 
end 

Затем контроллер должен выглядеть

render json: @blogs

внушения

Вы можете использовать JBuilder, Rabl, AMS или другую библиотеку шаблонов, которая позволит вам отделить здание ответа от логики контроллера/модели. Выполнение этого, безусловно, СУЩЕСТВУЕТ ваш код.

+0

Спасибо за ответ. Переопределение 'as_json' будет таким же, как' Blog.all.as_json (: include =>: posts) 'хотя, правильно? Поэтому все равно будет возникать неэффективный запрос N + 1. Спасибо, я проверю эти библиотеки. – Marc

+0

Я думаю, что все дело в том, что вы должны отделить свой шаблон «вид» от логики вашего контроллера. Что-то вроде '@blog = Blog.includes (: posts) .all' then' render json: @ blog', не вызывая as_json, но все же переопределяя его так, как я показал, вы бы DRYing его и предотвратить N + 1 запрос. –

Смежные вопросы