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

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

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

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

データベース

データベースとは、データの集合体を指します。また、そのデータの集合体の共用を可能にするシステムの意味を含めます

Active Record

Active Recordは、一つのオブジェクトに対しドメインのロジックとストレージの抽象性を結合するデザインパターンです。

Q&A

解決済

1回答

11992閲覧

RailsのActive Recordで多対多のDBを作成し、中間テーブルに情報をもたせた場合、どのようにアクセスするのがベストであるか。

mazu_mooping

総合スコア12

Ruby on Rails

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

データベース

データベースとは、データの集合体を指します。また、そのデータの集合体の共用を可能にするシステムの意味を含めます

Active Record

Active Recordは、一つのオブジェクトに対しドメインのロジックとストレージの抽象性を結合するデザインパターンです。

1グッド

1クリップ

投稿2014/10/25 19:44

タイトルでは説明しにくいので、実現したい例を以下に示します。

以下の3つのモデルがあり、データベースもすでに作成してあるとします。

[Projectモデル]
id,name
1,社内運動会
2,年末キャンペーン

[ProjectsMembersモデル]
(中間テーブル)
project_id,member_id

[Memberモデル]
id,name(UNIQUE)
1,山田
2,田中

このようなモデルがあった場合、Project内でのMemberの評価を指定できるようにしたいと思っています。
例えば

lang

1p1 = Project.find 1 2p1.members.find_by_name('山田').rate 3#山田さんの社内運動会プロジェクトでの評価は3 4 5p = Project.find 2 6p2.members.find_by_name('山田').rate 7#山田さんの年末キャンペーンでの評価は2

ここで、rateという属性を参照していますが、これをMembersモデルに実装(rateカラムを設ける)してしまうと
Projectごとの評価ができなくなってしまいます。

これを避けるために、中間テーブルにrateというカラムを設けたいと思っております
例えば

[ProjectsMembersモデル]
(中間テーブル)
project_id,member_id,rate
1,1,3
2,1,2

とすれば、プロジェクトごとにメンバーの方の評価を設定することができます。

ここで、タイトルの質問に戻りますが
中間テーブルにこのように情報をもたせた場合、どうやってアクセスすることがベストでしょうか。
上で書いたProjectsMembersモデルにrateカラムを設ける方法だと。

lang

1p1 = Project.find 1 2m1 = Member.find_by_name('山田') 3result = ProjectsMembers.find(:project_id => p1.id,:member_id => m1.id) 4result.rate

これで一応結果は得られる(と思い)ますが、中間テーブルにいい感じにアクセスできるような方法はありませんでしょうか。
もしくが、このような問題を別の方法で解決する方法はありますでしょうか。
ご教授お願い致します。

ikuwow👍を押しています

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

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

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

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

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

guest

回答1

0

ベストアンサー

テーブル間にアソシエーションを適宜設定することで、各種のアクセスメソッドが追加されます。

参考:

以下に長くなりますが、具体的な設定例、アクセス例を示します。
この例では、
Member の projects, project_ids で member に関係する Project が列挙できます。
member_rojects, member_project_ids で member に関する MemberProject が列挙できます。
Project の members, member_ids で Project に関係する Member が列挙できます。
member_projects, member_project_ids で Project に関する MemberProject が列挙できます。
山田さんの rate 一覧は次のように参照できます。
m1.member_projects.each do |mp|
puts "#{mp.project.name} : #{mp.rate}"
end

=> 社内運動会 : 10

年末キャンペーン : 20

例:
ますテーブルの定義をします。

lang

1 $ rails g model Member name:string 2 $ rails g model Project name:string 3 $ rails g model MemberProject member:references project:references rate:integer

app/deb/.rb を編集して、アソシエーションを設定します。(app/db/.rb)

lang

1class Member < ActiveRecord::Base 2 has_many :member_projects 3 has_many :projects, through: :member_project 4end 5 6class Project < ActiveRecord::Base 7 has_many :member_projects 8 has_many :members, through: :member_project 9end 10 11class MemberProject < ActiveRecord::Base 12 belongs_to :member 13 belongs_to :project 14end

rails console でデータを操作してみます。

$ rake db:migrate # 状況におじて db:drop や db:reset も合わせて実行する必要があります) $ rails c # rails コンソールを起動します。 > m1 = Member.create(name: '山田') > m1.projects.create(name: '社内運動会') > m1.projects.create(name: '年末キャンペーン') > m1.member_project_ids # => [1, 2] (山田さんの MemberProject の id の一覧) > m1.member_projects # => 山田さんの MemberProject の配列 > mp1 = m1.member_projects[0] > mp1.rate = 2 # 田中さん - 社内運動会 の rate を設定 > mp1.save! > Member.all # Member の現時点の内容を確認 (山田さんが登録されている) > Project.all # Project の現時点の内容を確認 (社内運動会, 社内運動会 が登録されている) > MemberProject.all # MemberProject の現時点の内容を確認 (田中さん - 社内運動会, 田中さん - 年末キャンペーン

投稿2014/10/26 00:30

katoy

総合スコア22324

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

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

katoy

2014/10/26 06:08

Gemfile に次を追加しておくと、DB 内容の表示が見やすくなります。 gem 'hirb' gem 'hirb-unicode' 最後の全テーブの内容表示は こんなふうな出力になります。 [14] pry(main)> Member.all Member Load (0.2ms) SELECT "members".* FROM "members" +----+------+-------------------------+-------------------------+ | id | name | created_at | updated_at | +----+------+-------------------------+-------------------------+ | 1 | 山田 | 2014-10-26 06:01:52 UTC | 2014-10-26 06:01:52 UTC | +----+------+-------------------------+-------------------------+ 1 row in set [15] pry(main)> Project.all Project Load (0.2ms) SELECT "projects".* FROM "projects" +----+------------------+-------------------------+-------------------------+ | id | name | created_at | updated_at | +----+------------------+-------------------------+-------------------------+ | 1 | 社内運動会 | 2014-10-26 06:02:38 UTC | 2014-10-26 06:02:38 UTC | | 2 | 年末キャンペーン | 2014-10-26 06:03:06 UTC | 2014-10-26 06:03:06 UTC | +----+------------------+-------------------------+-------------------------+ 2 rows in set [16] pry(main)> MemberProject.all MemberProject Load (0.2ms) SELECT "member_projects".* FROM "member_projects" +----+-----------+------------+------+-------------------------+-------------------------+ | id | member_id | project_id | rate | created_at | updated_at | +----+-----------+------------+------+-------------------------+-------------------------+ | 1 | 1 | 1 | 2 | 2014-10-26 06:02:38 UTC | 2014-10-26 06:04:23 UTC | | 2 | 1 | 2 | | 2014-10-26 06:03:06 UTC | 2014-10-26 06:03:06 UTC | +----+-----------+------------+------+-------------------------+-------------------------+
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問