回答:
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に移行するときは、すべての外部キー参照を同じに保つことが最も簡単です。
ActiveRecord::VERSION::STRING == "3.2.11"
ここに(sqlite3アダプタを使って)持っていて、上記は私にとってはうまくいきます。
試す
a_post = Post.new do |p|
p.id = 10
p.title = 'Test'
p.save
end
それはあなたが探しているものをあなたに与えるはずです。
次のようなものを使用することもできます。
Post.create({:id => 10, :title => 'Test'}, :without_protection => true)
docsで述べられているように、これは大量割り当てセキュリティをバイパスします。
Rails 4の場合:
Post.create(:title => 'Test').update_column(:id, 10)
その他のRails 4つの答えはなかったではない私のために働きます。それらの多くはRailsコンソールを使用して確認すると変更されたように見えましたが、MySQLデータベースの値を確認したところ、変更されていませんでした。他の回答は時々しか機能しませんでした。
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
+ create
を使用するように変更しても、この問題は引き続き発生します。同様に手動で変更しても、この問題が発生します。new
save
id
p.id = 10
常に機能するため、追加のデータベースクエリが必要になりますupdate_column
が、一般的にはを使用して変更しid
ます。これは、開発環境では表示されない可能性があるエラーですが、稼働していると言われている間、運用データベースを静かに破損させる可能性があります。
Post.new.update(id: 10, title: 'Test')
実際、次の作業を行うことがわかりました。
p = Post.new(:id => 10, :title => 'Test')
p.save(false)
validate: false
は、単に渡すのではなく、渡す場合でも機能しますfalse
。ただし、保護された属性の問題は引き続き発生します-私が私の回答で概説した別の方法があります。
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タスクを使用してデフォルトを作成する場合)、自動インクリメントを上書きしたい(タスクを実行するたびにテーブルに同じ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の先頭に配置し、明示的な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"})
このケースは、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">
コールバックは正常に機能します。
幸運を!。
id
Unixタイムスタンプに基づいて作成する必要がありました。私はそれを内部で行いましたbefore_create
。正常に動作します。
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}`
{}
上記のサミュエルの答え(Rails3)のように属性を入れないと私にとってはうまくいきません。
id
まだ10です
id
10として渡されました-それはまさにそれがそうあるべきものです。それがあなたが期待していたものではない場合、例で明確にできますか?