From 5ca67eca21d2adfb418f96b63e7d3de237737a1e Mon Sep 17 00:00:00 2001 From: Prem Sichanugrist Date: Sun, 15 May 2011 14:19:09 -0400 Subject: [PATCH 1/2] Add ActiveRecord::attribute_names to retrieve a list of attribute names. This method will also return an empty array on an abstract class or a model that the table doesn't exists. --- activerecord/CHANGELOG | 2 ++ activerecord/lib/active_record/base.rb | 8 ++++++++ activerecord/test/cases/base_test.rb | 13 +++++++++++++ 3 files changed, 23 insertions(+) diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index 32bcf02139..2e144745cd 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,7 @@ *Rails 3.1.0 (unreleased)* +* Add ActiveRecord::Base.attribute_names to return a list of attribute names. This will return an empty array if the model is abstract or table does not exists. [Prem Sichanugrist] + * CSV Fixtures are deprecated and support will be removed in Rails 3.2.0 * AR#new, AR#create, AR#create!, AR#update_attributes and AR#update_attributes! all accept a second hash as option that allows you diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index e1bf2ccc8a..cfe6d8d2de 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -767,6 +767,14 @@ module ActiveRecord #:nodoc: super || (table_exists? && column_names.include?(attribute.to_s.sub(/=$/, ''))) end + def attribute_names + @attribute_names ||= if !abstract_class? && table_exists? + column_names + else + [] + end + end + # Set the lookup ancestors for ActiveModel. def lookup_ancestors #:nodoc: klass = self diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index 9bc04ed29c..bfb66f07da 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -1790,4 +1790,17 @@ class BasicsTest < ActiveRecord::TestCase assert_equal expected.attributes, actual.attributes end + + def test_attribute_names + assert_equal ["id", "type", "ruby_type", "firm_id", "firm_name", "name", "client_of", "rating", "account_id"], + Company.attribute_names + end + + def test_attribute_names_on_table_not_exists + assert_equal [], NonExistentTable.attribute_names + end + + def test_attribtue_names_on_abstract_class + assert_equal [], AbstractCompany.attribute_names + end end From d77b306b63e20aabec5daf7159d31c8ee31492c9 Mon Sep 17 00:00:00 2001 From: Prem Sichanugrist Date: Sun, 15 May 2011 14:25:00 -0400 Subject: [PATCH 2/2] Make ParamsWrapper calling newly introduced `Model.attribute_names` instead of `.column_names` --- actionpack/CHANGELOG | 2 +- .../action_controller/metal/params_wrapper.rb | 6 +++--- .../test/controller/params_wrapper_test.rb | 18 ++++++++---------- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 68076b794e..15abfb8369 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -17,7 +17,7 @@ class PostsController < ActionController::Base stream :only => :index end - + Please read the docs at `ActionController::Streaming` for more information. * Added `ActionDispatch::Request.ignore_accept_header` to ignore accept headers and only consider the format given as parameter [José Valim] diff --git a/actionpack/lib/action_controller/metal/params_wrapper.rb b/actionpack/lib/action_controller/metal/params_wrapper.rb index b18be60201..aa7c1e09c2 100644 --- a/actionpack/lib/action_controller/metal/params_wrapper.rb +++ b/actionpack/lib/action_controller/metal/params_wrapper.rb @@ -145,7 +145,7 @@ module ActionController begin model_klass = model_name.constantize rescue NameError, ArgumentError => e - if e.message =~ /is not missing constant|uninitialized constant #{model_name}/ + if e.message =~ /is not missing constant|uninitialized constant #{model_name}/ namespaces = model_name.split("::") namespaces.delete_at(-2) break if namespaces.last == model_name @@ -163,8 +163,8 @@ module ActionController unless options[:only] || options[:except] model ||= _default_wrap_model - if !(model.respond_to?(:abstract_class?) && model.abstract_class?) && model.respond_to?(:column_names) - options[:only] = model.column_names + if model.respond_to?(:attribute_names) && model.attribute_names.present? + options[:only] = model.attribute_names end end diff --git a/actionpack/test/controller/params_wrapper_test.rb b/actionpack/test/controller/params_wrapper_test.rb index bed4a6a553..ae4ad8eb9c 100644 --- a/actionpack/test/controller/params_wrapper_test.rb +++ b/actionpack/test/controller/params_wrapper_test.rb @@ -133,9 +133,8 @@ class ParamsWrapperTest < ActionController::TestCase end def test_derived_wrapped_keys_from_matching_model - User.expects(:respond_to?).with(:abstract_class?).returns(false) - User.expects(:respond_to?).with(:column_names).returns(true) - User.expects(:column_names).returns(["username"]) + User.expects(:respond_to?).with(:attribute_names).returns(true) + User.expects(:attribute_names).twice.returns(["username"]) with_default_wrapper_options do @request.env['CONTENT_TYPE'] = 'application/json' @@ -146,9 +145,8 @@ class ParamsWrapperTest < ActionController::TestCase def test_derived_wrapped_keys_from_specified_model with_default_wrapper_options do - Person.expects(:respond_to?).with(:abstract_class?).returns(false) - Person.expects(:respond_to?).with(:column_names).returns(true) - Person.expects(:column_names).returns(["username"]) + Person.expects(:respond_to?).with(:attribute_names).returns(true) + Person.expects(:attribute_names).twice.returns(["username"]) UsersController.wrap_parameters Person @@ -159,8 +157,8 @@ class ParamsWrapperTest < ActionController::TestCase end def test_not_wrapping_abstract_model - User.expects(:respond_to?).with(:abstract_class?).returns(true) - User.expects(:abstract_class?).returns(true) + User.expects(:respond_to?).with(:attribute_names).returns(true) + User.expects(:attribute_names).returns([]) with_default_wrapper_options do @request.env['CONTENT_TYPE'] = 'application/json' @@ -198,13 +196,13 @@ class NamespacedParamsWrapperTest < ActionController::TestCase end class SampleOne - def self.column_names + def self.attribute_names ["username"] end end class SampleTwo - def self.column_names + def self.attribute_names ["title"] end end