How to set default values in Rails?

后端 未结 17 1327
醉话见心
醉话见心 2020-11-28 04:39

I\'m trying to find the best way to set default values for objects in Rails.

The best I can think of is to set the default value in the new method in

相关标签:
17条回答
  • 2020-11-28 04:43

    In Ruby on Rails v3.2.8, using the after_initialize ActiveRecord callback, you can call a method in your model that will assign the default values for a new object.

    after_initialize callback is triggered for each object that is found and instantiated by a finder, with after_initialize being triggered after new objects are instantiated as well (see ActiveRecord Callbacks).

    So, IMO it should look something like:

    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 for this instance unless the instance contains an attribute_whose_presence_has_been_validated previously on save/update. The default_value will then be used in conjunction with your view to render the form using the default_value for the bar attribute.

    At best this is hacky...

    EDIT - use 'new_record?' to check if instantiating from a new call

    Instead of checking an attribute value, use the new_record? built-in method with rails. So, the above example should look like:

    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
    

    This is much cleaner. Ah, the magic of Rails - it's smarter than me.

    0 讨论(0)
  • 2020-11-28 04:44

    If you are just setting defaults for certain attributes of a database backed model I'd consider using sql default column values - can you clarify what types of defaults you are using?

    There are a number of approaches to handle it, this plugin looks like an interesting option.

    0 讨论(0)
  • 2020-11-28 04:46

    I needed to set a default just as if it was specified as default column value in DB. So it behaves like this

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

    Because after_initialize callback is called after setting attributes from arguments, there was no way to know if the attribute is nil because it was never set or because it was intentionally set as nil. So I had to poke inside a bit and came with this simple solution.

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

    Works great for me. (Rails 3.2.x)

    0 讨论(0)
  • 2020-11-28 04:49

    "Correct" is a dangerous word in Ruby. There's usually more than one way to do anything. If you know you'll always want that default value for that column on that table, setting them in a DB migration file is the easiest way:

    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
    

    Because ActiveRecord autodiscovers your table and column properties, this will cause the same default to be set in any model using it in any standard Rails app.

    However, if you only want default values set in specific cases -- say, it's an inherited model that shares a table with some others -- then another elegant way is do it directly in your Rails code when the model object is created:

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

    Then, when you do a GenericPerson.new(), it'll always trickle the "Doe" attribute up to Person.new() unless you override it with something else.

    0 讨论(0)
  • 2020-11-28 04:50

    i answered a similar question here.. a clean way to do this is using 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 has been deprecated in Rails 3.2.. you could do this instead with pure Ruby

    class SOF
      attr_writer :is_awesome
    
      def is_awesome
        @is_awesome ||= true
      end
    end
    
    sof = SOF.new
    sof.is_awesome
    
    #=> true
    
    0 讨论(0)
  • 2020-11-28 04:52

    Based on SFEley's answer, here is an updated/fixed one for newer Rails versions:

    class SetDefault < ActiveRecord::Migration
      def change
        change_column :table_name, :column_name, :type, default: "Your value"
      end
    end
    
    0 讨论(0)
提交回复
热议问题