我如何在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”),然后它将进一步确保该对象始终存在一个值。

希望有帮助!

其他回答

尽管在大多数情况下这样设置默认值会令人困惑和尴尬,但您也可以使用:default_scope。点击这里查看squil的评论。

在开发Rails 6应用程序时,我也遇到过类似的挑战。

以下是我的解决方法:

我有一个用户表和一个角色表。Users表属于Roles表。我也有一个管理员和学生模型,从用户表继承。

然后需要在创建用户时为角色设置一个默认值,比如id = 1的管理员角色或id = 2的学生角色。

class User::Admin < User
  before_save :default_values

  def default_values
    # set role_id to '1' except if role_id is not empty
    return self.role_id = '1' unless role_id.nil?
  end
end

这意味着在数据库中创建/保存admin用户之前,如果role_id不为空,则将其设置为默认值1。

return self.role_id = '1' unless role_id.nil? 

等于:

return self.role_id = '1' unless self.role_id.nil?

和:

self.role_id = '1' if role_id.nil?

但是第一种方法更简洁,也更精确。

这是所有。

我希望这对你们有帮助

一个比建议的答案更好/更干净的潜在方法是覆盖访问器,像这样:

def status
  self['status'] || ACTIVE
end

请参阅ActiveRecord::Base文档中的“覆盖默认访问器”和StackOverflow中关于使用self的更多信息。

来自api文档http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html 在模型中使用before_validation方法,它为创建和更新调用提供了创建特定初始化的选项 例如,在这个例子中(同样摘自API文档的例子),数字字段被初始化为信用卡。您可以轻松地对其进行调整,以设置您想要的任何值

class CreditCard < ActiveRecord::Base
  # Strip everything but digits, so the user can specify "555 234 34" or
  # "5552-3434" or both will mean "55523434"
  before_validation(:on => :create) do
    self.number = number.gsub(%r[^0-9]/, "") if attribute_present?("number")
  end
end

class Subscription < ActiveRecord::Base
  before_create :record_signup

  private
    def record_signup
      self.signed_up_on = Date.today
    end
end

class Firm < ActiveRecord::Base
  # Destroys the associated clients and people when the firm is destroyed
  before_destroy { |record| Person.destroy_all "firm_id = #{record.id}"   }
  before_destroy { |record| Client.destroy_all "client_of = #{record.id}" }
end

令人惊讶的是,这里没有提到他

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

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

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