diff options
-rw-r--r-- | actionpack/lib/action_controller/record_identifier.rb | 21 | ||||
-rw-r--r-- | actionpack/test/lib/controller/fake_models.rb | 16 | ||||
-rw-r--r-- | actionpack/test/template/prototype_helper_test.rb | 3 | ||||
-rw-r--r-- | activemodel/lib/active_model/lint.rb | 23 | ||||
-rw-r--r-- | activemodel/lib/active_model/naming.rb | 2 | ||||
-rw-r--r-- | activemodel/test/cases/lint_test.rb | 8 | ||||
-rw-r--r-- | activerecord/lib/active_record/attribute_methods/primary_key.rb | 14 | ||||
-rw-r--r-- | activerecord/test/cases/pk_test.rb | 9 |
8 files changed, 94 insertions, 2 deletions
diff --git a/actionpack/lib/action_controller/record_identifier.rb b/actionpack/lib/action_controller/record_identifier.rb index 1165c3b7c5..9c35c5b0c3 100644 --- a/actionpack/lib/action_controller/record_identifier.rb +++ b/actionpack/lib/action_controller/record_identifier.rb @@ -60,13 +60,32 @@ module ActionController # # dom_id(Post.find(45), :edit) # => "edit_post_45" def dom_id(record, prefix = nil) - if record_id = record.id + if record_id = record_key_for_dom_id(record) "#{dom_class(record, prefix)}#{JOIN}#{record_id}" else dom_class(record, prefix || NEW) end end + # Returns a string representation of the key attribute(s) that is suitable for use in an HTML DOM id. + # This can be overwritten to customize the default generated string representation if desired. + # If you need to read back a key from a dom_id in order to query for the underlying database record, + # you should write a helper like 'person_record_from_dom_id' that will extract the key either based + # on the default implementation (which just joins all key attributes with '-') or on your own + # overwritten version of the method. By default, this implementation passes the key string through a + # method that replaces all characters that are invalid inside DOM ids, with valid ones. You need to + # make sure yourself that your dom ids are valid, in case you overwrite this method. + def record_key_for_dom_id(record) + return record.id unless record.respond_to?(:to_model) + key = record.to_model.key + key ? sanitize_dom_id(key.join('-')) : key + end + + # Replaces characters that are invalid in HTML DOM ids with valid ones. + def sanitize_dom_id(candidate_id) + candidate_id # TODO implement conversion to valid DOM id values + end + # Returns the plural class name of a record or class. Examples: # # plural_class_name(post) # => "posts" diff --git a/actionpack/test/lib/controller/fake_models.rb b/actionpack/test/lib/controller/fake_models.rb index a8c86f70b6..e4aed14dc0 100644 --- a/actionpack/test/lib/controller/fake_models.rb +++ b/actionpack/test/lib/controller/fake_models.rb @@ -6,6 +6,10 @@ class Customer < Struct.new(:name, :id) undef_method :to_json + def key + id ? [id] : nil + end + def to_param id.to_s end @@ -43,6 +47,10 @@ module Quiz extend ActiveModel::Naming include ActiveModel::Conversion + def key + id ? [id] : nil + end + def to_param id.to_s end @@ -59,6 +67,10 @@ class Post < Struct.new(:title, :author_name, :body, :secret, :written_on, :cost alias_method :secret?, :secret + def key + id ? [id] : nil + end + def new_record=(boolean) @new_record = boolean end @@ -84,6 +96,7 @@ class Comment attr_reader :id attr_reader :post_id def initialize(id = nil, post_id = nil); @id, @post_id = id, post_id end + def key; id ? [id] : nil end def save; @id = 1; @post_id = 1 end def new_record?; @id.nil? end def to_param; @id; end @@ -103,6 +116,7 @@ class Tag attr_reader :id attr_reader :post_id def initialize(id = nil, post_id = nil); @id, @post_id = id, post_id end + def key; id ? [id] : nil end def save; @id = 1; @post_id = 1 end def new_record?; @id.nil? end def to_param; @id; end @@ -122,6 +136,7 @@ class CommentRelevance attr_reader :id attr_reader :comment_id def initialize(id = nil, comment_id = nil); @id, @comment_id = id, comment_id end + def key; id ? [id] : nil end def save; @id = 1; @comment_id = 1 end def new_record?; @id.nil? end def to_param; @id; end @@ -137,6 +152,7 @@ class TagRelevance attr_reader :id attr_reader :tag_id def initialize(id = nil, tag_id = nil); @id, @tag_id = id, tag_id end + def key; id ? [id] : nil end def save; @id = 1; @tag_id = 1 end def new_record?; @id.nil? end def to_param; @id; end diff --git a/actionpack/test/template/prototype_helper_test.rb b/actionpack/test/template/prototype_helper_test.rb index d95bdc2b90..dab34f1201 100644 --- a/actionpack/test/template/prototype_helper_test.rb +++ b/actionpack/test/template/prototype_helper_test.rb @@ -4,6 +4,7 @@ require 'active_model' class Bunny < Struct.new(:Bunny, :id) extend ActiveModel::Naming include ActiveModel::Conversion + def key() id ? [id] : nil end end class Author @@ -11,6 +12,7 @@ class Author include ActiveModel::Conversion attr_reader :id + def key() id ? [id] : nil end def save; @id = 1 end def new_record?; @id.nil? end def name @@ -23,6 +25,7 @@ class Article include ActiveModel::Conversion attr_reader :id attr_reader :author_id + def key() id ? [id] : nil end def save; @id = 1; @author_id = 1 end def new_record?; @id.nil? end def name diff --git a/activemodel/lib/active_model/lint.rb b/activemodel/lib/active_model/lint.rb index 7bf0ad712d..c97286e61c 100644 --- a/activemodel/lib/active_model/lint.rb +++ b/activemodel/lib/active_model/lint.rb @@ -13,6 +13,29 @@ module ActiveModel module Lint module Tests + + # == Responds to <tt>key</tt> + # + # Returns an Enumerable of all (primary) key attributes + # or nil if model.new_record? is true + def test_key + assert model.respond_to?(:key), "The model should respond to key" + def model.new_record?() true end + assert model.key.nil? + def model.new_record?() false end + assert model.key.respond_to?(:each) + end + + # == Responds to <tt>to_param</tt> + # + # Returns a string representing the object's key suitable for use in URLs + # or nil if model.new_record? is true + def test_to_param + assert model.respond_to?(:to_param), "The model should respond to to_param" + def model.new_record?() true end + assert model.to_param.nil? + end + # == Responds to <tt>valid?</tt> # # Returns a boolean that specifies whether the object is in a valid or invalid diff --git a/activemodel/lib/active_model/naming.rb b/activemodel/lib/active_model/naming.rb index 89e8f8b1ea..39512a427b 100644 --- a/activemodel/lib/active_model/naming.rb +++ b/activemodel/lib/active_model/naming.rb @@ -41,7 +41,7 @@ module ActiveModel # To implement, just extend ActiveModel::Naming in your object: # # class BookCover - # exten ActiveModel::Naming + # extend ActiveModel::Naming # end # # BookCover.model_name #=> "BookCover" diff --git a/activemodel/test/cases/lint_test.rb b/activemodel/test/cases/lint_test.rb index 63804004ee..58716cbf85 100644 --- a/activemodel/test/cases/lint_test.rb +++ b/activemodel/test/cases/lint_test.rb @@ -10,6 +10,14 @@ class LintTest < ActiveModel::TestCase self end + def key + new_record? ? nil : [1] + end + + def to_param + key ? key.first.to_s : nil + end + def valid?() true end def new_record?() true end def destroyed?() true end diff --git a/activerecord/lib/active_record/attribute_methods/primary_key.rb b/activerecord/lib/active_record/attribute_methods/primary_key.rb index 365fdeb55a..ba64b8ee2f 100644 --- a/activerecord/lib/active_record/attribute_methods/primary_key.rb +++ b/activerecord/lib/active_record/attribute_methods/primary_key.rb @@ -39,6 +39,20 @@ module ActiveRecord end alias :primary_key= :set_primary_key end + + module InstanceMethods + + # Returns this record's primary key value wrapped in an Array + # or nil if the record is a new_record? + # This is done to comply with the AMo interface that expects + # every AMo compliant object to respond_to?(:key) and return + # an Enumerable object from that call, or nil if new_record? + def key + new_record? ? nil : [ self.id ] + end + + end + end end end diff --git a/activerecord/test/cases/pk_test.rb b/activerecord/test/cases/pk_test.rb index c121e0aa0f..2502c136cc 100644 --- a/activerecord/test/cases/pk_test.rb +++ b/activerecord/test/cases/pk_test.rb @@ -9,6 +9,15 @@ require 'models/mixed_case_monkey' class PrimaryKeysTest < ActiveRecord::TestCase fixtures :topics, :subscribers, :movies, :mixed_case_monkeys + def test_key + # test new record + topic = Topic.new + assert topic.key.nil? + # test existing record + topic = Topic.find(1) + assert_equal topic.key, [1] + end + def test_integer_key topic = Topic.find(1) assert_equal(topics(:first).author_name, topic.author_name) |