Rails MVC - Should database search logic go in the model or the controller
<h2>I would like to make sure my code is properly organized/designed according to the following paradigms/patterns:</h2>

<h3>- Model View Controller</h3>

<h3>- Rails Convention over Configuration</h3>

<h3>- Skinny Controller, Fat Model</h3>

<p>I have listed them here in the order I think is most important.</p>

<hr>

<h3>My issue</h3>

<blockquote>
  <p>After reading several articles, in particular <a href="http://www.sitepoint.com/10-ruby-on-rails-best-practices/" rel="noreferrer">this one</a> and <a href="http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model" rel="noreferrer">this one too</a>, I started to move some of the logic in my controllers, to my models.</p>
  
  <p>However, I can't decide whether or not to move my searching logic (explained in depth, later) from the controller to the model, even after reading more posts/articles like these: <a href="http://zenofcoding.com/2009/01/06/another-way-to-think-about-mvc/" rel="noreferrer">MVC Thinking</a>, and <a href="https://stackoverflow.com/questions/3499336/in-mvc-where-do-you-draw-the-line-between-a-controller-and-model?lq=1">Model vs. Controller</a>, <a href="https://stackoverflow.com/questions/29724991/cleaning-up-view-ruby-logic-and-separating-concerns-into-model-controller">Separating concerns</a> and many more not listed here.</p>
</blockquote>

<hr>

<h3>The scenario</h3>

<p><strong>View</strong></p>

<p>Two pages:  </p>

<ul>
<li><p>1 page contains a text field and submit button which sends the user's input as an argument in params in a POST request to the second page. </p></li>
<li><p>The second page simply renders each <strong>neatObject</strong> in a given array, let's call it <strong>@coolList</strong>.</p></li>
</ul>

<p><strong>Controller</strong></p>

<ul>
<li>A method, let's call it <strong>awesomeSearch</strong>, is invoked when the second page receives a POST request. (Thanks to Rails Routing)</li>
<li><strong>awesomeSearch</strong> should take the user's input, available as <strong>params[:searchString]</strong>, and work with the <strong>NeatObject</strong> model to build the <strong>@coolList</strong> and make that list available for the view to render.  </li>
</ul>

<p><strong>Model</strong>  </p>

<ul>
<li><p>The <strong>NeatObject</strong> model handles requests from controllers and returns <strong>neatObjects</strong> back to those controllers.</p></li>
<li><p>The <strong>NeatObject</strong> model defines the relationship between <strong>neatObjects</strong> and other tables in our database.  </p></li>
</ul>

<p><strong>Database</strong>  </p>

<p>These are the attributes that make up each <strong>neatObject</strong> according to our database:</p>

<ul>
<li>id - <em>int</em></li>
<li>description - <em>string</em></li>
<li>address - <em>string</em></li>
<li>date_created - <em>timestamp</em></li>
</ul>

<hr>

<h2>What's Missing?</h2>

<blockquote>
  <p><strong>How the controller works with the model to get matches for the user's input.</strong></p>
</blockquote>

<p>This is the part I am confused about. The logic itself is very simple, but I am not sure which pieces belong in the model, and which pieces belong in the controller.  </p>

<ul>
<li><p>Should the controller pass the search string to the model, and the model pass back the results? </p></li>
<li><p>Should the controller ask the model for <strong><em>all</em></strong> of the <strong>neatObjects</strong>, then only keep the ones that match?  </p></li>
<li><p>Is the solution a little of both?</p></li>
</ul>

<p>To be able to ask questions about specific bits of the logic, I'll next outline the search process with more detail.</p>

<hr>

<h3>The search logic in depth</h3>

<p>The process involves finding <strong>neatObjects</strong> that <strong><em>match</em></strong> the search string. It would be impossible to move on without defining what we consider <strong><em>matches</em></strong> for <strong>neatObjects</strong>. To keep things very simple, we will say that:  </p>

<blockquote>
  <p><strong>A neatObject <em>matches</em> a search string if the search string is contained within its description or its address, ignoring case and leading/trailing whitespace.</strong></p>
</blockquote>

<p><strong>This definition is not guaranteed to be permanent.</strong> There are several things that may change our definition. We may need to test against more attributes than just address and description, perhaps if the database guys add a new important attribute, or the UI guys decide users should be able to search by ID. And of course, the opposite of these scenarios would mean we need to remove an attribute from the list of attributes we are testing. There are many situations that could change our definition of a <strong><em>match</em></strong>. We could even have to add or remove logic, perhaps if it is decided that we should only test the first word in the description attribute, or perhaps if we should no longer ignore case.   </p>

<p>Now we know what defines a <strong><em>match</em></strong> and we know that our definition may change. Now we can more concretely define the search process.</p>

<p>Here is an outline of the steps:</p>

<ol>
<li>Get a reference to <strong><em>all</em></strong> <strong>neatObjects</strong></li>
<li>Loop through each <strong>neatObject</strong>, putting each individual one through the <strong><em>match</em></strong> test

<ol>
<li>Test passes - add/keep <strong>neatObject</strong> in results list</li>
<li>Test fails - do not keep <strong>neatObject</strong> for results</li>
</ol></li>
<li>Make results available to the view</li>
</ol>

<p>I will reference these steps as I show possible implementations.  </p>

<hr>

<h2>Implementation</h2>

<p>The search functionality can easily be implemented in either the <strong>NeatObject</strong> model, or the controller serving the view.  </p>

<p>Normally, I would just write all of the logic in the controller, but after I learned about the "Skinny controller, Fat model" design, I thought it definitely applied in this situation. <a href="http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model" rel="noreferrer">This article</a> in particular made me think to reorganize my code, after I saw the author had implemented a "search-like" function in the model. The author's function did not handle user input though, so I was wondering how it should be handled.  </p>

<p>This is how I would have written the code before learning about "SCFM":</p>

<h3>Search logic in controller:</h3>

<pre><code>#searches_controller.rb  

#This is the method invoked when second page receives POST request
def search
    @neatObjects = NeatObjects.all.to_a  

    @neatObjects.delete_if { 
        |neatObject| !matches?(neatObject, params[:searchString])
    }
end

def matches?(neatObject, searchString)
    if((neatObject.description.downcase.include? searchString.downcase) ||
       (neatObject.address.downcase.include? searchString.downcase))
        return true
    end
    return false
end
</code></pre>

<p>This method gets its reference to all of the <strong>neatObjects</strong> (Step 1) by calling <strong>.all()</strong> on the <strong>NeatObject</strong> model. It uses the array function <strong>delete_if</strong> to perform the <strong><em>match</em></strong> test on each <strong>neatObject</strong>, and only keeps those that pass (Step 2). Step 3 is accomplished automatically automatically since we store our results in an instance variable in the controller which serves the view.  </p>

<p>Placing the logic in the controller is very straight-forward, but when considering the "SCFM" design pattern, it seems very illogical.  </p>

<p>I've written another option, in which the controller sends the user's input to a function in the model, which will return the the <strong>neatObjects</strong> which <strong><em>match</em></strong> the input.</p>

<h3>Search logic in Model</h3>

<pre><code>#NeatObject.rb  

def self.get_matches_for(searchString)
    all.to_a.delete_if { |neighborhood| !matches?(searchString, neighborhood) }
end

def self.matches?(phrase, neighborhood)
    fields = [neighborhood.name, neighborhood.address]

    fields.map!(&amp;:downcase)
    phrase.downcase!

    fields.each do |field|
        if (
            (phrase.include? field) ||
            (field.include? phrase)
           )
            return true
        end
    end

    return false
end  
</code></pre>

<p>This method gets the complete list of <strong>neatObjects</strong> with <strong>all()</strong> (Step 1). Just like the first method, the model method uses delete_if to remove array elements (<strong>neatObjects</strong>) that don't meet a certain criteria (passing the <strong><em>match</em></strong> test) (Step 2). In this method, the controller serving the view would call get_matches_for on the <strong>NeatObject</strong> model, and store the results in an instance variable (Step 3), like this: <code>@neatObjects = NeatObject.get_matches_for( params[:searchString] )</code></p>

<p>I do think that the model option is cleaner, and slightly more maintanable, but I'll go more in depth in the following section.</p>

<hr>

<blockquote>
  <h2>Concerns</h2>
  
  <p>I can see pros and cons to both the model method and the controller method, but there are things that I'm still unsure about.</p>
</blockquote>

<p>When I read over that article I've referenced several times (just like I did <a href="http://weblog.jamisbuck.org/2006/10/18/skinny-controller-fat-model" rel="noreferrer">here</a>), it was very logical that the model defined a function to return the recently added people.  </p>

<p>The controller didn't have to implement the logic to determine if a <strong>person</strong> had been recently added. It makes sense that the controller shouldn't, because that is dependent on the data itself. There might be a completely different implementation of the "recency" test for <strong>messages</strong>. The recent people might include people added this week, while recent messages are only those messages sent today.  </p>

<p>A controller should just be able to say <code>People.find_recent</code> or <code>Message.find_recent</code> and know it got the correct results.  </p>

<ul>
<li><p>Is it correct to say the <code>find_recent</code> method could also be modified to take in a time symbol, and return objects for different time periods? Ex - <code>People.find_in_time( :before_this_month )</code> or <code>Messages.find_in_time( :last_year )</code>. Does that still follow the MVC pattern and Rails convention?</p></li>
<li><p>Should a controller be able to find <strong><em>matches</em></strong> for user input with <code>NeatObject.get_matches_for( searchString )</code>?'</p></li>
</ul>

<p>I think the matching logic belongs in the model, because there are certain/specific attributes that are used in testing, and those attributes are different depending on the data. We might have different attributes for different tables, and those attributes <strong><em>definitely</em></strong> shouldn't be defined by the controller. I know the controller depends on the model, not the other way around, so the model <strong><em>must</em></strong> define those attributes, even if the rest of the logic is in the controller.  </p>

<ul>
<li>And if the model defines the attributes that are used when searching, why shouldn't it define the entire search function?</li>
</ul>

<p>The above text explains why I think the model should handle the searching logic and expresses the majority of my questions/concerns, however I do have some opinions favoring the other option.  </p>

<ul>
<li>If the model is concerned only with the data, how can one justify passing user input to it?</li>
</ul>

<p>If the controller doesn't handle the search logic, it still needs to send the user's input to the model. Does it clean it up before it sends it? (Removing leading/trailing whitespace and downcasing the string.) Does it just send the exact input it got from the user?  </p>

<ul>
<li>Where is the testing done to make sure the input is not malicious? </li>
</ul>

<blockquote>
  <h3>Some of my biggest questions:</h3>
</blockquote>

<ul>
<li>Does the answer for where the logic goes change for each case?</li>
</ul>

<p>If the search/matching process was simpler, would the code's place change? For example, if the searching was simpler:  </p>

<ul>
<li><p>If the only attribute being tested was the address and that was unlikely to change, would we just handle the search with the controller? </p></li>
<li><p>If we were making an advanced search feature, where the user decided which attributes to include in the search and also controlled some other factors, there would be a lot of user input just to define the arguments to the search function. Would that be too much logic or user input to place in the model?  </p></li>
</ul>

<hr>

<blockquote>
  <h1>In conclusion</h1>
</blockquote>

<ul>
<li>How can I always be sure that I am putting logic in the right place (MVC)?  </li>
<li>For my specific case, with this data and this search/match process, how should I organize the code?</li>
<li>What guidelines can be followed when you find a gray area, or are unsure about where logic belongs?</li>
</ul>