Isaac
Isaac

Reputation: 13

Where Should I Put Rails Code that is Related to a Model but not Related to Database Operations?

I have a Rails application that is using a document scanner (Epson WorkForce 545). I have two models: Document and Scanner. I am having a hard time determining where I should put the code for the actual scanning operation. I initially thought I should have a scan method in the Scanner model to house the code. However, from what I've read I should keep only database-related operations in the model (see Yehuda's answer here). Having the scanner logic inside the model seems to violate this idea.

I then thought I should create a module called ScannerUtilities and place that in the /lib folder. I suppose that would work, but does it make sense to have code that is so closely involved with a model to be stuck in the /lib folder? Also, since the scanner is used to create a Document object, I'm calling the scan method from the Document controller. So, the code is involved with more than one model and controller.

From my OO thinking, what an object does should be defined as a method of that class. So, if a scanner scans, shouldn't the scan method be in the Scanner model?

Where is the best place to put this code?

Thanks!

Upvotes: 1

Views: 92

Answers (2)

David Aldridge
David Aldridge

Reputation: 52376

I would argue in favour of a "hybrid" method.

Consider creating a class for executing the scan, but access it through the Scanner model:

class Scanner

  def scan
    ScanExecutor.new(scanner: self).call
  end

end

This satisfies both the natural approach of "Scanners are what do scans", and the separation of the utility from the model which will prevent your fat model turning obese.

It also encourages good code in defining the scan operation, in that it does not have to be squeezed into a single method but can instead be a well-structured class of its own.

Upvotes: 0

Dennis Hackethal
Dennis Hackethal

Reputation: 14295

You are right, the scan method should be inside the scanner class, for several reasons:

  • Naturalism: Scanning is what a scanner does; in an object oriented world, you have scanners and one of the things they do is scan stuff
  • Dry code: You will be able to call the scan method from anywhere; in controllers you would need to replicate it in every controller where you need it; not really dry
  • Fat models: It follows the "fat model, skinny controller" paradigm - have a look at this presentation
  • Language: It is idiomatic and intuitive. Some people may disagree with me, but I think Rails encourages you to think in English more than to think in Ruby. Just talking about it makes it clear that a scanner scans things

So yes, I would put the scan method inside the canner model.

Upvotes: 2

Related Questions