Skip to content

Commit

Permalink
Prepopulate modal foreign keys regardless of inverse_of and only for …
Browse files Browse the repository at this point in the history
…has_one and has_many

Fixes #2585
  • Loading branch information
mshibuya committed Dec 25, 2021
1 parent 48665ec commit 75504d0
Show file tree
Hide file tree
Showing 9 changed files with 38 additions and 51 deletions.
10 changes: 2 additions & 8 deletions app/views/rails_admin/main/_form_filtering_multiselect.html.erb
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -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 "<i class=\"fas fa-plus\"></i> ".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 %>
17 changes: 3 additions & 14 deletions app/views/rails_admin/main/_form_filtering_select.html.erb
Original file line number Diff line number Diff line change
@@ -1,36 +1,25 @@
<%
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,
remote_source: index_path(config.abstract_model.to_param, source_object_id: form.object.id, source_abstract_model: source_abstract_model.to_param, associated_collection: field.name, current_action: current_action, compact: true)
}
%>

<% 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 "<i class=\"fas fa-plus\"></i> ".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 %>
Expand Down
5 changes: 5 additions & 0 deletions lib/rails_admin/config/fields/association.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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?
Expand Down
4 changes: 4 additions & 0 deletions lib/rails_admin/config/fields/types/has_many_association.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions lib/rails_admin/config/fields/types/has_one_association.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 6 additions & 5 deletions spec/integration/actions/new_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 4 additions & 12 deletions spec/integration/fields/belongs_to_association_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions spec/integration/fields/has_many_association_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 4 additions & 12 deletions spec/integration/fields/has_one_association_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 75504d0

Please sign in to comment.