2016-10-04 51 views
1

我對此很新,所以如果這是一個愚蠢的問題,或者如果我應該以不同的方式來解決這個問題,請提前道歉。幾乎所有的建議我都會接受!限制協會的數量根據他們的價值

我正在使用Rails 4創建一個Jeopardy後端API。目前,我已經爲約100個左右的類別播種了我的數據庫,並且每個類別都有多個線索,它們提供了問題,答案和價值。我也有一個遊戲模型,創建時,它隨機選擇最多5個類別及其線索。

我的問題是,我想知道是否有辦法確保每個遊戲只有五個線索,沒有重複的值(即我不想要5個價值100美元的線索)。我不確定這是否可以在後端執行,或者如果我只需要在前端進行過濾(我沒有使用任何視圖 - 我正在構建一個單獨的專用JS客戶端,它將使用AJAX獲取來自API的數據),但我覺得必須有Rails的方式才能做到這一點!

我沒有使用任何聯接表 - 線索belongs_to類別,和類別has_many線索,然後一個遊戲has_many類別,所以它是一個非常直的樹結構。我不知道什麼代碼將是有益的在這裏作爲參考,因爲我的類別和線索模型是相當赤裸的那一刻,但這裏是我的遊戲模式是什麼樣子:

class Game < ActiveRecord::Base 
    after_create :assign_category_ids, :create_response, :reset_clues 
    has_many :categories 
    has_one :response, as: :user_input 
    belongs_to :user 

    # On creation of a new game, picks a user-specified 
    # number of random categories 
    # and updates their game_ids to match this current game id 
    def assign_category_ids 
    game_id = id 
    num_cats = num_categories.to_i 
    @categories = Category.where(id: Category.pluck(:id).sample(num_cats)) 
    @categories.map { |cat| cat.game_id = game_id } 
    @categories.each(&:save) 
    end 

    # Creates response to calculate user answer 
    def create_response 
    build_response(game_id: id, user_id: user_id) 
    end 

# Resets categories and clues on every new game 
    def reset_clues 
    @categories = Category.where(game_id: id) 
    @categories.each do |category| 
     category.clues.each { |clue| clue.update_attributes(answered: false) } 
     category.update_attributes(complete: false) 
    end 
    end 
end 

任何意見都將不勝感激!先謝謝你!

+0

@meagar - 這是超級有用!非常感謝你!就像我說的,我對此非常新穎,所以建模對我來說仍然是一個很大的挑戰,但是這對於可視化結構非常有幫助。我非常感謝幫助! – Tuck

+0

我的榮幸。我必須指出,評論並不是真正意義上的這種擴展討論。如果你想繼續討論這個問題,我將把評論轉移到聊天室。還有[Ruby聊天室](https://chat.stackoverflow.com/rooms/44914/ruby-sometimes-on-rails)。不相關,但我的筆記本電腦電池已經死了,我在接下來的幾個小時內不會進一步回答。 – meagar

+0

評論不適用於擴展討論;這個對話已經[轉移到聊天](http://chat.stackoverflow.com/rooms/124901/discussion-on-question-by-tuck-limit-number-of-associations-based-on-their-value) 。 – meagar

回答

1

我認爲在基礎數據模型的一些混亂。

有效地將兩個應該分開的東西混合在一起:可以將您認爲是「靜態」數據的類別和線索的定義以及用戶創建的遊戲/響應(即「動態」數據。

簡化(免費驗證,)實現模型層的應該是這個樣子:

# This is pure data, it's the definition of a category 
class Category 
    has_many :clues 
    # name: string 
end 

# This is pure data, it's the definition of a category, it's not tied to any user or game 
class Clue 
    belongs_to :category 
    # answer: string 
    # question: string 
end 

# This ties a specific user to a set of clues through GameClue 
class Game 
    belongs_to :user 
    has_many :game_clues 
end 

# This ties together a Game, a Clue and the user's inputted answer 
class GameClue 
    belongs_to :game 
    belongs_to :clue 
    belongs_to :inputted_user_answer # Nil until a user inputs an answer 
end 

這裏的關鍵一點是,類別和線索應該永遠不會改變。線索是線索的定義,並且許多用戶可以提交對它的響應作爲許多不同遊戲的一部分。對於這個經常遇到的問題的答案是創建一個完全獨立的記錄類型來保存用戶的響應,在這種情況下GameClue:它將遊戲,線索和用戶的響應連接在一起,但是結束記錄。

這裏的想法是,你可以擁有儘可能多的遊戲,每個遊戲都分享許多相同的線索和分類,如果遊戲「擁有」特定線索並使用該線索無法完成記錄以存儲用戶的答案。


關於你提到的有關驗證原來的問題,並沿表格按照上面的數據模型,我會做類似下面的未經測試的代碼:

class Game 

    def self.create_for(user) 
    user.games.create do |game| 
     [100,200,300,400,500].each do |points| 
     Category.where(id: Category.pluck(:id).sample(5)).map do |cat| 
      game.game_clues.create(clue: cat.clues.where(points: points).offset(rand(cat.clues.length)).first 
     end 
     end 
    end 
    end 

    validates :game_clues, length: 5 

    validate :must_have_clues_from_5_categories 
    validate :must_have_proper_range_of_points 

    protected 

    def must_have_clues_from_5_categories 
    if game_clues.pluck(:category_id).uniq.length < 5 
     errors.add(:game_clues, :invalid) 
    end 
    end 

    def must_have_proper_range_of_points 
    if game_clues.pluck(:points).uniq.length < 5 
     errors.add(:game_clues, :invalid) 
    end 
    end 
end 

這裏的外賣是,你可以使用validate :method_name來提供一種自定義驗證方法,可以檢查複雜的條件並向對象添加錯誤,從而避免保存錯誤。

0

您可以通過用戶has_many :clues through :categories然後validates :clues, length: { maximum: 5 }

+0

這絕對不能確保線索並不都具有相同的分值。 – meagar