在ActiveRecord中创build重写id
是否有任何方式来重写创build模型的ID值? 就像是:
Post.create(:id => 10, :title => 'Test')
将是理想的,但显然不会工作。
ID只是attr_protected,这就是为什么你不能使用批量分配来设置它。 但是,手动设置时,它只是工作:
o = SomeObject.new o.id = 8888 o.save! o.reload.id # => 8888
我不确定最初的动机是什么,但是我在将ActiveHash模型转换为ActiveRecord时执行此操作。 ActiveHash允许您在ActiveRecord中使用相同的belongs_to语义,但是不必进行迁移和创build表,并且每次调用都会导致数据库的开销,您只需将数据存储在yml文件中即可。 数据库中的外键引用yml中的内存中的id。
ActiveHash非常适合那些不经常更换,而且只能由开发人员更改的挑选表和小表。 所以当从ActiveHash到ActiveRecord时,最简单的办法就是保持所有的外键引用都是一样的。
尝试
a_post = Post.new do |p| p.id = 10 p.title = 'Test' p.save end
这应该给你你想要的。
你也可以使用这样的东西:
Post.create({:id => 10, :title => 'Test'}, :without_protection => true)
虽然如文件所述 ,这将绕过大规模的分配安全。
对于Rails 4:
Post.create(:title => 'Test').update_column(:id, 10)
其他Rails 4答案没有为我工作。 他们中的许多似乎改变时检查使用Rails控制台,但是当我检查MySQL数据库中的值,他们保持不变。 其他答案有时只有工作。
至less对于MySQL来说,除非你使用update_column
否则在自动增量id号下面分配一个id
是行不通的。 例如,
p = Post.create(:title => 'Test') p.id => 20 # 20 was the id the auto increment gave it p2 = Post.create(:id => 40, :title => 'Test') p2.id => 40 # 40 > the next auto increment id (21) so allow it p3 = Post.create(:id => 10, :title => 'Test') p3.id => 10 # Go check your database, it may say 41. # Assigning an id to a number below the next auto generated id will not update the db
如果你改变create
使用new
+ save
你将仍然有这个问题。 手动更改id
像p.id = 10
也会产生这个问题。
一般来说,我会使用update_column
更改id
即使它花费额外的数据库查询,因为它会一直工作。 这是一个错误,可能在您的开发环境中不会显示,但可以悄悄地破坏您的生产数据库,一直说它正在工作。
事实上,结果是做了以下工作:
p = Post.new(:id => 10, :title => 'Test') p.save(false)
正如Jeff指出的那样,id的行为就好像是attr_protected。 为了防止这种情况,您需要覆盖默认的受保护属性列表。 在属性信息可以来自外部的任何地方要小心。 ID字段是默认保护的原因。
class Post < ActiveRecord::Base private def attributes_protected_by_default [] end end
(使用ActiveRecord 2.3.5进行testing)
我们可以覆盖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)
Post.create!(:title => "Test") { |t| t.id = 10 }
这并不意味着我通常想要做的事情,但是如果你需要用一组固定的id来填充一个表格(比如使用rake任务创build默认值),那么它就会工作的很好想要覆盖自动递增(以便每次运行任务时,表格都使用相同的ID填充):
post_types.each_with_index do |post_type| PostType.create!(:name => post_type) { |t| t.id = i + 1 } end
把这个create_with_id函数放在你的seeds.rb的顶部,然后用它来做你的对象创build,在需要显式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"})
这种情况是一个类似的问题,必须用一种自定义date来覆盖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">
callback工作正常。
祝你好运!。
在使用Postgresql 9.5.3的Rails 4.2.1中,只要没有id = 10的行, Post.create(:id => 10, :title => 'Test')
可以工作。
对于Rails 3,最简单的方法是在without_protection
细化中使用new
,然后save
:
Post.new({:id => 10, :title => 'Test'}, :without_protection => true).save
对于种子数据,绕过可以这样做的validation是有意义的:
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}`
你可以通过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