【问题标题】:Rails: create unique auto-incremental id based on sibling recordsRails:根据兄弟记录创建唯一的自动增量ID
【发布时间】:2019-06-11 05:07:03
【问题描述】:

我的rails项目中有三个模型,分别是User、Game、Match

用户可以在每场比赛中创建许多比赛 所以匹配的表结构就像

            table name: game_matches

+----+---------+---------+-------------+------------+
| id | user_id | game_id | match_type  | match_name |
+----+---------+---------+-------------+------------+
|  1 |       1 |       1 | practice    |            |
|  2 |       3 |       2 | challenge   |            |
|  3 |       1 |       1 | practice    |            |
|  4 |       3 |       2 | challenge   |            |
|  5 |       1 |       1 | challenge   |            |
|  6 |       3 |       2 | practice    |            |
+----+---------+---------+-------------+------------+

我想根据 user_id、game_id 和 match_type 值生成 match_name

for example match_name should be create like below


+----+---------+---------+-------------+-------------+
| id | user_id | game_id | match_type  | match_name  |
+----+---------+---------+-------------+-------------+
|  1 |       1 |       1 | practice    | Practice 1  |
|  2 |       3 |       2 | challenge   | Challenge 1 |
|  3 |       1 |       1 | practice    | Practice 2  |
|  4 |       3 |       2 | challenge   | Challenge 2 |
|  5 |       1 |       1 | challenge   | Challenge 1 |
|  6 |       3 |       2 | practice    | Practice 1  |
+----+---------+---------+-------------+-------------+

在创建新记录期间,如何在我的 rails 模型中实现此自动增量值。 任何帮助建议表示赞赏。

提前致谢。

【问题讨论】:

    标签: ruby-on-rails ruby database


    【解决方案1】:

    我看到有两种方法可以解决这个问题:

    • 数据库:触发器
    • 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)中构造名称,但背后的逻辑保持不变。

    【讨论】:

      【解决方案2】:

      您应该为这些user 检索最后一个match_name game,拆分它,增加计数器并用空格连接回来。不幸的是,SQL 不提供SPLIT 函数,所以有点像下面这样是一个好的开始:

      SELECT match_name
      FROM match_name
      WHERE user_id = 3
        AND game_id = 2
      ORDER BY id DESC
      LIMIT 1
      

      我实际上最好创建一个INT 类型的match_number 列,以按类型保留数字通过将类型与此数字连接来生成名称。

      【讨论】:

      • 所以你建议我为特定的用户和游戏寻找以前的比赛名称,并在此基础上生成新的比赛名称?
      • 建议存储match_typematch_number并即时构造match_name,因为在这种情况下你不需要解析之前的@987654331 @ 甚至可以从 DB TRIGGER 实现它。但无论如何,都需要查找,是的。
      • @AlekseiMatiushkin 我认为他不需要解析以前的名称,因为名称只是由相同类型的游戏数量和用户 + 1 构成。不过,存储数字而不是名字更好恕我直言(见我的回答)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-06-24
      • 1970-01-01
      • 2016-09-26
      • 2015-02-24
      • 1970-01-01
      • 2016-09-27
      • 2015-08-28
      相关资源
      最近更新 更多