Reputation: 1009
I have a Payment
model with an attribute invoice_nr
. This attribute should increment (by 1) before it's saved. It's important that all payments
have a unique invoice_nr
.
I could use a before_save
callback that increments invoice_nr
by 1 relative to Payment.maximum("invoice_nr")
:
class Payment < ActiveRecord::Base
before_save :increment_invoice_nr
private
def increment_invoice_nr
self.invoice_nr = Payment.maximum("invoice_nr") + 1
end
end
But I think this doesn't ensure the uniqueness of invoice_nr
. If two payments
get saved at the same time they theoretically could get the same invoice_nr
...right?
It's okay if there are gaps in between invoice_nrs
, but you'll get bonus points if you know a way to prevent this :)
EDIT
Some folks suggest using the auto increment feature that most databases have. This works but it would tie my app to the specific database I'm using. Therefore the auto increment logic belongs in the app imo.
Upvotes: 2
Views: 1725
Reputation: 47482
If you have a primary key with auto increment following should work
class Payment < ActiveRecord::Base
after_save :increment_invoice_nr
private
def increment_invoice_nr
some_high_integer = 10000000
self.update_attribute('invoice_nr', self.id + some_high_integer)
end
end
Upvotes: 1
Reputation: 826
You can try this one.
def increment_invoice_nr
invoice_nr_arr = Payment.all.map(&:invoice_nr)
invoice = Payment.maximum("invoice_nr")
until invoice_nr_arr.include?(invoice) == false
invoice += 1
end
self.invoice_nr = invoice
end
This method will first collect all invoice_nr. Then it will check the incremented invoice_nr includes/exists in your payments table or not. If it exists then it will go on incrementing the invoice_nr by 1 till it gets the unique invoice_nr.
Upvotes: 0
Reputation: 1675
You can use a database sequence.
migration:
def up
execute 'CREATE SEQUENCE tr_num_seq START 10000000;'
end
model:
class model < ActiveRecord:Base
after_initialize :set_omd_id
def set_unique_number
if self.tr_number.nil?
self.tr_number = ActiveRecord::Base.connection.select_value("select nextval('tr_number_seq')")
end
end
end
Everytime a model object is created, it will set a unqiue "invoice number id" if it is not already set
Upvotes: 2
Reputation: 81
You can have a unique validation in your model.That will prevent it save duplicate values. In your payment method add the following:
validates :invoice_nr, :uniqueness => true
You can also use auto increment
if you are using mysql or other RDBMS
Upvotes: 0
Reputation: 9110
I suggest using the auto increment feature from the RDBMS of your choice. Using it you wouldn't have to do it yourself and it'd be reliable.
Upvotes: 0