Gibt es eine Möglichkeit, den ID-Wert eines Modells beim Erstellen zu überschreiben? Etwas wie:
Post.create(:id => 10, :title => 'Test')
wäre ideal, wird aber offensichtlich nicht funktionieren.
Gibt es eine Möglichkeit, den ID-Wert eines Modells beim Erstellen zu überschreiben? Etwas wie:
Post.create(:id => 10, :title => 'Test')
wäre ideal, wird aber offensichtlich nicht funktionieren.
Antworten:
id ist nur attr_protected, weshalb Sie die Massenzuweisung nicht verwenden können, um sie festzulegen. Wenn Sie es jedoch manuell einstellen, funktioniert es einfach:
o = SomeObject.new
o.id = 8888
o.save!
o.reload.id # => 8888
Ich bin mir nicht sicher, was die ursprüngliche Motivation war, aber ich mache das, wenn ich ActiveHash-Modelle in ActiveRecord konvertiere. Mit ActiveHash können Sie in ActiveRecord dieselbe Semantik zur Zugehörigkeit verwenden. Anstatt jedoch eine Migration durchzuführen und eine Tabelle zu erstellen und bei jedem Aufruf den Overhead der Datenbank zu verursachen, speichern Sie Ihre Daten einfach in yml-Dateien. Die Fremdschlüssel in der Datenbank verweisen auf die speicherinternen IDs in der yml.
ActiveHash eignet sich hervorragend für Auswahllisten und kleine Tabellen, die sich nur selten und nur von Entwicklern ändern. Wenn Sie also von ActiveHash zu ActiveRecord wechseln, ist es am einfachsten, alle Fremdschlüsselreferenzen gleich zu halten.
ActiveRecord::VERSION::STRING == "3.2.11"
hier (mit dem sqlite3-Adapter) und das oben genannte funktioniert für mich.
Versuchen
a_post = Post.new do |p|
p.id = 10
p.title = 'Test'
p.save
end
das sollte dir geben, wonach du suchst.
Sie könnten auch so etwas verwenden:
Post.create({:id => 10, :title => 'Test'}, :without_protection => true)
Obwohl dies in den Dokumenten angegeben ist , wird dadurch die Sicherheit der Massenzuweisung umgangen.
Für Schienen 4:
Post.create(:title => 'Test').update_column(:id, 10)
Andere Rails 4-Antworten haben bei mir nicht funktioniert. Viele von ihnen schienen sich bei der Überprüfung mit der Rails-Konsole zu ändern, aber als ich die Werte in der MySQL-Datenbank überprüfte, blieben sie unverändert. Andere Antworten funktionierten nur manchmal.
Zumindest für MySQL id
funktioniert das Zuweisen einer ID-Nummer unter der automatischen Inkrementierung nur , wenn Sie sie verwenden update_column
. Beispielsweise,
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
Wenn Sie create
zu new
+ wechseln , tritt save
dieses Problem weiterhin auf. Manuelles Ändern der id
Artp.id = 10
erzeugt ebenfalls dieses Problem.
Im Allgemeinen würde ich das update_column
ändern id
, obwohl es eine zusätzliche Datenbankabfrage kostet, da es die ganze Zeit funktioniert. Dies ist ein Fehler, der möglicherweise nicht in Ihrer Entwicklungsumgebung angezeigt wird, aber Ihre Produktionsdatenbank stillschweigend beschädigen kann, während Sie sagen, dass sie funktioniert.
Post.new.update(id: 10, title: 'Test')
Tatsächlich stellt sich heraus, dass Folgendes funktioniert:
p = Post.new(:id => 10, :title => 'Test')
p.save(false)
validate: false
, anstatt einfach false
. Sie stoßen jedoch immer noch auf das Problem mit geschützten Attributen - es gibt einen separaten Weg, um das zu umgehen, was ich in meiner Antwort beschrieben habe.
Wie Jeff betont, verhält sich id so, als wäre es attr_protected. Um dies zu verhindern, müssen Sie die Liste der standardmäßig geschützten Attribute überschreiben. Seien Sie überall dort vorsichtig, wo Attributinformationen von außen kommen können. Das ID-Feld ist aus einem bestimmten Grund standardmäßig geschützt.
class Post < ActiveRecord::Base
private
def attributes_protected_by_default
[]
end
end
(Getestet mit ActiveRecord 2.3.5)
Wir können Attribute_protected_by_default überschreiben
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 }
Dies scheint mir nicht das zu sein, was Sie normalerweise tun möchten, aber es funktioniert ganz gut, wenn Sie eine Tabelle mit einem festen Satz von IDs füllen müssen (z. B. wenn Sie Standardeinstellungen mit einer Rechenaufgabe erstellen) und Sie Sie möchten die automatische Inkrementierung überschreiben (damit die Tabelle jedes Mal, wenn Sie die Aufgabe ausführen, mit denselben IDs gefüllt wird):
post_types.each_with_index do |post_type|
PostType.create!(:name => post_type) { |t| t.id = i + 1 }
end
Fügen Sie diese Funktion create_with_id oben in Ihre seeds.rb ein und verwenden Sie sie dann, um Ihre Objekterstellung durchzuführen, wenn explizite IDs gewünscht werden.
def create_with_id(clazz, params)
obj = clazz.send(:new, params)
obj.id = params[:id]
obj.save!
obj
end
und benutze es so
create_with_id( Foo, {id:1,name:"My Foo",prop:"My other property"})
anstatt zu verwenden
Foo.create({id:1,name:"My Foo",prop:"My other property"})
Dieser Fall ist ein ähnliches Problem, das erforderlich war, um das id
mit einer Art benutzerdefiniertem Datum zu überschreiben :
# 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
Und dann :
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">
Rückrufe funktionieren gut.
Viel Glück!.
id
auf Unix basierenden Zeitstempel erstellen . Ich habe das drinnen gemacht before_create
. Funktioniert gut.
Für Rails 3 ist der einfachste Weg, dies zu tun, die Verwendung new
mit der without_protection
Verfeinerung und dann save
:
Post.new({:id => 10, :title => 'Test'}, :without_protection => true).save
Für Seed-Daten kann es sinnvoll sein, die Validierung zu umgehen, was Sie folgendermaßen tun können:
Post.new({:id => 10, :title => 'Test'}, :without_protection => true).save(validate: false)
Wir haben ActiveRecord :: Base tatsächlich eine Hilfsmethode hinzugefügt, die unmittelbar vor der Ausführung von Seed-Dateien deklariert wird:
class ActiveRecord::Base
def self.seed_create(attributes)
new(attributes, without_protection: true).save(validate: false)
end
end
Und nun:
Post.seed_create(:id => 10, :title => 'Test')
Für Rails 4 sollten Sie StrongParams anstelle von geschützten Attributen verwenden. In diesem Fall können Sie einfach zuweisen und speichern, ohne Flags an new
folgende Adresse zu übergeben :
Post.new(id: 10, title: 'Test').save # optionally pass `{validate: false}`
{}
wie Samuels Antwort oben (Rails3) einzugeben.
id
ist noch 10.
id
wurde als 10 übergeben - genau das sollte es also sein. Wenn Sie das nicht erwartet haben, können Sie dies anhand eines Beispiels klären?