Search code examples
ruby-on-railsoopmodel-view-controllersearchrails-cells

Is handling requests/accessing database in cells a good practice? and more about MVC with cells and OOP


I am just wondering whether this is a good approach to make a model request inside a cell definition....?

I am also need to define in general what is more convenient way to implement different representations for search results in different context from OOP point of view.

What do I need this for?

I have categories with items. I want to implement search results as a cell. Search results should be represented in a bit different way according to three cases:

  • search for all items in specified category

E.g. let category be "animals" (this category contains: dog, cat, and bird items in the database) then I should see in browser:

 Category Items
    dog
    cat
    bird
  • search for items similar to specified "pattern" in all categories

E.g let pattern be "do":

Similar Items
   Animals
      dog
   Cars
      dodge
  • search for items similar to specified "pattern" inside specified "category"

E.g. let pattern be "do" and category be "animals":

Category Items
    dog
Similar Items
    Cars
       dodge

I decided to experiment with cells gem to implement this stuff...

This is what i want to display via cell: (app/cells/search_result/display.html.haml)

%h1
  = @category_items[:title]
%ul
  - for i in @category_items[:items]
    %li
      = link_to "#{i.code} #{i.summary}", category_item_path(i.category.name, i.code)

%h1
  = @similar_items_by_category[:title]
%ul
  - for cat in @similar_items_by_category[:items_by_category].keys
    %li
      = "#{cat.name}"
      %ul
        - for i in @similar_items_by_category[:items_by_category][cat]
          %li
            = link_to "#{i.code} #{i.summary}", category_item_path(i.category.name, i.code)

This is my cell: (app/cells/search_result_cell.rb)

class SearchResultCell < Cell::Rails

  def display options
    setup! options

    render
  end

  def setup! options

    #some code here that defines
    # category_items_title, like "Category Items"
    # array_of_found_items
    # similar_item_title, like "Similar Items"
    # hash_of_found_items_by_category
    #this code will be different for each search case in correspondent overridden function

    @category_items = { title: category_items_title, items: array_of_found_items }
    @similar_items_by_category = { title: similar_item_title, items_by_category: hash_of_found_items_by_category }
  end

end

I am going to have separate cell class for each "search" case, derive it from the SearchResultCell (maybe I'll rename it to something like GenericSearchResultCell), and override setup! function for each case... And then will use builder to define wich class to build...

This is my view: (app/views/items/index.html.haml)

= render_cell :search_result, :display #, ... - and here some options...

Now QUESTIONS:

  1. Should I make real search requests inside "setup!" function in a cell? And then make my controller ItemsController just "parse" route, and provide that options to be passed to my SearchCell...

  2. Or should I make my ItemsController be responsible for both "parsing" route and making search requests (defining array_of_found_items, and hash_of_found_items_by_category by itself)? And then just pass all this stuff to the SearchCell as options...

  3. Is all this "cells experiments" worthy? Is there any more convenient way to implement my "search" views and controllers?


Solution

  • You should decouple your querying logic completely from the controller and the rendering. Introduce a class ItemsFinder that does all the search stuff and that returns a result set.

    Now that you have proper model sets to talk about you can move on to the rendering. Usually, when the view is not too complex (no if-else, not too many nested partials) the "old" Rails partials way is just fine.

    However, often you want to override just a small piece of a sub-sub-subpartial and that is where cells' view inheritance kicks in. It also encourages you to define interfaces for your "partials", so keep that in mind.

    I agree with Max that cells usually helps keeping your controllers clean when you have reusable "widgets" in your view. Do not overuse it, thou ;-)