Skip to content

Commit

Permalink
Use correct key in unconventional associations (#2292)
Browse files Browse the repository at this point in the history
* Reproduction of bug

* Correct key to use in this case

* Hopefully better phrasing

* Deprecation notice, just in case anyone cares
  • Loading branch information
pablobm authored Apr 6, 2023
1 parent 7dd3ee1 commit 8dab2ac
Showing 6 changed files with 68 additions and 13 deletions.
12 changes: 11 additions & 1 deletion lib/administrate/field/associative.rb
Original file line number Diff line number Diff line change
@@ -7,6 +7,10 @@ def self.foreign_key_for(resource_class, attr)
reflection(resource_class, attr).foreign_key
end

def self.association_primary_key_for(resource_class, attr)
reflection(resource_class, attr).association_primary_key
end

def self.associated_class(resource_class, attr)
reflection(resource_class, attr).klass
end
@@ -49,10 +53,16 @@ def associated_dashboard
end

def primary_key
# Deprecated, renamed `association_primary_key`
Administrate.warn_of_deprecated_method(self.class, :primary_key)
association_primary_key
end

def association_primary_key
if option_given?(:primary_key)
deprecated_option(:primary_key)
else
:id
self.class.association_primary_key_for(resource.class, attribute)
end
end

7 changes: 5 additions & 2 deletions lib/administrate/field/belongs_to.rb
Original file line number Diff line number Diff line change
@@ -23,12 +23,15 @@ def permitted_attribute

def associated_resource_options
candidate_resources.map do |resource|
[display_candidate_resource(resource), resource.send(primary_key)]
[
display_candidate_resource(resource),
resource.send(association_primary_key),
]
end
end

def selected_option
data && data.send(primary_key)
data&.send(association_primary_key)
end

def include_blank_option
9 changes: 6 additions & 3 deletions lib/administrate/field/has_many.rb
Original file line number Diff line number Diff line change
@@ -30,15 +30,18 @@ def attribute_key
end

def associated_resource_options
candidate_resources.map do |resource|
[display_candidate_resource(resource), resource.send(primary_key)]
candidate_resources.map do |associated_resource|
[
display_candidate_resource(associated_resource),
associated_resource.send(association_primary_key),
]
end
end

def selected_options
return if data.empty?

data.map { |object| object.send(primary_key) }
data.map { |object| object.send(association_primary_key) }
end

def limit
11 changes: 11 additions & 0 deletions spec/features/edit_page_spec.rb
Original file line number Diff line number Diff line change
@@ -87,4 +87,15 @@
expect(page).to have_text(new_email)
expect(page).to have_flash("Custom name was successfully updated.")
end

it "handles complex associations" do
country = create(:country, code: "CO")
customer = create(:customer, territory: country)

visit edit_admin_customer_path(customer)
click_on "Update Customer"

customer.reload
expect(customer.territory).to eq(country)
end
end
2 changes: 1 addition & 1 deletion spec/lib/fields/belongs_to_spec.rb
Original file line number Diff line number Diff line change
@@ -196,7 +196,7 @@
remove_constants :Foo, :FooDashboard
end

it "determines what primary key is used on the relationship for the form" do
it "is the associated table key that matches our foreign key" do
association =
Administrate::Field::BelongsTo.with_options(
primary_key: "uuid", class_name: "Foo",
40 changes: 34 additions & 6 deletions spec/lib/fields/has_many_spec.rb
Original file line number Diff line number Diff line change
@@ -87,7 +87,7 @@
remove_constants :Foo, :FooDashboard
end

it "determines what primary key is used on the relationship for the form" do
it "is the key matching the associated foreign key" do
association =
Administrate::Field::HasMany.with_options(
primary_key: "uuid", class_name: "Foo",
@@ -241,14 +241,42 @@
end

describe "#selected_options" do
it "returns a collection of primary keys" do
model = double("model", id: 123)
value = MockRelation.new([model])
it "returns a collection of keys to use for the association" do
associated_resource1 = double(
"AssociatedResource1",
associated_resource_key: "associated-1",
)
associated_resource2 = double(
"AssociatedResource2",
associated_resource_key: "associated-2",
)
attribute_value = MockRelation.new(
[
associated_resource1,
associated_resource2,
],
)

primary_resource = double(
"Resource",
class: double(
"ResourceClass",
reflect_on_association: double(
"ResourceReflection",
association_primary_key: "associated_resource_key",
),
),
)

association = Administrate::Field::HasMany
field = association.new(:customers, value, :show)
field = association.new(
:customers,
attribute_value,
:show,
resource: primary_resource,
)

expect(field.selected_options).to eq([123])
expect(field.selected_options).to eq(["associated-1", "associated-2"])
end

context "when there are no records" do

0 comments on commit 8dab2ac

Please sign in to comment.