twelve17
twelve17

Reputation: 718

ActiveRecord: scheme for setting default attributes on new records

I'm curious as to whether it's feasible to develop a scheme for setting the default values for new ActiveRecord records. Based on some of the answers here, and this post on setting attributes, I've come up with something like this:

class Taco < ActiveRecord::Base

  DEFAULT_ATTR = {spice_level: 4}

  before_save do |taco|
    if new_record?
      DEFAULT_ATTR.each do |k,v|
        taco[k] ||= v
      end 
    end 
  end 

end

For the paranoid, the constant could be used to also set the default in the migration:

class CreateTacos  < ActiveRecord::Migration

  def defaults
    Taco::DEFAULT_ATTR
  end 

  def change
    add_column :tacos, :spice_level, :integer, :default => defaults[:spice_level]
  end 
end

What could be useful (until someone points out some obvious aspect I've overlooked!) is if this scheme was built into ActiveRecord as a callback, ala before_save (something like "new_record_defaults"). You could override the method and return a hash of symbol => default pairs, and maybe even the paranoid migration code could also leverage this.

I'm still fairly new to Rails, so I'm prepared to be told a scheme already exists or why this is a dumb idea, but feedback is welcome. :)

Update: Per Anton Grigoriev's answer, I think the attribute-defaults gem is the way to go. For posterity, here is an additional Concern, based on the author's original, for getting access to the defaults created:

module ActiveRecord
  module AttributesWithDefaultsAccessor
    extend ActiveSupport::Concern
    def all_defaults
      defaults = {}
      self.private_methods.each do |method|
        if method =~ /^__eval_attr_default_for_(.+)$/
          defaults[$1.to_sym] = self.send(method)
        end
      end
      defaults
    end
  end
  class Base
    include AttributesWithDefaultsAccessor
  end
end

Upvotes: 0

Views: 538

Answers (2)

Billy Chan
Billy Chan

Reputation: 24815

I would prefer to keep this logic in application level instead of database level(by migration).

In application level, this is simply an overwriting of attribute

class Taco < ActiveRecord::Base
  def spice_level
    read_attribute(:spice_level) || 4
  end
end

The basic is, if you have set this attribute to something say 5, it is 5. If not, it is 4.

Ref about overwriting attribute: http://api.rubyonrails.org/classes/ActiveRecord/Base.html#label-Overwriting+default+accessors

Upvotes: 0

Anton Grigoryev
Anton Grigoryev

Reputation: 1219

You could use this gem https://github.com/bsm/attribute-defaults for setting attribute default values

Upvotes: 1

Related Questions