-
Notifications
You must be signed in to change notification settings - Fork 0
Dom Structure
In order to keep an AJAX app orderly, you need some patterns that keep response targets simple and clean. You can develop your own if you choose, but these patterns have proven to work smoothly over years of use and refinement.
In general, when adding a new resource to a list, you'll want to append or prepend the new element to a list container for the type of resource. Also, you'll want a typical error response to be a new rendering of the form with errors that replaces the old form. Reset on success is useful if the interface is commonly used to add multiple resources at a time.
<%= form_for User.new,
html: ajax_form_hash('#user_list',
error_target: '#new_user_form_container',
insert_method: 'append', reset_on_success: true) do |f| %>
...
<% end %>
A new resource will need a new target element. The target element is used to swap out edit and show views, so it cannot be a part of the show view itself. A show wrapper is needed to supple the target element. It should be rendered with a new resource. For existing resources it will be rendered by the index view.
def create
@user = User.create(clean_params)
if @user.errors.empty?
render partial: 'show_wrapper', locals: {user: @user}
else
render partial: 'new', locals: {user: @user}
end
end
When the index view renders a resource, it should use the wrapper partial. That way the edit link can swap out the contents of the target element with the edit form.
<%= ajax_link 'edit', edit_user_path(user), {}, dom_target(user) %>
Typically rendering the edit view is just a matter of calling render_ajax
def edit
render_ajax
end
It bears repeating that the edit and show views do not render the target element, as that could end up in repeated, nested target elements. Only the show wrapper renders the target element, referred to hear with the helper dom_target(user)
.
<%= form_for user, html: ajax_form_hash(dom_target(user)) do |f| %>
...
<% end %>
Unlike creating a new resource, updating a resource will render the show view upon success, since the wrapper is already on the page and now we are just toggling between edit and show within the target element. Remember the wrapper with the target element is only rendered by the index view or the create action.
def update
@user.update_attributes(clean_params)
if @user.errors.empty?
render partial: 'show', locals: {user: @user}
else
render partial: 'edit', locals: {user: @user}
end
end
The index renders the wrapper view in order to establish the target element for the resource. Notice that we cannot use an instance variable for user, since it is a collection. You could use the collection option to render if you like, but either way we end up needing a local variable in the show wrapper, show, and edit views.
<section id="user_list>
<% @users.each do |user| %>
<%= render partial: 'show_wrapper', locals: {user: user} %>
<% end %>
</section>
The show wrapper view establishes the target element that will be used to toggle the edit and show views for the resource.
<div id="<%= dom_id(user) %>>
<%= render partial: 'show', locals: {user: user} %>
</div>