aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/lib/action_controller/record_identifier.rb21
-rw-r--r--actionpack/test/lib/controller/fake_models.rb16
-rw-r--r--actionpack/test/template/prototype_helper_test.rb3
-rw-r--r--activemodel/lib/active_model/lint.rb23
-rw-r--r--activemodel/lib/active_model/naming.rb2
-rw-r--r--activemodel/test/cases/lint_test.rb8
-rw-r--r--activerecord/lib/active_record/attribute_methods/primary_key.rb14
-rw-r--r--activerecord/test/cases/pk_test.rb9
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)