diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index b1c5987fe4ae7..8da82aab84f62 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -35,4 +35,8 @@
*Bryan Ricker*
+* Add support for wrapping parameters matching aliased attribute names.
+
+ *Patrick Van Stee*
+
Please check [4-0-stable](https://github.com/rails/rails/blob/4-0-stable/actionpack/CHANGELOG.md) for previous changes.
diff --git a/actionpack/lib/action_controller/metal/params_wrapper.rb b/actionpack/lib/action_controller/metal/params_wrapper.rb
index c9f1d8dcb4097..7a6cd6c09ccf4 100644
--- a/actionpack/lib/action_controller/metal/params_wrapper.rb
+++ b/actionpack/lib/action_controller/metal/params_wrapper.rb
@@ -44,7 +44,7 @@ module ActionController
#
# On ActiveRecord models with no +:include+ or +:exclude+ option set,
# it will only wrap the parameters returned by the class method
- # attribute_names.
+ # attribute_method_names.
#
# If you're going to pass the parameters to an +ActiveModel+ object (such as
# User.new(params[:user])), you might consider passing the model class to
@@ -106,8 +106,8 @@ def include
@include_set = true
unless super || exclude
- if m.respond_to?(:attribute_names) && m.attribute_names.any?
- self.include = m.attribute_names
+ if m.respond_to?(:attribute_method_names) && m.attribute_method_names.any?
+ self.include = m.attribute_method_names
end
end
end
diff --git a/actionpack/test/controller/params_wrapper_test.rb b/actionpack/test/controller/params_wrapper_test.rb
index d87e2b85b0653..cc795a08beb86 100644
--- a/actionpack/test/controller/params_wrapper_test.rb
+++ b/actionpack/test/controller/params_wrapper_test.rb
@@ -155,8 +155,8 @@ def test_nested_params
end
def test_derived_wrapped_keys_from_matching_model
- User.expects(:respond_to?).with(:attribute_names).returns(true)
- User.expects(:attribute_names).twice.returns(["username"])
+ User.expects(:respond_to?).with(:attribute_method_names).returns(true)
+ User.expects(:attribute_method_names).twice.returns(["username"])
with_default_wrapper_options do
@request.env['CONTENT_TYPE'] = 'application/json'
@@ -167,8 +167,8 @@ def test_derived_wrapped_keys_from_matching_model
def test_derived_wrapped_keys_from_specified_model
with_default_wrapper_options do
- Person.expects(:respond_to?).with(:attribute_names).returns(true)
- Person.expects(:attribute_names).twice.returns(["username"])
+ Person.expects(:respond_to?).with(:attribute_method_names).returns(true)
+ Person.expects(:attribute_method_names).twice.returns(["username"])
UsersController.wrap_parameters Person
@@ -179,8 +179,8 @@ def test_derived_wrapped_keys_from_specified_model
end
def test_not_wrapping_abstract_model
- User.expects(:respond_to?).with(:attribute_names).returns(true)
- User.expects(:attribute_names).returns([])
+ User.expects(:respond_to?).with(:attribute_method_names).returns(true)
+ User.expects(:attribute_method_names).returns([])
with_default_wrapper_options do
@request.env['CONTENT_TYPE'] = 'application/json'
@@ -209,13 +209,13 @@ def parse
end
class SampleOne
- def self.attribute_names
+ def self.attribute_method_names
["username"]
end
end
class SampleTwo
- def self.attribute_names
+ def self.attribute_method_names
["title"]
end
end
@@ -298,7 +298,7 @@ class IrregularInflectionParamsWrapperTest < ActionController::TestCase
include ParamsWrapperTestHelp
class ParamswrappernewsItem
- def self.attribute_names
+ def self.attribute_method_names
['test_attr']
end
end
diff --git a/activemodel/CHANGELOG.md b/activemodel/CHANGELOG.md
index 6fc34ecd60b66..0dde69e114b78 100644
--- a/activemodel/CHANGELOG.md
+++ b/activemodel/CHANGELOG.md
@@ -7,4 +7,9 @@
*Nick Sutterer*
+* Add the `ActiveModel#attribute_method_names` method, which returns an
+ array of attribute names and aliases as strings.
+
+ *Patrick Van Stee*
+
Please check [4-0-stable](https://github.com/rails/rails/blob/4-0-stable/activemodel/CHANGELOG.md) for previous changes.
diff --git a/activemodel/lib/active_model/attribute_methods.rb b/activemodel/lib/active_model/attribute_methods.rb
index 98cde8ba59198..1e7aef119189e 100644
--- a/activemodel/lib/active_model/attribute_methods.rb
+++ b/activemodel/lib/active_model/attribute_methods.rb
@@ -72,9 +72,10 @@ module AttributeMethods
CALL_COMPILABLE_REGEXP = /\A[a-zA-Z_]\w*[!?]?\z/
included do
- class_attribute :attribute_aliases, :attribute_method_matchers, instance_writer: false
+ class_attribute :attribute_aliases, :attribute_method_matchers, :defined_attribute_names, instance_writer: false
self.attribute_aliases = {}
self.attribute_method_matchers = [ClassMethods::AttributeMethodMatcher.new]
+ self.defined_attribute_names = []
end
module ClassMethods
@@ -276,6 +277,10 @@ def define_attribute_methods(*attr_names)
# person.name # => "Bob"
# person.name_short? # => true
def define_attribute_method(attr_name)
+ attr_name = attr_name.to_s
+
+ self.defined_attribute_names << attr_name unless defined_attribute_names.include?(attr_name)
+
attribute_method_matchers.each do |matcher|
method_name = matcher.method_name(attr_name)
@@ -285,10 +290,11 @@ def define_attribute_method(attr_name)
if respond_to?(generate_method, true)
send(generate_method, attr_name)
else
- define_proxy_call true, generated_attribute_methods, method_name, matcher.method_missing_target, attr_name.to_s
+ define_proxy_call true, generated_attribute_methods, method_name, matcher.method_missing_target, attr_name
end
end
end
+
attribute_method_matchers_cache.clear
end
@@ -322,6 +328,22 @@ def undefine_attribute_methods
attribute_method_matchers_cache.clear
end
+ # Returns an array of attribute names and aliases as strings.
+ #
+ # class Person
+ # include ActiveModel::AttributeMethods
+ #
+ # define_attribute_method :name
+ #
+ # alias_attribute :nickname, :name
+ # end
+ #
+ # Person.attribute_method_names
+ # # => ["name", "nickname"]
+ def attribute_method_names
+ defined_attribute_names + attribute_aliases.keys
+ end
+
# Returns true if the attribute methods defined have been generated.
def generated_attribute_methods #:nodoc:
@generated_attribute_methods ||= Module.new.tap { |mod| include mod }
diff --git a/activemodel/test/cases/attribute_methods_test.rb b/activemodel/test/cases/attribute_methods_test.rb
index 25eb4860e32a8..4ba7b0808db12 100644
--- a/activemodel/test/cases/attribute_methods_test.rb
+++ b/activemodel/test/cases/attribute_methods_test.rb
@@ -186,6 +186,15 @@ def foo
assert_equal "value of end", ModelWithRubyKeywordNamedAttributes.new.to
end
+ test '#attribute_method_names returns attribute names and attribute aliases' do
+ klass = Class.new(ModelWithAttributes) do
+ define_attribute_methods :foo
+ alias_attribute :bar, :foo
+ end
+
+ assert_equal ["foo", "bar"], klass.attribute_method_names
+ end
+
test '#undefine_attribute_methods removes attribute methods' do
ModelWithAttributes.define_attribute_methods(:foo)
ModelWithAttributes.undefine_attribute_methods
diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb
index 28839a9c4b550..6ba2e865de469 100644
--- a/railties/test/application/configuration_test.rb
+++ b/railties/test/application/configuration_test.rb
@@ -514,7 +514,7 @@ def index
app_file 'app/models/post.rb', <<-RUBY
class Post
- def self.attribute_names
+ def self.attribute_method_names
%w(title)
end
end