【问题标题】:Generate an auto increment field in rails在rails中生成一个自动增量字段
【发布时间】:2012-03-19 19:14:37
【问题描述】:

我有一个模型 Token,它有一个我需要自动递增的字段 token_number(从 1001 开始),当且仅当用户不提供它时。问题是,由于用户可以选择提供这个字段,我不能准确地查询数据库并要求最大的 token_number。我在这个论坛上找到了一个答案,但我很确定必须有比执行 SQL 语句更好的方法吗? Auto increment a non-primary key field in Ruby on Rails

【问题讨论】:

    标签: ruby-on-rails auto-increment rails-migrations


    【解决方案1】:

    另一种选择是在您的 postgresql 中将 nextval 设置为默认值

    这使我们不需要编写回调

    class CreateTokens < ActiveRecord::Migration
    
      def self.up
        create_table :tokens do |t|
          t.string :name
          t.integer :token_number
    
          t.timestamps
        end
    
        execute "CREATE SEQUENCE tokens_token_number_seq START 1001"
        execute "ALTER TABLE tokens ALTER COLUMN token_number SET DEFAULT NEXTVAL('tokens_token_number_seq')"
      end
    
      def self.down
        drop_table :tokens
    
        execute "DROP SEQUENCE tokens_token_number_seq"
      end
    end
    

    【讨论】:

    • 此方法工作正常,但当我创建新记录时,它不会直接返回 auto_increment 字段:#&lt;Device id: 3, name: "a23234fsdg", token_number: nil, created_at: "2021-05-28 11:30:36.238238000 +0200", updated_at: "2021-05-28 11:30:36.238238000 +0200"&gt;,即使它直接插入数据库。有没有办法在不对新对象调用“重新加载”的情况下获取该字段?
    • @Joe 是的,如果你通过控制台创建它,create! 的返回值为 nil,让它也返回自动生成值是通过回调或修补 active record persistence 但我认为你不是需要这样做,因为在网络中它可以工作/自动重新加载以某种方式
    • 也检查这个建议在测试或控制台中重新加载stackoverflow.com/questions/5309430/…
    【解决方案2】:

    对我来说很有趣的问题。不幸的是,rails 没有提供自动增加列的方法,所以我们必须求助于几乎没有自动化的 SQL。我在 Rails 3.0.7 中使用 PostgreSQL 作为我的数据库进行了尝试,它可以工作,希望这会有用:

    为token_number PGSql Documentation创建序列

    class CreateTokens < ActiveRecord::Migration
    
      def self.up
        create_table :tokens do |t|
          t.string :name
          t.integer :token_number
    
          t.timestamps
        end
    
        execute "CREATE SEQUENCE tokens_token_number_seq START 1001"
      end
    
      def self.down
        drop_table :tokens
    
        execute "DROP SEQUENCE tokens_token_number_seq"
      end
    end
    

    现在,由于用户手动设置了 token_number 的可能性,我们只需要在没有设置 token_number 的情况下生成它。 Read about Callbacks here。有了这个,

    class Token < ActiveRecord::Base
      # Generate the sequence no if not already provided.
      before_validation(:on => :create) do
        self.application_no = next_seq unless attribute_present?("application_no")
      end
    
      private
        def next_seq(column = 'application_no')
          # This returns a PGresult object [http://rubydoc.info/github/ged/ruby-pg/master/PGresult]
          result = Token.connection.execute("SELECT nextval('tokens_token_number_seq')")
    
          result[0]['nextval']
        end 
    end
    

    样本运行。请注意,对于第一个令牌,我没有设置 token_number,它会生成 token_number 序列,而我正在分配第二个。

    token = Token.new
    # => #<Token id: nil, name: nil, token_number: nil, created_at: nil, updated_at: nil> 
    
    token.save
      SQL (0.8ms)  BEGIN
      SQL (1.7ms)  SELECT nextval('tokens_token_number_seq')
      SQL (6.6ms)   SELECT tablename
     FROM pg_tables
     WHERE schemaname = ANY (current_schemas(false))
    
      SQL (33.7ms)  INSERT INTO "tokens" ("name", "token_number", "created_at", "updated_at") VALUES (NULL, 1001, '2012-03-02 12:04:00.848863', '2012-03-02 12:04:00.848863') RETURNING "id"
      SQL (15.9ms)  COMMIT
    # => true 
    
    token = Token.new
    # => #<Token id: nil, name: nil, token_number: nil, created_at: nil, updated_at: nil> 
    
    token.token_number = 3000
    # => 3000 
    
    token.save
      SQL (0.8ms)  BEGIN
      SQL (1.5ms)  INSERT INTO "tokens" ("name", "token_number", "created_at", "updated_at") VALUES (NULL, 3000, '2012-03-02 12:04:22.924834', '2012-03-02 12:04:22.924834') RETURNING "id"
      SQL (19.2ms)  COMMIT
    # => true 
    

    【讨论】:

    • 是否有可能以某种方式将默认值与nextval 结合使用以避免使用回调?
    猜你喜欢
    • 2019-07-26
    • 2018-12-12
    • 2013-05-09
    • 2011-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-12
    • 2016-09-27
    相关资源
    最近更新 更多