As shown in the image below, it is a function to display a list of products belonging to the selected category. The categories are multi-level, and the lower the level, the more narrowed the search becomes. Categories are created using gem's ancestry.
-A category table is created using ancestry. ・ Category: Product = 1: There are many relationships. -The category id of the lowest layer is registered in the category_id of the product model.
The app in this article uses three levels of categories. Also, in this article, the top category is the "parent category" and the hierarchy below it is the "child category". Below that is expressed as the "grandchild category".
The following articles will be helpful for how to install ancestry. https://qiita.com/Sotq_17/items/120256209993fb05ebac https://qiita.com/pdm21/items/fe0055b3190af790f1c0
First, we will create a list page that displays all categories. Use the index action of the categories controller.
app/controllers/categories_controller.rb
def index
@parents = Category.where(ancestry: nil)
end
Since the ancestry column of the parent category is nil, you can get the parent category with the above description.
app/views/categories/index.html.haml
%h1 category list
%ul.categories
- @parents.each do |parent|
%li.parents= link_to "#{parent.name}", category_path(parent)
%ul.categories__children
- parent.children.each do |child|
%li.childern= link_to "#{child.name}", category_path(child)
%ul.categories__grandchildren
- child.children.each do |grandchild|
%li= link_to "#{grandchild.name}", category_path(grandchild)
Now you can list all the categories. Each category name is linked to the product list page by category described later.
Next, we will create a page that lists the products that belong to the selected category. Use the show action of the categories controller.
app/controllers/categories_controller.rb
before_action :set_category, only: :show
def show
@items = @category.set_items
@items = @items.where(buyer_id: nil).order("created_at DESC").page(params[:page]).per(9)
end
private
def set_category
@category = Category.find(params[:id])
end
Use the model method set_items described later to get the products in the category.
app/models/category.rb
has_many :items
has_ancestry
def set_items
#For parent category
if self.root?
start_id = self.indirects.first.id
end_id = self.indirects.last.id
items = Item.where(category_id: start_id..end_id)
return items
#For child categories
elsif self.has_children?
start_id = self.children.first.id
end_id = self.children.last.id
items = Item.where(category_id: start_id..end_id)
return items
#For grandchild categories
else
return self.items
end
end
The id of the grandchild category is registered in the category_id of the product. Therefore, if you simply write @items = @ category.items, you can get the product information only when @category is a grandchild. Therefore, as described above, conditional branching is performed depending on which of the parent, child, or grandchild the category corresponds to. If the category is parent or child, the product is acquired by specifying the id range of the grandchild category that it owns.
The following articles will be helpful when using ancestry's own methods such as root? And indirects. https://qiita.com/Rubyist_SOTA/items/49383aa7f60c42141871
app/views/categories/show.html.haml
.products-container
.products-index
.title
= "#{@category.name}Product list"
.title__border
- if @items
%ul.lists
= render "items/item", items: @items
= paginate @items
The partial template used on all product list pages is shared. The displayed contents are changed according to the value of @items.
Finally, add links to other categories as shown below to make it easier to find products. If the display category is parent or child, link to the category one level below, For grandchildren, display links to grandchildren categories that belong to the same child category.
app/controllers/categories_controller.rb
def set_category
@category = Category.find(params[:id])
#Postscript---------------------------------
if @category.has_children?
@category_links = @category.children
else
@category_links = @category.siblings
end
# -------------------------------------
end
app/views/categories/show.html.haml
//Postscript--------------------------------------------------
.category_wrapper
.category_links
- @category_links.each do |category|
= link_to category.name, category_path(category)
// -----------------------------------------------------
.products-container
.products-index
.title
= "#{@category.name}Product list"
.title__border
- if @items
%ul.lists
= render "items/item", items: @items
= paginate @items
After that, if you arrange the CSS appropriately, it will be completed.
This completes the function to search for products from multi-level categories. Thank you for reading this far.
Recommended Posts