RailsからActiveRecordを切り離してみた
2020年11月27日
こんにちは。
CTOの徳江です。
今日は私の経験をお送りしたいと思います。
エピローグ
とある受託案件 社内向けRailsアプリ(シンプルなMonolith)のリリース目前にて、
「このシステム、セキュリティの関係でDBを直繋ぎ禁止になった! API経由にできない?」
エヘヘ(●´∀`).。o○(やっべ、たのしそ🤤 やってみちゃぉ🙃)
というわけで、既存のRailsアプリを、
- API+DB側rails (security-group などで厳しめに保護)
- フロント側rails (rails 既存資産を生かすため)
に分離しました。
※ どちらも内省で、自由に改修可能
※ フロント部分は完成しており、ルーティング含め手を入れたくない → 最短でRailsで行く
※ 成功を保証するものではありません。ご了承を😜
※ どちらも内省で、自由に改修可能
※ フロント部分は完成しており、ルーティング含め手を入れたくない → 最短でRailsで行く
※ 成功を保証するものではありません。ご了承を😜
レシピ:1.API+DB側rails
全テーブル分をgrapeでcrud作っちゃいます。
module GrapeApi class Base < Grape::API ActiveRecord::Base.connection.tables.map(&:classify).map(&:safe_constantize) ApplicationRecord.descendants.each do |model| entity = ResourcesEntityFactory.create(model) resource model.table_name.to_s, desc: model.model_name.human do get do authenticate! scope = search_scope(model, params) params.each { |key, value| scope = scope.where(key.to_sym => value) if model.new.attributes.keys.include? key } entity.represent scope end get '/:id' {...} post {...} put '/:id' {...} delete '/:id' {...} # *1 fields, associations, scopes get '/schema' do authenticate! { fields: model.attribute_types, associations: model.reflect_on_all_associations.map(&:name), scopes: scopes(model) } end # *2 association namespace '/:id' do model.reflect_on_all_associations.each do |assoc| resource assoc.name.to_sym do get '' do authenticate! Array.wrap(model.find(params[:id]).send(assoc.name)) end end end end end end end end
- レシピ
- grape
- grape-swagger #openapi documentation
- pundit #権限管理
- 隠し味
レシピ: 2. フロント側rails
ここからが本領、ですね。
めっちゃ難しかった(= 楽しかった🙃)
- ActiveRecord → ActiveModel + her gem
class ApplicationRecord < ActiveRecord::Base
↓
class ApplicationRecord include Her::Model include ActiveModel::Serialization parse_root_in_json false, format: :active_model_serializers request_new_object_on_build true include_root_in_json true
- DB adapter → nulldb gem
サービス起動時などで意図せずDB接続が発生。
DBのadapter階層で撲滅 🙉
DBのadapter階層で撲滅 🙉
- ActiveRecorde系
- そのままでOK🎉
- AR accept_nested_attribute_for ← 一括コミットに大事 🎉🎉🎉
- ARのscopeの遅延実行 🎉
- それっぽく独自実装💪
- save(validate: false, callback: false, context: 'aaaa')
- find: raiseしてくれないので、find! を作って置き換え
- オブジェクトキャッシュ -> request_store gem
- polymorphic 関連
- ApplicationRecordへコピー実装 😅
- enum
- has_secure_token
- 今回はスルー 🙈
- ActiveRecordのincludes, preload、eager_load
- i18n: APIとサーバーで二重実装
- find_each, find_in_batches
- transaction系
- 多くはaccept_nested_attribute_forで一括コミット
- ↑で処理できない範囲は…専用APIが必要
- → apiのrequest-responseをリダイレクトするようなclientを作って対応
- そのままでOK🎉
- gem系
- そのままでOK🎉
- simple_form
- kaminari -> application_recordでAPIにそのまま流す
- paranoid, acts_as_list
- papertrail (API側に託す)
- Draper(decorator)
- 大玉: her用adapter自作
- devise
デフォルトで、activerecord用とmongoid用のadapterがあります。
→ her用のadapterを、模倣しながら自作(ちょっと怖いので非公開🙊)
参考: dynamoid-devise, devise-activeresource - ransack
ここはやばかったですね😭(非公開)
極力、シンプルにher型のAPIに変換して投げるように工夫(かなり不十分)
- devise
- 今回はスルー🙈
- activerecord-import
- kaminari の ページネーションURL
- そのままでOK🎉
というわけで、
どうにかなりました。
大分趣味的パズルですが、
どこかの誰かの助けになれば幸いです 😉
コメント
最新記事
2024年09月12日
JINの夏休み -ミッション達成に向けた種まきの旅- in20242024年09月06日
地方創生のリーディングカンパニーを視察してきた2024年08月30日
共働き夫婦の増加と生活の変化2024年08月22日
未経験エンジニアが語る!~地方支社の魅力と可能性~2024年08月15日
大学生にインターンシップを実施しました!2024年08月08日
地方創生ツアーを実施しました!【後編】2024年08月01日
地方創生ツアーを実施しました!【前編】2024年07月25日
IT企業が新規事業として農業に取り組んで失敗するまで【後編】2024年07月17日
【社員インタビュー】エンジニアの休日の過ごし方って?2024年07月11日
中学生が職場体験に来てくれました! in. 小林支社
過去記事(年月別)
- 2024年09月(2)
- 2024年08月(4)
- 2024年07月(4)
- 2024年06月(4)
- 2024年05月(4)
- 2024年04月(2)
- 2024年03月(4)
- 2024年02月(3)
- 2024年01月(3)
- 2023年12月(3)
- 2023年11月(2)
- 2023年10月(3)
- 2023年09月(1)
- 2023年08月(2)
- 2023年07月(3)
- 2023年06月(5)
- 2023年05月(3)
- 2023年04月(4)
- 2023年03月(5)
- 2023年02月(5)
- 2023年01月(4)
- 2022年12月(3)
- 2022年11月(4)
- 2022年10月(4)
- 2022年09月(6)
- 2022年08月(2)
- 2022年07月(4)
- 2022年06月(4)
- 2022年05月(5)
- 2022年04月(7)
- 2022年03月(7)
- 2022年02月(3)
- 2022年01月(4)
- 2021年12月(2)
- 2021年08月(1)
- 2021年06月(2)
- 2021年04月(1)
- 2021年02月(1)
- 2020年12月(2)
- 2020年11月(3)
- 2020年10月(3)
- 2020年07月(2)
- 2020年02月(3)
- 2020年01月(2)
- 2019年12月(1)
- 2019年09月(1)
- 2018年10月(1)
タグ