web-dev-qa-db-ja.com

rails

モデルトークンがあります。このトークンには、ユーザーが指定しない場合に限り、自動インクリメントする必要のあるフィールドtoken_number(1001から開始)があります。問題は、ユーザーがこのフィールドを提供するオプションを持っているため、データベースに正確にクエリを実行して最大のtoken_numberを要求できないことです。このフォーラムで1つの答えを見つけましたが、SQLステートメントを実行するよりも良い方法が必要だと確信しています。 Ruby on Rails の非主キーフィールドを自動インクリメントします

18
Wahaj Ali

私にとって興味深い質問です。残念ながら、Railsは列を自動インクリメントする方法を提供しないため、自動化をほとんど行わずにSQLに頼る必要があります。Rails 3.0でこれを試しました。 7 PostgreSQLをデータベースとして使用し、それが機能し、これが役立つことを願っています。

Token_numberのシーケンスを作成しています PGSqlドキュメント

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が設定されていない場合にのみ生成する必要があります。 コールバックについてはこちらをご覧ください 。それで、

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シーケンスが生成され、2番目のトークンには割り当てていることに注意してください。

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 
15
Syed Aslam