Как установить значения по умолчанию в Rails?
Я пытаюсь найти лучший способ установить значения по умолчанию для объектов в Rails.
Самое лучшее, о чем я могу думать, - установить значение по умолчанию в методе new
в контроллере.
Есть ли у кого-нибудь какие-либо данные, если это приемлемо или если есть лучший способ сделать это?
Ответы
Ответ 1
"Правильно" - опасное слово в 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()
, если вы не переопределите его чем-то другим.
Ответ 2
В соответствии с ответом SFEley, это обновленный/исправленный для новых версий Rails:
class SetDefault < ActiveRecord::Migration
def change
change_column :table_name, :column_name, :type, default: "Your value"
end
end
Ответ 3
Прежде всего вы не можете перегружать 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.
Ответ 4
Вы также можете попробовать 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
Ответ 5
Если вы имеете в виду объекты 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
Ответ 6
В 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
.
Ответ 8
Если вы имеете дело с моделью, вы можете использовать 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
Ответ 9
Если вы просто устанавливаете значения по умолчанию для определенных атрибутов модели, поддерживаемой базой данных, я бы рассмотрел использование значений столбца по умолчанию для sql - можете ли вы уточнить, какие типы значений по умолчанию вы используете?
Существует несколько подходов к его обработке, этот плагин выглядит как интересный вариант.
Ответ 10
Предложение о переопределении new/initialize, вероятно, является неполным. Rails будет (часто) вызывать выделение для объектов ActiveRecord, а вызовы для выделения не приведут к вызовам для инициализации.
Если вы говорите об объектах ActiveRecord, посмотрите на переопределение after_initialize.
Эти сообщения в блоге (не мои) полезны:
Значения по умолчанию
Конструкторы по умолчанию не вызываются
[Edit: SFEley указывает, что Rails на самом деле смотрит на значение по умолчанию в базе данных при создании экземпляра нового объекта в памяти - я этого не осознавал.]
Ответ 11
Мне нужно было установить значение по умолчанию так же, как если бы он был указан как значение столбца по умолчанию в БД. Таким образом, он ведет себя так:
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)
Ответ 12
Потенциально даже лучший/более чистый потенциальный путь, чем предлагаемые ответы, заключается в том, чтобы перезаписать аксессор, например:
def status
self['name_of_var'] || 'desired_default_value'
end
См. "Перезаписывание аксессуаров по умолчанию" в документация ActiveRecord:: Base и fooobar.com/questions/18100/....
Ответ 13
Я ответил на аналогичный вопрос здесь. Чистый способ сделать это - использовать 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
Ответ 14
Если вы говорите об объектах ActiveRecord, я использую "атрибут-по умолчанию".
Документация и загрузка: https://github.com/bsm/attribute-defaults
Ответ 15
Вы можете использовать драгоценный камень rails_default_value. например:
class Foo < ActiveRecord::Base
# ...
default :bar => 'some default value'
# ...
end
https://github.com/keithrowell/rails_default_value
Ответ 16
Создайте миграцию и используйте change_column_default
, она краткая и обратимая:
class SetDefaultAgeInPeople < ActiveRecord::Migration[5.2]
def change
change_column_default :people, :age, { from: nil, to: 0 }
end
end
Ответ 17
Вы можете переопределить конструктор для модели 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