Как установить значения по умолчанию в Rails?

Я пытаюсь найти лучший способ установить значения по умолчанию для объектов в Rails.

Самое лучшее, о чем я могу думать, - установить значение по умолчанию в методе new в контроллере.

Есть ли у кого-нибудь какие-либо данные, если это приемлемо или если есть лучший способ сделать это?

+101
источник поделиться
17 ответов

"Правильно" - опасное слово в Ruby. Обычно существует более чем один способ сделать что-либо. Если вы знаете, что всегда будете хотеть, чтобы это значение по умолчанию для этого столбца в этой таблице, установка их в файле миграции DB является самым простым способом:

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

Поскольку ActiveRecord автоматически обнаруживает ваши свойства таблицы и столбца, это приведет к тому, что один и тот же параметр по умолчанию будет установлен в любой модели, используя его в любом стандартном приложении Rails.

Однако, если вам нужны только значения по умолчанию, установленные в определенных случаях - скажем, это унаследованная модель, которая разделяет таблицу с некоторыми другими, - тогда еще один элегантный способ - сделать это непосредственно в коде Rails при создании объекта модели

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

Затем, когда вы выполняете GenericPerson.new(), он всегда будет стекать с атрибутом Doe до Person.new(), если вы не переопределите его чем-то другим.

+92
источник

В соответствии с ответом SFEley, это обновленный/исправленный для новых версий Rails:

class SetDefault < ActiveRecord::Migration
  def change
    change_column :table_name, :column_name, :type, default: "Your value"
  end
end
+54
источник
другие ответы

Связанные вопросы


Похожие вопросы

Прежде всего вы не можете перегружать initialize(*args), поскольку он не вызывается во всех случаях.

Ваш лучший вариант - поместить ваши значения по умолчанию в вашу миграцию:

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

Вторым преимуществом является размещение настроек по умолчанию в вашей модели, но это будет работать только с атрибутами, которые изначально ноль. У вас могут быть проблемы со столбцами boolean:

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

Вам нужен new_record?, поэтому значения по умолчанию не переопределяют значения, загруженные из базы данных.

Вам нужно ||= остановить Rails от переопределения параметров, переданных в метод initialize.

+20
источник

Вы также можете попробовать change_column_default в своих миграциях (протестировано в 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
источник

Если вы имеете в виду объекты ActiveRecord, у вас есть (более) два способа сделать это:

1. Используйте параметр: default в DB

например.

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

Дополнительная информация здесь: http://api.rubyonrails.org/classes/ActiveRecord/Migration.html

2. Использовать обратный вызов

например. before_validation_on_create

Дополнительная информация здесь: http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html#M002147

+7
источник

В Ruby on Rails v3.2.8, используя обратный вызов after_initialize ActiveRecord, вы можете вызвать метод в своей модели, который будет присваивать значения по умолчанию для нового объекта.

after_initialize обратный вызов запускается для каждого объекта, который найден и инстанцируется с помощью поискового устройства, причем after_initialize запускается после создания новых объектов (см. обратные вызовы ActiveRecord).

Итак, IMO он должен выглядеть примерно так:

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 для этого экземпляра, если только экземпляр не содержит attribute_whose_presence_has_been_validated ранее при сохранении/обновлении. Затем default_value будет использоваться вместе с вашим представлением для визуализации формы с помощью default_value для атрибута bar.

В лучшем случае это хаки...

EDIT - используйте 'new_record?' чтобы проверить, не создает ли экземпляр нового вызова

Вместо проверки значения атрибута используйте встроенный метод new_record? с рельсами. Итак, приведенный выше пример должен выглядеть так:

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

Это намного чище. Ах, магия Rails - это умнее меня.

+7
источник

Для логических полей в Rails 3.2.6 по крайней мере это будет работать в вашей миграции.

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

Помещение 1 или 0 по умолчанию не будет работать здесь, так как это логическое поле. Это должно быть значение true или false.

+5
источник

Если вы имеете дело с моделью, вы можете использовать API Attriutes в Rails 5+ http://api.rubyonrails.org/classes/ActiveRecord/Attributes/ClassMethods.html#method-i-attribute

просто добавьте миграцию с правильным именем столбца, а затем в модели установите его:

class StoreListing < ActiveRecord::Base
  attribute :country, :string, default: 'PT'
end
+4
источник

Если вы просто устанавливаете значения по умолчанию для определенных атрибутов модели, поддерживаемой базой данных, я бы рассмотрел использование значений столбца по умолчанию для sql - можете ли вы уточнить, какие типы значений по умолчанию вы используете?

Существует несколько подходов к его обработке, этот плагин выглядит как интересный вариант.

+1
источник

Предложение о переопределении new/initialize, вероятно, является неполным. Rails будет (часто) вызывать выделение для объектов ActiveRecord, а вызовы для выделения не приведут к вызовам для инициализации.

Если вы говорите об объектах ActiveRecord, посмотрите на переопределение after_initialize.

Эти сообщения в блоге (не мои) полезны:

Значения по умолчанию Конструкторы по умолчанию не вызываются

[Edit: SFEley указывает, что Rails на самом деле смотрит на значение по умолчанию в базе данных при создании экземпляра нового объекта в памяти - я этого не осознавал.]

+1
источник

Мне нужно было установить значение по умолчанию так же, как если бы он был указан как значение столбца по умолчанию в БД. Таким образом, он ведет себя так:

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

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

Поскольку after_initialize callback вызывается после установки атрибутов из аргументов, не было никакого способа узнать, является ли атрибут нулевым, потому что он никогда не был установлен или потому, что он был намеренно установлен как nil. Поэтому мне пришлось немного засунуть внутрь и пришли с этим простым решением.

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

Отлично работает для меня. (Rails 3.2.x)

+1
источник

Потенциально даже лучший/более чистый потенциальный путь, чем предлагаемые ответы, заключается в том, чтобы перезаписать аксессор, например:

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

См. "Перезаписывание аксессуаров по умолчанию" в документация ActiveRecord:: Base и fooobar.com/questions/18100/....

+1
источник

Я ответил на аналогичный вопрос здесь. Чистый способ сделать это - использовать 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 устарел в Rails 3.2.. вы могли бы сделать это вместо чистого Ruby

class SOF
  attr_writer :is_awesome

  def is_awesome
    @is_awesome ||= true
  end
end

sof = SOF.new
sof.is_awesome

#=> true
0
источник

Если вы говорите об объектах ActiveRecord, я использую "атрибут-по умолчанию".

Документация и загрузка: https://github.com/bsm/attribute-defaults

0
источник

Вы можете использовать драгоценный камень rails_default_value. например:

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

https://github.com/keithrowell/rails_default_value

0
источник

Создайте миграцию и используйте change_column_default, она краткая и обратимая:

class SetDefaultAgeInPeople < ActiveRecord::Migration[5.2]
  def change
    change_column_default :people, :age, { from: nil, to: 0 }
  end
end
0
источник

Вы можете переопределить конструктор для модели ActiveRecord.

Вот так:

def initialize(*args)
  super(*args)
  self.attribute_that_needs_default_value ||= default_value
  self.attribute_that_needs_another_default_value ||= another_default_value
  #ad nauseum
end
-3
источник

Посмотрите другие вопросы по меткам или Задайте вопрос