这似乎很容易。我正在分批创建具有唯一ID的东西。在数据库上验证了唯一性,并在模型级别进行了验证。如果它存在,是否有快速轨道技巧才能跳过记录?
Box控件
def create
@box = Box.find(params[:box_id])
start = params[:start].scan(/\d/).join('').to_i
params[:quantity].to_i.downto(1) do
UniqueNumber.create(uin: 'ERB' + "%07d" % start, box_id: @box.id, active: true)
start += 1
end
redirect_to @box
end
所以......如果数据库中存在框561 ......我告诉系统,从500开始并添加100个框,我希望它跳过561而不是对我大喊大叫。
我正在考虑在控制器中执行此操作:
params[:quantity].to_i.downto(1) do
if Box.where(uin: 'ERB' + "%07d" % start).blank?
UniqueNumber.create(uin: 'ERB' + "%07d" % start, box_id: @box.id, active: true)
start += 1
end
end
但是我不禁想到模型级别内置了什么东西?
答案 0 :(得分:1)
您建议的方法确实已经可以使用。请参阅rails docs中的find_or_create_by
。
更好的方法,因为您知道要创建的框的范围,将对范围内的所有框执行单个查询,然后从创建循环中排除这些框。这样,在开始插入之前,您只需要进行一次查找。
答案 1 :(得分:1)
由于UniqueNumber
个实例同时包含uin
,active
和box_id
属性,但您仅想要对{{{}进行验证1}} - 您可以使用create_with
链接find_or_create_by
以生成所需的查询:
uin
为了说明,假设UniqueNumber.create_with(box_id: @box.id, active: true).find_or_create_by(uin: 'ERB' + "%07d" % start)
UniqueNumber
uin
已存在:
ERB0000005
假设它是UniqueNumber.first
#=> #<UniqueNumber id: 1, uin: "ERB0000005", box_id: 1, active: true>
表中的唯一条目,则以下情况属实:
unique_numbers
无论您是否对返回的记录执行任何操作(在您的情况下,您不应该这样做),只有在# Creates a NEW record
UniqueNumber.create_with(box_id: 2, active: true).find_or_create_by(uin: "ERB0000004")
#=> #<UniqueNumber id: 2, uin: "ERB0000004", box_id: 2, active: true>
# Returns an EXISTING record
UniqueNumber.create_with(box_id: 2, active: true).find_or_create_by(uin: "ERB0000005")
#=> #<UniqueNumber id: 1, uin: "ERB0000005", box_id: 1, active: true>
被UniqueNumber
查询时,您才会创建新记录还没有存在。因此,在代码中,您可以实现以下内容:
uin
<强>更新强>:
[W]这应该与UniqueNumber.where不同(uin:'ERB'+“%07d”%start,box_id:@ box.id,active:true).first_or_create
答案是是,这显然是不同的。请看以下示例:
params[:quantity].to_i.downto(1) do
UniqueNumber.create_with(box_id: @box.id, active: true).find_or_create_by(uin: 'ERB' + "%07d" % start)
start += 1
end
您希望第二个查询返回现有记录,因为# Returns an EXISTING record
UniqueNumber.where(uin: "ERB0000005", box_id: 1, active: true).find_or_create
#=> #<UniqueNumber id: 1, uin: "ERB0000005", box_id: 1, active: true>
# Creates a NEW record – even though it should not
UniqueNumber.where(uin: "ERB0000005", box_id: 2, active: true).find_or_create
#=> #<UniqueNumber id: 3, uin: "ERB0000005", box_id: 2, active: true>
已存在,但它实际上是在创建新记录。为什么?由于您的uin
子句必须与所有三个属性匹配,但您仅希望与where
匹配。因此,对于uin
,您可能会无意中创建具有相同first_or_create
值的多个UniqueNumber
对象。
但是,如果您要将uin
子句限制为where
属性,则可以将其余属性传递给{{1创作:
uin
在上面的例子中,将first_or_create
与# Returns an EXISTING record
UniqueNumber.where(uin: "ERB0000005").find_or_create(box_id: 3, active: true)
#=> #<UniqueNumber id: 1, uin: "ERB0000005", box_id: 1, active: true>
# Creates a NEW record – as it should
UniqueNumber.where(uin: "ERB0000006").find_or_create(box_id: 3, active: true)
#=> #<UniqueNumber id: 4, uin: "ERB0000006", box_id: 3, active: true>
链接起来与将where
与find_or_create
链接起来的效果相同。我更喜欢后者,因为它更清楚/更明确地发生了什么,IMO,但两者之间的偏好可能归结为学术上的区别。