有没有办法在创建时覆盖模型的id值?类似的东西:
Post.create(:id => 10, :title => 'Test')
会很理想,但显然不会起作用。
答案 0 :(得分:116)
id只是attr_protected,这就是为什么你不能使用质量赋值来设置它。但是,手动设置时,它只是起作用:
o = SomeObject.new
o.id = 8888
o.save!
o.reload.id # => 8888
我不确定最初的动机是什么,但我在将ActiveHash模型转换为ActiveRecord时这样做。 ActiveHash允许您在ActiveRecord中使用相同的belongs_to语义,但不是进行迁移和创建表,而是在每次调用时产生数据库的开销,您只需将数据存储在yml文件中。数据库中的外键引用yml中的内存中的ID。
ActiveHash非常适用于不经常更改且仅由开发人员更改的选项列表和小型表。因此,当从ActiveHash转到ActiveRecord时,最简单的方法就是保持所有外键引用相同。
答案 1 :(得分:29)
尝试
a_post = Post.new do |p|
p.id = 10
p.title = 'Test'
p.save
end
应该可以为您提供所需的信息。
答案 2 :(得分:27)
您也可以使用以下内容:
Post.create({:id => 10, :title => 'Test'}, :without_protection => true)
尽管如docs中所述,这将绕过质量分配安全性。
答案 3 :(得分:6)
实际上,事实证明做以下工作:
p = Post.new(:id => 10, :title => 'Test')
p.save(false)
答案 4 :(得分:6)
正如Jeff指出的那样,id的行为就好像是attr_protected一样。为防止这种情况,您需要覆盖默认受保护属性的列表。在属性信息可以来自外部的任何地方都要小心。出于某种原因,id字段是默认保护的。
class Post < ActiveRecord::Base
private
def attributes_protected_by_default
[]
end
end
(使用ActiveRecord 2.3.5测试)
答案 5 :(得分:6)
我们可以覆盖attributes_protected_by_default
class Example < ActiveRecord::Base
def self.attributes_protected_by_default
# default is ["id", "type"]
["type"]
end
end
e = Example.new(:id => 10000)
答案 6 :(得分:5)
Post.create!(:title => "Test") { |t| t.id = 10 }
这并不是我通常想要做的事情,但是如果你需要使用一组固定的id填充表格(例如使用rake任务创建默认值时)它会很好用并且你想要覆盖自动递增(这样每次运行任务时,表都会填充相同的ID):
post_types.each_with_index do |post_type|
PostType.create!(:name => post_type) { |t| t.id = i + 1 }
end
答案 7 :(得分:2)
将此 create_with_id 函数放在seeds.rb的顶部,然后使用它来创建需要显式ID的对象。
def create_with_id(clazz, params)
obj = clazz.send(:new, params)
obj.id = params[:id]
obj.save!
obj
end
并像这样使用
create_with_id( Foo, {id:1,name:"My Foo",prop:"My other property"})
而不是使用
Foo.create({id:1,name:"My Foo",prop:"My other property"})
答案 8 :(得分:1)
此案例是一个类似的问题,必须使用某种自定义日期覆盖id
:
# in app/models/calendar_block_group.rb
class CalendarBlockGroup < ActiveRecord::Base
...
before_validation :parse_id
def parse_id
self.id = self.date.strftime('%d%m%Y')
end
...
end
然后:
CalendarBlockGroup.create!(:date => Date.today)
# => #<CalendarBlockGroup id: 27072014, date: "2014-07-27", created_at: "2014-07-27 20:41:49", updated_at: "2014-07-27 20:41:49">
回调功能正常。
祝你好运!
答案 9 :(得分:0)
对于Rails 3,最简单的方法是使用new
进行without_protection
优化,然后使用save
:
Post.new({:id => 10, :title => 'Test'}, :without_protection => true).save
对于种子数据,绕过验证可能是有意义的,你可以这样做:
Post.new({:id => 10, :title => 'Test'}, :without_protection => true).save(validate: false)
我们实际上在ActiveRecord :: Base中添加了一个辅助方法,该方法在执行种子文件之前立即声明:
class ActiveRecord::Base
def self.seed_create(attributes)
new(attributes, without_protection: true).save(validate: false)
end
end
现在:
Post.seed_create(:id => 10, :title => 'Test')
对于Rails 4,您应该使用StrongParams而不是受保护的属性。如果是这种情况,您只需分配并保存,而不会将任何标记传递给new
:
Post.new(id: 10, title: 'Test').save # optionally pass `{validate: false}`
答案 10 :(得分:0)
在使用Postgresql 9.5.3的Rails 4.2.1中,Post.create(:id => 10, :title => 'Test')
只要没有id = 10的行就可以正常工作。
答案 11 :(得分:0)
你可以通过sql:
插入id arr = record_line.strip.split(",")
sql = "insert into records(id, created_at, updated_at, count, type_id, cycle, date) values(#{arr[0]},#{arr[1]},#{arr[2]},#{arr[3]},#{arr[4]},#{arr[5]},#{arr[6]})"
ActiveRecord::Base.connection.execute sql