Giter VIP home page Giter VIP logo

default_value_for's Introduction

Introduction

The default_value_for plugin allows one to define default values for ActiveRecord models in a declarative manner. For example:

class User < ActiveRecord::Base
  default_value_for :name, "(no name)"
  default_value_for :last_seen do
    Time.now
  end
end

u = User.new
u.name       # => "(no name)"
u.last_seen  # => Mon Sep 22 17:28:38 +0200 2008

Note: critics might be interested in the "When (not) to use default_value_for?" section. Please read on.

Installation

Rails 3.2 - 4.2 / Ruby 1.9.3 and higher

The current version of default_value_for (3.x+) is compatible with Rails 3.2 or higher, and Ruby 1.9.3 and higher.

Add it to your Gemfile:

gem "default_value_for", "~> 3.0"

This gem is signed using PGP with the Phusion Software Signing key: http://www.phusion.nl/about/gpg. That key in turn is signed by the rubygems-openpgp Certificate Authority: http://www.rubygems-openpgp-ca.org/.

You can verify the authenticity of the gem by following The Complete Guide to Verifying Gems with rubygems-openpgp: http://www.rubygems-openpgp-ca.org/blog/the-complete-guide-to-verifying-gems-with-rubygems-openpgp.html

Rails 3.0 - 3.1 / Ruby 1.9.3 and lower

To use default_value_for with older versions of Ruby and Rails, you must use the previous stable release, 2.0.3. This version works with Rails 3.0, 3.1, and 3.2; and Ruby 1.8.7 and higher. It does not work with Rails 4.

gem "default_value_for", "~> 2.0.3"

Rails 2

To use default_value_for with Rails 2.x you must use an older version:

./script/plugin install git://github.com/FooBarWidget/default_value_for.git -r release-1.0.7

The default_value_for method

The default_value_for method is available in all ActiveRecord model classes.

The first argument is the name of the attribute for which a default value should be set. This may either be a Symbol or a String.

The default value itself may either be passed as the second argument:

  default_value_for :age, 20

...or it may be passed as the return value of a block:

  default_value_for :age do
    if today_is_sunday?
      20
    else
      30
    end
  end

If you pass a value argument, then the default value is static and never changes. However, if you pass a block, then the default value is retrieved by calling the block. This block is called not once, but every time a new record is instantiated and default values need to be filled in.

The latter form is especially useful if your model has a UUID column. One can generate a new, random UUID for every newly instantiated record:

class User < ActiveRecord::Base
  default_value_for :uuid do
    UuidGenerator.new.generate_uuid
  end
end

User.new.uuid  # => "51d6d6846f1d1b5c9a...."
User.new.uuid  # => "ede292289e3484cb88...."

Note that record is passed to the block as an argument, in case you need it for whatever reason:

class User < ActiveRecord::Base
  default_value_for :uuid do |x|
    x   # <--- a User object
    UuidGenerator.new.generate_uuid
  end
end

default_value_for options

  • allows_nil (default: true) - Sets explicitly passed nil values if option is set to true.

You can pass this options hash as 2nd parameter and have to pass the default value through the :value option in this case e.g.:

default_value_for :age, :value => 20, :allows_nil => false

You can still pass the default value through a block:

default_value_for :uuid, :allows_nil => false do
  UuidGenerator.new.generate_uuid
end

The default_values method

As a shortcut, you can use +default_values+ to set multiple default values at once.

default_values :age  => 20,
               :uuid => lambda { UuidGenerator.new.generate_uuid }

If you like to override default_value_for options for each attribute you can do so:

default_values :age  => { :value => 20 },
               :uuid => { :value => lambda { UuidGenerator.new.generate_uuid }, :allows_nil => false }

The difference is purely aesthetic. If you have lots of default values which are constants or constructed with one-line blocks, +default_values+ may look nicer. If you have default values constructed by longer blocks, default_value_for suit you better. Feel free to mix and match.

As a side note, due to specifics of Ruby's parser, you cannot say,

default_value_for :uuid { UuidGenerator.new.generate_uuid }

because it will not parse. One needs to write

default_value_for(:uuid) { UuidGenerator.new.generate_uuid }

instead. This is in part the inspiration for the +default_values+ syntax.

Rules

Instantiation of new record

Upon instantiating a new record, the declared default values are filled into the record. You've already seen this in the above examples.

Retrieval of existing record

Upon retrieving an existing record in the following case, the declared default values are not filled into the record. Consider the example with the UUID:

user = User.create
user.uuid   # => "529c91b8bbd3e..."

user = User.find(user.id)
# UUID remains unchanged because it's retrieved from the database!
user.uuid   # => "529c91b8bbd3e..."

But when the declared default value is set to not allow nil and nil is passed the default values will be set on retrieval. Consider this example:

default_value_for(:number, :allows_nil => false) { 123 }

user = User.create

# manual SQL by-passing active record and the default value for gem logic through ActiveRecord's after_initialize callback
user.update_attribute(:number, nil)

# declared default value should be set
User.find(user.id).number # => 123 # = declared default value

Mass-assignment

If a certain attribute is being assigned via the model constructor's mass-assignment argument, that the default value for that attribute will not be filled in:

user = User.new(:uuid => "hello")
user.uuid   # => "hello"

However, if that attribute is protected by +attr_protected+ or +attr_accessible+, then it will be filled in:

class User < ActiveRecord::Base
  default_value_for :name, 'Joe'
  attr_protected :name
end

user = User.new(:name => "Jane")
user.name   # => "Joe"

# the without protection option will work as expected
user = User.new({:name => "Jane"}, :without_protection => true)
user.name   # => "Jane"

Explicitly set nil values for accessible attributes will be accepted:

class User < ActiveRecord::Base
  default_value_for :name, 'Joe'
end

user = User(:name => nil)
user.name # => nil

... unless the accessible attribute is set to not allowing nil:

class User < ActiveRecord::Base
  default_value_for :name, 'Joe', :allows_nil => false
end

user = User(:name => nil)
user.name # => "Joe"

Inheritance

Inheritance works as expected. All default values are inherited by the child class:

class User < ActiveRecord::Base
  default_value_for :name, 'Joe'
end

class SuperUser < User
end

SuperUser.new.name   # => "Joe"

Attributes that aren't database columns

default_value_for also works with attributes that aren't database columns. It works with anything for which there's an assignment method:

# Suppose that your 'users' table only has a 'name' column.
class User < ActiveRecord::Base
  default_value_for :name, 'Joe'
  default_value_for :age, 20
  default_value_for :registering, true

  attr_accessor :age

  def registering=(value)
    @registering = true
  end
end

user = User.new
user.age    # => 20
user.instance_variable_get('@registering')    # => true

Default values are duplicated

The given default values are duplicated when they are filled in, so if you mutate a value that was filled in with a default value, then it will not affect all subsequent default values:

class Author < ActiveRecord::Base
  # This model only has a 'name' attribute.
end

class Book < ActiveRecord::Base
  belongs_to :author

  # By default, a Book belongs to a new, unsaved author.
  default_value_for :author, Author.new
end

book1 = Book.new
book1.author.name  # => nil
# This does not mutate the default value:
book1.author.name = "John"

book2 = Book.new
book2.author.name  # => nil

However the duplication is shallow. If you modify any objects that are referenced by the default value then it will affect subsequent default values:

class Author < ActiveRecord::Base
  attr_accessor :useless_hash
  default_value_for :useless_hash, { :foo => [] }
end

author1 = Author.new
author1.useless_hash    # => { :foo => [] }
# This mutates the referred array:
author1.useless_hash[:foo] << 1

author2 = Author.new
author2.useless_hash    # => { :foo => [1] }

You can prevent this from happening by passing a block to default_value_for, which returns a new object instance with fresh references every time:

class Author < ActiveRecord::Base
  attr_accessor :useless_hash
  default_value_for :useless_hash do
    { :foo => [] }
  end
end

author1 = Author.new
author1.useless_hash    # => { :foo => [] }
author1.useless_hash[:foo] << 1

author2 = Author.new
author2.useless_hash    # => { :foo => [] }

Caveats

A conflict can occur if your model class overrides the 'initialize' method, because this plugin overrides 'initialize' as well to do its job.

class User < ActiveRecord::Base
  def initialize  # <-- this constructor causes problems
    super(:name => 'Name cannot be changed in constructor')
  end
end

We recommend you to alias chain your initialize method in models where you use default_value_for:

class User < ActiveRecord::Base
  default_value_for :age, 20

  def initialize_with_my_app
    initialize_without_my_app(:name => 'Name cannot be changed in constructor')
  end

  alias_method_chain :initialize, :my_app
end

Also, stick with the following rules:

  • There is no need to +alias_method_chain+ your initialize method in models that don't use default_value_for.

  • Make sure that +alias_method_chain+ is called after the last default_value_for occurrence.

If your default value is accidentally similar to default_value_for's options hash wrap your default value like this:

default_value_for :attribute_name, :value => { :value => 123, :other_value => 1234 }

When (not) to use default_value_for?

You can also specify default values in the database schema. For example, you can specify a default value in a migration as follows:

create_table :users do |t|
  t.string    :username,  :null => false, :default => 'default username'
  t.integer   :age,       :null => false, :default => 20
end

This has similar effects as passing the default value as the second argument to default_value_for:

default_value_for(:username, 'default_username')
default_value_for(:age, 20)

Default values are filled in whether you use the schema defaults or the default_value_for defaults:

user = User.new
user.username   # => 'default username'
user.age        # => 20

It's recommended that you use this over default_value_for whenever possible.

However, it's not possible to specify a schema default for serialized columns. With default_value_for, you can:

class User < ActiveRecord::Base
  serialize :color
  default_value_for :color, [255, 0, 0]
end

And if schema defaults don't provide the flexibility that you need, then default_value_for is the perfect choice. For example, with default_value_for you could specify a per-environment default:

class User < ActiveRecord::Base
  if Rails.env ## "development"
    default_value_for :is_admin, true
  end
end

Or, as you've seen in an earlier example, you can use default_value_for to generate a default random UUID:

class User < ActiveRecord::Base
  default_value_for :uuid do
    UuidGenerator.new.generate_uuid
  end
end

Or you could use it to generate a timestamp that's relative to the time at which the record is instantiated:

class User < ActiveRecord::Base
  default_value_for :account_expires_at do
    3.years.from_now
  end
end

User.new.account_expires_at   # => Mon Sep 22 18:43:42 +0200 2008
sleep(2)
User.new.account_expires_at   # => Mon Sep 22 18:43:44 +0200 2008

Finally, it's also possible to specify a default via an association:

# Has columns: 'name' and 'default_price'
class SuperMarket < ActiveRecord::Base
  has_many :products
end

# Has columns: 'name' and 'price'
class Product < ActiveRecord::Base
  belongs_to :super_market

  default_value_for :price do |product|
    product.super_market.default_price
  end
end

super_market = SuperMarket.create(:name => 'Albert Zwijn', :default_price => 100)
soap = super_market.products.create(:name => 'Soap')
soap.price   # => 100

What about before_validate/before_save?

True, +before_validate+ and +before_save+ does what we want if we're only interested in filling in a default before saving. However, if one wants to be able to access the default value even before saving, then be prepared to write a lot of code. Suppose that we want to be able to access a new record's UUID, even before it's saved. We could end up with the following code:

# In the controller
def create
  @user = User.new(params[:user])
  @user.generate_uuid
  email_report_to_admin("#{@user.username} with UUID #{@user.uuid} created.")
  @user.save!
end

# Model
class User < ActiveRecord::Base
  before_save :generate_uuid_if_necessary

  def generate_uuid
    self.uuid = ...
  end

  private
    def generate_uuid_if_necessary
      if uuid.blank?
        generate_uuid
      end
    end
end

The need to manually call +generate_uuid+ here is ugly, and one can easily forget to do that. Can we do better? Let's see:

# Controller
def create
  @user = User.new(params[:user])
  email_report_to_admin("#{@user.username} with UUID #{@user.uuid} created.")
  @user.save!
end

# Model
class User < ActiveRecord::Base
  before_save :generate_uuid_if_necessary

  def uuid
    value = read_attribute('uuid')
    if !value
      value = generate_uuid
      write_attribute('uuid', value)
    end
    value
  end

  # We need to override this too, otherwise User.new.attributes won't return
  # a default UUID value. I've never tested with User.create() so maybe we
  # need to override even more things.
  def attributes
    uuid
    super
  end

  private
    def generate_uuid_if_necessary
      uuid  # Reader method automatically generates UUID if it doesn't exist
    end
end

That's an awful lot of code. Using default_value_for is easier, don't you think?

What about other plugins?

I've only been able to find 2 similar plugins:

'Default Value' appears to be unmaintained; its SVN link is broken. This leaves only 'ActiveRecord Defaults'. However, it is semantically dubious, which leaves it wide open for corner cases. For example, it is not clearly specified what ActiveRecord Defaults will do when attributes are protected by +attr_protected+ or +attr_accessible+. It is also not clearly specified what one is supposed to do if one needs a custom +initialize+ method in the model.

I've taken my time to thoroughly document default_value_for's behavior.

Credits

I've wanted such functionality for a while now and it baffled me that ActiveRecord doesn't provide a clean way for me to specify default values. After reading http://groups.google.com/group/rubyonrails-core/browse_thread/thread/b509a2fe2b62ac5/3e8243fa1954a935, it became clear that someone needs to write a plugin. This is the result.

Thanks to Pratik Naik for providing the initial code snippet on which this plugin is based on: http://m.onkey.org/2007/7/24/how-to-set-default-values-in-your-model

Thanks to Matthew Draper for Rails 5 support.

Thanks to Norman Clarke and Tom Mango for Rails 4 support.

default_value_for's People

Contributors

aaronjensen avatar agios avatar ajh avatar bertg avatar boblail avatar brendon avatar chrisarcand avatar dolzenko avatar dougkeller avatar drewski371-bot avatar firien avatar foobarwidget avatar francois avatar fryguy avatar htanata avatar igor-drozdov avatar jrafanie avatar kevslashnull avatar marcjeanson avatar marzapower avatar matthewd avatar mnaberez avatar niels avatar njakobsen avatar norman avatar peeja avatar rymai avatar rywall avatar seanhussey avatar tenderlove avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

default_value_for's Issues

Tests are order-dependent

I discovered in #46 that the tests do not clean up after themselves reliably on Rails 4.1+, for reasons I do not yet know. Making the tests order-dependent allows them to run successfully, but we should make them order-independent again.

Issue with default_value_for nested items

Hi,

I have some problem with setting default_values_for nested items. Not sure if it's specific default_value_for plugin's bug.
Using Rails 2.3
Plugin commit

I have models Invoice & Items

class Invoice < ActiveRecord::Base
  has_many :items

  accepts_nested_attributes_for :items,  :allow_destroy => true, :reject_if => lambda {|a| a[:qty].blank? }

  default_value_for :items do
    items = []
    Product.some_specific_products_group.each do |p|
      items << item.new(:product_id => p.id)
    end
    items
  end

So when I create new record it successfully pops up with all the needed Items populated.
However when I try to save Invoice, all Items get overrided with same empty default values.

#controller stuff  
  def new
    @invoice = Invoice.new(params[:invoice])
  end

  def create
    @invoice = Invoice.new(params[:invoice])
    if @invoice.save
      flash[:notice] = "Įrašas sukurtas."
      redirect_to invoices_path
    else
      render :action => :new
    end
  end

Upgrade to version 3.0.4 breaks gitlab

Hi,

the upgrade from version 3.0.3 to 3.0.4 breaks the gitlab installation.

You can reproduce it by executing:

su -l git -c "cd /usr/local/www/gitlab && rake --trace gitlab:env:info RAILS_ENV=production"
** Invoke gitlab:env:info (first_time)
** Invoke environment (first_time)
** Execute environment
The PGconn, PGresult, and PGError constants are deprecated, and will be
removed as of version 1.0.

You should use PG::Connection, PG::Result, and PG::Error instead, respectively.

Called from /usr/local/lib/ruby/gems/2.4/gems/activesupport-4.2.10/lib/active_support/dependencies.rb:240:in `load_dependency'
** Execute gitlab:env:info

System information
System:
Current User:   git
Using RVM:      no
Ruby Version:   2.4.3p205
Gem Version:    2.7.4
Bundler Version:1.16.1
Rake Version:   12.3.0
Redis Version:  3.2.11
Git Version:    2.16.1
Sidekiq Version:5.1.0
Go Version:     go1.9.3 freebsd/amd64
rake aborted!
NoMethodError: undefined method `issues_enabled' for #<Project id: some-group/some-project>
/usr/local/lib/ruby/gems/2.4/gems/activemodel-4.2.10/lib/active_model/attribute_methods.rb:433:in `method_missing'
/usr/local/lib/ruby/gems/2.4/gems/default_value_for-3.0.4/lib/default_value_for.rb:163:in `block in set_default_values'
/usr/local/lib/ruby/gems/2.4/gems/default_value_for-3.0.4/lib/default_value_for.rb:154:in `each'
/usr/local/lib/ruby/gems/2.4/gems/default_value_for-3.0.4/lib/default_value_for.rb:154:in `set_default_values'
/usr/local/lib/ruby/gems/2.4/gems/activesupport-4.2.10/lib/active_support/callbacks.rb:432:in `block in make_lambda'
/usr/local/lib/ruby/gems/2.4/gems/activesupport-4.2.10/lib/active_support/callbacks.rb:228:in `block in halting_and_conditional'
/usr/local/lib/ruby/gems/2.4/gems/activesupport-4.2.10/lib/active_support/callbacks.rb:506:in `block in call'
/usr/local/lib/ruby/gems/2.4/gems/activesupport-4.2.10/lib/active_support/callbacks.rb:506:in `each'
/usr/local/lib/ruby/gems/2.4/gems/activesupport-4.2.10/lib/active_support/callbacks.rb:506:in `call'
/usr/local/lib/ruby/gems/2.4/gems/activesupport-4.2.10/lib/active_support/callbacks.rb:92:in `__run_callbacks__'
/usr/local/lib/ruby/gems/2.4/gems/activesupport-4.2.10/lib/active_support/callbacks.rb:778:in `_run_initialize_callbacks'
/usr/local/lib/ruby/gems/2.4/gems/activerecord-4.2.10/lib/active_record/core.rb:284:in `initialize'
/usr/local/lib/ruby/gems/2.4/gems/default_value_for-3.0.4/lib/default_value_for.rb:142:in `initialize'
/usr/local/lib/ruby/gems/2.4/gems/state_machines-activerecord-0.5.0/lib/state_machines/integrations/active_record.rb:463:in `initialize'
/usr/local/lib/ruby/gems/2.4/gems/activerecord-4.2.10/lib/active_record/inheritance.rb:61:in `new'
/usr/local/lib/ruby/gems/2.4/gems/activerecord-4.2.10/lib/active_record/inheritance.rb:61:in `new'
/usr/local/lib/ruby/gems/2.4/gems/activerecord-4.2.10/lib/active_record/reflection.rb:141:in `build_association'
/usr/local/lib/ruby/gems/2.4/gems/activerecord-4.2.10/lib/active_record/associations/association.rb:250:in `build_record'
/usr/local/lib/ruby/gems/2.4/gems/activerecord-4.2.10/lib/active_record/associations/collection_association.rb:157:in `build'
/usr/local/lib/ruby/gems/2.4/gems/activerecord-4.2.10/lib/active_record/associations/collection_proxy.rb:259:in `build'
/usr/local/www/gitlab/lib/tasks/gitlab/info.rake:40:in `block (3 levels) in <top (required)>'
/usr/local/lib/ruby/gems/2.4/gems/rake-12.3.0/lib/rake/task.rb:251:in `block in execute'
/usr/local/lib/ruby/gems/2.4/gems/rake-12.3.0/lib/rake/task.rb:251:in `each'
/usr/local/lib/ruby/gems/2.4/gems/rake-12.3.0/lib/rake/task.rb:251:in `execute'
/usr/local/lib/ruby/gems/2.4/gems/rake-12.3.0/lib/rake/task.rb:195:in `block in invoke_with_call_chain'
/usr/local/lib/ruby/2.4/monitor.rb:214:in `mon_synchronize'
/usr/local/lib/ruby/gems/2.4/gems/rake-12.3.0/lib/rake/task.rb:188:in `invoke_with_call_chain'
/usr/local/lib/ruby/gems/2.4/gems/rake-12.3.0/lib/rake/task.rb:181:in `invoke'
/usr/local/lib/ruby/gems/2.4/gems/rake-12.3.0/lib/rake/application.rb:160:in `invoke_task'
/usr/local/lib/ruby/gems/2.4/gems/rake-12.3.0/lib/rake/application.rb:116:in `block (2 levels) in top_level'
/usr/local/lib/ruby/gems/2.4/gems/rake-12.3.0/lib/rake/application.rb:116:in `each'
/usr/local/lib/ruby/gems/2.4/gems/rake-12.3.0/lib/rake/application.rb:116:in `block in top_level'
/usr/local/lib/ruby/gems/2.4/gems/rake-12.3.0/lib/rake/application.rb:125:in `run_with_threads'
/usr/local/lib/ruby/gems/2.4/gems/rake-12.3.0/lib/rake/application.rb:110:in `top_level'
/usr/local/lib/ruby/gems/2.4/gems/rake-12.3.0/lib/rake/application.rb:83:in `block in run'
/usr/local/lib/ruby/gems/2.4/gems/rake-12.3.0/lib/rake/application.rb:186:in `standard_exception_handling'
/usr/local/lib/ruby/gems/2.4/gems/rake-12.3.0/lib/rake/application.rb:80:in `run'
/usr/local/lib/ruby/gems/2.4/gems/rake-12.3.0/exe/rake:27:in `<top (required)>'
/usr/local/bin/rake:23:in `load'
/usr/local/bin/rake:23:in `<main>'
Tasks: TOP => gitlab:env:info

I'm not sure if this is related to gitlab, but doing a downgrade to version 3.0.3 bring gitlab back to live.

Subclassing issues

  1. Overriding default_values in a subclass are modifying the parent class. The following fails on the last assert_equal because the subclass is modifying the parent class' value.
define_model_class("TestSuperClass") do
  default_value_for :number, 1234
end
define_model_class("TestClass", "TestSuperClass") do
  default_value_for :number, 5678
end

object = TestClass.new
assert_equal 5678, object.number

object = TestSuperClass.new
assert_equal 1234, object.number
  1. New default_values in a subclass are being added to the parent class. The following fails because TestSuperClass.new tries to call .hello=, which doesn't exist.
define_model_class("TestSuperClass") do
  default_value_for :number, 1234
end
define_model_class("TestClass", "TestSuperClass") do
  default_value_for :hello, "hi"
  attr_accessor :hello
end

assert_nothing_raised { TestSuperClass.new }

Merging into Rails

Good day, @FooBarWidget!

I think your gem gives fundamental Rails' feature. Don't you know if is lack of this feature principal in Rails? Didn't you try to request merging of your gem?

Bug in blank attribute detection w/o column backing

attribute_blank = if attributes.has_key?(attribute)
column = self.class.columns_hash[attribute]
if column && column.type == :boolean
attributes[attribute].nil?
else
attributes[attribute].blank?
end
elsif respond_to?(attribute)
send(attribute).nil?
else
instance_variable_get("@#{attribute}").nil?
end

The above code has a few more edge cases that are missed, specifically with the second two cases in the outer conditional where the attribute is not backed by a database column. The next two cases must account for the same issue (attribute can either be a boolean where false is not 'blank', it's a set value, but false.nil? == true, or a collection that is empty via blank?).

This whole thing should be cleaned up, with perhaps a few comments explaining each case.

See d155ba7#commitcomment-30274475

cc/ @romaind

Rails 4.2.0.beta1 throws: can't modify frozen ActiveSupport::HashWithIndifferentAccess

First, thanks for a great and useful gem. :-)

After trying to test against Rails 4.2.0.beta1 with default_values_for version 3.0.0.1, I get this error:

RuntimeError: can't modify frozen ActiveSupport::HashWithIndifferentAccess
from /Users/allen/.rvm/gems/ruby-2.1.2/gems/activesupport-4.2.0.beta1/lib/active_support/hash_with_indifferent_access.rb:226:in `delete'

in default_value_for-3.0.0.1/lib/default_value_for.rb:169:in `block in set_default_values'
changed_attributes.delete(attribute)
is now causing the Exception. I suspect ActiveRecord/Support is now providing a "frozen" hash to work with.

When I remove the default_values_for declaration from the model, I am able to instantiate the object.

POTENTIAL SOLUTION: (Needs more thought and testing)

def set_default_values
  @changed_attr ||= Hash.new { |h,k| h[k] = changed_attributes[k] }
  # ...
  @changed_attr.delete(attribute)
   #...
end

(This made model instantiation work, but I don't know what it breaks elsewhere)

STACK TRACE:

0: /Users/allen/.rvm/gems/ruby-2.1.2/gems/activesupport-4.2.0.beta1/lib/active_support/hash_with_indifferent_access.rb:226:in delete' 1: /Users/allen/.rvm/gems/ruby-2.1.2/gems/activesupport-4.2.0.beta1/lib/active_support/hash_with_indifferent_access.rb:226:indelete'
2: /Users/allen/.rvm/gems/ruby-2.1.2/gems/default_value_for-3.0.0.1/lib/default_value_for.rb:169:in block in set_default_values' 3: /Users/allen/.rvm/gems/ruby-2.1.2/gems/default_value_for-3.0.0.1/lib/default_value_for.rb:152:ineach'
4: /Users/allen/.rvm/gems/ruby-2.1.2/gems/default_value_for-3.0.0.1/lib/default_value_for.rb:152:in set_default_values' 5: /Users/allen/.rvm/gems/ruby-2.1.2/gems/activesupport-4.2.0.beta1/lib/active_support/callbacks.rb:424:inblock in make_lambda'
6: /Users/allen/.rvm/gems/ruby-2.1.2/gems/activesupport-4.2.0.beta1/lib/active_support/callbacks.rb:222:in call' 7: /Users/allen/.rvm/gems/ruby-2.1.2/gems/activesupport-4.2.0.beta1/lib/active_support/callbacks.rb:222:inblock in halting_and_conditional'
8: /Users/allen/.rvm/gems/ruby-2.1.2/gems/activesupport-4.2.0.beta1/lib/active_support/callbacks.rb:87:in call' 9: /Users/allen/.rvm/gems/ruby-2.1.2/gems/activesupport-4.2.0.beta1/lib/active_support/callbacks.rb:87:inrun_callbacks'
10: /Users/allen/.rvm/gems/ruby-2.1.2/gems/activerecord-4.2.0.beta1/lib/active_record/core.rb:267:in initialize' 11: /Users/allen/.rvm/gems/ruby-2.1.2/gems/default_value_for-3.0.0.1/lib/default_value_for.rb:142:ininitialize'
12: /Users/allen/.rvm/gems/ruby-2.1.2/gems/activerecord-4.2.0.beta1/lib/active_record/inheritance.rb:61:in `new'

ActiveModel::ForbiddenAttributesError on Rails 4.2

For a simple model

class Foo < ActiveRecord::Base
  default_value_for :my_attr, 'my_value'
end

This works:

Foo.create

But what is typically called in the controller raises ActiveModel::ForbiddenAttributesError. Example:

Foo.create ActionController::Parameters.new

Doesn't work with rails 6

Can you please confirm this gem works in a rails 6.0.0 application?

It didn't work in mine. It was working fine in Rails 6.0.0.rc2 but not in 6.0.0

factory_girl compatibility

Seems it's not possible to use params from factory_girl's create/build methods in default_value_for block.

Default value for overrides nested attributes

class Person < ActiveRecord::Base
  belongs_to :contact
  accepts_nested_attributes_for :contact

  default_value_for :contact do
    Contact.new
  end
end

it "should pass nested attributes to contact" do
  Person.new({
    :contact_attributes => {
      :email => "foo@bar"
    }
  }).contact.email.should == "foo@bar" # but is nil or whatever was given in the default value
end

Fails with wrong number of arguments when used inside a subclass in Ruby 2.6+

If using default_value_for within a subclass of another model, then the class instance initialization will fail with: ArgumentError (wrong number of arguments (given 2, expected 0..1))

This is version 3.3.0 and using all combinations of Ruby 2.6.5 and 2.7, and with Rails 5.2 and 6.0.

For example consider the classes:

class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
end

class Example < ApplicationRecord
  default_value_for :name, "Hello"
end

Then calling Example.new will abort with the error. If on the other hand that were to subclass directly from ActiveRecord::Base instead of ApplicationRecord then it works fine.

I think I've tracked it down to calling super() within the initialize method. If I replace
the code in default_value_for.rb

  module InstanceMethods
    def initialize(attributes = nil, options = {})
      ...
      if self.class.respond_to? :protected_attributes
        super(attributes, options)

with

  module InstanceMethods
    def initialize(attributes = nil, options = {})
      ..
      if self.class.respond_to? :protected_attributes
        super(attributes.merge(options))   # <<<< CHANGE THIS LINE

then it seems to work fine. Though I am not comfortable that this is the correct change to make.

Issue with ActiveModel::MissingAttributeError for `allow_nils: true`

I have an error with rails 4.2.10 and default_value_for (3.0.4), db: postgres:9.6.
Steps to reproduce:

create_table :users do |t|
  t.string :name
  t.string :surname
  t.integer :age

  t.timestamps null: false
end

Setup default values

class User < ActiveRecord::Base
  default_values(
    name:      { value: 'some name',     allows_nil: false },
    surname:   { value: 'some surname', allows_nil: false },
    age:       { value: 10, allows_nil: false }
  )
end
# execute query
irb(main):005:0> User.all.select(:name).first

ActiveModel::MissingAttributeError: missing attribute: surname
	from /usr/local/bundle/gems/activerecord-4.2.10/lib/active_record/attribute_methods/read.rb:93:in `block in _read_attribute'
	from /usr/local/bundle/gems/activerecord-4.2.10/lib/active_record/attribute_set.rb:31:in `block in fetch_value'
	from /usr/local/bundle/gems/activerecord-4.2.10/lib/active_record/attribute.rb:150:in `value'
	from /usr/local/bundle/gems/activerecord-4.2.10/lib/active_record/attribute_set.rb:31:in `fetch_value'
	from /usr/local/bundle/gems/activerecord-4.2.10/lib/active_record/attribute_methods/read.rb:93:in `_read_attribute'
	from /usr/local/bundle/gems/activerecord-4.2.10/lib/active_record/attribute_methods.rb:50:in `__temp__375727e616d656'
	from /usr/local/bundle/gems/default_value_for-3.0.4/lib/default_value_for.rb:163:in `block in set_default_values'
	from /usr/local/bundle/gems/default_value_for-3.0.4/lib/default_value_for.rb:154:in `each'
	from /usr/local/bundle/gems/default_value_for-3.0.4/lib/default_value_for.rb:154:in `set_default_values'
	from /usr/local/bundle/gems/activesupport-4.2.10/lib/active_support/callbacks.rb:432:in `block in make_lambda'
	from /usr/local/bundle/gems/activesupport-4.2.10/lib/active_support/callbacks.rb:228:in `block in halting_and_conditional'
	from /usr/local/bundle/gems/activesupport-4.2.10/lib/active_support/callbacks.rb:506:in `block in call'
	from /usr/local/bundle/gems/activesupport-4.2.10/lib/active_support/callbacks.rb:506:in `each'
	from /usr/local/bundle/gems/activesupport-4.2.10/lib/active_support/callbacks.rb:506:in `call'
	from /usr/local/bundle/gems/activesupport-4.2.10/lib/active_support/callbacks.rb:92:in `__run_callbacks__'
	from /usr/local/bundle/gems/activesupport-4.2.10/lib/active_support/callbacks.rb:778:in `_run_initialize_callbacks'

I have monkey patch, which fixes that issue (I can make a PR, if this is valid solution):

module DefaultValueFor
  module InstanceMethods
    def set_default_values
      self.class._all_default_attribute_values.each do |attribute, container|
        next unless new_record? || self.class._all_default_attribute_values_not_allowing_nil.include?(attribute)

        connection_default_value_defined = new_record? && respond_to?("#{attribute}_changed?") && !__send__("#{attribute}_changed?")

        column = self.class.columns.detect {|c| c.name == attribute}
        #
        # Monkey patch goes here
        # let's check if attribute is fetched from db.
        #
        if has_attribute?(attribute)
          attribute_blank = if column && column.type == :boolean
            attributes[attribute].nil?
          else
            attributes[attribute].blank?
          end
        else
          attribute_blank = true
        end

        next unless connection_default_value_defined || attribute_blank

        # allow explicitly setting nil through allow nil option
        next if @initialization_attributes.is_a?(Hash) &&
                (
                  @initialization_attributes.has_key?(attribute) ||
                  (
                    @initialization_attributes.has_key?("#{attribute}_attributes") &&
                    nested_attributes_options.stringify_keys[attribute]
                  )
                ) &&
                !self.class._all_default_attribute_values_not_allowing_nil.include?(attribute)

        __send__("#{attribute}=", container.evaluate(self))
        if respond_to?(:clear_attribute_changes, true)
          clear_attribute_changes [attribute] if has_attribute?(attribute)
        else
          changed_attributes.delete(attribute)
        end
      end
    end
  end
end

Possible conflict with rspec-rails gem

I'm not sure which gem is at fault but default_value_for does not work with rspec-rails. I've raised this on the rspec mailing list too.

When default_value_for is used in conjuction with rsepc-rails (latest versions) there is something that prevents cucumber features being run. Used with a clean rails install, the following gemfile throws issues:

source :rubygems

gem "rake"
gem "rails", ">=3.0.7"

group :development, :test do
  # up to date
  gem "faker"
  gem "factory_girl_rails"
  gem "ruby-debug19"
  gem "capybara", ">= 0.4.1.2"
  gem 'cucumber-rails'
  gem 'database_cleaner'
  gem "rspec-rails"
  gem "default_value_for"
end

Add License information to gemfile

This will make it show up on rubygems.org. I'm doing due diligence on our gems and need to find out the licenses for all the gems. Having it show up on rubygems.org cuts out the step of having to go to the github repo.

merge error with 2.0

I'm getting this error with every model using default_value_for

NoMethodError: undefined method `merge' for []:Array
    from /.rvm/gems/ruby-1.9.3-p125/gems/default_value_for-2.0.0/lib/default_value_for.rb:114:in `_all_default_attribute_values_not_allowing_nil'


  default_value_for :central_key, :allows_nil => false do
    SecureRandom.hex(10)
  end

Class methods not applied to association proxy classes

Since pulling #37 we have some test failures on 4.1 and 4.2 because the assocation proxy classes are not receiving the methods defined in DelayedMethods:

$ BUNDLE_GEMFILE=Gemfile.rails.4.2.rb bundle exec rake
/Users/norman/.rbenv/versions/2.1.3/bin/ruby test.rb

Testing with Active Record version 4.2.0.rc2

Run options: --seed 52699

# Running:

....................F........

Finished in 0.212521s, 136.4571 runs/s, 211.7438 assertions/s.

  1) Failure:
DefaultValuePluginTest#test_can_specify_default_value_via_association [test.rb:360]:
Expected: 123
  Actual: 1234

29 runs, 45 assertions, 1 failures, 0 errors, 0 skips
rake aborted!
Command failed with status (1): [/Users/norman/.rbenv/versions/2.1.3/bin/ru...]
/Users/norman/work/default_value_for/Rakefile:5:in `block in <top (required)>'
Tasks: TOP => default => test
(See full trace by running task with --trace)

I'm about to push a solution for 4.2 but am still working on resolving this for 4.1.

Rails 4 support

Is this supported for Rails 4, running into some issue with it.

Default value for datetime and allowing it to be changed in the form

Hi there,

I've run into an issue where:

default_value_for :happening_at do
  Time.zone.now.change(:hour => 9)
end

is in the model, but we also allow the user to edit that in the form when creating their event:

<p><%= form.label :happening_at, 'Date &amp; Time' %>
<%= form.datetime_select :happening_at, {:order => [:day, :month, :year, :hour, :minute]} %> <%= Time.zone %></p>

If the time is changed in the form and the record saved, the time that was in the form is overridden by the time in the default_value_for call. Editing the record using the same form still works however.

Any idea what's happening here? Is it a conflict between the way dvf works and the way rails structures its composite datetime form fields?

Cheers,

Brendon

The <<-operator changes the default value for new instances

I'm using it to set a default value to a serialized column. In a before_save filter in the same model i push (<<) a value to the array that the serialized column gives me.

This had the effect that the next time I initialized a new instance of that model the column's default value had changed.

I found this test case in the test file: http://gist.github.com/487565#file_default_value_for_original_test.rb
I was expecting the behavior to be http://gist.github.com/487565#file_default_value_for_modified_test.rb

To get my modified test to pass I did this change to the implementation: http://gist.github.com/487565#file_default_value_for_original_init.diff

If you'd like I can send you a pull request but first of all I wanted to make sure I didn't completely misunderstood something elemental.

Thank you for providing a very useful plugin!

Kind regards,
Nicklas Ramhöj

default_value_for gem

Have you considered packaging this in a gem? It would be a great for keeping up with the current version.

2.minutes is not allowed

default_value_for :duration, 2.minutes

sure with a block it is allowed but isn't there a way to use it this way, because in this case i don't see the purpose of evaluating every time?

TypeError: can't dup Fixnum
    from /Users/benjaminhuber/.rvm/gems/ruby-1.8.7-p302/gems/activesupport-3.0.9/lib/active_support/duration.rb:102:in `dup'
    from /Users/benjaminhuber/.rvm/gems/ruby-1.8.7-p302/gems/activesupport-3.0.9/lib/active_support/duration.rb:102:in `send'
    from /Users/benjaminhuber/.rvm/gems/ruby-1.8.7-p302/gems/activesupport-3.0.9/lib/active_support/duration.rb:102:in `method_missing'
    from /Users/benjaminhuber/.rvm/gems/ruby-1.8.7-p302/gems/default_value_for-1.0.5/lib/default_value_for.rb:29:in `evaluate'
    from /Users/benjaminhuber/.rvm/gems/ruby-1.8.7-p302/gems/default_value_for-1.0.5/lib/default_value_for.rb:97:in `initialize'
    from /Users/benjaminhuber/.rvm/gems/ruby-1.8.7-p302/gems/activesupport-3.0.9/lib/active_support/ordered_hash.rb:139:in `each'
    from /Users/benjaminhuber/.rvm/gems/ruby-1.8.7-p302/gems/activesupport-3.0.9/lib/active_support/ordered_hash.rb:139:in `each'
    from /Users/benjaminhuber/.rvm/gems/ruby-1.8.7-p302/gems/default_value_for-1.0.5/lib/default_value_for.rb:95:in `initialize'
    from /Users/benjaminhuber/.rvm/gems/ruby-1.8.7-p302/gems/activerecord-3.0.9/lib/active_record/base.rb:1414:in `initialize_without_defaults'
    from /Users/benjaminhuber/.rvm/gems/ruby-1.8.7-p302/gems/default_value_for-1.0.5/lib/default_value_for.rb:83:in `initialize'
    from (irb):2:in `new'
    from (irb):2

default_value_for before establishing database connection

When I'm trying to start rails server it throws (it only happens when database is lazy loaded):

/Users/filip/.rvm/gems/ruby-2.1.2/gems/activerecord-4.1.5/lib/active_record/dynamic_matchers.rb:26:in `method_missing': undefined method `default_value_for' for Review (call 'Review.connection' to establish a connection):Class (NoMethodError)
    from /Users/filip/programming/service_matters/app/models/review.rb:25:in `<class:Review>'
    from /Users/filip/programming/service_matters/app/models/review.rb:1:in `<top (required)>'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:443:in `load'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:443:in `block in load_file'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:633:in `new_constants_in'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:442:in `load_file'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:342:in `require_or_load'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:480:in `load_missing_constant'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:180:in `const_missing'
    from /Users/filip/programming/service_matters/app/admin/review.rb:1:in `<top (required)>'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:241:in `load'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:241:in `block in load'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:232:in `load_dependency'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:241:in `load'
    from /Users/filip/.rvm/gems/ruby-2.1.2/bundler/gems/activeadmin-83059dc2894b/lib/active_admin/application.rb:179:in `block in load'
    from /Users/filip/.rvm/gems/ruby-2.1.2/bundler/gems/activeadmin-83059dc2894b/lib/active_admin/error.rb:40:in `capture'
    from /Users/filip/.rvm/gems/ruby-2.1.2/bundler/gems/activeadmin-83059dc2894b/lib/active_admin/application.rb:179:in `load'
    from /Users/filip/.rvm/gems/ruby-2.1.2/bundler/gems/activeadmin-83059dc2894b/lib/active_admin/application.rb:171:in `block in load!'
    from /Users/filip/.rvm/gems/ruby-2.1.2/bundler/gems/activeadmin-83059dc2894b/lib/active_admin/application.rb:171:in `each'
    from /Users/filip/.rvm/gems/ruby-2.1.2/bundler/gems/activeadmin-83059dc2894b/lib/active_admin/application.rb:171:in `load!'
    from /Users/filip/.rvm/gems/ruby-2.1.2/bundler/gems/activeadmin-83059dc2894b/lib/active_admin/application.rb:193:in `routes'
    from /Users/filip/.rvm/gems/ruby-2.1.2/bundler/gems/activeadmin-83059dc2894b/lib/active_admin.rb:80:in `routes'
    from /Users/filip/programming/service_matters/config/routes.rb:3:in `block in <top (required)>'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/actionpack-4.1.5/lib/action_dispatch/routing/route_set.rb:337:in `instance_exec'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/actionpack-4.1.5/lib/action_dispatch/routing/route_set.rb:337:in `eval_block'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/actionpack-4.1.5/lib/action_dispatch/routing/route_set.rb:315:in `draw'
    from /Users/filip/programming/service_matters/config/routes.rb:1:in `<top (required)>'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:241:in `load'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:241:in `block in load'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:232:in `load_dependency'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:241:in `load'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/railties-4.1.5/lib/rails/application/routes_reloader.rb:40:in `block in load_paths'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/railties-4.1.5/lib/rails/application/routes_reloader.rb:40:in `each'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/railties-4.1.5/lib/rails/application/routes_reloader.rb:40:in `load_paths'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/railties-4.1.5/lib/rails/application/routes_reloader.rb:16:in `reload!'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/railties-4.1.5/lib/rails/application/routes_reloader.rb:26:in `block in updater'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/activesupport-4.1.5/lib/active_support/file_update_checker.rb:75:in `call'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/activesupport-4.1.5/lib/active_support/file_update_checker.rb:75:in `execute'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/railties-4.1.5/lib/rails/application/routes_reloader.rb:27:in `updater'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/railties-4.1.5/lib/rails/application/routes_reloader.rb:7:in `execute_if_updated'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/railties-4.1.5/lib/rails/application/finisher.rb:71:in `block in <module:Finisher>'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/railties-4.1.5/lib/rails/initializable.rb:30:in `instance_exec'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/railties-4.1.5/lib/rails/initializable.rb:30:in `run'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/railties-4.1.5/lib/rails/initializable.rb:55:in `block in run_initializers'
    from /Users/filip/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/tsort.rb:226:in `block in tsort_each'
    from /Users/filip/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/tsort.rb:348:in `block (2 levels) in each_strongly_connected_component'
    from /Users/filip/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/tsort.rb:427:in `each_strongly_connected_component_from'
    from /Users/filip/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/tsort.rb:347:in `block in each_strongly_connected_component'
    from /Users/filip/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/tsort.rb:345:in `each'
    from /Users/filip/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/tsort.rb:345:in `call'
    from /Users/filip/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/tsort.rb:345:in `each_strongly_connected_component'
    from /Users/filip/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/tsort.rb:224:in `tsort_each'
    from /Users/filip/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/tsort.rb:205:in `tsort_each'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/railties-4.1.5/lib/rails/initializable.rb:54:in `run_initializers'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/railties-4.1.5/lib/rails/application.rb:300:in `initialize!'
    from /Users/filip/programming/service_matters/config/environment.rb:5:in `<top (required)>'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:247:in `require'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:247:in `block in require'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:232:in `load_dependency'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:247:in `require'
    from /Users/filip/programming/service_matters/config.ru:3:in `block in <main>'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/rack-1.5.2/lib/rack/builder.rb:55:in `instance_eval'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/rack-1.5.2/lib/rack/builder.rb:55:in `initialize'
    from /Users/filip/programming/service_matters/config.ru:in `new'
    from /Users/filip/programming/service_matters/config.ru:in `<main>'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/rack-1.5.2/lib/rack/builder.rb:49:in `eval'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/rack-1.5.2/lib/rack/builder.rb:49:in `new_from_string'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/rack-1.5.2/lib/rack/builder.rb:40:in `parse_file'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/rack-1.5.2/lib/rack/server.rb:277:in `build_app_and_options_from_config'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/rack-1.5.2/lib/rack/server.rb:199:in `app'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/railties-4.1.5/lib/rails/commands/server.rb:50:in `app'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/rack-1.5.2/lib/rack/server.rb:314:in `wrapped_app'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/railties-4.1.5/lib/rails/commands/server.rb:130:in `log_to_stdout'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/railties-4.1.5/lib/rails/commands/server.rb:67:in `start'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/railties-4.1.5/lib/rails/commands/commands_tasks.rb:81:in `block in server'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/railties-4.1.5/lib/rails/commands/commands_tasks.rb:76:in `tap'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/railties-4.1.5/lib/rails/commands/commands_tasks.rb:76:in `server'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/railties-4.1.5/lib/rails/commands/commands_tasks.rb:40:in `run_command!'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/railties-4.1.5/lib/rails/commands.rb:17:in `<top (required)>'
    from /Users/filip/programming/service_matters/bin/rails:8:in `require'
    from /Users/filip/programming/service_matters/bin/rails:8:in `<top (required)>'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/spring-1.1.3/lib/spring/client/rails.rb:27:in `load'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/spring-1.1.3/lib/spring/client/rails.rb:27:in `call'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/spring-1.1.3/lib/spring/client/command.rb:7:in `call'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/spring-1.1.3/lib/spring/client.rb:26:in `run'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/spring-1.1.3/bin/spring:48:in `<top (required)>'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/spring-1.1.3/lib/spring/binstub.rb:11:in `load'
    from /Users/filip/.rvm/gems/ruby-2.1.2/gems/spring-1.1.3/lib/spring/binstub.rb:11:in `<top (required)>'
    from /Users/filip/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
    from /Users/filip/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
    from /Users/filip/programming/service_matters/bin/spring:16:in `<top (required)>'
    from bin/rails:3:in `load'
    from bin/rails:3:in `<main>'

Is compatible with Rails 6?

Rails 6 is coming, and it will be great to make gem compatible with it (even if Rails 6 is still in beta, alpha, and so on) 👍

Rails 5.1: Relax version spec in gemspec

Rails 5.1 is now out. DefaultValueFor requires Rails < 5.1.

default_value_for (~> 3.0) was resolved to 3.0.0, which depends on
      activerecord (< 5.0, >= 3.2.0)

Relax the gem version requirements?

class_inheritable_attribute is deprecated in Rails 3.1

Getting the following when using in a 3.1.0.beta1 app:
DEPRECATION WARNING: class_inheritable_attribute is deprecated, please use class_attribute method instead. Notice their behavior are slightly different, so refer to class_attribute documentation first.

default_value_for on a non-column attribute doesn't honor initialized attributes when `allows_nil` is false.

Here's what's currently in default_value_for.rb

        attribute_blank = if column && column.type == :boolean
          attributes[attribute].nil?
        else
          attributes[attribute].blank?
        end

Since the attributes hash is the only thing inspected, for non-column values this will always be nil.

It seems like the fix for this should be as easy as switching from checking the attributes hash to using the getter method.

Doesn't respect :without_protection => true

class Man < ActiveRecord::Base
  # email, role
  attr_accessible :email
  default_value_for :role, "user"

  def self.create_admin
    create!({:email => "[email protected]", :role => "admin"}, :without_protection => true)
  end
end

Raises: ActiveModel::MassAssignmentSecurity::Error: Can't mass-assign protected attributes: role (Rails 3.2.3)

STI bug

class Document < ActiveRecord::Base
  default_value_for :active, true
end

class Invoice < Document
  default_value_for :currency, 'usd'
end

Invoice.new.save doesn't save 'active' attribute to database. Removing default_value_for from Invoice helps.

`method_missing': undefined method `default_value_for'...

I was super psyched to find this gem, but I can't get it to work. I have gem "default_value_for", "~> 3.0.0" in my Gemfile, and after bundle install I get 'method_missing': undefined methoddefault_value_for'when startingrails c`.

Have you seen this before? The line it is erroring on is default_value_for :default_billing_cycle_day, 1

Thanks!

Documentation is confusing about defaut value for datetime/timestamp columns

I'm talking about this part:

You can also specify default values in the database schema. For example, you can specify a
default value in a migration as follows:

create_table :users do |t|
  ...
  t.timestamp :last_seen, :null => false, :default => Time.now
end

This has the same effect as passing the default value as the second argument to default_value_for.

Default value in migration sets the default value of column to the time of migration:

# migrated at 19:33:00
>> User.new
=> #<User id: nil, username: "default", last_seen: "2010-08-18 19:33:00">
>> User.new
=> #<User id: nil, username: "default", last_seen: "2010-08-18 19:33:00">

If I use default_value_for, it sets the default value of column to the time the class is loaded:

class User < ActiveRecord::Base
    default_value_for(:last_seen)  Time.now 
end

# console started at 19:34
>> User.new
=> #<User id: nil, username: "default", last_seen: "2010-08-18 19:34:00">
# restart 
>> User.new
=> #<User id: nil, username: "default", last_seen: "2010-08-18 19:34:35">

The behaviour is not the same as presented.

In my case I'm using the plugin for setting the default value of datetime
column to the time the object is initialized. I believe I can't reached this
behaviour by setting any default value in migration.

class User < ActiveRecord::Base
    default_value_for(:last_seen) { Time.now }
end

I think this is a good example when to use the plugin.

(Rails 2.3.8)

Problems in initalization with Rails 3.0.3, doesn't find ActiveRecord

    /Library/Ruby/Gems/1.8/gems/default_value_for-1.0.1/lib/rails.rb:23: uninitialized constant ActiveRecord (NameError)
from /Library/Ruby/Gems/1.8/gems/railties-3.0.3/lib/rails/all.rb:1:in `require'
from /Library/Ruby/Gems/1.8/gems/railties-3.0.3/lib/rails/all.rb:1
from /Users/tarmot/Sites/clients/avor/office/config/application.rb:3:in `require'
from /Users/tarmot/Sites/clients/avor/office/config/application.rb:3
from /Library/Ruby/Gems/1.8/gems/railties-3.0.3/lib/rails/commands.rb:21:in `require'
from /Library/Ruby/Gems/1.8/gems/railties-3.0.3/lib/rails/commands.rb:21
from script/rails:6:in `require'
from script/rails:6

default_value_for overrides values provided by an ActionController::Parameters object

My application uses permitted parameters when initializing a record. When attempting to provide nested attributes for a model that uses default_value_for, the ActionController::Parameters provided are ignored and overridden with the default value.

As of Rails 5, ActionController::Parameters no longer inherits from Hash. Because of this, the initialize method in default_value_for.rb does not handle instances of ActionController::Parameters correctly.

The issue lies at default_value_for.rb#L127. If attributes is a hash, it sets @initialization_attributes to be the result of attributes.stringify_keys. Otherwise, it sets it to an empty Hash, {}

This should support instances of ActionController::Parameters as well as Hashes.

Broken test suite

Is the test suite up to date and passing? I get a single failure:

test_can_specify_default_value_via_association(DefaultValuePluginTest):
NoMethodError: undefined method `default_number' for nil:NilClass

I've tried in 1.8.7-p352 and 1.9.2-p290. Any ideas?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.