現在、以下のような機能を作りたいと思っています。
・ユーザーが好きなゲームをフォロー出来る。
・ユーザーはゲームをフォローする際、自身のゲームレベルをゲーム毎に登録しておける。
・ゲームはユーザーをフォロー出来ない。(しない)
この場合の適切なテーブル設計はどのようになりますか??
自分で考えて実装したのは以下の通りです。
①ユーザー(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テーブルに追加する方法はないでしょうか???
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。