record_identifier.rb 3.4 KB
Newer Older
J
Jeremy Kemper 已提交
1 2
require 'active_support/core_ext/module'

3
module ActionController
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
  # The record identifier encapsulates a number of naming conventions for dealing with records, like Active Records or 
  # Active Resources or pretty much any other model type that has an id. These patterns are then used to try elevate
  # the view actions to a higher logical level. Example:
  #
  #   # routes
  #   map.resources :posts
  #
  #   # view
  #   <% div_for(post) do %>     <div id="post_45" class="post">
  #     <%= post.body %>           What a wonderful world!
  #   <% end %>                  </div>
  #
  #   # controller
  #   def destroy
  #     post = Post.find(params[:id])
  #     post.destroy
  #
  #     respond_to do |format|
  #       format.html { redirect_to(post) } # Calls polymorphic_url(post) which in turn calls post_url(post)
  #       format.js do
  #         # Calls: new Effect.fade('post_45');
  #         render(:update) { |page| page[post].visual_effect(:fade) }
  #       end
  #     end
  #   end
  #
30
  # As the example above shows, you can stop caring to a large extent what the actual id of the post is. You just know
31 32 33 34 35
  # that one is being assigned and that the subsequent calls in redirect_to and the RJS expect that same naming 
  # convention and allows you to write less code if you follow it.
  module RecordIdentifier
    extend self

36 37 38
    JOIN = '_'.freeze
    NEW = 'new'.freeze

39 40 41 42 43 44 45 46 47 48
    # The DOM class convention is to use the singular form of an object or class. Examples:
    #
    #   dom_class(post)   # => "post"
    #   dom_class(Person) # => "person"
    #
    # If you need to address multiple instances of the same class in the same view, you can prefix the dom_class:
    #
    #   dom_class(post, :edit)   # => "edit_post"
    #   dom_class(Person, :edit) # => "edit_person"
    def dom_class(record_or_class, prefix = nil)
49 50
      singular = singular_class_name(record_or_class)
      prefix ? "#{prefix}#{JOIN}#{singular}" : singular
51 52
    end

53
    # The DOM id convention is to use the singular form of an object or class with the id following an underscore.
54 55
    # If no id is found, prefix with "new_" instead. Examples:
    #
56
    #   dom_id(Post.find(45))       # => "post_45"
57
    #   dom_id(Post.new)            # => "new_post"
58 59 60
    #
    # If you need to address multiple instances of the same class in the same view, you can prefix the dom_id:
    #
61
    #   dom_id(Post.find(45), :edit) # => "edit_post_45"
62
    def dom_id(record, prefix = nil) 
63 64 65 66 67
      if record_id = record.id
        "#{dom_class(record, prefix)}#{JOIN}#{record_id}"
      else
        dom_class(record, prefix || NEW)
      end
68 69 70 71 72 73 74
    end

    # Returns the plural class name of a record or class. Examples:
    #
    #   plural_class_name(post)             # => "posts"
    #   plural_class_name(Highrise::Person) # => "highrise_people"
    def plural_class_name(record_or_class)
75
      model_name_from_record_or_class(record_or_class).plural
76 77 78 79 80 81 82
    end

    # Returns the singular class name of a record or class. Examples:
    #
    #   singular_class_name(post)             # => "post"
    #   singular_class_name(Highrise::Person) # => "highrise_person"
    def singular_class_name(record_or_class)
83
      model_name_from_record_or_class(record_or_class).singular
84 85 86
    end

    private
87 88
      def model_name_from_record_or_class(record_or_class)
        (record_or_class.is_a?(Class) ? record_or_class : record_or_class.class).model_name
89 90
      end
  end
91
end