Rails 4 Action Mailer Previews and Factory Girl issues
Asked Answered
W

2

9

I've been running into quite an annoying issue when dealing with Rails 4 action mailer previews and factory girl. Here's an example of some of my code:

class TransactionMailerPreview < ActionMailer::Preview
  def purchase_receipt
    account = FactoryGirl.build_stubbed(:account)
    user = account.owner
    transaction = FactoryGirl.build_stubbed(:transaction, account: account, user: user)
    TransactionMailer.purchase_receipt(transaction)
  end
end

This could really be any action mailer preview. Lets say I get something wrong (happens every time), and there's an error. I fix the error and refresh the page. Every time this happens I get a:

"ArgumentError in Rails::MailersController#preview A copy of User has been removed from the module tree but is still active!"

Then my only way out is to restart my server.

Am I missing something here? Any clue as to what is causing this and how it could be avoided? I've restarted my server 100 times over the past week because of this.

EDIT: It may actually be happening any time I edit my code and refresh the preview?

Whiff answered 20/8, 2015 at 12:45 Comment(0)
W
1

This answers my question:

https://mcmap.net/q/1021210/-a-copy-of-xxx-has-been-removed-from-the-module-tree-but-is-still-active

I used approach #3: Just put a :: in front of the offending module.

Whiff answered 26/12, 2018 at 19:5 Comment(1)
To clarify, in your FactoryBot factory definition, change factory :account do ... to factory :account, class: '::Account' do ....Reborn
H
0

Though this is not exactly an answer (but perhaps a clue), I've had this problem too.

Do your factories cause any records to actually be persisted?

I ended up using Factory.build where I could, and stubbing out everything else with private methods and OpenStructs to be sure all objects were being created fresh on every reload, and nothing was persisting to be reloaded.

I'm wondering if what FactoryGirl.build_stubbed uses to trick the system into thinking the objects are persisted are causing the system to try and reload them (after they are gone).

Here's a snippet of what is working for me:

class SiteMailerPreview < ActionMailer::Preview

  def add_comment_to_page
    page = FactoryGirl.build :page, id: 30, site: cool_site
    user = FactoryGirl.build :user
    comment = FactoryGirl.build :comment, commentable: page, user: user
    SiteMailer.comment_added(comment)
  end

  private

  # this works across reloads where `Factory.build :site` would throw the error: 
  # A copy of Site has been removed from the module tree but is still active!
  def cool_site
    site = FactoryGirl.build :site, name: 'Super cool site'
    def site.users
      user = OpenStruct.new(email: '[email protected]')
      def user.settings(sym)
        OpenStruct.new(comments: true)
      end
      [user]
    end
    site
  end

end

Though I am not totally satisfied with this approach, I don't get those errors anymore.

I would be interested to hear if anyone else has a better solution.

Hancock answered 21/8, 2015 at 13:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.