Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Changeset 6731

Show
Ignore:
Timestamp:
05/14/07 17:30:35 (2 years ago)
Author:
david
Message:

Added record identifications to FormHelper#form_for and PrototypeHelper#remote_form_for [DHH]

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/actionpack/CHANGELOG

    r6730 r6731  
    11*SVN* 
     2 
     3* Added record identifications to FormHelper#form_for and PrototypeHelper#remote_form_for [DHH]. Examples: 
     4 
     5    <% form_for(@post) do |f| %> 
     6      ... 
     7    <% end %> 
     8   
     9  This will expand to be the same as: 
     10   
     11    <% form_for :post, @post, :url => post_path(@post), :html => { :method => :put, :class => "edit_post", :id => "edit_post_45" } do |f| %> 
     12      ... 
     13    <% end %> 
     14   
     15  And for new records: 
     16   
     17    <% form_for(Post.new) do |f| %> 
     18      ... 
     19    <% end %> 
     20   
     21  This will expand to be the same as: 
     22   
     23    <% form_for :post, @post, :url => posts_path, :html => { :class => "new_post", :id => "new_post" } do |f| %> 
     24      ... 
     25    <% end %> 
    226 
    327* Rationalize route path escaping according to RFC 2396 section 3.3.  #7544, #8307. [Jeremy Kemper, chrisroos, begemot, jugend] 
  • trunk/actionpack/lib/action_controller/base.rb

    r6729 r6731  
    10001000      # 
    10011001      # * <tt>Hash</tt>: The URL will be generated by calling url_for with the +options+. 
     1002      # * <tt>Record</tt>: The URL will be generated by calling url_for with the +options+, which will reference a named URL for that record. 
    10021003      # * <tt>String starting with protocol:// (like http://)</tt>: Is passed straight through as the target for redirection. 
    10031004      # * <tt>String not containing a protocol</tt>: The current protocol and host is prepended to the string. 
     
    10071008      # Examples: 
    10081009      #   redirect_to :action => "show", :id => 5 
     1010      #   redirect_to post 
    10091011      #   redirect_to "http://www.rubyonrails.org" 
    10101012      #   redirect_to "/images/screenshot.jpg" 
  • trunk/actionpack/lib/action_controller/polymorphic_routes.rb

    r6729 r6731  
    88      case 
    99      when options[:action] == "new" 
    10         url_writer.send(action_prefix(options) + RecordIdentifier.singular_class_name(record) + routing_type(options)) 
     10        url_writer.send( 
     11          action_prefix(options) + RecordIdentifier.singular_class_name(record) + routing_type(options) 
     12        ) 
    1113 
    1214      when record.respond_to?(:new_record?) && record.new_record? 
    13         url_writer.send(RecordIdentifier.plural_class_name(record) + routing_type(options)) 
     15        url_writer.send( 
     16          action_prefix(options) + RecordIdentifier.plural_class_name(record) + routing_type(options) 
     17        ) 
    1418 
    1519      else 
  • trunk/actionpack/lib/action_controller/record_identifier.rb

    r6633 r6731  
    6464    #   dom_class(Post.new(:id => 45), :edit) # => "edit_post_45" 
    6565    def dom_id(record, prefix = nil)  
    66       prefix ||= 'new' unless record.id  
     66      prefix ||= 'new' unless record.id 
    6767      [ prefix, singular_class_name(record), record.id ].compact * '_' 
    6868    end 
  • trunk/actionpack/lib/action_view/helpers/form_helper.rb

    r6689 r6731  
    103103      # The above form will then have the <tt>id</tt> attribute with the value </tt>person_form</tt>, which you can then 
    104104      # style with CSS or manipulate with JavaScript. 
     105      # 
     106      # === Relying on record identification 
     107      # 
     108      # In addition to manually configuring the form_for call, you can also rely on record identification, which will use 
     109      # the conventions and named routes of that approach. Examples: 
     110      # 
     111      #   <% form_for(@post) do |f| %> 
     112      #     ... 
     113      #   <% end %> 
     114      # 
     115      # This will expand to be the same as: 
     116      # 
     117      #   <% form_for :post, @post, :url => post_path(@post), :html => { :method => :put, :class => "edit_post", :id => "edit_post_45" } do |f| %> 
     118      #     ... 
     119      #   <% end %> 
     120      # 
     121      # And for new records: 
     122      # 
     123      #   <% form_for(Post.new) do |f| %> 
     124      #     ... 
     125      #   <% end %> 
     126      # 
     127      # This will expand to be the same as: 
     128      # 
     129      #   <% form_for :post, @post, :url => posts_path, :html => { :class => "new_post", :id => "new_post" } do |f| %> 
     130      #     ... 
     131      #   <% end %> 
     132      # 
     133      # You can also overwrite the individual conventions, like this: 
     134      # 
     135      #   <% form_for(@post, :url => super_post_path(@post)) do |f| %> 
     136      #     ... 
     137      #   <% end %> 
     138      # 
     139      # === Customized form builders 
    105140      # 
    106141      # You can also build forms using a customized FormBuilder class. Subclass FormBuilder and override or define some more helpers, 
     
    121156      # 
    122157      # If you don't need to attach a form to a model instance, then check out FormTagHelper#form_tag. 
    123       def form_for(object_name, *args, &proc) 
     158      def form_for(record_or_name, *args, &proc) 
    124159        raise ArgumentError, "Missing block" unless block_given? 
     160 
    125161        options = args.last.is_a?(Hash) ? args.pop : {} 
     162 
     163        case record_or_name 
     164        when String, Symbol 
     165          object_name = record_or_name 
     166        else 
     167          object      = record_or_name 
     168          object_name = ActionController::RecordIdentifier.singular_class_name(record_or_name) 
     169          apply_form_for_options!(object, options) 
     170        end 
     171 
    126172        concat(form_tag(options.delete(:url) || {}, options.delete(:html) || {}), proc.binding) 
    127173        fields_for(object_name, *(args << options), &proc) 
    128174        concat('</form>', proc.binding) 
     175      end 
     176       
     177      def apply_form_for_options!(object, options) #:nodoc: 
     178        html_options = if object.respond_to?(:new_record?) && object.new_record? 
     179          { :class  => dom_class(object, :new),  :id => dom_id(object), :method => :post } 
     180        else 
     181          { :class  => dom_class(object, :edit), :id => dom_id(object, :edit), :method => :put } 
     182        end 
     183         
     184        options[:html] ||= {} 
     185        options[:html].reverse_merge!(html_options) 
     186 
     187        options[:url] ||= polymorphic_path(object, self)         
    129188      end 
    130189 
  • trunk/actionpack/lib/action_view/helpers/prototype_helper.rb

    r6633 r6731  
    182182 
    183183      # Works like form_remote_tag, but uses form_for semantics. 
    184       def remote_form_for(object_name, *args, &proc) 
     184      def remote_form_for(record_or_name, *args, &proc) 
    185185        options = args.last.is_a?(Hash) ? args.pop : {} 
     186 
     187        case record_or_name 
     188        when String, Symbol 
     189          object_name = record_or_name 
     190        else 
     191          object      = record_or_name 
     192          object_name = ActionController::RecordIdentifier.singular_class_name(record_or_name) 
     193          apply_form_for_options!(object, options) 
     194        end 
     195 
    186196        concat(form_remote_tag(options), proc.binding) 
    187197        fields_for(object_name, *(args << options), &proc) 
  • trunk/actionpack/lib/action_view/helpers/record_identification_helper.rb

    r6633 r6731  
    1 module RecordIdentificationHelper 
    2   # See ActionController::RecordIdentifier.partial_path -- this is just a delegate to that for convenient access in the view. 
    3   def partial_path(*args, &block) 
    4     ActionController::RecordIdentifier.partial_path(*args, &block) 
    5   end 
     1module ActionView 
     2  module Helpers 
     3    module RecordIdentificationHelper 
     4      # See ActionController::RecordIdentifier.partial_path -- this is just a delegate to that for convenient access in the view. 
     5      def partial_path(*args, &block) 
     6        ActionController::RecordIdentifier.partial_path(*args, &block) 
     7      end 
    68 
    7   # See ActionController::RecordIdentifier.dom_class -- this is just a delegate to that for convenient access in the view. 
    8   def dom_class(*args, &block) 
    9     ActionController::RecordIdentifier.dom_class(*args, &block) 
    10   end 
     9      # See ActionController::RecordIdentifier.dom_class -- this is just a delegate to that for convenient access in the view. 
     10      def dom_class(*args, &block) 
     11        ActionController::RecordIdentifier.dom_class(*args, &block) 
     12      end 
    1113 
    12   # See ActionController::RecordIdentifier.dom_id -- this is just a delegate to that for convenient access in the view. 
    13   def dom_id(*args, &block) 
    14     ActionController::RecordIdentifier.dom_id(*args, &block) 
     14      # See ActionController::RecordIdentifier.dom_id -- this is just a delegate to that for convenient access in the view. 
     15      def dom_id(*args, &block) 
     16        ActionController::RecordIdentifier.dom_id(*args, &block) 
     17      end 
     18    end 
    1519  end 
    1620end 
  • trunk/actionpack/lib/action_view/helpers/record_tag_helper.rb

    r6633 r6731  
    1 module RecordTagHelper 
    2   # Produces a wrapper DIV element with id and class parameters that 
    3   # relate to the specified ActiveRecord object. Usage example: 
    4   # 
    5   #    <% div_for(@person, :class => "foo") do %> 
    6   #       <%=h @person.name %> 
    7   #    <% end %> 
    8   # 
    9   # produces: 
    10   # 
    11   #    <div id="person_123" class="person foo"> Joe Bloggs </div> 
    12   # 
    13   def div_for(record, *args, &block) 
    14     content_tag_for(:div, record, *args, &block) 
    15   end 
     1module ActionView 
     2  module Helpers 
     3    module RecordTagHelper 
     4      # Produces a wrapper DIV element with id and class parameters that 
     5      # relate to the specified ActiveRecord object. Usage example: 
     6      # 
     7      #    <% div_for(@person, :class => "foo") do %> 
     8      #       <%=h @person.name %> 
     9      #    <% end %> 
     10      # 
     11      # produces: 
     12      # 
     13      #    <div id="person_123" class="person foo"> Joe Bloggs </div> 
     14      # 
     15      def div_for(record, *args, &block) 
     16        content_tag_for(:div, record, *args, &block) 
     17      end 
    1618   
    17   # content_tag_for creates an HTML element with id and class parameters 
    18   # that relate to the specified ActiveRecord object. For example: 
    19   # 
    20   #    <% content_tag_for(:tr, @person) do %> 
    21   #      <td><%=h @person.first_name %></td> 
    22   #      <td><%=h @person.last_name %></td> 
    23   #    <% end %> 
    24   # 
    25   # would produce hthe following HTML (assuming @person is an instance of 
    26   # a Person object, with an id value of 123): 
    27   # 
    28   #    <tr id="person_123" class="person">....</tr> 
    29   # 
    30   # If you require the HTML id attribute to have a prefix, you can specify it: 
    31   # 
    32   #    <% content_tag_for(:tr, @person, :foo) do %> ... 
    33   # 
    34   # produces: 
    35   #     
    36   #    <tr id="foo_person_123" class="person">... 
    37   # 
    38   # content_tag_for also accepts a hash of options, which will be converted to 
    39   # additional HTML attributes. If you specify a +:class+ value, it will be combined 
    40   # with the default class name for your object. For example: 
    41   # 
    42   #    <% content_tag_for(:li, @person, :class => "bar") %>... 
    43   # 
    44   # produces: 
    45   # 
    46   #    <li id="person_123" class="person bar">... 
    47   # 
    48   def content_tag_for(tag_name, record, *args, &block) 
    49     prefix  = args.first.is_a?(Hash) ? nil : args.shift 
    50     options = args.first.is_a?(Hash) ? args.shift : {} 
    51     concat content_tag(tag_name, capture(&block),  
    52       options.merge({ :class => "#{dom_class(record)} #{options[:class]}".strip, :id => dom_id(record, prefix) })),  
    53       block.binding 
     19      # content_tag_for creates an HTML element with id and class parameters 
     20      # that relate to the specified ActiveRecord object. For example: 
     21      # 
     22      #    <% content_tag_for(:tr, @person) do %> 
     23      #      <td><%=h @person.first_name %></td> 
     24      #      <td><%=h @person.last_name %></td> 
     25      #    <% end %> 
     26      # 
     27      # would produce hthe following HTML (assuming @person is an instance of 
     28      # a Person object, with an id value of 123): 
     29      # 
     30      #    <tr id="person_123" class="person">....</tr> 
     31      # 
     32      # If you require the HTML id attribute to have a prefix, you can specify it: 
     33      # 
     34      #    <% content_tag_for(:tr, @person, :foo) do %> ... 
     35      # 
     36      # produces: 
     37      #     
     38      #    <tr id="foo_person_123" class="person">... 
     39      # 
     40      # content_tag_for also accepts a hash of options, which will be converted to 
     41      # additional HTML attributes. If you specify a +:class+ value, it will be combined 
     42      # with the default class name for your object. For example: 
     43      # 
     44      #    <% content_tag_for(:li, @person, :class => "bar") %>... 
     45      # 
     46      # produces: 
     47      # 
     48      #    <li id="person_123" class="person bar">... 
     49      # 
     50      def content_tag_for(tag_name, record, *args, &block) 
     51        prefix  = args.first.is_a?(Hash) ? nil : args.shift 
     52        options = args.first.is_a?(Hash) ? args.shift : {} 
     53        concat content_tag(tag_name, capture(&block),  
     54          options.merge({ :class => "#{dom_class(record)} #{options[:class]}".strip, :id => dom_id(record, prefix) })),  
     55          block.binding 
     56      end 
     57    end 
    5458  end 
    5559end 
  • trunk/actionpack/test/controller/record_identifier_test.rb

    r6633 r6731  
    11require File.dirname(__FILE__) + '/../abstract_unit' 
    22 
    3 class Pos
     3class Commen
    44  attr_reader :id 
    55  def save; @id = 1 end 
    66  def new_record?; @id.nil? end 
    77  def name 
    8     @id.nil? ? 'new post' : "post ##{@id}" 
     8    @id.nil? ? 'new comment' : "comment ##{@id}" 
    99  end 
    10   class Nested < Post; end 
    1110end 
     11 
     12class Comment::Nested < Comment; end 
    1213 
    1314class Test::Unit::TestCase 
    1415  protected 
    15     def posts_url 
    16       'http://www.example.com/posts' 
     16    def comments_url 
     17      'http://www.example.com/comments' 
    1718    end 
    1819     
    19     def post_url(post) 
    20       "http://www.example.com/posts/#{post.id}" 
     20    def comment_url(comment) 
     21      "http://www.example.com/comments/#{comment.id}" 
    2122    end 
    2223end 
     
    2728 
    2829  def setup 
    29     @klass  = Pos
     30    @klass  = Commen
    3031    @record = @klass.new 
    31     @singular = 'post' 
    32     @plural = 'posts' 
     32    @singular = 'comment' 
     33    @plural = 'comments' 
    3334  end 
    3435 
     
    5455    expected = "#{@plural}/#{@singular}" 
    5556    assert_equal expected, partial_path(@record) 
    56     assert_equal expected, partial_path(Post) 
     57    assert_equal expected, partial_path(Comment) 
    5758  end 
    5859 
     
    8990class NestedRecordIdentifierTest < RecordIdentifierTest 
    9091  def setup 
    91     @klass  = Post::Nested 
     92    @klass  = Comment::Nested 
    9293    @record = @klass.new 
    93     @singular = 'post_nested' 
    94     @plural = 'post_nesteds' 
     94    @singular = 'comment_nested' 
     95    @plural = 'comment_nesteds' 
    9596  end 
    9697 
    9798  def test_partial_path 
    98     expected = "post/nesteds/nested" 
     99    expected = "comment/nesteds/nested" 
    99100    assert_equal expected, partial_path(@record) 
    100     assert_equal expected, partial_path(Post::Nested) 
     101    assert_equal expected, partial_path(Comment::Nested) 
    101102  end 
    102103end 
  • trunk/actionpack/test/template/form_helper_test.rb

    r6729 r6731  
    11require "#{File.dirname(__FILE__)}/../abstract_unit" 
     2 
     3silence_warnings do 
     4  Post = Struct.new(:title, :author_name, :body, :secret, :written_on, :cost) 
     5  Post.class_eval do 
     6    alias_method :title_before_type_cast, :title unless respond_to?(:title_before_type_cast) 
     7    alias_method :body_before_type_cast, :body unless respond_to?(:body_before_type_cast) 
     8    alias_method :author_name_before_type_cast, :author_name unless respond_to?(:author_name_before_type_cast) 
     9 
     10    def new_record=(boolean) 
     11      @new_record = boolean 
     12    end 
     13     
     14    def new_record? 
     15      @new_record 
     16    end 
     17  end 
     18end 
    219 
    320class FormHelperTest < Test::Unit::TestCase 
     
    825  include ActionView::Helpers::TextHelper 
    926  include ActionView::Helpers::ActiveRecordHelper 
    10  
    11   silence_warnings do 
    12     Post = Struct.new("Post", :title, :author_name, :body, :secret, :written_on, :cost) 
    13     Post.class_eval do 
    14       alias_method :title_before_type_cast, :title unless respond_to?(:title_before_type_cast) 
    15       alias_method :body_before_type_cast, :body unless respond_to?(:body_before_type_cast) 
    16       alias_method :author_name_before_type_cast, :author_name unless respond_to?(:author_name_before_type_cast) 
    17     end 
    18   end 
     27  include ActionView::Helpers::RecordIdentificationHelper 
    1928 
    2029  def setup 
     
    547556 
    548557    expected = "<form action=\"/posts/123\" method=\"post\"></form>" 
     558    assert_equal expected, _erbout 
     559  end 
     560 
     561  def test_form_for_with_existing_object 
     562    _erbout = '' 
     563 
     564    form_for(@post) do |f| end 
     565 
     566    expected = "<form action=\"/posts/123\" class=\"edit_post\" id=\"edit_post_123\" method=\"post\"><div style=\"margin:0;padding:0\"><input name=\"_method\" type=\"hidden\" value=\"put\" /></div></form>" 
     567    assert_equal expected, _erbout 
     568  end 
     569 
     570  def test_form_for_with_new_object 
     571    _erbout = '' 
     572 
     573    post = Post.new 
     574    post.new_record = true 
     575    def post.id() nil end 
     576 
     577    form_for(post) do |f| end 
     578 
     579    expected = "<form action=\"/posts\" class=\"new_post\" id=\"new_post\" method=\"post\"></form>" 
     580    assert_equal expected, _erbout 
     581  end 
     582 
     583  def test_form_for_with_existing_object_and_custom_url 
     584    _erbout = '' 
     585 
     586    form_for(@post, :url => "/super_posts") do |f| end 
     587 
     588    expected = "<form action=\"/super_posts\" class=\"edit_post\" id=\"edit_post_123\" method=\"post\"><div style=\"margin:0;padding:0\"><input name=\"_method\" type=\"hidden\" value=\"put\" /></div></form>" 
     589    assert_equal expected, _erbout 
    549590  end 
    550591   
     
    562603  protected 
    563604    def polymorphic_path(record, url_writer) 
    564       "/posts/#{record.id}" 
     605      if record.new_record? 
     606        "/posts" 
     607      else 
     608        "/posts/#{record.id}" 
     609      end 
    565610    end 
    566611end 
  • trunk/actionpack/test/template/prototype_helper_test.rb

    r6729 r6731  
    22 
    33Bunny = Struct.new(:Bunny, :id) 
     4 
     5class Author 
     6  attr_reader :id 
     7  def save; @id = 1 end 
     8  def new_record?; @id.nil? end 
     9  def name 
     10    @id.nil? ? 'new author' : "author ##{@id}" 
     11  end 
     12end 
     13 
     14class Author::Nested < Author; end 
     15 
    416 
    517module BaseTest 
     
    1426  include ActionView::Helpers::FormHelper 
    1527  include ActionView::Helpers::CaptureHelper 
     28  include ActionView::Helpers::RecordIdentificationHelper 
    1629   
    1730  def setup 
     
    4255  include BaseTest 
    4356   
     57  def setup 
     58    @record = Author.new 
     59    super 
     60  end 
     61 
    4462  def test_link_to_remote 
    45     assert_dom_equal %(<a class=\"fine\" href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true}); return false;\">Remote outpost</a>), 
    46       link_to_remote("Remote outpost", { :url => { :action => "whatnot"  }}, { :class => "fine"  }) 
    47     assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onComplete:function(request){alert(request.reponseText)}}); return false;\">Remote outpost</a>), 
    48       link_to_remote("Remote outpost", :complete => "alert(request.reponseText)", :url => { :action => "whatnot"  })       
    49     assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onSuccess:function(request){alert(request.reponseText)}}); return false;\">Remote outpost</a>), 
    50       link_to_remote("Remote outpost", :success => "alert(request.reponseText)", :url => { :action => "whatnot"  }) 
    51     assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onFailure:function(request){alert(request.reponseText)}}); return false;\">Remote outpost</a>), 
    52       link_to_remote("Remote outpost", :failure => "alert(request.reponseText)", :url => { :action => "whatnot"  }) 
    53     assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot?a=10&amp;b=20', {asynchronous:true, evalScripts:true, onFailure:function(request){alert(request.reponseText)}}); return false;\">Remote outpost</a>), 
    54       link_to_remote("Remote outpost", :failure => "alert(request.reponseText)", :url => { :action => "whatnot", :a => '10', :b => '20' }) 
     63    assert_dom_equal %(<a class=\"fine\" href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true}); return false;\">Remote outauthor</a>), 
     64      link_to_remote("Remote outauthor", { :url => { :action => "whatnot"  }}, { :class => "fine"  }) 
     65    assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onComplete:function(request){alert(request.reponseText)}}); return false;\">Remote outauthor</a>), 
     66      link_to_remote("Remote outauthor", :complete => "alert(request.reponseText)", :url => { :action => "whatnot"  })       
     67    assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onSuccess:function(request){alert(request.reponseText)}}); return false;\">Remote outauthor</a>), 
     68      link_to_remote("Remote outauthor", :success => "alert(request.reponseText)", :url => { :action => "whatnot"  }) 
     69    assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onFailure:function(request){alert(request.reponseText)}}); return false;\">Remote outauthor</a>), 
     70      link_to_remote("Remote outauthor", :failure => "alert(request.reponseText)", :url => { :action => "whatnot"  }) 
     71    assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot?a=10&amp;b=20', {asynchronous:true, evalScripts:true, onFailure:function(request){alert(request.reponseText)}}); return false;\">Remote outauthor</a>), 
     72      link_to_remote("Remote outauthor", :failure => "alert(request.reponseText)", :url => { :action => "whatnot", :a => '10', :b => '20' }) 
    5573  end 
    5674   
     
    8199    assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\">Hello world!</form>), _erbout 
    82100  end 
    83    
     101 
     102  def test_remote_form_for_with_record_identification_with_new_record 
     103    _erbout = '' 
     104    remote_form_for(@record, {:html => { :id => 'create-author' }}) {} 
     105     
     106    expected = %(<form action='#{authors_url}' onsubmit="new Ajax.Request('#{authors_url}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='new_author' id='create-author' method='post'></form>) 
     107    assert_dom_equal expected, _erbout 
     108  end 
     109 
     110  def test_remote_form_for_with_record_identification_without_html_options 
     111    _erbout = '' 
     112    remote_form_for(@record) {} 
     113     
     114    expected = %(<form action='#{authors_url}' onsubmit="new Ajax.Request('#{authors_url}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='new_author' method='post' id='new_author'></form>) 
     115    assert_dom_equal expected, _erbout 
     116  end 
     117 
     118  def test_remote_form_for_with_record_identification_with_existing_record 
     119    @record.save 
     120    _erbout = '' 
     121    remote_form_for(@record) {} 
     122     
     123    expected = %(<form action='#{author_url(@record)}' id='edit_author_1' method='post' onsubmit="new Ajax.Request('#{author_url(@record)}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='edit_author'><div style='margin:0;padding:0'><input name='_method' type='hidden' value='put' /></div></form>) 
     124    assert_dom_equal expected, _erbout 
     125  end 
     126 
    84127  def test_on_callbacks 
    85128    callbacks = [:uninitialized, :loading, :loaded, :interactive, :complete, :success, :failure] 
     
    162205  end 
    163206 
     207 
     208  protected 
     209    def author_url(record) 
     210      "/authors/#{record.id}" 
     211    end 
     212     
     213    def authors_url 
     214      "/authors" 
     215    end 
     216   
     217    def polymorphic_path(record, url_writer) 
     218      if record.new_record? 
     219        "/authors" 
     220      else 
     221        "/authors/#{record.id}" 
     222      end 
     223    end 
    164224end 
    165225