Ruby-on-rails 在 ActiveRecord 中创建时覆盖 id

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/431617/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 20:54:16  来源:igfitidea点击:

Overriding id on create in ActiveRecord

ruby-on-railsactiverecord

提问by Codebeef

Is there any way of overriding a model's id value on create? Something like:

有没有办法在创建时覆盖模型的 id 值?就像是:

Post.create(:id => 10, :title => 'Test')

would be ideal, but obviously won't work.

将是理想的,但显然行不通。

回答by

id is just attr_protected, which is why you can't use mass-assignment to set it. However, when setting it manually, it just works:

id 只是 attr_protected,这就是为什么你不能使用 mass-assignment 来设置它。但是,手动设置时,它只是有效:

o = SomeObject.new
o.id = 8888
o.save!
o.reload.id # => 8888

I'm not sure what the original motivation was, but I do this when converting ActiveHash models to ActiveRecord. ActiveHash allows you to use the same belongs_to semantics in ActiveRecord, but instead of having a migration and creating a table, and incurring the overhead of the database on every call, you just store your data in yml files. The foreign keys in the database reference the in-memory ids in the yml.

我不确定最初的动机是什么,但我在将 ActiveHash 模型转换为 ActiveRecord 时这样做了。ActiveHash 允许您在 ActiveRecord 中使用相同的belongs_to 语义,但无需迁移和创建表,并在每次调用时产生数据库开销,您只需将数据存储在 yml 文件中。数据库中的外键引用 yml 中的内存 ID。

ActiveHash is great for picklists and small tables that change infrequently and only change by developers. So when going from ActiveHash to ActiveRecord, it's easiest to just keep all of the foreign key references the same.

ActiveHash 非常适合不经常更改且仅由开发人员更改的选项列表和小表。因此,当从 ActiveHash 到 ActiveRecord 时,最简单的方法是保持所有外键引用相同。

回答by PJ Davis

Try

尝试

a_post = Post.new do |p| 
  p.id = 10
  p.title = 'Test'
  p.save
end

that should give you what you're looking for.

这应该给你你正在寻找的东西。

回答by Samuel Heaney

You could also use something like this:

你也可以使用这样的东西:

Post.create({:id => 10, :title => 'Test'}, :without_protection => true)

Although as stated in the docs, this will bypass mass-assignment security.

尽管如文档中所述,这将绕过批量分配安全性。

回答by Rick Smith

For Rails 4:

对于 Rails 4:

Post.create(:title => 'Test').update_column(:id, 10)

Other Rails 4 answers did notwork for me. Many of them appearedto change when checking using the Rails Console, but when I checked the values in MySQL database, they remained unchanged. Other answers only worked sometimes.

其他轨道4个回答并没有对我来说有效。在使用 Rails 控制台检查时,它们中的许多似乎发生了变化,但是当我检查 MySQL 数据库中的值时,它们保持不变。其他答案有时只管用。

For MySQL at least, assigning an idbelow the auto increment id number does notwork unless you use update_column. For example,

对于MySQL至少,分配一个id低于自动增量ID号并没有工作,除非你使用update_column。例如,

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

If you change createto use new+ saveyou will still have this problem. Manually changing the idlike p.id = 10also produces this problem.

如果你create改为使用new+save你仍然会遇到这个问题。手动更改idlikep.id = 10也会产生此问题。

In general, I would use update_columnto change the ideven though it costs an extra database query because it will work all the time. This is an error that might not show up in your development environment, but can quietly corrupt your production database all the while saying it is working.

通常,我会使用update_column更改 ,id即使它需要额外的数据库查询,因为它会一直工作。这是一个错误,可能不会出现在您的开发环境中,但会一直悄悄地破坏您的生产数据库,同时表明它正在工作。

回答by Codebeef

Actually, it turns out that doing the following works:

实际上,事实证明,执行以下操作是有效的:

p = Post.new(:id => 10, :title => 'Test')
p.save(false)

回答by Nic Benders

As Jeff points out, id behaves as if is attr_protected. To prevent that, you need to override the list of default protected attributes. Be careful doing this anywhere that attribute information can come from the outside. The id field is default protected for a reason.

正如杰夫指出的那样, id 表现得好像是 attr_protected。为了防止这种情况,您需要覆盖默认受保护的属性列表。在属性信息可能来自外部的任何地方执行此操作时要小心。由于某种原因, id 字段默认受到保护。

class Post < ActiveRecord::Base

  private

  def attributes_protected_by_default
    []
  end
end

(Tested with ActiveRecord 2.3.5)

(使用 ActiveRecord 2.3.5 测试)

回答by user510319

we can override attributes_protected_by_default

我们可以覆盖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)

回答by Sean Cameron

Post.create!(:title => "Test") { |t| t.id = 10 }

This doesn't strike me as the sort of thing that you would normally want to do, but it works quite well if you need to populate a table with a fixed set of ids (for example when creating defaults using a rake task) and you want to override auto-incrementing (so that each time you run the task the table is populate with the same ids):

这在我看来并不是您通常想要做的那种事情,但是如果您需要使用一组固定的 id 填充表(例如,在使用 rake 任务创建默认值时)并且您想要覆盖自动递增(以便每次运行任务时表都填充相同的 ID):

post_types.each_with_index do |post_type|
  PostType.create!(:name => post_type) { |t| t.id = i + 1 }
end

回答by Darren Hicks

Put this create_with_idfunction at the top of your seeds.rb and then use it to do your object creation where explicit ids are desired.

将此create_with_id函数放在您的 seed.rb 的顶部,然后使用它来创建需要显式 ID 的对象。

def create_with_id(clazz, params)
obj = clazz.send(:new, params)
obj.id = params[:id]
obj.save!
    obj
end

and use it like this

并像这样使用它

create_with_id( Foo, {id:1,name:"My Foo",prop:"My other property"})

instead of using

而不是使用

Foo.create({id:1,name:"My Foo",prop:"My other property"})

Foo.create({id:1,name:"My Foo",prop:"My other property"})

回答by CristianOrellanaBak

This case is a similar issue that was necessary overwrite the idwith a kind of custom 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

And then :

进而 :

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">

Callbacks works fine.

回调工作正常。

Good Luck!.

祝你好运!。