diff --git a/lib/administrate/field/associative.rb b/lib/administrate/field/associative.rb index 989fb6c899414ec31a0ef316a252ae7a2f00e81f..73d0434e81f6a2754cfef79c3f8d592bed8c1184 100644 --- a/lib/administrate/field/associative.rb +++ b/lib/administrate/field/associative.rb @@ -7,6 +7,10 @@ module Administrate 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 @@ module Administrate 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 diff --git a/lib/administrate/field/belongs_to.rb b/lib/administrate/field/belongs_to.rb index 95fdebbf0a30aabc5436f02d8080243e3cf1d7d1..a86762805855356ea0d7c28787b03b147fb4ac91 100644 --- a/lib/administrate/field/belongs_to.rb +++ b/lib/administrate/field/belongs_to.rb @@ -23,12 +23,15 @@ module Administrate 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 diff --git a/lib/administrate/field/has_many.rb b/lib/administrate/field/has_many.rb index 912cd3ce9f9bcde5b13363722e08f60d2db084bd..13ddebd9c7081b038a25fa3534b81346062f97ba 100644 --- a/lib/administrate/field/has_many.rb +++ b/lib/administrate/field/has_many.rb @@ -30,15 +30,18 @@ module Administrate 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 diff --git a/spec/features/edit_page_spec.rb b/spec/features/edit_page_spec.rb index d988e11c852d68ef69b5be4317c202dd42ee30d1..9600d39424bae47ace6cd59c34a0ee71a6c42c9c 100644 --- a/spec/features/edit_page_spec.rb +++ b/spec/features/edit_page_spec.rb @@ -87,4 +87,15 @@ describe "customer edit page" do 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 diff --git a/spec/lib/fields/belongs_to_spec.rb b/spec/lib/fields/belongs_to_spec.rb index 9499e5b49a8e9125c245eaa5d7453e920e5147ae..14be213bbd7474e3b37a65cfbb1f0ef2af5f8310 100644 --- a/spec/lib/fields/belongs_to_spec.rb +++ b/spec/lib/fields/belongs_to_spec.rb @@ -196,7 +196,7 @@ describe Administrate::Field::BelongsTo do 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", diff --git a/spec/lib/fields/has_many_spec.rb b/spec/lib/fields/has_many_spec.rb index 7fcdd056c45370bb5bd8bd1330d035b8b9774fde..027681f69cd48a9f83acdb2737bbc0d1b9e9594c 100644 --- a/spec/lib/fields/has_many_spec.rb +++ b/spec/lib/fields/has_many_spec.rb @@ -87,7 +87,7 @@ describe Administrate::Field::HasMany do 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 @@ describe Administrate::Field::HasMany do 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