トップ «前の日記(2008-10-10) 最新 次の日記(2008-10-19)» 編集

3 日坊主日記


2008-10-14 [長年日記]

_ [Rails] polymorphic routes for uncountable name

news のように単数形と複数形が一致する、いわゆる不可算名詞を map.resources に指定すると

# config/routes.rb:
  map.resources :news
$ rake routes
...
              news_index GET    /news                  {:controller=>"news", :action=>"index"}
    formatted_news_index GET    /news.:format          {:controller=>"news", :action=>"index"}
                         POST   /news                  {:controller=>"news", :action=>"create"}
                         POST   /news.:format          {:controller=>"news", :action=>"create"}
                new_news GET    /news/new              {:controller=>"news", :action=>"new"}
      formatted_new_news GET    /news/new.:format      {:controller=>"news", :action=>"new"}
               edit_news GET    /news/:id/edit         {:controller=>"news", :action=>"edit"}
     formatted_edit_news GET    /news/:id/edit.:format {:controller=>"news", :action=>"edit"}
                    news GET    /news/:id              {:controller=>"news", :action=>"show"}
          formatted_news GET    /news/:id.:format      {:controller=>"news", :action=>"show"}
                         PUT    /news/:id              {:controller=>"news", :action=>"update"}
                         PUT    /news/:id.:format      {:controller=>"news", :action=>"update"}
                         DELETE /news/:id              {:controller=>"news", :action=>"destroy"}
                         DELETE /news/:id.:format      {:controller=>"news", :action=>"destroy"}

このように "index" action の named routes に "_index" が付く。 実装は:

lib/action_controller/resources.rb:
...
      def map_default_collection_actions(map, resource)
        index_action_options = action_options_for("index", resource)
        index_route_name = "#{resource.name_prefix}#{resource.plural}"

        if resource.uncountable?
          index_route_name << "_index"
        end

        map_named_routes(map, index_route_name, resource.path, index_action_options)

        create_action_options = action_options_for("create", resource)
        map_unnamed_routes(map, resource.path, create_action_options)
      end
...
      def uncountable?
        @singular.to_s == @plural.to_s
      end

このように named routes だけを見ると問題はないのだが、 polymorphic_routes はこの "_index" に対応していない。このため new.html.erb を評価するとこける。

具体的には form_for(@news) で @news が new_record? である場合、 routes method として "news_path" が生成されて評価されてしまう。 news_path は "show" action の named routes であるから失敗する。

view で対応するなら polymorphic_routes を使わずに named routes を直接書けば回避できる。

<% form_for(:news, @news, :url => @news.new_record? ? news_index_path : news_path(@news), :html => { :method => @news.new_record? ? :post : :put }) do |f| %>

が、きれいではない。

やはり

<% form_for(@news) do |f| %>

こう書けるべき。

というわけで patch です。

head
diff --git a/actionpack/lib/action_controller/record_identifier.rb b/actionpack/lib/action_controller/record_identifier.rb
index 742d290..e4b4399 100644
--- a/actionpack/lib/action_controller/record_identifier.rb
+++ b/actionpack/lib/action_controller/record_identifier.rb
@@ -85,7 +85,10 @@ module ActionController
     #   plural_class_name(post)             # => "posts"
     #   plural_class_name(Highrise::Person) # => "highrise_people"
     def plural_class_name(record_or_class)
-      model_name_from_record_or_class(record_or_class).plural
+      name = model_name_from_record_or_class(record_or_class)
+      plural = name.plural
+      singular = name.singular
+      singular == plural ? plural + '_index' : plural
     end

     # Returns the singular class name of a record or class. Examples:
actionpack-2.1.0
diff -r aba573a617d5 -r c64ac27e8996 lib/action_controller/record_identifier.rb
--- a/lib/action_controller/record_identifier.rb	Tue Oct 14 18:11:33 2008 +0900
+++ b/lib/action_controller/record_identifier.rb	Tue Oct 14 18:27:58 2008 +0900
@@ -78,7 +78,9 @@
     #   plural_class_name(post)             # => "posts"
     #   plural_class_name(Highrise::Person) # => "highrise_people"
     def plural_class_name(record_or_class)
-      singular_class_name(record_or_class).pluralize
+      singular = singular_class_name(record_or_class)
+      plural = singular.pluralize
+      singular == plural ? plural + '_index' : plural
     end

     # Returns the singular class name of a record or class. Examples:
@@ -94,4 +96,4 @@
         record_or_class.is_a?(Class) ? record_or_class : record_or_class.class
       end
   end
-end
\ No newline at end of file
+end
[]