Search code examples
ruby-on-railsrubyconflictclassnameruport

Resolving a class name conflict in a Rails application


I have been building a Rails application that performs accounting functionality. As part of this, I have a model with the class name Transaction. So far so good, I have been building this functionality for a month or so, and everything is working as expected.

Until now...

I have just discovered some older reporting functionality that was developed months ago using the Ruport library has stopped working. It appears that Ruport, when generating PDFs, requires a library that also has a class/module named Transaction.

TypeError in Admin/team reportsController#generate
Transaction is not a module

...

This error occurred while loading the following files:
  pdf/writer
  transaction/simple

So, I'm looking for a quick fix here. One that hopefully doesn't involve renaming my Transaction model and refactoring the last few weeks worth of code.

Looking forward to some clever suggestions :)


Solution

  • I believe the issue is down to Ruport requiring the PDF::Writer gem, which in turn requires the Transaction::Simple gem which defines the module Transaction.

    There is certainly a #transaction method in ActiveRecord, but I do not think there is a Transaction module or class within Rails. I'll be happy to be corrected on that one.

    Namespacing is usually the best practice for avoiding naming conflicts like this. E.g.

    module Account
      class Transaction < ActiveRecord::Base
        ....
      end
    end 
    

    However, namespacing ActiveRecord models may throw up other issues.

    As time consuming as it may be, renaming your Transaction model may be the best bet.

    You can still keep your existing transactions database table if you wanted, so your migrations don't need to change, by putting self.table_name = "transactions" inside your model.

    Your associations with other models can also still be named "transaction(s)" by specifying the class_name in your association call. E.g.

    class User < ActiveRecord::Base
    
      has_many :transactions, :class_name => "AccountTransaction"
    
    end
    

    Those two suggestions may or may not save you some time.