Skip to content

Commit

Permalink
Add support for editing polymorphic fields - Revisited (thoughtbot#1020)
Browse files Browse the repository at this point in the history
This adds support for editing polymorphic fields. Props go to @pedantic-git, on whose work this is based. This PR supersedes thoughtbot#984.

An important aspect of this PR is how it handles the polymorphic value. At heart, polymorphic values are split in two: an id and a type. Using [the `globalid` gem](https://github.com/rails/globalid) we can obtain a string that represents both. However, we still need to tell that this string is indeed a globalid and not a literal value when we get to `Administrate::ApplicationController#resource_params`. I handle this by splitting the field in two:

  * `my_field[value]`: the global id, which includes both type and instance id.
  * `my_field[type]`: literally `"Administrate::Field::Polymorphic"`

Then `#resource_params` can look at the param values and treat them appropriately. If it's a simple value such a string, it does nothing special. However, if it comes in this value/type form, we treat it as polymorphic, reading the global id.
  • Loading branch information
pablobm authored Nov 17, 2017
1 parent 844d7b2 commit 8329b21
Show file tree
Hide file tree
Showing 49 changed files with 421 additions and 86 deletions.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ gemspec
gem "administrate-field-image"
gem "autoprefixer-rails"
gem "faker"
gem "globalid"
gem "pg"
gem "redcarpet"
gem "sentry-raven"
Expand Down
3 changes: 3 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ GEM
activesupport
capybara
i18n
globalid (0.4.0)
activesupport (>= 4.2.0)
hashdiff (0.3.6)
highline (1.7.8)
i18n (0.8.6)
Expand Down Expand Up @@ -266,6 +268,7 @@ DEPENDENCIES
factory_bot_rails
faker
formulaic
globalid
i18n-tasks
launchy
pg
Expand Down
15 changes: 14 additions & 1 deletion app/controllers/administrate/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,20 @@ def resource_includes

def resource_params
params.require(resource_class.model_name.param_key).
permit(dashboard.permitted_attributes)
permit(dashboard.permitted_attributes).
transform_values { |v| read_param_value(v) }
end

def read_param_value(data)
if data.is_a?(ActionController::Parameters) && data[:type]
if data[:type] == Administrate::Field::Polymorphic.to_s
GlobalID::Locator.locate(data[:value])
else
raise "Unrecognised param data: #{data.inspect}"
end
else
data
end
end

delegate :dashboard_class, :resource_class, :resource_name, :namespace,
Expand Down
17 changes: 11 additions & 6 deletions app/views/fields/polymorphic/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,15 @@ so this partial renders a message to that effect.
[1]: http://www.rubydoc.info/gems/administrate/Administrate/Field/Polymorphic
%>

<div class="field-unit__label">
<%= f.label field.name %>
</div>
<%= f.fields_for field.attribute do |pf| %>
<div class="field-unit__label">
<%= pf.label :value, field.name.humanize %>
</div>

<div class="field-unit__field">
<%= t("administrate.fields.polymorphic.not_supported") %>
</div>
<div class="field-unit__field">
<%= pf.hidden_field(:type, value: field.class.name) %>
<%= pf.select(:value) do %>
<%= grouped_options_for_select(field.associated_resource_grouped_options, field.selected_global_id, prompt: true) %>
<% end %>
</div>
<% end %>
12 changes: 8 additions & 4 deletions app/views/fields/polymorphic/_show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@ By default, the relationship is rendered as a link to the associated object.
%>

<% if field.data %>
<%= link_to(
field.display_associated_resource,
[namespace, field.data],
) %>
<% if valid_action?(:show, field.attribute) %>
<%= link_to(
field.display_associated_resource,
[namespace, field.data],
) %>
<% else %>
<%= field.display_associated_resource %>
<% end %>
<% end %>
2 changes: 0 additions & 2 deletions config/locales/administrate.ar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ ar:
has_many:
more: إظهار %{count} من %{total_count}
none: "لا يوجد"
polymorphic:
not_supported: "غير مدعمه \"Polymorphic\" هذه العلاقه"
has_one:
not_supported: "غير مدعمه \"HasOne\" هذه العلاقه"
search:
Expand Down
2 changes: 0 additions & 2 deletions config/locales/administrate.bs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ bs:
has_many:
more: Prikazuje %{count} od %{total_count}
none: Niko
polymorphic:
not_supported: Polimorfne asocijacije još nisu podržane. Žao nam je!
has_one:
not_supported: Asocijacije HasOne još nije podržana. Žao nam je!
search:
Expand Down
2 changes: 0 additions & 2 deletions config/locales/administrate.ca.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ ca:
has_many:
more: Mostrant %{count} de %{total_count}
none: Cap
polymorphic:
not_supported: Els formularis amb relacions polimòrfiques no estàn suportats.
has_one:
not_supported: Els formularis amb relacions "HasOne" no estàn suportats.
search:
Expand Down
2 changes: 0 additions & 2 deletions config/locales/administrate.da.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ da:
has_many:
more: "Viser %{count} af %{total_count}"
none: Ingen
polymorphic:
not_supported: "Formularer med polymorphic relationships er ikke understøttede."
has_one:
not_supported: "Formularer med has_one associationer er ikke understøttede."
search:
Expand Down
2 changes: 0 additions & 2 deletions config/locales/administrate.de.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ de:
has_many:
more: "%{count} von %{total_count}"
none: Keine
polymorphic:
not_supported: Polymorphe Beziehungen werden nicht unterstützt.
has_one:
not_supported: HasOne Beziehungen werden nicht unterstützt.
search:
Expand Down
2 changes: 0 additions & 2 deletions config/locales/administrate.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ en:
has_many:
more: Showing %{count} of %{total_count}
none: None
polymorphic:
not_supported: Polymorphic relationship forms are not supported.
has_one:
not_supported: HasOne relationship forms are not supported.
search:
Expand Down
2 changes: 0 additions & 2 deletions config/locales/administrate.es.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ es:
has_many:
more: Mostrando %{count} de %{total_count}
none: Ninguno
polymorphic:
not_supported: Los formularios con relaciones polimórficas no están soportados.
has_one:
not_supported: Los formularios con relaciones HasOne no están soportados.
search:
Expand Down
2 changes: 0 additions & 2 deletions config/locales/administrate.fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ fr:
has_many:
more: "%{count} sur %{total_count}"
none: Aucun
polymorphic:
not_supported: Les relations polymorphiques dans les formulaires ne sont pas supportées.
has_one:
not_supported: Les relations HasOne dans les formulaires ne sont pas supportées.
search:
Expand Down
2 changes: 0 additions & 2 deletions config/locales/administrate.it.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ it:
has_many:
more: Visualizzo %{count} di %{total_count}
none: Nessuno
polymorphic:
not_supported: Associazioni polimorfiche non ancora supportate. Spiacenti!
has_one:
not_supported: Associazioni HasOne non ancora supportate. Spiacenti!
search:
Expand Down
2 changes: 0 additions & 2 deletions config/locales/administrate.ja.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ ja:
has_many:
more: "%{total_count} 件中 %{count} 件表示"
none: データがありません
polymorphic:
not_supported: フォームでは「多:多」の関連をサポートしていません。
has_one:
not_supported: フォームでは「1:1」の関連をサポートしていません。
search:
Expand Down
2 changes: 0 additions & 2 deletions config/locales/administrate.ko.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ ko:
has_many:
more: "%{total_count} 개 중에서 %{count} 개"
none: 없음
polymorphic:
not_supported: 상속 관계에 대한 양식은 제공되지 않습니다.
has_one:
not_supported: 일대일 관계에 대한 양식은 제공되지 않습니다.
search:
Expand Down
2 changes: 0 additions & 2 deletions config/locales/administrate.nl.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ nl:
has_many:
more: Resultaat %{count} van %{total_count}
none: Geen
polymorphic:
not_supported: Polymorphische relaties formulieren worden niet ondersteund.
has_one:
not_supported: HasOne relaties formulieren worden niet ondersteund.
search:
Expand Down
2 changes: 0 additions & 2 deletions config/locales/administrate.pl.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ pl:
has_many:
more: Wyświetlanie %{count} z %{total_count}
none: Brak
polymorphic:
not_supported: Relacje polimorficzne nie są obsługiwane.
has_one:
not_supported: Relacje jeden-do-jednego nie są obsługiwane.
search:
Expand Down
2 changes: 0 additions & 2 deletions config/locales/administrate.pt-BR.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ pt-BR:
has_many:
more: "Exibindo %{count} de %{total_count}"
none: Nenhum
polymorphic:
not_supported: Relações polimórficas nos formulários não são suportadas.
has_one:
not_supported: Relações um para muitos nos formulários não são suportadas.
search:
Expand Down
2 changes: 0 additions & 2 deletions config/locales/administrate.pt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ pt:
has_many:
more: "Mostrando %{count} de %{total_count}"
none: Nenhum
polymorphic:
not_supported: Relações polimórficas nos formulários não são suportadas.
has_one:
not_supported: Relações um para muitos nos formulários não são suportadas.
search:
Expand Down
2 changes: 0 additions & 2 deletions config/locales/administrate.ru.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ ru:
has_many:
more: "%{count} из %{total_count}"
none: Нет
polymorphic:
not_supported: Полиморфные отношения в формах не поддерживаются.
has_one:
not_supported: HasOne отношения в формах не поддерживаются.
search:
Expand Down
2 changes: 0 additions & 2 deletions config/locales/administrate.sv.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ sv:
has_many:
more: "%{count} av %{total_count}"
none: Inga
polymorphic:
not_supported: Formulär med polymorfiska relationer stöds inte.
has_one:
not_supported: Formulär med HasOne relationer stöds inte.
search:
Expand Down
2 changes: 0 additions & 2 deletions config/locales/administrate.uk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ uk:
has_many:
more: "%{count} із %{total_count}"
none: Немає
polymorphic:
not_supported: Поліморфні відношення у формах не підтримуються.
has_one:
not_supported: HasOne відношення у формах не підтримуються.
search:
Expand Down
2 changes: 0 additions & 2 deletions config/locales/administrate.vi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ vi:
has_many:
more: "%{count} trên %{total_count}"
none: Không
polymorphic:
not_supported: Quan hệ Polymorphic chưa được hỗ trợ.
has_one:
not_supported: Quan hệ HasOne chưa được hỗ trợ.
search:
Expand Down
2 changes: 0 additions & 2 deletions config/locales/administrate.zh-CN.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ zh-CN:
has_many:
more: 显示所有 %{total_count} 中 %{count} 条
none:
polymorphic:
not_supported: Polymorphic 关系暂不支持
has_one:
not_supported: HasOne 关系暂不支持.
search:
Expand Down
2 changes: 0 additions & 2 deletions config/locales/administrate.zh-TW.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ zh-TW:
has_many:
more: 顯示 %{total_count} 筆中的 %{count} 筆資料
none:
polymorphic:
not_supported: 表單尚未支援 Polymorphic 關聯。
has_one:
not_supported: 表單尚未支援 HasOne 關聯。
search:
Expand Down
5 changes: 5 additions & 0 deletions docs/customizing_dashboards.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ Or, to display a distance in kilometers:
)
```

**Field::Polymorphic**

`:classes` - Specify a list of classes whose objects will be used to populate select boxes for editing this polymorphic field.
Default is `[]`.

**Field::Select**

`:collection` - Specify the array or range to select from. Defaults to `[]`.
Expand Down
1 change: 1 addition & 0 deletions gemfiles/rails42.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ source "https://rubygems.org"
gem "administrate-field-image"
gem "autoprefixer-rails"
gem "faker"
gem "globalid"
gem "pg"
gem "redcarpet"
gem "sentry-raven"
Expand Down
1 change: 1 addition & 0 deletions gemfiles/rails50.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ source "https://rubygems.org"
gem "administrate-field-image"
gem "autoprefixer-rails"
gem "faker"
gem "globalid"
gem "pg"
gem "redcarpet"
gem "sentry-raven"
Expand Down
1 change: 1 addition & 0 deletions gemfiles/rails51.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ source "https://rubygems.org"
gem "administrate-field-image"
gem "autoprefixer-rails"
gem "faker"
gem "globalid"
gem "pg"
gem "redcarpet"
gem "sentry-raven"
Expand Down
1 change: 1 addition & 0 deletions gemfiles/sass_3_4.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ source "https://rubygems.org"
gem "administrate-field-image"
gem "autoprefixer-rails"
gem "faker"
gem "globalid"
gem "pg"
gem "redcarpet"
gem "sentry-raven"
Expand Down
44 changes: 41 additions & 3 deletions lib/administrate/field/polymorphic.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,49 @@

module Administrate
module Field
class Polymorphic < Associative
class Polymorphic < BelongsTo
def associated_resource_grouped_options
classes.map do |klass|
[klass.to_s, candidate_resources_for(klass).map do |resource|
[display_candidate_resource(resource), resource.to_global_id]
end]
end
end

def self.permitted_attribute(attr)
{ attr => %i{type value} }
end

def permitted_attribute
{ attribute => %i{type value} }
end

def selected_global_id
data ? data.to_global_id : nil
end

protected

def associated_dashboard
"#{data.class.name}Dashboard".constantize.new
def associated_dashboard(klass = data.class)
"#{klass.name}Dashboard".constantize.new
end

def classes
options.fetch(:classes) || []
end

private

def order
@_order ||= options.delete(:order)
end

def candidate_resources_for(klass)
order ? klass.order(order) : klass.all
end

def display_candidate_resource(resource)
associated_dashboard(resource.class).display_resource(resource)
end
end
end
Expand Down
Loading

0 comments on commit 8329b21

Please sign in to comment.