Skip to content
Permalink
Browse files

Allow proc defaults with the Attributes API

This is a variant implementation of the changes proposed in #19914.
Unlike that PR, the change in behavior is isolated in its own class.
This is to prevent wonky behavior if a Proc is assigned outside of the
default, and it is a natural place to place the behavior required by #19921
as well.

Close #19914.

[Sean Griffin & Kir Shatrov]
  • Loading branch information
sgrif committed May 28, 2015
1 parent 73aab03 commit a6e3cdae0ce1d05a6b9f7dff4499f6be3fbf63c2
@@ -0,0 +1,19 @@
require 'active_record/attribute'

module ActiveRecord
class Attribute # :nodoc:
class UserProvidedDefault < FromUser
def initialize(name, value, type)
super(name, value, type)
end

def type_cast(value)
if value.is_a?(Proc)
super(value.call)
else
super
end
end
end
end
end
@@ -1,3 +1,5 @@
require 'active_record/attribute/user_provided_default'

module ActiveRecord
# See ActiveRecord::Attributes::ClassMethods for documentation
module Attributes
@@ -236,7 +238,11 @@ def define_default_attribute(name, value, type, from_user:)
if value == NO_DEFAULT_PROVIDED
default_attribute = _default_attributes[name].with_type(type)
elsif from_user
default_attribute = Attribute.from_user(name, value, type)
default_attribute = Attribute::UserProvidedDefault.new(
name,
value,
type,
)
else
default_attribute = Attribute.from_database(name, value, type)
end
@@ -125,6 +125,16 @@ def deserialize(*)
assert_equal "from user", model.wibble
end

test "procs for default values" do
klass = Class.new(OverloadedType) do
@@counter = 0
attribute :counter, :integer, default: -> { @@counter += 1 }
end

assert_equal 1, klass.new.counter
assert_equal 2, klass.new.counter
end

if current_adapter?(:PostgreSQLAdapter)
test "arrays types can be specified" do
klass = Class.new(OverloadedType) do

2 comments on commit a6e3cda

@PikachuEXE

This comment has been minimized.

Copy link
Contributor

PikachuEXE replied May 30, 2015

Can the proc call instance method without receiver?
It's not clear with current test

@sgrif

This comment has been minimized.

Copy link
Contributor Author

sgrif replied May 30, 2015

No, the proc doesn't get instance_eval ed, as it's meant to be a class level default. You should use after_initialize if you need more complex behavior.

Please sign in to comment.
You can’t perform that action at this time.