Testing dependent: :destroy association results in false positive

Hi, I’m testing the dependent: :destroy functionality for a many-to-many association in a TDD way. So to check that the associated records are deleted in the join table (theme_projects) I wrote this integration test:

 scenario "Dependent associations are destroyed when admin deletes research project" do
    research_theme_1 = Fabricate(:research_theme)
    research_theme_2 = Fabricate(:research_theme)

    @research_project.research_themes << research_theme_1
    @research_project.research_themes << research_theme_2

    themes = @research_project.research_themes

    click_link "Delete"

    themes.each do |theme|
        theme.research_projects.should_not include(@research_project)
    end
  end

I expected this test to fail, becauce I hadn’t yet added dependent: :destroy to my many to many association:

class ResearchProject < ActiveRecord::Base
  validates :title, :body, presence: true

  has_many :theme_projects
  has_many :research_themes, through: :theme_projects
end

To my surprise however the test passes. When I do a sanity check, the records for the deleted research project are not removed from the join tabel.

So is my test not valid?

When I add the dependent: :destroy directive to my many to many association, the records for a deleted research project are removed from the join table.

My repo is at: https://github.com/acandael/posplus-rails

the integration test is at: spec/features/admin_handles_research_projects_spec.rb

Thanks for your help,

Anthony

There’s stuff going on here that I cant see because you apparently have it tucked away in a before block (stting the instance variable, for instance). So as a sidebar to this discussion, I’d suggest checking out: Let's Not

Anyway, I think what is happening is that the way your accessing and adding to the research_themes is not also updating the in-memory copy of your research project. I don’t know what Fabricate is, but I’m guessing it’s similar to FactoryGirl and is createing a ResearchTheme. You likely need some inverse_of declarations on your associations. See: ActiveRecord::Associations::ClassMethods

1 Like

Hi Derek, thanks for your reply. Yes some stuff is tucked away in a before block:

background do
  @research_project = Fabricate(:research_project)
  admin = Fabricate(:admin)
  sign_in(admin)
  visit admin_research_projects_path    
end

I agree with Joe Ferris that you shouldn’t tuck away to much so that you’re test aren’t readable anymore, but if it’s the same setup code you repeat in every every test, than having your setup code defined just once in a before block is really handy.

The problem I’m having with this test is not that it passes, but also when I remove the ‘dependent: destroy’ methods from my research_theme model and research_project model, the test passes. So as a mather of fact, I can’t make the test fail.

greetings,

Anthony

Did you look at the inverse_of documentation I linked to? It appears as though your creating related data via one relationship and asserting against that data from what is supposed to be an equivalent relationship. It’s possible Rails hasn’t drawn the connection that one relationship is the inverse of the other.

Hi Derek,

Not sure where to apply ‘inverse of’. It’s a many-to-many association. Research Projects have many Research Themes and Research Themes have many Research Projects

my join model ThemeProject looks like this:

class ThemeProject < ActiveRecord::Base
  belongs_to :research_theme
  belongs_to :research_project
end

So I should apply ‘inverse of’ like so? :

class ThemeProject < ActiveRecord::Base
  belongs_to :research_theme, inverse_of: :research_project
  belongs_to :research_project, inverse_of: :research_theme
end