Skip to content

Associations are persisted before validation of main record #5430

@tkalliom

Description

@tkalliom

Expected behavior

When updating a record with changes to its children that make the record fail validation, no changes are saved to the database.

Actual behavior

The invalid association change is persisted, and then the user gets redirected to a form displaying a validation error.

How to reproduce

require 'bundler/inline'

gemfile(true) do
  source 'https://rubygems.org'

  gem 'activeadmin', ENV['ACTIVE_ADMIN_PATH'] ? {path: ENV['ACTIVE_ADMIN_PATH'], require: false} : {github: 'activeadmin/activeadmin', require: false}
  gem 'rails', '~> 5.1.0'
  gem 'sass-rails'
  gem 'sqlite3', platform: :mri
  gem 'activerecord-jdbcsqlite3-adapter', "~> 51.0", platform: :jruby
end

require 'active_record'

ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
ActiveRecord::Base.logger = Logger.new(STDOUT)

ActiveRecord::Schema.define do
  create_table :agents, force: true do |t|
    t.string :full_name
  end

  create_table :agents_clients, force: true do |t|
    t.bigint :agent_id, null: false
    t.bigint :client_id, null: false
  end

  create_table :clients, force: true do |t|
    t.string :name
  end
end

require 'action_controller/railtie'
require 'action_view/railtie'
require 'active_admin'

class TestApp < Rails::Application
  config.root = __dir__
  secrets.secret_token = 'secret_token'
  secrets.secret_key_base = 'secret_key_base'

  config.eager_load = false
  Rails.logger = config.logger = Logger.new($stdout)
end

class ApplicationController < ActionController::Base
  include Rails.application.routes.url_helpers
end

class Client < ActiveRecord::Base
  has_and_belongs_to_many :agents
  validates :agents, presence: true
end

class Agent < ActiveRecord::Base
  has_and_belongs_to_many :clients
end

ActiveAdmin.setup do |config|
  config.authentication_method = false
  config.current_user_method = false
end

Rails.application.initialize!

ActiveAdmin.register Client do
  permit_params agent_ids: []
  
  form do |f|
    f.input :agents, as: :check_boxes
  end
end

Rails.application.routes.draw do
  ActiveAdmin.routes(self)
end

require 'minitest/autorun'
require 'rack/test'

class HabtmTest < ActionDispatch::IntegrationTest
  def test_clients
    Agent.create! full_name: 'John Doe'
    Client.create! name: 'ACME', agents: [Agent.first]

    patch admin_client_url(Client.first), params: {client: {agent_ids: []}}
    assert_response :success
    assert_select "p.inline-errors", "can't be blank"
    assert_equal 1, Client.first.agents.count
  end

  private

  def app
    Rails.application
  end
end

This seems to be due to the behavior of assign_attributes (as detailed in http://guides.rubyonrails.org/association_basics.html#has-and-belongs-to-many-association-reference). Maybe update_resource should check if an ids field is present, and if so use collection.build for that?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions