Подтвердить что ты не робот

Как добавить последовательности в перенос и использовать их в модели?

Я хочу иметь модель "Customer" с обычным первичным ключом и другим столбцом для хранения пользовательского "номера клиента". Кроме того, я хочу, чтобы db обрабатывал номера клиентов по умолчанию. Я думаю, что определение последовательности - лучший способ сделать это. Я использую PostgreSQL. Посмотрите мою миграцию:

class CreateAccountsCustomers < ActiveRecord::Migration
  def up

    say "Creating sequenze for customer number starting at 1002"
    execute 'CREATE SEQUENCE customer_no_seq START 1002;'

    create_table :accounts_customers do |t|
      t.string :type
      t.integer :customer_no, :unique => true
      t.integer :salutation, :limit => 1
      t.string :cp_name_1
      t.string :cp_name_2
      t.string :cp_name_3
      t.string :cp_name_4
      t.string :name_first, :limit => 55
      t.string :name_last, :limit => 55
      t.timestamps
    end

    say "Adding NEXTVAL('customer_no_seq') to column cust_id"
    execute "ALTER TABLE accounts_customers ALTER COLUMN customer_no SET DEFAULT NEXTVAL('customer_no_seq');"

  end

  def down
    drop_table :accounts_customers
    execute 'DROP SEQUENCE IF EXISTS customer_no_seq;'
  end

end

Если вы знаете лучший подход, подобный рельсам, чтобы добавлять последовательности, было бы замечательно сообщить мне.

Теперь, если я сделаю что-то вроде

cust = Accounts::Customer.new
cust.save

поле customer_no не заполняется предварительно следующим значением последовательности (должно быть 1002).

Знаете ли вы хороший способ интегрировать последовательности? Или есть хороший плагин? Приветствую всех ответов!

4b9b3361

Ответ 1

У меня нет предложений для более "путей рельсов" для обработки пользовательских последовательностей, но я могу сказать вам, почему поле customer_no, похоже, не заполняется после сохранения.

Когда ActiveRecord сохраняет новую запись, оператор SQL возвращает только идентификатор новой записи, а не все ее поля, вы можете видеть, где это происходит в текущем источнике рельсов здесь https://github.com/rails/rails/blob/cf013a62686b5156336d57d57cb12e9e17b5d462/activerecord/lib/active_record/persistence.rb#L313

Чтобы увидеть значение, которое вам нужно будет перезагрузить объект...

cust = Accounts::Customer.new
cust.save
cust.reload

Если вы всегда этого хотите, подумайте о том, чтобы добавить к вашему классу класс add_create...

class Accounts::Customer < ActiveRecord::Base
  after_create :reload
end

Ответ 2

Я считаю, что ответ роботов неверен.

Я попытался реализовать это в своем приложении (точно так же env: RoR + PostgreSQL), и я узнал, что когда save выдается на RoR с объектом, имеющим пустые атрибуты, он пытается выполнить INSERT на в которой указывается, что для всех значений VALUES должно быть установлено значение NULL. Проблема заключается в том, как PostgreSQL обрабатывает NULL: в этом случае будет создана новая строка, но все значения будут пустыми, то есть значение DEFAULT будет проигнорировано. Если save написал только атрибуты инструкции INSERT, заполненные на RoR, это будет нормально работать.

Другими словами, и фокусировка только на атрибутах type и customer_no, упомянутых выше, так ведет себя PostgreSQL:

СИТУАЦИЯ 1:

INSERT INTO accounts_customers (type, customer_no) VALUES (NULL, NULL);

(так работает Rails 'save)

Результат: новая строка с пустым type и пустой customer_no

СИТУАЦИЯ 2:

INSERT INTO accounts_customers (type) VALUES (NULL);

Результат: новая строка с пустыми type и customer_no, заполненная последовательностью NEXTVAL

У меня есть поток об этом, проверьте его:

Ruby on Rails + PostgreSQL: использование настраиваемых последовательностей

Ответ 3

У меня возникла аналогичная проблема, но я также положил :null => false на поле, прыгая, что он будет автоматически заполнен с nextval.

Ну, в моем случае AR все еще пыталась вставить NULL, если в запросе не было атрибута, и это привело к исключению из-за невязкого ограничения.

Вот мой способ обхода. Я просто удалил этот ключ атрибута из @attributes и @changed_attributes, и в этом случае postgres правильно помещают ожидаемую последовательность nextval.

Я поместил это в модель:

before_save do
  if (@attributes["customer_no"].nil? || @attributes["customer_no"].to_i == 0)
    @attributes.delete("customer_no")
    @changed_attributes.delete("customer_no")
  end
end

Rails 3.2/Postgres 9.1

Ответ 4

Если вы используете PostgreSQL, проверьте, что я написал gem, pg_sequencer:

https://github.com/code42/pg_sequencer

Он предоставляет DSL для создания, удаления и изменения последовательностей в миграции ActiveRecord.