Как добавить последовательности в перенос и использовать их в модели?
Я хочу иметь модель "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).
Знаете ли вы хороший способ интегрировать последовательности? Или есть хороший плагин?
Приветствую всех ответов!
Ответы
Ответ 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.