Slide 1

Slide 1 text

pixiv Inc. pixivコミックで作品が公開 されるってどういうこと? @ikumin

Slide 2

Slide 2 text

Profile ikumin エンジニア 2016年入社 コミック事業部 pixivコミック部 業務では主にバックエンドを担当し ていてRailsを書いています

Slide 3

Slide 3 text

● 2012年から始まったマンガ サービス ● ブラウザ/Android/iOS ● 商業作品の連載 ● 電子書籍の販売 ● pixivに投稿された作品の閲覧

Slide 4

Slide 4 text

● 期間中、無料で何度も読める ● 購入すると読める 連載エピソードの形態

Slide 5

Slide 5 text

エピソードの公開設定

Slide 6

Slide 6 text

基本のデータ

Slide 7

Slide 7 text

エピソードの公開設定 ● 公開期間 ● 種類 ● (種類によっては)価格

Slide 8

Slide 8 text

エピソードの公開設定 # 公開設定 class PublishingSetting < ApplicationRecord ## typeによってどの公開設定化を判別する def free? type == 'PublishingSetting::Free' end def sell? type == 'PublishingSetting::Sell' end end

Slide 9

Slide 9 text

全話開放キャンペーン

Slide 10

Slide 10 text

公開中のエピソードを取得するには ● 各種公開フラグがONかどうか? ● 期間内の公開設定はあるか? ● 全話開放キャンペーン対象かどうか? を確認する必要がある

Slide 11

Slide 11 text

普通にやってみる SELECT `stories`.* FROM `stories` INNER JOIN `works` `work` ON `work`.`id` = `stories`.`work_id` INNER JOIN `magazines` `magazine` ON `magazine`.`id` = `work`.`magazine_id` INNER JOIN `publish_all_story_campaign_works` ON `publish_all_story_campaign_works`.`work_id` = `work`.`id` INNER JOIN `publishing_settings` ON `publishing_settings`.`story_id` = `stories`.`id` WHERE `work`.`is_public` = 1 AND `magazine`.`is_public` = 1 AND ( (`publishing_settings`.`start_at` <= :now) AND (`publishing_settings`.`finish_at` < :now OR `publishing_settings`.`finish_at` IS NULL) OR `publish_all_story_campaigns`.`approved` = 1 )

Slide 12

Slide 12 text

他にも… ● レーティングの問題でアプリでは表示できない作品がある ● 販売中のエピソードをは購入しなければ読めない ● 公開中の作品の最新話を取得したい ● 最新話の公開日順に作品を並べ替えたい

Slide 13

Slide 13 text

● 公開中のエピソードへの関連と 最新話の公開日を持つキャッ シュ代わりのテーブルを用意 ● 毎日12時に更新 キャッシュテーブルの用意

Slide 14

Slide 14 text

● 一括で取得した情報をモデルのインスタンスに紐づけて くれるgem ● https://github.com/walf443/bulk_loader BulkLoaderの利用

Slide 15

Slide 15 text

購入情報を一括で取得する class Story < ApplicationRecord #... bulk_loader, :purchased? do |ids, user_id| next {} if user_id.nil? # APIで購入の有無を問い合わせ purchased_story_ids = Store::App::OrderedEpisodes.get(user_id, ids) # {id => purchased?} という形式のHashに変換 ids.index_with {|id| purchased_story_ids.include?(id) } end end

Slide 16

Slide 16 text

購入情報を一括で取得する # ログインユーザーがstoriesを購入しているかどうかを調べる Story.bulk_loader.load(:purchased?, stories, current_user) stories.each do |story| story.purchased? # bulk_loaderでAPIから取得したエピソードごとの購入 有無を引ける end

Slide 17

Slide 17 text

● エピソードが購入済みか ● エピソードが無料公開中か ● エピソードが販売中か ● 作品が全話開放キャンペーン中か これを利用して

Slide 18

Slide 18 text

まとめ ● 複雑な要件に対応するため、いろんなところに公開に関 わるデータが散らばっている ● 複数のテーブルに絡んだ条件をキャッシュして緩和 ● BulkLoaderを使ってデータの取得を簡便化

Slide 19

Slide 19 text

ご清聴ありがとうござい ました!