Я вижу два способа решения этой проблемы:
- БД: триггер
- Rails: обратный вызов
Триггер (при условии Postgres):
DROP TRIGGER IF EXISTS trigger_add_match_name ON customers;
DROP FUNCTION IF EXISTS function_add_match_name();
CREATE FUNCTION function_add_match_name()
RETURNS trigger AS $$
BEGIN
NEW.match_name := (
SELECT
CONCAT(game_matches.match_type, ' ', COALESCE(count(*), 0))
FROM game_matches
WHERE game_matches.user_id = NEW.user_id AND game_matches.match_type = NEW.match_type
);
RETURN NEW;
END
$$ LANGUAGE 'plpgsql';
CREATE TRIGGER trigger_add_match_name
BEFORE INSERT ON game_matches
FOR EACH ROW
EXECUTE PROCEDURE function_add_match_name();
Обратите внимание, что это не проверено.
Рельсы
class GameMatch
before_create :assign_match_name
private
def assign_match_name
number = GameMatch.where(user_id: user_id, match_type: match_type).count || 0
name = "#{match_type} #{number + 1}"
self.match_name = name
end
end
Опять не проверено.
Я бы предпочел триггерное решение, поскольку обратные вызовы могут быть пропущены или вообще пропущены при вставке через чистый SQL.
Кроме того, я бы добавил столбец «match_number» вместо полного имени, а затем создал бы имя внутри модели, декоратора или помощника представления (более гибкое, I18n), но логика осталась прежней.