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

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

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

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

Active Record

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

Q&A

解決済

1回答

1684閲覧

【rails】DBの設計(1対多)

gogoackman3

総合スコア109

Ruby on Rails

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

Active Record

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

0グッド

0クリップ

投稿2016/10/26 06:51

編集2016/10/26 08:30

現在、以下のような機能を作りたいと思っています。

・ユーザーが好きなゲームをフォロー出来る。
・ユーザーはゲームをフォローする際、自身のゲームレベルをゲーム毎に登録しておける。
・ゲームはユーザーをフォロー出来ない。(しない)

この場合の適切なテーブル設計はどのようになりますか??

自分で考えて実装したのは以下の通りです。

①ユーザー(User)
②ゲーム(Game)
③中間テーブル(FollowGame)

①user.rb

ruby

1has_many :follow_games

①のテーブルは、deviseを利用して生成されたものそのまま。

②game.rb

ruby

1has_many :follow_games

②のテーブル

ruby

1class CreateGames < ActiveRecord::Migration[5.0] 2 def change 3 create_table :games do |t| 4 t.boolean :active, null: false, default: true 5 t.string :title, null: false, default: '' 6 t.string :icon, null: false, default: '' 7 t.string :rank_name, null: false, default: '' 8 t.string :search_tag, null: false, default: '' 9 t.integer :feed_range, null: false, default: 0 10 t.integer :follower_num, null: false, default: 0 11 12 t.timestamps 13 end 14 end 15end

③follow_game.rb

ruby

1belongs_to :user 2belongs_to :game

③のテーブル

ruby

1class CreateFollowGames < ActiveRecord::Migration[5.0] 2 def change 3 create_table :follow_games do |t| 4 t.boolean :active, null: false, default: true 5 t.references :user, foreign_key: true 6 t.references :game, foreign_key: true 7 t.integer :rank 8 9 t.timestamps 10 end 11 end 12end

しかし、これだと、2点問題が発生しています。

問題その1

ユーザーがゲームをフォローする際に、既にフォローしているか判定する処理を入れており、その時のSQL文が誤ってしまう。

▼実際のフォローするフォーム

ruby

1 = form_for(current_user.follow_games.build) do |f| 2 = f.text_field :rank, id:'rank', placeholder: "#{game.rank_name}を入力" 3 = f.hidden_field :game_id, value:"#{game.id}" 4 = f.hidden_field :user_id, value:"#{current_user.id}" 5 6 = f.submit '追加', id:"rank_set"

▼follow_game.controller.rb

ruby

1class FollowGamesController < ApplicationController 2 3 before_action :set_game 4 5 def create 6 current_user.follow_games << @game unless current_user.follow_games.exists?(@game.id) 7 end 8 9 def delete 10 current_user.follow_games.destroy(@game) 11 @game.reload 12 end 13 14 private 15 def set_game 16 @game = Game.find(params[:follow_game][:game_id]) 17 end 18end

▼フォームからPOSTした際の重複確認のログ

Started POST "/follow_games" for 10.0.2.2 at 2016-10-26 15:01:24 +0900 Cannot render console from 10.0.2.2! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255 Processing by FollowGamesController#create as HTML Parameters: {"utf8"=>"✓", "authenticity_token"=>"eOSwJDG64yCLSgXmvpSiuzcpoDtF4Se2dAizxrCPkHMP5N1KHmEerUN2bFGgGFQXqz3D5wT6+r1qxswdYCYXnQ==", "follow_game"=>{"rank"=>"2", "game_id"=>"3", "user_id"=>"12"}, "commit"=>"追加"} User Load (0.4ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 12 ORDER BY `users`.`id` ASC LIMIT 1 Game Load (0.1ms) SELECT `games`.* FROM `games` WHERE `games`.`id` = 3 LIMIT 1 FollowGame Exists (0.1ms) SELECT 1 AS one FROM `follow_games` WHERE `follow_games`.`user_id` = 12 AND `follow_games`.`id` = 3 LIMIT 1 (0.1ms) BEGIN (0.1ms) ROLLBACK Completed 500 Internal Server Error in 6ms (ActiveRecord: 0.8ms)

FollowGame Existsの部分でfollow_games.idとなってしまっています。
本来はfollow_games.game_idとならないとダメだと思っています。
どうすればそのように出来るのでしょうか?modelの関連付けの部分かな?と思って色々調べたのですが、わからず、、教えて欲しいです。

問題その2
②偶然にも重複しなく、insertが走った場合でも、以下のエラーが発生する。

ActiveRecord::AssociationTypeMismatch in FollowGamesController#create

このエラーはこちら(http://kyohei8.hatenablog.com/entry/2013/04/25/115002)で調べたところ、以下の原因のようなのですが、今回の自分の場合の解決方法が分かりかねています。

railsでデータをinsertしようとした際、参照項目に対し、モデル以外を指定すると上記のようなエラーが発生する。

ご教示頂ければ幸いです。

###追記

以下の方法で①の問題は解決出来ました。

▼user.rb に以下のfollowing_gamesを追加

ruby

1has_many :follow_games 2has_many :following_games, through: :follow_games, source: :game

▼follow_games_controller.rb もfollowing_gamesに修正

ruby

1 def create 2 current_user.following_games << @game unless current_user.following_games.exists?(@game.id) 3 end

###しかし!

今度は②の部分でinsertしようとすると、以下のエラーが発生しているようです。

NoMethodError in FollowGamesController#create undefined method `rank' for #<Game:0x007f2278169e18>

rankはfollow_gamesテーブルのカラムなので、gameテーブルにはありません。
どうにしかして、postで受け取ったrank情報もfollow_gamesテーブルに追加する方法はないでしょうか???

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

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

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

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

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

guest

回答1

0

自己解決

追記である程度の自己解決方法を記載したので、こちらは解決済みにしてしまいます。

投稿2016/10/26 09:45

gogoackman3

総合スコア109

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問