根据价值

时间:2016-10-04 12:53:03

标签: ruby-on-rails ruby-on-rails-4

我对此很新,如果这是一个愚蠢的问题,或者我应该以不同的方式接近这个问题,请提前道歉。我当然对几乎所有建议持开放态度!

我正在使用Rails 4创建一个Jeopardy后端API。目前,我已经在大约100个左右的类别中播放了我的数据库,每个类别都有多个线索,其中包含问题,答案和值。我还有一个游戏模型,在创建时,随机选择最多5个类别及其线索。

我的问题是,我想知道是否有办法确保每个游戏只有五条线索,而且没有重复的值(即,我不想要5条线索,价值100美元)。我不确定这是否可以在后端进行,或者我是否应该在前端过滤掉它(我没有使用任何视图 - 我正在构建一个单独的专用JS客户端,它将使用AJAX来获取来自API的数据),但我觉得必须有一个Rails方法来做到这一点!

我没有使用任何连接表 - 线索belongs_to类别,类别has_many线索,然后是游戏has_many类别,所以它是一个非常直的树结构。我不确定哪些代码在这里有用,以供参考,因为我的Category和Clue模型目前相当简陋,但这就是我的Game模型:

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

任何建议都将非常感谢!!提前谢谢!

2 个答案:

答案 0 :(得分:1)

我认为您的基础数据模型存在一些混淆。

你有效地将两个应该分开的东西混合在一起:你可以想到的类别和线索的定义为&#34;静态&#34;数据,以及用户创建的游戏/响应,即动态&#34;数据

模型层的简化(无验证)实现应如下所示:

# 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提供自定义验证方法,该方法可以检查复杂条件并向对象添加错误,从而防止其被保存。

答案 1 :(得分:0)

您可以使用has_many :clues through :categories,然后validates :clues, length: { maximum: 5 }