{"action":"created","issue":{"url":"https://api.github.com/repos/rails/rails/issues/24301","repository_url":"https://api.github.com/repos/rails/rails","labels_url":"https://api.github.com/repos/rails/rails/issues/24301/labels{/name}","comments_url":"https://api.github.com/repos/rails/rails/issues/24301/comments","events_url":"https://api.github.com/repos/rails/rails/issues/24301/events","html_url":"https://github.com/rails/rails/issues/24301","id":143275845,"number":24301,"title":"Rails ActiveRecord::RecordInvalid exception not raised in after_create of association","user":{"login":"mountriv99","id":584545,"avatar_url":"https://avatars.githubusercontent.com/u/584545?v=3","gravatar_id":"","url":"https://api.github.com/users/mountriv99","html_url":"https://github.com/mountriv99","followers_url":"https://api.github.com/users/mountriv99/followers","following_url":"https://api.github.com/users/mountriv99/following{/other_user}","gists_url":"https://api.github.com/users/mountriv99/gists{/gist_id}","starred_url":"https://api.github.com/users/mountriv99/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mountriv99/subscriptions","organizations_url":"https://api.github.com/users/mountriv99/orgs","repos_url":"https://api.github.com/users/mountriv99/repos","events_url":"https://api.github.com/users/mountriv99/events{/privacy}","received_events_url":"https://api.github.com/users/mountriv99/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/rails/rails/labels/activerecord","name":"activerecord","color":"0b02e1"},{"url":"https://api.github.com/repos/rails/rails/labels/With%20reproduction%20steps","name":"With reproduction steps","color":"009800"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":9,"created_at":"2016-03-24T15:22:21Z","updated_at":"2016-03-26T07:53:52Z","closed_at":null,"body":"### Steps to reproduce\r\n\r\nI have 3 simple tables that are built with the following lines:\r\n\r\n```\r\nrails g model receipt\r\nrails g model receipt_item receipt:references\r\nrails g model transaction transacted_at:datetime\r\n```\r\n\r\nand the models look like this:\r\n\r\n```\r\nclass Receipt < ActiveRecord::Base\r\n  has_many :receipt_items\r\nend\r\n\r\nclass ReceiptItem < ActiveRecord::Base\r\n  after_create :create_transaction\r\n  belongs_to :receipt\r\nprivate\r\n  def create_transaction\r\n    Transaction.new.save!\r\n  end\r\nend\r\n\r\nclass Transaction < ActiveRecord::Base\r\n  validates :transacted_at, :presence => true\r\nend\r\n```\r\n\r\n### Expected behaviour\r\n\r\nSo every time a new ReceiptItem is created, it triggers the after_create callback to create a new Transaction object using save!. But because Transaction requires that the column transacted_at to be present, Transaction.new.save! should raise an ActiveRecord::RecordInvalid every time, I assumed.\r\n\r\n### Actual behaviour\r\n\r\nSo then I created 3 tests:\r\n\r\n```\r\ntest \"creating an invalid transaction\" do\r\n    assert_raises ActiveRecord::RecordInvalid do\r\n        Transaction.new.save!\r\n    end\r\nend\r\n\r\ntest \"creating invalid transaction in after_create\" do\r\n    assert_raises ActiveRecord::RecordInvalid do\r\n        ReceiptItem.new.save!\r\n    end\r\nend\r\n\r\ntest \"creating invalid transaction in after_create of associated model\" do\r\n    assert_raises ActiveRecord::RecordInvalid do\r\n        r = Receipt.new\r\n        i = r.receipt_items.new\r\n        r.save!\r\n    end\r\nend\r\n```\r\nThe first two tests passed as expected. The third test, however, failed because the exception was never raised. As a matter of fact, if I add the following lines after the 'r.save!' line:\r\n\r\n```\r\nr.reload\r\np r\r\np r.receipt_items\r\n```\r\nI could see that the Receipt and the ReceiptItem have been created successfully.\r\n\r\n```\r\n#<Receipt id: 980190963, created_at: \"2016-03-24 14:39:43\", updated_at: \"2016-03-24 14:39:43\">\r\n#<ActiveRecord::Associations::CollectionProxy [#<ReceiptItem id: 980190964, receipt_id: 980190963, created_at: \"2016-03-24 14:39:43\", updated_at: \"2016-03-24 14:39:43\">]>\r\n```\r\n\r\nFurthermore, if I replaced\r\n\r\n`assert_raises ActiveRecord::RecordInvalid do`\r\nwith\r\n`assert_difference \"Transaction.count\", +1 do`\r\n\r\nThe test also failed and I confirmed that the Receipt and the ReceiptItems were created but the Transaction wasn't. That means the creation of the Transaction failed, but was silently ignored, even though I used 'save!' as opposed to just 'save'.\r\n\r\nIs this the intended behaviour, or is this a bug?\r\n\r\n### System configuration\r\n**Rails version**: Tried this in Rails 4.0.13 and 4.2.0\r\n\r\n**Ruby version**: 2.1.2p95 and  2.0.0p353\r\n"},"comment":{"url":"https://api.github.com/repos/rails/rails/issues/comments/201727152","html_url":"https://github.com/rails/rails/issues/24301#issuecomment-201727152","issue_url":"https://api.github.com/repos/rails/rails/issues/24301","id":201727152,"user":{"login":"twonegatives","id":1937799,"avatar_url":"https://avatars.githubusercontent.com/u/1937799?v=3","gravatar_id":"","url":"https://api.github.com/users/twonegatives","html_url":"https://github.com/twonegatives","followers_url":"https://api.github.com/users/twonegatives/followers","following_url":"https://api.github.com/users/twonegatives/following{/other_user}","gists_url":"https://api.github.com/users/twonegatives/gists{/gist_id}","starred_url":"https://api.github.com/users/twonegatives/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/twonegatives/subscriptions","organizations_url":"https://api.github.com/users/twonegatives/orgs","repos_url":"https://api.github.com/users/twonegatives/repos","events_url":"https://api.github.com/users/twonegatives/events{/privacy}","received_events_url":"https://api.github.com/users/twonegatives/received_events","type":"User","site_admin":false},"created_at":"2016-03-26T07:53:52Z","updated_at":"2016-03-26T07:53:52Z","body":"could we get a RoR member comment on this, please?\r\nnote that even though `receipt_item` is wrapped in a silent `save` call, it gets saved regardless of an exception raised in its `after_save` block.[Halting execution](http://guides.rubyonrails.org/active_record_callbacks.html#halting-execution) section of guide mentiones that exceptions raised inside of `after_save` should rollback (at least) `receipt_item` saving transaction."}}