-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support nested forms for has_many relationships
Closes #192 Feature: When I create or edit a model that has_many nested models, I want to view and edit the attributes of the nested models so I can set up all the relationships with a single form. Implementation: Introduce a new field type, `NestedHasMany`. I considered building the feature into the existing `HasMany` field, but this would get in the way of `HasMany` relationships that aren't directly nested, such as in many-to-many relationships. The `NestedHasMany` field builds off of the [Cocoon] gem. It renders fields from the nested model, based on the fields defined in the nested model's dashboard class. Cocoon provides helpers and javascript to easily add and remove nested form fields from the page. [Cocoon]: https://github.com/nathanvda/cocoon
- Loading branch information
Showing
9 changed files
with
149 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,9 @@ | ||
//= require jquery | ||
//= require jquery_ujs | ||
//= require selectize | ||
//= require moment | ||
|
||
//= require cocoon | ||
//= require datetime_picker | ||
//= require moment | ||
//= require selectize | ||
|
||
//= require_tree . |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<div class="nested-fields" style="width:100%"> | ||
|
||
<%# TODO filter out the parent relationship, without this crude array slicing %> | ||
<% field.associated_form.attributes[1..-1].each do |attribute| -%> | ||
<div class="field"> | ||
<%= render_field attribute, f: f %> | ||
</div> | ||
<% end -%> | ||
|
||
<%# TODO I18n %> | ||
<%= link_to_remove_association "Remove #{field.associated_class_name.titleize}", f %> | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<div class="nested-fields" style="width: 40%; margin-left: 20%;"> | ||
|
||
<%= f.fields_for field.association_name do |nested_form| %> | ||
<%= render( | ||
partial: "fields/nested_has_many/fields", | ||
locals: { | ||
f: nested_form, | ||
field: field, | ||
}, | ||
) %> | ||
<% end %> | ||
|
||
<div class="links"> | ||
<%= link_to_add_association( | ||
# TODO I18n | ||
"Add #{field.associated_class_name.titleize}", | ||
f, | ||
field.association_name, | ||
partial: "fields/nested_has_many/fields", | ||
render_options: { locals: { field: field } }, | ||
) %> | ||
</div> | ||
|
||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<%# | ||
# HasMany Index Partial | ||
This partial renders a has_many relationship, | ||
to be displayed on a resource's index page. | ||
By default, the relationship is rendered | ||
as a count of how many objects are associated through the relationship. | ||
## Local variables: | ||
- `field`: | ||
An instance of [Administrate::Field::HasMany][1]. | ||
A wrapper around the has_many relationship pulled from the database. | ||
[1]: http://www.rubydoc.info/gems/administrate/Administrate/Field/HasMany | ||
%> | ||
|
||
<%= pluralize(field.data.size, field.attribute.to_s.humanize.downcase) %> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
<%# | ||
# HasMany Show Partial | ||
This partial renders a has_many relationship, | ||
to be displayed on a resource's show page. | ||
By default, the relationship is rendered | ||
as a table of the first few associated resources. | ||
The columns of the table are taken | ||
from the associated resource class's dashboard. | ||
## Local variables: | ||
- `field`: | ||
An instance of [Administrate::Field::HasMany][1]. | ||
Contains methods to help display a table of associated resources. | ||
[1]: http://www.rubydoc.info/gems/administrate/Administrate/Field/HasMany | ||
%> | ||
|
||
<% if field.resources.any? %> | ||
<%= render( | ||
"collection", | ||
collection_presenter: field.associated_collection, | ||
resources: field.resources | ||
) %> | ||
|
||
<% if field.more_than_limit? %> | ||
<span> | ||
<%= t( | ||
'administrate.fields.has_many.more', | ||
count: field.limit, | ||
total_count: field.data.count, | ||
) %> | ||
</span> | ||
<% end %> | ||
|
||
<% else %> | ||
<%= t("administrate.fields.has_many.none") %> | ||
<% end %> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
require "cocoon" | ||
require "datetime_picker_rails" | ||
require "jquery-rails" | ||
require "kaminari" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
require_relative "has_many" | ||
require "administrate/page/form" | ||
|
||
module Administrate | ||
module Field | ||
class NestedHasMany < Administrate::Field::HasMany | ||
DEFAULT_ATTRIBUTES = [:id, :_destroy].freeze | ||
|
||
def to_s | ||
data | ||
end | ||
|
||
protected | ||
|
||
def self.dashboard_for_resource(resource) | ||
"#{resource.to_s.classify}Dashboard".constantize | ||
end | ||
|
||
def self.associated_attributes(associated_resource) | ||
DEFAULT_ATTRIBUTES + | ||
dashboard_for_resource(associated_resource).new.permitted_attributes | ||
end | ||
|
||
public | ||
|
||
def self.permitted_attribute(associated_resource) | ||
{ | ||
"#{associated_resource}_attributes".to_sym => | ||
associated_attributes(associated_resource) | ||
} | ||
end | ||
|
||
def associated_class_name | ||
options.fetch(:class_name, attribute.to_s.singularize.camelcase) | ||
end | ||
|
||
def association_name | ||
associated_class_name.underscore.pluralize | ||
end | ||
|
||
def associated_form | ||
Administrate::Page::Form.new(associated_dashboard, association_name) | ||
end | ||
end | ||
end | ||
end |