想写一个 model,有一列是 number,这列需要自动生成值就像主键一样。如何利用 rails 的特性自动生成一个连续的 number?也可以和主键值一样,只不过是一个 string 类型的列。
例如我存入一个 model,id 会是 1,此时 number 也会存入 00001.当存入第二个 model 的时候 id 是 2 而 number 自动存入 00002
谢谢各位。
不会。反正不能取数据库里面最后一条数据,然后加一保存,同时 2 个并发就会出现重复。
或者直接用 id,用的时候转换成 string,或者直接做个虚拟字段(应该叫虚拟属性还是啥滴),里面把 id 根据逻辑要求转换成对应的字符。
class App < ActiveRecord::Base
after_save :generate_number
private
def generate_number
if self.number.nil?
self.number = self.id.to_s
self.save
end
end
end
class CreateNumberings < ActiveRecord::Migration
def self.up
create_table :numberings do |t|
t.column :name,:string #名称
t.column :types,:string #类型
t.column :template,:string,:default=>'' # 模板
t.text :note
end
end
def self.down
drop_table :numberings
end
end
class Numbering < ActiveRecord::Base
#根据类型产生一个新的编码,同时保存到数据库中
def self.new_number!(type)
numbering = self.get_numbering(type)
number = numbering.template.next_number
numbering.update_attributes(:template=> number)
number
end
# #根据类型产生一个新的编码
def self.new_number(type)
numbering = self.get_numbering(type)
numbering.template.next_number
end
private
def self.get_numbering(type)
numbering = Numbering.find_or_create_by_types(type)
if numbering.template.blank?
# model = type.to_s.singularize.camelize.constantize
model = type.to_s.camelize.constantize
numbering.update_attributes(:name=>model.class_name,:template=>"#{type}00000")
end
numbering
end
end
class NilClass
def next_number(qty=1)
end
def -(number)
end
def region_to(qty=1)
end
def region_sizeof(number)
end
end
class String
#得到字符串的下一个编号,是对字符串中数值区域的值的增加,
#如果该字符串没有数值区域,那么返回原字符串
#例如
# 'abc'.next_number -> abc
# 'abc100'.next_number ->abc101
# '100'.next_number ->101
# '100abc'.next_number ->101abc
# '0100abc'.next_number ->0101abc
# '0099abc'.next_number ->0100abc
# "abc100".next_number(10) ->"abc110"
# "100abc".next_number(10) ->"110abc"
# "100abc100".next_number(10) ->"100abc110"
def next_number(qty=1)
self.reverse.sub(/(0*)\d+/) { |match| (match.reverse.to_i+qty.to_i).to_s.rjust(match.length,"0").reverse }.reverse
end
#两个字符串相减,得到两个字符串之间相减的数量
#例如:
# "abc"-"abc" ->0
# "abc110"-"abc100" ->10
# "110abc"-"100abc" ->10
def -(number)
match1 = /\d+/.match(self)
match2 = /\d+/.match(number)
(match1 && match2) ? match1[0].to_i - match2[0].to_i : 0
end
#从当前区段得到下一区段,区段的间隔由qty指定,区段包括首尾部分
#例如:
# "a100".region_to(1) ->"a100"
# "a100".region_to(2) ->"a101"
def region_to(qty=1)
raise "参数不允许为0" if qty==0
next_number(qty<0? qty+1: qty-1)
end
#计算两个区段之间的大小,区段是包含首尾部分
#例如:
# "a100".region_sizeof("a100") ->1
# "a100".region_sizeof("a101") ->2
def region_sizeof(number)
(self-number).abs+1
end
end
上面 3 个代码块是核心模块了,哎,5 年前的东西了。杨总的结晶
class Name < ActiveRecord::Base
attr_accessible :blog
before_validation :show_id
after_validation :show_id
before_save :show_id
before_create :show_id
after_create :show_id
after_save :show_id
private
def show_id
p self.id
end
end
$ spring rails runner 'Name.create'
nil
nil
nil
nil
4
4
按照 http://guides.rubyonrails.org/active_record_validations_callbacks.html#available-callbacks 的 callbacks 顺序,在 save 之后就生成了 id。包括 around_create
和 around_save
的后半段代码。
#17 楼 @evil850209 嗯,@blacktulip 的方案可以稍微精简一下,并按你要求的 string 格式来:
def generate_number
update_attribute(:number, "%05d" % id) unless number
end