我如何在ActiveRecord设置默认值?

我看到Pratik的一篇文章,描述了一段丑陋而复杂的代码:http://m.onkey.org/2007/7/24/how-to-set-default-values-in-your-model

class Item < ActiveRecord::Base  
  def initialize_with_defaults(attrs = nil, &block)
    initialize_without_defaults(attrs) do
      setter = lambda { |key, value| self.send("#{key.to_s}=", value) unless
        !attrs.nil? && attrs.keys.map(&:to_s).include?(key.to_s) }
      setter.call('scheduler_type', 'hotseat')
      yield self if block_given?
    end
  end
  alias_method_chain :initialize, :defaults
end

我在谷歌上看到了以下例子:

  def initialize 
    super
    self.status = ACTIVE unless self.status
  end

and

  def after_initialize 
    return unless new_record?
    self.status = ACTIVE
  end

我也见过有人把它放在迁移中,但我更愿意看到它在模型代码中定义。

是否有一个规范的方法来设置默认值的字段在ActiveRecord模型?


当前回答

这里有一个我用过的解决方案,我有点惊讶还没有加入。

它分为两部分。第一部分是在实际迁移中设置默认值,第二部分是在模型中添加验证,以确保存在为真。

add_column :teams, :new_team_signature, :string, default: 'Welcome to the Team'

您将看到这里已经设置了默认值。现在在验证中,你想要确保字符串总是有一个值,那么就这样做吧

 validates :new_team_signature, presence: true

这将为您设置默认值。(对我来说,我有“Welcome to the Team”),然后它将进一步确保该对象始终存在一个值。

希望有帮助!

其他回答

class Item < ActiveRecord::Base
  def status
    self[:status] or ACTIVE
  end

  before_save{ self.status ||= ACTIVE }
end

如果该列恰好是一个“状态”类型的列,并且您的模型适合使用状态机,那么可以考虑使用aasm gem,然后您可以简单地这样做

  aasm column: "status" do
    state :available, initial: true
    state :used
    # transitions
  end

它仍然没有初始化未保存记录的值,但它比使用init或其他方法来滚动自己的记录要简洁一些,而且您还可以获得aasm的其他好处,例如为所有状态设置范围。

我也看到人们在迁徙中使用这种方法,但我更愿意看到 在模型代码中定义。 是否有一个规范的方法来设置字段的默认值 ActiveRecord模型?

在Rails 5之前,规范的Rails方法实际上是在迁移中设置它,只需要在db/schema中查找即可。rb每当想要看到什么默认值是由DB为任何模型设置。

与@Jeff Perrin的回答相反(这有点老),在使用Model时,迁移方法甚至会应用默认值。新的,由于一些Rails魔法。在Rails 4.1.16中验证。

最简单的东西往往是最好的。较少的知识负债和代码库中的潜在混淆点。而且它‘just works’。

class AddStatusToItem < ActiveRecord::Migration
  def change
    add_column :items, :scheduler_type, :string, { null: false, default: "hotseat" }
  end
end

或者,在不创建新列的情况下更改列,然后执行以下操作:

class AddStatusToItem < ActiveRecord::Migration
  def change
    change_column_default :items, :scheduler_type, "hotseat"
  end
end

或者更好:

class AddStatusToItem < ActiveRecord::Migration
  def change
    change_column :items, :scheduler_type, :string, default: "hotseat"
  end
end

查看官方RoR指南以获得列更改方法中的选项。

null: false禁止在DB中使用null值,而且,作为一个额外的好处,它还会进行更新,以便所有先前为null的DB记录也会使用该字段的默认值设置。如果您愿意,您可以在迁移中排除这个参数,但我发现它非常方便!

Rails 5+的规范方式是,正如@Lucas Caton所说:

class Item < ActiveRecord::Base
  attribute :scheduler_type, :string, default: 'hotseat'
end

类似的问题,但背景略有不同: -如何为Rails activerecord的模型中的属性创建默认值?

最佳回答:这取决于你想要什么!

如果你想让每个对象都以一个值开始:使用after_initialize:init

您希望new.html表单在打开页面时具有默认值?使用https://stackoverflow.com/a/5127684/1536309

class Person < ActiveRecord::Base
  has_one :address
  after_initialize :init

  def init
    self.number  ||= 0.0           #will set the default value only if it's nil
    self.address ||= build_address #let's you set a default association
  end
  ...
end 

如果你想让每个对象都有一个从用户输入中计算出来的值:使用before_save:default_values 你想让用户输入X然后Y = X+'foo'?使用:

class Task < ActiveRecord::Base
  before_save :default_values
  def default_values
    self.status ||= 'P'
  end
end

这就是构造函数的作用!重写模型的initialize方法。

使用after_initialize方法。