From 75504d08ee6197a3a2c72a56ea30f01272b1d28b Mon Sep 17 00:00:00 2001 From: "M.Shibuya" Date: Sat, 25 Dec 2021 19:22:40 +0900 Subject: [PATCH] Prepopulate modal foreign keys regardless of inverse_of and only for has_one and has_many Fixes #2585 --- .../main/_form_filtering_multiselect.html.erb | 10 ++-------- .../main/_form_filtering_select.html.erb | 17 +++-------------- lib/rails_admin/config/fields/association.rb | 5 +++++ .../config/fields/types/has_many_association.rb | 4 ++++ .../config/fields/types/has_one_association.rb | 4 ++++ spec/integration/actions/new_spec.rb | 11 ++++++----- .../fields/belongs_to_association_spec.rb | 16 ++++------------ .../fields/has_many_association_spec.rb | 6 ++++++ .../fields/has_one_association_spec.rb | 16 ++++------------ 9 files changed, 38 insertions(+), 51 deletions(-) diff --git a/app/views/rails_admin/main/_form_filtering_multiselect.html.erb b/app/views/rails_admin/main/_form_filtering_multiselect.html.erb index 090ada252c..2c504efcc1 100644 --- a/app/views/rails_admin/main/_form_filtering_multiselect.html.erb +++ b/app/views/rails_admin/main/_form_filtering_multiselect.html.erb @@ -1,13 +1,8 @@ <% - related_id = params[:associations] && params[:associations][field.name.to_s] config = field.associated_model_config source_abstract_model = RailsAdmin.config(form.object.class).abstract_model - if form.object.new_record? && related_id.present? && related_id != 'new' - selected = [config.abstract_model.get(related_id)] - else - selected = form.object.send(field.name) - end + selected = form.object.send(field.name) selected_ids = selected.map{|s| s.send(field.associated_primary_key)} current_action = params[:action].in?(['create', 'new']) ? 'create' : 'update' @@ -43,7 +38,6 @@ <% selected_ids = (hdv = field.form_default_value).nil? ? selected_ids : hdv %> <%= form.select field.method_name, collection, { selected: selected_ids, object: form.object }, field.html_attributes.reverse_merge({data: { filteringmultiselect: true, options: js_data.to_json }, multiple: true}) %> <% if authorized?(:new, config.abstract_model) && field.inline_add %> - <% path_hash = { model_name: config.abstract_model.to_param, modal: true } %> - <% path_hash.merge!({ associations: { field.inverse_of => (form.object.persisted? ? form.object.id : 'new') } }) if field.inverse_of %> + <% path_hash = { model_name: config.abstract_model.to_param, modal: true }.merge!(field.associated_prepopulate_params) %> <%= link_to " ".html_safe + wording_for(:link, :new, config.abstract_model), '#', data: { link: new_path(path_hash) }, class: "create btn btn-info", style: 'margin-left:10px' %> <% end %> diff --git a/app/views/rails_admin/main/_form_filtering_select.html.erb b/app/views/rails_admin/main/_form_filtering_select.html.erb index 41506a09b9..a3c7b38e59 100644 --- a/app/views/rails_admin/main/_form_filtering_select.html.erb +++ b/app/views/rails_admin/main/_form_filtering_select.html.erb @@ -1,24 +1,14 @@ <% config = field.associated_model_config - related_id = params[:associations] && params[:associations][field.name.to_s] source_abstract_model = RailsAdmin.config(form.object.class).abstract_model - if form.object.new_record? && related_id.present? && related_id != 'new' - selected = config.abstract_model.get(related_id) - selected_id = selected.send(field.associated_primary_key) - selected_name = selected.send(field.associated_object_label_method) - else - selected_id = field.selected_id - selected_name = field.formatted_value - end - current_action = params[:action].in?(['create', 'new']) ? 'create' : 'update' edit_url = authorized?(:edit, config.abstract_model) ? edit_path(model_name: config.abstract_model.to_param, modal: true, id: '__ID__') : '' xhr = !field.associated_collection_cache_all - collection = xhr ? [[selected_name, selected_id]] : controller.list_entries(config, :index, field.associated_collection_scope, false).map { |o| [o.send(field.associated_object_label_method), o.send(field.associated_primary_key)] } + collection = xhr ? [[field.formatted_value, field.selected_id]] : controller.list_entries(config, :index, field.associated_collection_scope, false).map { |o| [o.send(field.associated_object_label_method), o.send(field.associated_primary_key)] } js_data = { xhr: xhr, @@ -26,11 +16,10 @@ } %> -<% selected_id = (hdv = field.form_default_value).nil? ? selected_id : hdv %> +<% selected_id = (hdv = field.form_default_value).nil? ? field.selected_id : hdv %> <%= form.select field.method_name, collection, { selected: selected_id, include_blank: true }, field.html_attributes.reverse_merge({ data: { filteringselect: true, options: js_data.to_json }, placeholder: t('admin.misc.search'), style: "float: left" }) %> <% if authorized?(:new, config.abstract_model) && field.inline_add %> - <% path_hash = { model_name: config.abstract_model.to_param, modal: true } %> - <% path_hash.merge!({ associations: { field.inverse_of => (form.object.persisted? ? form.object.id : 'new') } }) if field.inverse_of %> + <% path_hash = { model_name: config.abstract_model.to_param, modal: true }.merge!(field.associated_prepopulate_params) %> <%= link_to " ".html_safe + wording_for(:link, :new, config.abstract_model), '#', data: { link: new_path(path_hash) }, class: "btn btn-info create", style: 'margin-left:10px' %> <% end %> <% if edit_url.present? && field.inline_edit %> diff --git a/lib/rails_admin/config/fields/association.rb b/lib/rails_admin/config/fields/association.rb index 58afd20d75..3ac7233fa3 100644 --- a/lib/rails_admin/config/fields/association.rb +++ b/lib/rails_admin/config/fields/association.rb @@ -89,6 +89,11 @@ def associated_primary_key association.primary_key end + # Returns params which are to be set in modals + def associated_prepopulate_params + {} + end + # Reader whether this is a polymorphic association def polymorphic? association.polymorphic? diff --git a/lib/rails_admin/config/fields/types/has_many_association.rb b/lib/rails_admin/config/fields/types/has_many_association.rb index 83c4aadce7..13bfd97c0b 100644 --- a/lib/rails_admin/config/fields/types/has_many_association.rb +++ b/lib/rails_admin/config/fields/types/has_many_association.rb @@ -25,6 +25,10 @@ def method_name def errors bindings[:object].errors[name] end + + def associated_prepopulate_params + {associated_model_config.abstract_model.param_key => {association.foreign_key => bindings[:object].try(:id)}} + end end end end diff --git a/lib/rails_admin/config/fields/types/has_one_association.rb b/lib/rails_admin/config/fields/types/has_one_association.rb index cb44b92db9..397d81392a 100644 --- a/lib/rails_admin/config/fields/types/has_one_association.rb +++ b/lib/rails_admin/config/fields/types/has_one_association.rb @@ -28,6 +28,10 @@ def method_name def multiple? false end + + def associated_prepopulate_params + {associated_model_config.abstract_model.param_key => {association.foreign_key => bindings[:object].try(:id)}} + end end end end diff --git a/spec/integration/actions/new_spec.rb b/spec/integration/actions/new_spec.rb index 433d4964f5..da1b14332a 100644 --- a/spec/integration/actions/new_spec.rb +++ b/spec/integration/actions/new_spec.rb @@ -44,15 +44,16 @@ expect(page).to have_css('input[value=Sam]') end - it 'prepropulates belongs to relationships' do - @team = FactoryBot.create :team, name: 'belongs_to association prepopulated' - visit new_path(model_name: 'player', associations: {team: @team.id}) - expect(page).to have_css("select#player_team_id option[selected='selected'][value='#{@team.id}']") + it 'prepropulates has_one relationships' do + @draft = FactoryBot.create :draft + @player = FactoryBot.create :player, name: 'has_one association prepopulated' + visit new_path(model_name: 'player', player: {draft_id: @draft.id}) + expect(page).to have_css("select#player_draft_id option[selected='selected'][value='#{@draft.id}']") end it 'prepropulates has_many relationships' do @player = FactoryBot.create :player, name: 'has_many association prepopulated' - visit new_path(model_name: 'team', associations: {players: @player.id}) + visit new_path(model_name: 'team', team: {player_ids: [@player.id]}) expect(page).to have_css("select#team_player_ids option[selected='selected'][value='#{@player.id}']") end end diff --git a/spec/integration/fields/belongs_to_association_spec.rb b/spec/integration/fields/belongs_to_association_spec.rb index 6c57d83c3f..ac463b28cc 100644 --- a/spec/integration/fields/belongs_to_association_spec.rb +++ b/spec/integration/fields/belongs_to_association_spec.rb @@ -3,18 +3,10 @@ RSpec.describe 'BelongsToAssociation field', type: :request do subject { page } - describe 'with inverse_of option' do - it 'adds a related id to the belongs_to create team link' do - @player = FactoryBot.create :player - visit edit_path(model_name: 'player', id: @player.id) - is_expected.to have_selector("a[data-link='/admin/team/new?associations%5Bplayers%5D=#{@player.id}&modal=true']") - end - - it 'adds a related id to the has_many create team link' do - @team = FactoryBot.create :team - visit edit_path(model_name: 'team', id: @team.id) - is_expected.to have_selector("a[data-link='/admin/player/new?associations%5Bteam%5D=#{@team.id}&modal=true']") - end + it 'does not add a related id to the belongs_to create team link' do + @player = FactoryBot.create :player + visit edit_path(model_name: 'player', id: @player.id) + is_expected.to have_selector("a[data-link='/admin/team/new?modal=true']") end describe 'on create' do diff --git a/spec/integration/fields/has_many_association_spec.rb b/spec/integration/fields/has_many_association_spec.rb index ae2872c00f..f57e17d157 100644 --- a/spec/integration/fields/has_many_association_spec.rb +++ b/spec/integration/fields/has_many_association_spec.rb @@ -3,6 +3,12 @@ RSpec.describe 'HasManyAssociation field', type: :request do subject { page } + it 'adds a related id to the has_many create team link' do + @team = FactoryBot.create :team + visit edit_path(model_name: 'team', id: @team.id) + is_expected.to have_selector("a[data-link='/admin/player/new?modal=true&player%5Bteam_id%5D=#{@team.id}']") + end + context 'when an association is readonly' do it 'is not editable' do @league = FactoryBot.create :league diff --git a/spec/integration/fields/has_one_association_spec.rb b/spec/integration/fields/has_one_association_spec.rb index 5f82e176a5..d42f31f3bc 100644 --- a/spec/integration/fields/has_one_association_spec.rb +++ b/spec/integration/fields/has_one_association_spec.rb @@ -3,18 +3,10 @@ RSpec.describe 'HasOneAssociation field', type: :request do subject { page } - describe 'with inverse_of option' do - it 'adds a related id to the belongs_to create team link' do - @player = FactoryBot.create :player - visit edit_path(model_name: 'player', id: @player.id) - is_expected.to have_selector("a[data-link='/admin/team/new?associations%5Bplayers%5D=#{@player.id}&modal=true']") - end - - it 'adds a related id to the has_many create team link' do - @team = FactoryBot.create :team - visit edit_path(model_name: 'team', id: @team.id) - is_expected.to have_selector("a[data-link='/admin/player/new?associations%5Bteam%5D=#{@team.id}&modal=true']") - end + it 'adds a related id to the has_one create draft link' do + @player = FactoryBot.create :player + visit edit_path(model_name: 'player', id: @player.id) + is_expected.to have_selector("a[data-link='/admin/draft/new?draft%5Bplayer_id%5D=#{@player.id}&modal=true']") end context 'on create' do