質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Ruby on Rails 6

Ruby on Rails 6は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

キャッシュ

キャッシュはドキュメントやデータを一時的に保管するもので、アクセス処理時間を短くするために使用されます。

Q&A

解決済

1回答

1109閲覧

Railsのクラス変数のキャッシュ保持について

退会済みユーザー

退会済みユーザー

総合スコア0

Ruby on Rails 6

Ruby on Rails 6は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

キャッシュ

キャッシュはドキュメントやデータを一時的に保管するもので、アクセス処理時間を短くするために使用されます。

0グッド

0クリップ

投稿2021/04/01 05:36

Railsのクラス変数のキャッシュ保持の仕様について

概要

現在Rails6系で作成中のアプリにおいて、仕様がかなり被っている二つのモデルを扱っています。
CRUDアクションを各コントローラーに別々に書くのはDRYでは無いので、コントローラー、モデルの双方ついて抽象クラスを作ってそちらにCRUDアクションを定義しています。

当然、抽象クラス内からどちらのモデルにクエリを出すのかを判別する必要があるので、クラス変数として該当のモデルをセットして呼び出す仕様にしているのですが、リクエスト毎にクラス変数が更新され無い状況です。

具体的には、後述のコード中において、
self.modelの中身が毎回変わってくれず、Dog::CategoriesControllerにアクセスしているのにcat_categoriesテーブルにクエリが行ってしまうという状況です。

おそらくクラスの初期化が毎回行われずにキャッシュされたものをRailsが使っているという事なのかと思いますが、
恥ずかしながらこのあたりの仕様について理解しておらず、対応策について困っています。

※一応ですがRailsはAPIモードで開発しており、viewについては別で開発しております。

質問

リクエスト毎にクラス変数がセットされる様にするためにはどうすれば良いか?
もしくは、その方法があったとしてもその方法を取る事はパフォーマンス等の観点から問題があれば、どの様に対応するのがベストか?
(後者については抽象的な質問になってしまっており恐縮ですが、、、)

コード

Controller

  • ApplicationController

Ruby

1class ApplicationController < ActionController::API 2 def initialize 3 super 4 self.model = self.class.get_model_class 5 end 6 7 def self.call_default_functions 8 self.set_class_name_prefix 9 self.set_class_name_suffix 10 end 11 12 def self.set_class_name_prefix 13 @@class_name_prefix = self.name.split('::')[0] 14 end 15 16 def self.set_class_name_suffix 17 @@class_name_suffix = self.name.gsub(/Controller/, '').split('::')[-1] 18 end 19 20 def self.get_model_class 21 "#{self.class_name_prefix}::#{self.class_name_suffix.singularize}".safe_constantize 22 end 23end
  • 抽象Controller

Ruby

1class Abstract::CategoriesController < ApplicationController 2 def index 3 categories = self.model.find_index({query: category_params}) 4 render json: {result: true, body: self.model.to_json(cards)} 5 end 6end
  • 具体Controller

Ruby

1class Dog::CategoriesController < Abstract::CategoriesController 2 self.call_default_functions 3 4 private 5 def category_params 6 params.require(:category).permit( 7 :name, 8 ) 9 end 10 end 11end

※似た様な形でCat::CategoriesControllerがあると考えていただけると幸いです。

Model

  • 抽象Model
class Abstract::Category < ApplicationRecord self.abstract_class = true def self.define_common_associations #class_name_prefixなどはコントローラーと同様にapplication_recordで定義しています。 has_many :foods, class_name: "#{self.class_name_prefix}::Food", foreign_key: "#{self.table_name_prefix}_food_id" end end
  • 具体モデル

Ruby

1class Dog::Category < Abstract::Category 2 self.define_common_associations 3 self.find_index(params) 4 return self.all 5 end 6end

お手数ですが、何卒よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2021/04/01 05:40

concernsではなく親クラスを立てるという選択肢をとった理由はなにかありますか?
退会済みユーザー

退会済みユーザー

2021/04/01 05:54 編集

私も経験が浅く、恥ずかしながら自身を持って言える理由はありませんが、以下の通りです。 ・モジュールについては拡張の仕様について自分が詳しく無いという消極的な理由 ・受けつけるパラメータが少々違うレベルの実装で、is_aの関係等基本的な考え方から言っても親クラスとして実装する方が自然だと考えられた ・親クラスとして実装する方が強制力が高く、前項と合わせてその方が良いと考えました。(アプリの全体像を説明する必要があるので、これについては少し言葉足らずになってしまいますが、、、) ・concernsについては、より横断的なモジュールのみにしておいた方が綺麗だと感じた(例えば複数のモデルで使われる画像アップロード用のモジュール等)
退会済みユーザー

退会済みユーザー

2021/04/01 05:55

自然だと考えられた、綺麗だと感じたの理由までちゃんと書かないと回答になりませんね、、申し訳ありませんが時間の都合上この程度でお許しいただけると幸いです、、、
guest

回答1

0

ベストアンサー

リクエスト毎にクラス変数が更新され無い状況です。

はい、本番サーバではクラスはサーバ起動時(あるいは処理スレッドの作成時)に1度ロードされるだけですので、クラス変数はリクエストを越えて共有されてしまいます。このような、リクエストごとのデータに使えるものではありません。

投稿2021/04/01 05:46

編集2021/04/01 05:53
maisumakun

総合スコア145121

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2021/04/01 05:48

この場合、クラスインスタンス変数(@class_name_prefix、@class_name_suffix)あるいはclass_attributeを使えばいいかと思います。
退会済みユーザー

退会済みユーザー

2021/04/01 05:53

早々のご回答ありがとうございます! 自身で調べてみて、消化してからまた返答させて頂きます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問