RailsでN+1が出ないようにas_jsonぽくする奴を作った
smart_json: RailsでN+1が出ないas_jsonぽい奴作りました。
https://github.com/tompng/smart_json
ちょくちょく直しながら作ってます。んで、実践投入しようかなと思ってるので記事書いとこうと。
smart_json?
gem 'smart_json', github: 'tompng/smart_json'
blogs.as_smart_json(posts: [:タイトル日付のみ, author: :詳細, comments: {user: :名前だけ}])
と指定してjsonを作れる、そして必要なincludesを自動でやってくれるのでN+1問題も起きない(はず)
smart_jsonが解決する問題:その1
posts.as_json(include: {comments: {include: :user}})
とかするとN+1クエリが出る、かといって
posts.includes(comments: :user).as_json(include: {comments: {include: :user}})
とするのはだるい。Don't repeat yourselfだくそ野郎
smart_jsonを使うと...
posts.as_smart_json(comments: :user)
smart_jsonが解決する問題:その2
as_jsonでonlyやmethodsに指定する内容は数通りしかないので、そのままだと
user.as_json(only: [:id, :name])
comment.as_json(only: [:id, :text], include: {user: {only: [:id, :name]}})
posts.as_json(include: {comments: {only: [:id, :text]}})
blogs.as_json(include: {owner: {only: ...}, posts: {include: {author: {only: ...}, comments: {only: ...}}}})
と重複だらけになってひどいしN+1対策でさらに長くなる。
smart_jsonでスタイルを定義しておけば...
class User smart_json_style(:default){as_json only: [:id, :name]} end class Comment smart_json_style(:default){as_json only: [:id, :text]} smart_json_style(:詳細, :user) end class Post smart_json_style(:簡易){{title: title, body: body[0..30]}} smart_json_style(:コメントなど含む, :簡易, :author, comments: :詳細) end
user.as_smart_json
comment.as_smart_json(:詳細)
posts.as_smart_json(:comments)
blogs.as_smart_json(:owner, posts: :コメントなど含む)
とすっきり書ける。これまた依存関係全部includesしてくれる。
誰か実験台になってくれちょ
(あと似たようなのが既にあれば教えてほしい)