Module: ActionView::RecordIdentifier

Extended by:
ModelNaming, RecordIdentifier
Includes:
ModelNaming
Included in:
Helpers::FormHelper, RecordIdentifier, TestCase::Behavior
Defined in:
lib/action_view/record_identifier.rb

Overview

Action View Record Identifier

RecordIdentifier encapsulates methods used by various ActionView helpers to associate records with DOM elements.

Consider for example the following code that form of post:

<%= form_with(model: post) do |f| %>
  <%= f.text_field :body %>
<% end %>

When post is a new, unsaved ActiveRecord::Base instance, the resulting HTML is:

<form class="new_post" id="new_post" action="/posts" accept-charset="UTF-8" method="post">
  <input type="text" name="post[body]" id="post_body" />
</form>

When post is a persisted ActiveRecord::Base instance, the resulting HTML is:

<form class="edit_post" id="edit_post_42" action="/posts/42" accept-charset="UTF-8" method="post">
  <input type="text" value="What a wonderful world!" name="post[body]" id="post_body" />
</form>

In both cases, the id and class of the wrapping DOM element are automatically generated, following naming conventions encapsulated by the RecordIdentifier methods #dom_id and #dom_class:

dom_id(Post)             # => "new_post"
dom_class(Post)          # => "post"
dom_id(Post.new)         # => "new_post"
dom_class(Post.new)      # => "post"
dom_id(Post.find 42)     # => "post_42"
dom_class(Post.find 42)  # => "post"

Note that these methods do not strictly require Post to be a subclass of ActiveRecord::Base. Any Post class will work as long as its instances respond to to_key and model_name, given that model_name responds to param_key. For instance:

class Post
  attr_accessor :to_key

  def model_name
    OpenStruct.new param_key: 'post'
  end

  def self.find(id)
    new.tap { |post| post.to_key = [id] }
  end
end

Constant Summary collapse

JOIN =
"_"
NEW =
"new"

Instance Method Summary collapse

Methods included from ModelNaming

convert_to_model, model_name_from_record_or_class

Instance Method Details

#dom_class(record_or_class, prefix = nil) ⇒ Object

The DOM class convention is to use the singular form of an object or class.

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"


78
79
80
81
# File 'lib/action_view/record_identifier.rb', line 78

def dom_class(record_or_class, prefix = nil)
  singular = model_name_from_record_or_class(record_or_class).param_key
  prefix ? "#{prefix}#{JOIN}#{singular}" : singular
end

#dom_id(record_or_class, prefix = nil) ⇒ Object

The DOM id convention is to use the singular form of an object or class with the id following an underscore. If no id is found, prefix with “new_” instead.

dom_id(Post.find(45)) # => "post_45"
dom_id(Post)          # => "new_post"

If you need to address multiple instances of the same class in the same view, you can prefix the dom_id:

dom_id(Post.find(45), :edit) # => "edit_post_45"
dom_id(Post, :custom)        # => "custom_post"

Raises:

  • (ArgumentError)


93
94
95
96
97
98
99
100
101
102
# File 'lib/action_view/record_identifier.rb', line 93

def dom_id(record_or_class, prefix = nil)
  raise ArgumentError, "dom_id must be passed a record_or_class as the first argument, you passed #{record_or_class.inspect}" unless record_or_class

  record_id = record_key_for_dom_id(record_or_class) unless record_or_class.is_a?(Class)
  if record_id
    "#{dom_class(record_or_class, prefix)}#{JOIN}#{record_id}"
  else
    dom_class(record_or_class, prefix || NEW)
  end
end