Skip to content

Add support for editing polymorphic fields #984

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed

Conversation

pedantic-git
Copy link
Contributor

This PR allows users to edit Field::Polymorphic fields (previously they were just told this was not possible).

The <select> is a grouped select, populated using the contents of zero-or-more model classes specified in the :classes option.

I appreciate I haven't really added much in the way of testing for this, but I think it's comparable with the amount of testing the other complex built-in types already have (e.g. Field::HasMany).

The one place in the core that's changed here and might be controversial, is that #resource_params now auto-converts anything that looks like a GlobalID. This is necessary for a polymorphic field without JavaScript as GlobalIDs are the only IDs that work across multiple models. Let me know if you need this implementing a different way.


describe '#selected_global_id' do
it "returns the global ID of the data" do
item = double('SomeModel', to_global_id: "gid://myapp/SomeModel/1")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping.

@@ -37,4 +38,16 @@ def display_resource(*)
end
end
end

describe '#selected_global_id' do

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping.

@@ -37,4 +38,16 @@ def display_resource(*)
end
end
end

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trailing whitespace detected.

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trailing whitespace detected.

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trailing whitespace detected.

def self.permitted_attribute(attr)
attr
end

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trailing whitespace detected.

end ]
end
end

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trailing whitespace detected.

classes.map do |klass|
[ klass.to_s, candidate_resources(klass).map do |resource|
[display_candidate_resource(resource), resource.to_global_id]
end ]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Space inside square brackets detected.

class Polymorphic < BelongsTo
def associated_resource_grouped_options
classes.map do |klass|
[ klass.to_s, candidate_resources(klass).map do |resource|

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Space inside square brackets detected.

@@ -120,7 +120,7 @@ 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| v.respond_to?(:starts_with?) && v.starts_with?("gid://") ? GlobalID::Locator.locate(v) : v }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Space between { and | missing.
Line is too long. [162/80]

permit(dashboard.permitted_attributes)
permit(dashboard.permitted_attributes).
transform_values do |v|
(v.respond_to?(:starts_with?) && v.starts_with?("gid://")) ?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid multi-line ternary operators, use if or unless instead.
Omit parentheses for ternary conditions.

@ewilliam
Copy link

any plans to implement this? or any polymorphic field solution?

@pablobm
Copy link
Collaborator

pablobm commented Nov 1, 2017

@pedantic-git - Thank you for your PR. I've been having a look at this and I like the general direction. You are right that the implementation of #resource_params is a pickle, so I gave it some thought. I think I have with a good solution now, and I have implemented it on a separate PR #1020, on top of your work.

The main change is in how to deal with this global id. Instead of relying on the global id only, I split the field in two:

  • my_field[value]: the global id
  • my_field[type]: literally "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.

Something to note is that the globalid gem is not a default in old versions of Rails. Therefore I had to add it as a dependency. I could have done without it, but I liked it when I saw it on your code.

Additionally, I added some tests. I may add a couple more, but this does pretty well for now.

Closing this as it's superseded by the new PR.

@pablobm pablobm closed this Nov 1, 2017
pablobm added a commit that referenced this pull request Nov 17, 2017
This adds support for editing polymorphic fields. Props go to @pedantic-git, on whose work this is based. This PR supersedes #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.
svqualitydev pushed a commit to svqualitydev/admin-cms that referenced this pull request Dec 16, 2019
This adds support for editing polymorphic fields. Props go to @pedantic-git, on whose work this is based. This PR supersedes thoughtbot/administrate#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.
KingTiger001 added a commit to KingTiger001/admin-Rails-project that referenced this pull request Jan 15, 2023
This adds support for editing polymorphic fields. Props go to @pedantic-git, on whose work this is based. This PR supersedes thoughtbot/administrate#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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants