webentwicklung-frage-antwort-db.com.de

Wie setze ich Standardwerte in Rails?

Ich versuche, die beste Möglichkeit zum Festlegen von Standardwerten für Objekte in Rails zu finden.

Das Beste, was ich mir vorstellen kann, ist, den Standardwert in der new -Methode im Controller festzulegen.

Hat jemand eine Eingabe, ob dies akzeptabel ist oder ob es einen besseren Weg gibt, dies zu tun?

104
biagidp

"Richtig" ist ein gefährliches Wort in Ruby. Normalerweise gibt es mehr als eine Möglichkeit, etwas zu tun. Wenn Sie wissen, dass Sie immer diesen Standardwert für diese Spalte in dieser Tabelle möchten, ist das Festlegen dieser Werte in einer DB-Migrationsdatei der einfachste Weg:

class SetDefault < ActiveRecord::Migration
  def self.up
    change_column :people, :last_name, :type, :default => "Doe"
  end

  def self.down
    # You can't currently remove default values in Rails
    raise ActiveRecord::IrreversibleMigration, "Can't remove the default"
  end
end

Da ActiveRecord Ihre Tabellen- und Spalteneigenschaften automatisch erkennt, wird derselbe Standardwert in jedem Modell festgelegt, das ihn in jeder Standardanwendung von Rails verwendet.

Wenn Sie jedoch nur in bestimmten Fällen Standardwerte festlegen möchten, z. B. wenn es sich um ein vererbtes Modell handelt, das eine Tabelle mit anderen gemeinsam nutzt, können Sie dies auch direkt in Ihrem Rails Code tun, wenn das Modell verwendet wird Objekt wird erstellt:

class GenericPerson < Person
  def initialize(attributes=nil)
    attr_with_defaults = {:last_name => "Doe"}.merge(attributes)
    super(attr_with_defaults)
  end
end

Wenn Sie dann eine GenericPerson.new() ausführen, wird das Attribut "Doe" immer auf Person.new() gesetzt, es sei denn, Sie überschreiben es mit etwas anderem.

95
SFEley

Basierend auf der Antwort von SFEley ist hier eine aktualisierte/korrigierte Version für neuere Rails Versionen:

class SetDefault < ActiveRecord::Migration
  def change
    change_column :table_name, :column_name, :type, default: "Your value"
  end
end
56
J-_-L

Erstens können Sie initialize(*args) nicht überladen, da es nicht in allen Fällen aufgerufen wird.

Ihre beste Option ist, Ihre Standardeinstellungen in Ihre Migration einzubeziehen:

add_column :accounts, :max_users, :integer, :default => 10

Das zweitbeste ist, Standardeinstellungen in Ihr Modell einzufügen. Dies funktioniert jedoch nur mit Attributen, die anfangs null sind. Möglicherweise haben Sie Probleme mit boolean Spalten:

def after_initialize
  if new_record?
    max_users ||= 10
  end
end

Du brauchst das new_record? Die Standardeinstellungen überschreiben also nicht die aus der Datenbank geladenen Werte.

Du brauchst ||=, um zu verhindern, dass Rails) Parameter überschreibt, die an die initialize-Methode übergeben wurden.

20
Ian Purton

Sie können auch change_column_default in Ihren Migrationen (getestet in Rails 3.2.8):

class SetDefault < ActiveRecord::Migration
  def up
    # Set default value
    change_column_default :people, :last_name, "Smith"
  end

  def down
    # Remove default
    change_column_default :people, :last_name, nil
  end
end

change_column_default Rails API docs

13

Wenn Sie auf ActiveRecord-Objekte verweisen, haben Sie (mehr als) zwei Möglichkeiten:

1. Verwenden Sie einen: Standardparameter im DB

Z.B.

class AddSsl < ActiveRecord::Migration
  def self.up
    add_column :accounts, :ssl_enabled, :boolean, :default => true
  end

  def self.down
    remove_column :accounts, :ssl_enabled
  end
end

Weitere Informationen hier: http://api.rubyonrails.org/classes/ActiveRecord/Migration.html

2. Verwenden Sie einen Rückruf

Z.B. before_validation_on_create

Weitere Informationen hier: http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html#M002147

7
Vlad Zloteanu

In Ruby on Rails v3.2.8 mit dem after_initialize ActiveRecord-Rückruf, Sie können eine Methode in Ihrem Modell aufrufen, die die Standardwerte für ein neues Objekt zuweist.

after_initialize-Rückruf wird für jedes Objekt ausgelöst, das von einem Finder gefunden und instanziiert wird, wobei after_initialize auch ausgelöst wird, nachdem neue Objekte instanziiert wurden ( siehe ActiveRecord-Rückrufe ).

Also, IMO sollte es ungefähr so ​​aussehen:

class Foo < ActiveRecord::Base
  after_initialize :assign_defaults_on_new_Foo
  ...
  attr_accessible :bar
  ...
  private
  def assign_defaults_on_new_Foo
    # required to check an attribute for existence to weed out existing records
    self.bar = default_value unless self.attribute_whose_presence_has_been_validated
  end
end

Foo.bar = default_value für diese Instanz, es sei denn, die Instanz enthält ein attribute_whose_presence_has_been_validated zuvor beim Speichern/Aktualisieren. Das default_value wird dann in Verbindung mit Ihrer Ansicht verwendet, um das Formular mit dem default_value für das bar Attribut.

Bestenfalls ist das hacky ...

EDIT - benutze 'new_record?' um zu überprüfen, ob bei einem neuen Anruf eine Instanz erstellt wurde

Anstatt einen Attributwert zu überprüfen, verwenden Sie den Befehl new_record? eingebaute Methode mit Rails. Das obige Beispiel sollte also so aussehen:

class Foo < ActiveRecord::Base
  after_initialize :assign_defaults_on_new_Foo, if: 'new_record?'
  ...
  attr_accessible :bar
  ...
  private
  def assign_defaults_on_new_Foo
    self.bar = default_value
  end
end

Das ist viel sauberer. Ah, die Magie von Rails - es ist schlauer als ich.

7
erroric

Zumindest für boolesche Felder in Rails 3.2.6 funktioniert dies in Ihrer Migration.

def change
  add_column :users, :eula_accepted, :boolean, default: false
end

Das Setzen eines 1 Oder 0 Als Standard funktioniert hier nicht, da es sich um ein Boolesches Feld handelt. Es muss ein true oder false Wert sein.

5
Silasj

Falls Sie sich mit einem Modell befassen, können Sie die Attriutes-API in Rails 5+ http://api.rubyonrails.org/classes/ActiveRecord/Attributes/ClassMethods) verwenden .html # method-i-attribute

fügen Sie einfach eine Migration mit einem korrekten Spaltennamen hinzu und setzen Sie sie dann im Modell mit:

class StoreListing < ActiveRecord::Base
  attribute :country, :string, default: 'PT'
end
4
Paulo Fidalgo

Generiere eine Migration und benutze change_column_default, ist prägnant und umkehrbar:

class SetDefaultAgeInPeople < ActiveRecord::Migration[5.2]
  def change
    change_column_default :people, :age, { from: nil, to: 0 }
  end
end
1
pj.martorell

Wenn Sie nur Standardeinstellungen für bestimmte Attribute eines datenbankgestützten Modells festlegen, würde ich die Verwendung von SQL-Standardspaltenwerten in Betracht ziehen. Können Sie klären, welche Arten von Standardeinstellungen Sie verwenden?

Es gibt eine Reihe von Ansätzen, um damit umzugehen. Dieses Plugin sieht nach einer interessanten Option aus.

1
paulthenerd

Ein potenziell noch besserer/saubererer potenzieller Weg als die vorgeschlagenen Antworten besteht darin, den Accessor wie folgt zu überschreiben:

def status
  self['name_of_var'] || 'desired_default_value'
end

Siehe "Überschreiben von Standard-Accessoren" in ActiveRecord :: Base-Dokumentation und mehr von StackOverflow zur Verwendung von self .

1
peterhurford

Ich musste einen Standard festlegen, als ob er als Standardspaltenwert in der Datenbank angegeben wäre. So verhält es sich also

a = Item.new
a.published_at # => my default value

a = Item.new(:published_at => nil)
a.published_at # => nil

Da der after_initialize-Rückruf nach dem Festlegen von Attributen aus Argumenten aufgerufen wird, konnte nicht festgestellt werden, ob das Attribut null ist, da es nie festgelegt wurde oder absichtlich auf null festgelegt wurde. Also musste ich ein bisschen reingehen und kam mit dieser einfachen Lösung.

class Item < ActiveRecord::Base
  def self.column_defaults
    super.merge('published_at' => Time.now)
  end
end

Funktioniert gut für mich. (Rails 3.2.x)

Der Vorschlag, new/initialize zu überschreiben, ist wahrscheinlich unvollständig. Rails ruft (häufig) die Zuweisung für ActiveRecord-Objekte auf, und zuzuweisende Aufrufe führen nicht zu Initialisierungsaufrufen.

Wenn Sie über ActiveRecord-Objekte sprechen, werfen Sie einen Blick auf das Überschreiben von after_initialize.

Diese Blog-Beiträge (nicht meine) sind nützlich:

StandardwerteStandardkonstruktoren werden nicht aufgerufen

[Edit: SFEley weist darauf hin, dass Rails prüft tatsächlich die Standardeinstellung in der Datenbank, wenn es ein neues Objekt im Speicher instanziiert - ich hatte das nicht bemerkt.]

1
James Moore

ich beantwortete eine ähnliche Frage hier .. eine saubere Möglichkeit, dies zu tun, ist die Verwendung von Rails attr_accessor_with_default

class SOF
  attr_accessor_with_default :is_awesome,true
end

sof = SOF.new
sof.is_awesome

=> true

[~ # ~] Update [~ # ~]

attr_accessor_with_default wurde in Rails 3.2. veraltet. Sie könnten dies stattdessen mit reinem Ruby tun

class SOF
  attr_writer :is_awesome

  def is_awesome
    @is_awesome ||= true
  end
end

sof = SOF.new
sof.is_awesome

#=> true
0
Orlando

Sie können das Gem Rails_default_value verwenden. z.B:

class Foo < ActiveRecord::Base
  # ...
  default :bar => 'some default value'
  # ...
end

https://github.com/keithrowell/Rails_default_value

0
Keith Rowell

Wenn Sie über ActiveRecord-Objekte sprechen, verwende ich den Edelstein 'attribute-defaults'.

Dokumentation & Download: https://github.com/bsm/attribute-defaults

0
aidan