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

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

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

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

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

解決済

RailsでSTI親クラスのリレーションが子クラスに引き継がれない

PJZ9n
PJZ9n

総合スコア12

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

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

1回答

0評価

0クリップ

602閲覧

投稿2022/01/17 00:33

編集2022/01/21 13:50

前提・実現したいこと

RailsでSTIを用いた開発を行っています。
そこで、子クラスのロードがされない問題が発生したため https://guides.rubyonrails.org/autoloading_and_reloading_constants.html#single-table-inheritance を参考に、STI子クラスの自動ロードをするコードを書きました。

発生している問題・エラーメッセージ

rails consoleにて次のコードを実行する

>> user = User.create!(name: "Hoge") => User id=1 >> tweet = user.normal_tweets.create!(text: "Fuga") => NormalTweet id=1 >> tweet.author => User id=1

rails consoleを再起動し、次のコードを実行する

>> Tweet.find(1).author => C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/activerecord-7.0.1/lib/active_record/associations.rb:301:in `association': Association named 'author' was not found on NormalTweet; perhaps you misspelled it? (ActiveRecord::AssociationNotFoundError)

このように、エラーが発生します。※Tweetモデルからinclude StiPreloadを削除した場合この問題は起きません。

>> Tweet.find(1).author_id => 1

もちろん、外部キーであるauthor_id自体は存在しています。

該当のソースコード

rb:user.rb

class User < ApplicationRecord has_many :normal_tweets, dependent: :destroy, class_name: "NormalTweet", foreign_key: :author_id end

rb:tweet.rb

require "sti_preload" class Tweet < ApplicationRecord include StiPreload belongs_to :author, class_name: "User" end

rb:normal_tweet.rb

class NormalTweet < Tweet has_many :replies, class_name: "Reply", foreign_key: :reply_to_id, dependent: :nullify end

rb:

class Reply < NormalTweet belongs_to :reply_to, class_name: "NormalTweet", optional: true end

rb:sti_preload.rb

module StiPreload unless Rails.application.config.eager_load extend ActiveSupport::Concern included do cattr_accessor :preloaded, instance_accessor: false cattr_accessor :preloading, instance_accessor: false end class_methods do def descendants preload_sti unless preloaded super end def preload_sti return if self.preloading self.preloading = true types_in_db = \ base_class. unscoped. select(inheritance_column). distinct. pluck(inheritance_column). compact types_in_db.each do |type| logger.debug("Preloading STI type #{type}") type.safe_constantize # 重要: safeでないconstantizeを使うと例外が発生する end self.preloading = false self.preloaded = true end end end end

https://github.com/PJZ9n/RailsSTIProblem

試したこと

StiPreloadモジュールを使わず、手動でロードしてやると問題なく動作します。

>> [Tweet, NormalTweet, Reply]

補足情報(FW/ツールのバージョンなど)

$ rails -v Rails 7.0.1 $ ruby -v ruby 3.0.3p157 (2021-11-24 revision 3fb7d2cadc) [x64-mingw32]

良い質問の評価を上げる

以下のような質問は評価を上げましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

  • プログラミングに関係のない質問
  • やってほしいことだけを記載した丸投げの質問
  • 問題・課題が含まれていない質問
  • 意図的に内容が抹消された質問
  • 過去に投稿した質問と同じ内容の質問
  • 広告と受け取られるような投稿

評価を下げると、トップページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

まだ回答がついていません

会員登録して回答してみよう

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

ただいまの回答率
87.20%

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

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

質問する

関連した質問

同じタグがついた質問を見る

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

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