add Match model

This commit is contained in:
2026-11-03 16:14:10 +03:00
parent 1cadf00280
commit f48094cd55
6 changed files with 236 additions and 1 deletions
+43
View File
@@ -0,0 +1,43 @@
class Match < ApplicationRecord
belongs_to :player1, class_name: "User"
belongs_to :player2, class_name: "User"
enum :status, {
ongoing: 0,
player1_won: 1,
player2_won: 2,
draw: 3,
abandoned: 4
}
before_validation :assign_uuid, on: :create
validates :uuid, presence: true, uniqueness: true
validates :status, presence: true
validates :game_server, presence: true
validates :started_at, presence: true
validates :duration_seconds, numericality: { only_integer: true, greater_than_or_equal_to: 0 }, allow_nil: true
validates :player1_rating_before, :player2_rating_before,
presence: true, numericality: { only_integer: true }
validates :player1_rating_change, :player2_rating_change,
presence: true, numericality: { only_integer: true }
validate :players_must_differ
scope :finished, -> { where.not(finished_at: nil) }
scope :for_user, ->(user_or_id) {
id = user_or_id.is_a?(User) ? user_or_id.id : user_or_id
where(player1_id: id).or(where(player2_id: id))
}
private
def assign_uuid
self.uuid ||= SecureRandom.uuid
end
def players_must_differ
if player1_id.present? && player1_id == player2_id
errors.add(:player2, "must differ from player1")
end
end
end
+9
View File
@@ -2,6 +2,8 @@ class User < ApplicationRecord
has_secure_password validations: false
has_many :sessions, dependent: :destroy
has_many :matches_as_player1, class_name: "Match", foreign_key: :player1_id, dependent: :restrict_with_exception, inverse_of: :player1
has_many :matches_as_player2, class_name: "Match", foreign_key: :player2_id, dependent: :restrict_with_exception, inverse_of: :player2
has_one_attached :avatar
normalizes :nickname, with: ->(n) { n.strip }
@@ -11,6 +13,13 @@ class User < ApplicationRecord
validates :password, presence: true, length: { minimum: 6 }, if: -> { new_record? || password_digest_changed? }
validate :avatar_content_type, if: -> { avatar.attached? }
# All matches of this user that have finished, newest first.
def finished_matches
Match.where("player1_id = :id OR player2_id = :id", id: id)
.where.not(finished_at: nil)
.order(finished_at: :desc)
end
private
def avatar_content_type
unless avatar.blob.content_type.in?(%w[image/png image/jpeg image/gif image/webp])