aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib')
-rw-r--r--activerecord/lib/active_record.rb1
-rw-r--r--activerecord/lib/active_record/attribute_methods/read.rb35
-rw-r--r--activerecord/lib/active_record/attribute_methods/write.rb33
-rw-r--r--activerecord/lib/active_record/base.rb1
-rw-r--r--activerecord/lib/active_record/secure_token.rb49
-rw-r--r--activerecord/lib/active_record/type/boolean.rb4
6 files changed, 76 insertions, 47 deletions
diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb
index 2eec62846b..d9d47c3d99 100644
--- a/activerecord/lib/active_record.rb
+++ b/activerecord/lib/active_record.rb
@@ -67,6 +67,7 @@ module ActiveRecord
autoload :Transactions
autoload :Translation
autoload :Validations
+ autoload :SecureToken
eager_autoload do
autoload :ActiveRecordError, 'active_record/errors'
diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb
index f6ab543015..4b72fe7d7e 100644
--- a/activerecord/lib/active_record/attribute_methods/read.rb
+++ b/activerecord/lib/active_record/attribute_methods/read.rb
@@ -1,5 +1,3 @@
-require 'active_support/core_ext/module/method_transplanting'
-
module ActiveRecord
module AttributeMethods
module Read
@@ -38,29 +36,22 @@ module ActiveRecord
module ClassMethods
protected
- if Module.methods_transplantable?
- def define_method_attribute(name)
- method = ReaderMethodCache[name]
- generated_attribute_methods.module_eval { define_method name, method }
- end
- else
- def define_method_attribute(name)
- safe_name = name.unpack('h*').first
- temp_method = "__temp__#{safe_name}"
-
- ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
+ def define_method_attribute(name)
+ safe_name = name.unpack('h*').first
+ temp_method = "__temp__#{safe_name}"
- generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
- def #{temp_method}
- name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
- _read_attribute(name) { |n| missing_attribute(n, caller) }
- end
- STR
+ ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
- generated_attribute_methods.module_eval do
- alias_method name, temp_method
- undef_method temp_method
+ generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
+ def #{temp_method}
+ name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
+ _read_attribute(name) { |n| missing_attribute(n, caller) }
end
+ STR
+
+ generated_attribute_methods.module_eval do
+ alias_method name, temp_method
+ undef_method temp_method
end
end
end
diff --git a/activerecord/lib/active_record/attribute_methods/write.rb b/activerecord/lib/active_record/attribute_methods/write.rb
index 16804f86bf..ab017c7b54 100644
--- a/activerecord/lib/active_record/attribute_methods/write.rb
+++ b/activerecord/lib/active_record/attribute_methods/write.rb
@@ -1,5 +1,3 @@
-require 'active_support/core_ext/module/method_transplanting'
-
module ActiveRecord
module AttributeMethods
module Write
@@ -25,27 +23,18 @@ module ActiveRecord
module ClassMethods
protected
- if Module.methods_transplantable?
- def define_method_attribute=(name)
- method = WriterMethodCache[name]
- generated_attribute_methods.module_eval {
- define_method "#{name}=", method
- }
- end
- else
- def define_method_attribute=(name)
- safe_name = name.unpack('h*').first
- ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
+ def define_method_attribute=(name)
+ safe_name = name.unpack('h*').first
+ ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
- generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
- def __temp__#{safe_name}=(value)
- name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
- write_attribute(name, value)
- end
- alias_method #{(name + '=').inspect}, :__temp__#{safe_name}=
- undef_method :__temp__#{safe_name}=
- STR
- end
+ generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
+ def __temp__#{safe_name}=(value)
+ name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
+ write_attribute(name, value)
+ end
+ alias_method #{(name + '=').inspect}, :__temp__#{safe_name}=
+ undef_method :__temp__#{safe_name}=
+ STR
end
end
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index bb01231bca..100d3780f6 100644
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -312,6 +312,7 @@ module ActiveRecord #:nodoc:
include Reflection
include Serialization
include Store
+ include SecureToken
end
ActiveSupport.run_load_hooks(:active_record, Base)
diff --git a/activerecord/lib/active_record/secure_token.rb b/activerecord/lib/active_record/secure_token.rb
new file mode 100644
index 0000000000..23d4292cbb
--- /dev/null
+++ b/activerecord/lib/active_record/secure_token.rb
@@ -0,0 +1,49 @@
+module ActiveRecord
+ module SecureToken
+ extend ActiveSupport::Concern
+
+ module ClassMethods
+ # Example using has_secure_token
+ #
+ # # Schema: User(toke:string, auth_token:string)
+ # class User < ActiveRecord::Base
+ # has_secure_token
+ # has_secure_token :auth_token
+ # end
+ #
+ # user = User.new
+ # user.save
+ # user.token # => "44539a6a59835a4ee9d7b112"
+ # user.auth_token # => "e2426a93718d1817a43abbaa"
+ # user.regenerate_token # => true
+ # user.regenerate_auth_token # => true
+ #
+ # SecureRandom is used to generate the 24-character unique token, so collisions are highly unlikely.
+ # We'll check to see if the generated token has been used already using #exists?, and retry up to 10
+ # times to find another unused token. After that a RuntimeError is raised if the problem persists.
+ #
+ # Note that it's still possible to generate a race condition in the database in the same way that
+ # validates_presence_of can. You're encouraged to add a unique index in the database to deal with
+ # this even more unlikely scenario.
+ def has_secure_token(attribute = :token)
+ # Load securerandom only when has_secure_key is used.
+ require 'securerandom'
+ define_method("regenerate_#{attribute}") { update! attribute => self.class.generate_unique_secure_token(attribute) }
+ before_create { self.send("#{attribute}=", self.class.generate_unique_secure_token(attribute)) }
+ end
+
+ def generate_unique_secure_token(attribute)
+ 10.times do |i|
+ SecureRandom.hex(12).tap do |token|
+ if exists?(attribute => token)
+ raise "Couldn't generate a unique token in 10 attempts!" if i == 9
+ else
+ return token
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
diff --git a/activerecord/lib/active_record/type/boolean.rb b/activerecord/lib/active_record/type/boolean.rb
index 2e24afc7c0..f6a75512fd 100644
--- a/activerecord/lib/active_record/type/boolean.rb
+++ b/activerecord/lib/active_record/type/boolean.rb
@@ -10,10 +10,8 @@ module ActiveRecord
def cast_value(value)
if value == ''
nil
- elsif ConnectionAdapters::Column::FALSE_VALUES.include?(value)
- false
else
- true
+ !ConnectionAdapters::Column::FALSE_VALUES.include?(value)
end
end
end