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

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

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

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

Ruby

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

Ruby on Rails

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

Q&A

解決済

2回答

929閲覧

RailsのN+1問題とアソシエーションについて

no1knows

総合スコア3365

Ruby on Rails 5

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

Ruby

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

Ruby on Rails

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

0グッド

0クリップ

投稿2019/04/02 00:08

編集2019/04/02 17:34

前提・実現したいこと

N+1問題とアソシエーションに関してきちんと理解ができず、少し混乱気味なので、現在作成中のアプリを実例として教えていただければと思います。

会社に所属する人、会社の銀行口座といった形で下記のようなモデルを作っています。

#model CompanyーーーーUser      | └ーUser      | └ーUser      |      └ーーーBank(銀行・支店コード)ー(?)ーBankcode(銀行・支店名)      └ーーーBank(銀行・支店コード)ー(?)ーBankcode(銀行・支店名)

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

①この場合、アソシエーションの設定は下記のような形になるとの認識で良いでしょうか?

class Company < ApplicationRecord has_many :users end class User < ApplicationRecord belongs_to :company end class Bank < ApplicationRecord belongs_to :company has_one :bankcode end class Bankcode < ApplicationRecord belongs_to :bank end

②下記のような形で銀行口座名を求めたのですが、コンソールを確認するとN+1問題が発生していました。
RailsGuideのAuthorとBookだと理解できていると思うのですが、いざ自分でやろうとするとわからなくなってしまいました。
解決方法を教えていただければと思います。

#banks_controller.rb > index.html.erb <tbody> <% @banks.each do |bank| %> <tr> <td><%= Bankcode.find_by(bank: bank.bank_code).name %></td> <td><%= Bankcode.find_by(bank: bank.bank_code, branch: bank.branch_code ).name %></td> </tr> <% end %> </tbody>
#class BanksController < ApplicationController def index #deviseを利用しているためcurrent_user.idにてログイン中のUserIDを取得 @user = User.find_by(id: current_user.id) @company = Company.find(@user.company_id) @banks = Bank.where(company_id:@company.id) end

どうぞよろしくお願いいたします。

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

ruby 2.6.2
rails 5.2.2

追記(Bank(銀行・支店コード)ーBankcode(銀行・支店名)について)

Bank(銀行・支店コード)とBankcode(銀行・支店名)のテーブルの構造が下記のようになっています。
そのため通常のアソシエーションではうまくデータを取得できないことがわかりました。

BanksTable

1 2#会社の銀行口座の銀行コード(bank_code)、支店コード(branch_code)が記載されているテーブル 3 4ID|bank_code|branch_code|company_id|...... 51 |0001 |738 |2 |...... 62 |0001 |599 |2 |...... 73 |0005 |056 |2 |...... 8

Bankcodestable

1 2#全国銀行協会で定められたの銀行コード(bank)、支店コード(branch)が記載されているテーブル 3 4ID|bank|branch|name     |...... 51 |0001|000 |みずほ銀行   |...... 610|0001|738 |たまプラーザ支店|...... 720|0001|599 |あざみ野支店 |...... 830|0005|000 |三菱UFJ銀行 |...... 930|0005|056 |あびこ支店  |...... 10

このようなテーブルの場合に下記のような結果を得るためにはどのようにすればよいでしょうか?

#banks_controller.rb > index.html.erb <tbody> <% @banks.each do |bank| %> <tr> <td>銀行名</td> <td>支店名</td> </tr> <% end %> </tbody>

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

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

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

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

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

guest

回答2

0

ベストアンサー

bankcodeに銀行と支店の双方が入っているなら、アソシエーションもそれぞれ作らないといけません

ruby

1class Bank < ApplicationRecord 2 belongs_to :company 3 4 # with_options で同じ条件をまとめるつつ 5 # 銀行名は1つなので has_one, 支店は複数なので has_many で関連を作る 6 with_options primary_key: :bank_code, 7 foreign_key: :bank_code, 8 class_name: 'Bankcode' do 9 has_one :bank_bankcode, -> { where(branch_code: '0000') } 10 has_many :branch_bankcodes, -> { where.not(branch_code: '0000') } 11 end 12end 13 14class Bankcode < ApplicationRecord 15 with_optoins primary_key: :bank_code, foreign_key: :bank_code do 16 belongs_to :bank 17 18 # 自身と同じ bank_code で branch_code が 0000 が自分の銀行 19 has_one :main_bankcode, -> { where(branch_code: '0000') }, class_name: 'Bankcode' 20 end 21end

描画例A

ruby

1 def index 2 # 略 3 4 # それぞれ事前読み込みを行います 5 @banks = @company.banks.preload(:bank_bankcode, :branch_bankcodes) 6 end

erb

1 <tbody> 2 <% @banks.each do |bank| %> 3 - # 表示の目的である支店でループしつつ 4 <% bank.branch_bankcodes.each do |branch_bankcode| %> 5 <tr> 6 - # 銀行名は bank 側で事前読み込みしているものを参照する 7 <td><%= bank.bank_bankcode.name %></td> 8 9 - # 支店を表示する 10 <td><%= branch_bankcode.name %></td> 11 </tr> 12 <% end %> 13 <% end %> 14 </tbody>

描画例B

ruby

1 def index 2 # 略 3 4 # 支店側で銀行まで事前読み込みを行います 5 @banks = @company.banks.preload(branch_bankcodes: :bank_bankcode) 6 end

erb

1 <tbody> 2 <% @banks.each do |bank| %> 3 - # 表示の目的である支店でループしつつ 4 <% bank.branch_bankcodes.each do |branch_bankcode| %> 5 <tr> 6 - # 銀行名は支店側で事前読み込みしているものを参照する 7 <td><%= branch_bankcod.bank_bankcode.name %></td> 8 9 - # 支店を表示する 10 <td><%= branch_bankcode.name %></td> 11 </tr> 12 <% end %> 13 <% end %> 14 </tbody>

補足

外部データのようなので仕方ないですがRails的な理想は違う構造なら別テーブルであることが理想です
それなら上記のアソシエーションは where とかが無くなりシンプルになると思います
上記アソシエーション設定は、設定上で下記構造になるよう切り分けるために頑張っていると思ってください

#bankcodes ID|bank|branch|name     |...... 1 |0001|000 |みずほ銀行   |...... 30|0005|000 |三菱UFJ銀行 |......
#branchcodes ID|bank|branch|name     |...... 10|0001|738 |たまプラーザ支店|...... 20|0001|599 |あざみ野支店 |...... 30|0005|056 |あびこ支店  |......

投稿2019/04/03 09:30

Ighrs

総合スコア656

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

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

no1knows

2019/04/04 03:18

詳しい説明を頂きありがとうございます。 アソシエーションに関して、より深く理解することができました。 また「Rails的な理想」というのも頂いた回答をみて納得しました。 銀行テーブルに関してはこちらで加工ができるので、そちらも検討してみたいと思います。
guest

0

定義

参照しているので company - banks も定義しておくと良いでしょう

ruby

1class Company < ApplicationRecord 2 has_many :users 3 has_many :banks 4end

ruby

1 def index 2 @user = User.find_by(id: current_user.id) 3 @company = @user.company # belongs_to定義してるので呼べる 4 5 # has_many定義すると @company.banks で呼べる 6 # preload で事前に一括で読み込む 7 @banks = @company.banks.preload(:bankcode) 8 end

find_byは each の中で使うべきではない

find_byはSQLを発行するのでその使い方だと必ずN+1になります

erb

1<tbody> 2 <% @banks.each do |bank| %> 3 <tr> 4 - # preloadしたものを呼ぶことで N+1 を解消 5 <td><%= bank.bankcode.name %></td> 6 7 - # branchとは何でしょうか? 8 - # アソシエーションとは異なる関連があるならN+1の回避は難しいです 9 <td><%= Bankcode.find_by(bank: bank.bank_code, branch: bank.branch_code ).name %></td> 10 </tr> 11 <% end %> 12</tbody>

投稿2019/04/02 09:06

Ighrs

総合スコア656

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

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

no1knows

2019/04/02 17:35

ご回答いただきありがとうございます。 アソシエーションに関するコメントで非常にわかりやすくて助かりました。 こちらをもとに動かそうとして混乱している部分がわかったので、再度、質問させてください。 Bank⇔Bankcodeのアソシエーションを勘違いしていました。 質問にテーブルの構成を追記しましたので、このような場合の値の取り出し方を教えていただけないでしょうか? どうぞよろしくお願いいたします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問