rails show each category content - ruby-on-rails

This is how my CategoriesController looks like:
class CategoriesController < ApplicationController
def index
#categories = Category.all
end
def show
#category = Category.find(params[:id])
end
end
inside my show.html.erb I wrote this to display the category name:
<h2><%= #category.name %></h2>
I also have a PagesController which I made relations with the Category
I have few Pages assigned to Category (for example category_id: 1)
When I click on the category link from my homepage:
<%= link_to "category", category_path(cat) %>
It goes to the show page which is great
How can I display on the show.html.erb all the Pages that belongs to this category that I've clicked on?

You should call the pages assosication with the category model as,
<%= #category.name %>
<h1> PAGES </h1>
<table>
<tr>
<% #category.pages.each do |page| %>
<td> <%= page.title %> </td>
<td> <%= page.content %> </td>
<% end %>
</tr>
</table>
This will do for you.

You should use includes for enhanced performance of your application. It will return all expected records from pages also and that's without firing database query again. #category.pages in ERB will not make database query. Hence, you will have efficient code.
In your show action:
def show
#category = Category.find(params[:id]).includes(:pages)
end
In show.html.erb:
<%= "Category: #{#category.name}" %>
<h1> POSTS </h1>
<table>
<tr>
<% #category.pages.each do |page| %>
<td> <%= page.field1 %> </td>
<td> <%= page.field2 %> </td>
<% end %>
</tr>
</table>
Rich Peck edit
Normally, ActiveRecord does something called lazy loading, which means that it will only execute a DB query when it needs to. This is normally highly efficient; unfortunately causes a problem when you call associative data.
When calling #category.pages, you get the n+1 issue, which means that each time you call the Category.find query, an extra query will be used to load the pages:
The above code will execute just 2 queries, as opposed to 11 queries in the previous case:
SELECT * FROM clients LIMIT 10
SELECT addresses.* FROM addresses
WHERE (addresses.client_id IN (1,2,3,4,5,6,7,8,9,10))
So using .includes essentially appends all the pages to your #category, making it much more efficient than letting it load lazily.

Well mostly it depends on how you made your relationships between category and page. With what i can see from your code, you can do something like this.
#pages = Page.where(:category_id => 1)
Update
As per to your relationships
#pages = #category.pages

Related

Paginating Multiple Objects of the Same Model on the Same Page with Kaminari

Background
In my website, I'm trying to display 2 tables with data that I have scraped from another website and have place into an object called Product. The Product object has 2 categories which are stored as enums, registered and unregistered.
Problem
The problem comes when I apply pagination with Kaminari. Below are some images to demonstrate the problem.
Before the problem:
When I click '2' on the Registered Products table, the Unregistered Products table also goes to '2'
Problem:
I'm guessing it's because the data from both tables come from the same object? Anyway below are the relevant files.
My Model
class Product < ApplicationRecord
enum product_type: [:registered, :unregistered, :cosmetic]
paginates_per 8
end
My Controller
class HomeController < ApplicationController
def index
#registered_products = Product.where(product_type: 0).page params[:page]
#unregistered_products = Product.where(product_type: 1).page params[:page]
end
end
My partial for registered products
<table>
<thead>
<tr>
<th scope='col'>Name</th>
<th scope='col'>Chemical</th>
</tr>
</thead>
<tbody>
<% #registered_products.each do |product| %>
<tr>
<td><%= product.product_name %></td>
<td><%= product.chemical %></td>
</tr>
<% end %>
</tbody>
</table>
<%= paginate #registered_products %>
My partial for unregistered products is the same, replace #registered_products with #unregistered products.
index.html.erb
<h2>Registered Products</h2>
<%= render partial: "registered" %>
<h2>Unregistered Products</h2>
<%= render partial: "unregistered" %>
What I tried
I was looking through the Kaminari documentation and noticed that arrays can be paginated. So I tried that. Below are the modified files.
Controller
class HomeController < ApplicationController
def index
registered_products = Product.where(product_type: 0).to_a
unregistered_products = Product.where(product_type: 1).to_a
#registered_products_array = Kaminari.paginate_array(registered_products).page(params[:page]).per(10)
#unregistered_products_array = Kaminari.paginate_array(unregistered_products).page(params[:page]).per(10)
end
end
Every other relevant file is the same just substitute with the new global variables created. The problem still persists.
So my questions is how do I fix this problem and is it the problem occurring because I'm paginating the same object multiple times in the same page?
The reason why this problem is happening is because you are using the same params[:page] attribute to navigate through the pages. This results in the same number being passed to both the queries for your Product model. You will need to do this instead to get it working.
Partial for registered page:
...
<%= paginate #registered_products, param_name: :registered_page_no %>
And in the unregistered page partial, you will have to do the same, but with a unique name like unregistered_page_no
In your controller, all you need to do is this:
class HomeController < ApplicationController
def index
#registered_products = Product.where(product_type: 0).page params[:registered_page_no]
#unregistered_products = Product.where(product_type: 1).page params[:unregistered_page_no]
end
end
To know more about param_name, read the docs: https://github.com/kaminari/kaminari#changing-the-parameter-name-param_name-for-the-links

Display last two(few) values without replicating in rails

Hi I am trying to display last two(few) values in my index page How to do that in rails?
Here is my _index.html.erb file (rendering in new)
<table class="table table-hover">
<% PriceLog.order(price_date: :desc).each_with_index do |price_dated,index| %> // problem is here in looping
<tr>
<% #products.each do |product| %>
<td>
<%= PriceLog.where({product_id: product.id, price_date: price_dated.price_date}).last.price_date.strftime('%d-%B-%Y') %>
</td>
<td>
<%= PriceLog.where({product_id: product.id, price_date: price_dated.price_date}).last.price %>
</td>
<% end %>
</tr>
<% end %>
</table>
and in my controller
def new
#pricelog = PriceLog.new
#products = Product.all
#price = PriceLog.all
end
Updated
Here is the output I am getting like this I have three different products like Product1,Product2,Product3 and respected date and price for that
Here my values are duplicating 3 times(every time i hit submitting in form values it showing 3 times but storing once ) How should i stop duplicating and display only last few values
Any help must appreciated
Thanks
Have you tried something along the lines Model.last(2)?
You're running a loop within a loop. Your PriceLog.each_with_index loops over all your PriceLogs, and then within it your #products.each (which you have defined in the controller) loops over all your products. So each Product gets repeated once for every PriceLog.
Outside of that, you have a lot of logic in your view. It's generally frowned upon to call the model from there; that should happen either in the controller, a helper, or some custom presenter object.
In your controller instead of
#products = Product.all
change it to
#products = Product.all.order("id DESC").limit(2)

Eager Loading from nested partial

The gem bullet is saying that I have an N + 1 error when loading meal_foods for each meal food that's loaded to the page. Let me explain...
In my rails app I have some nested partials being rendered like so:
Meals > Meal Foods..
So multiple meals are rendered, and then for each meal that is rendered, it's corresponding meal food(s) are rendered within it as well, if any.
Here's the code for that.
Within meal/show:
<% if #meals != nil %>
<%= render(partial: "meal", collection: #meals) %>
<% else %>
<p style="text-align:center">No meals created yet.</p>
<% end %>
Here is within the _meals.html.erb
<tbody>
<%= render(partial: "meal_foods/meal_food", collection: meal.meal_foods) %>
</tbody>
Finally this is part of the _meal_foods.html.erb
<td class="left"><%= meal_food.name %></td>
<td class="left">
<%= form_for meal_food, action: :update do |f| %>
<%= f.text_field :servings %>
<% end %>
</td>
Meals Controller:
def show
#meals = current_client.meals
#new_meal = current_client.meals.build
end
The specific error:
N+1 Query detected
Meal => [:meal_foods]
Add to your finder: :include => [:meal_foods]
N+1 Query method call stack
/app/views/meals/_meal.html.erb:23:in
The line this error is pointing to is the render line for the _meal.html.erb partial..
The funny thing is that if I include earger loading in that partial bullet gives me the error "Unused eager loading!" and also the meal foods in the first food are carried over to the rest of the meals incorrectly.
This method looks like this:
Within the _meal.html.erb...
<tbody>
<% mf = MealFood.includes(:meal) %>
<%= render(partial: "meal_foods/meal_food", collection: mf) %>
</tbody>
Change your #meals variable to be current_client.meals.includes(:meal_food). As #artimees said this eager loads the data and prevents an n+1 query. It worked because the #meals without .includes(:meal_food) run 1 query to get the meals... and in every partial (this line specifically meal.meal_foods) it run 1 query for every meal you have... so if you have n meals you run 1 query to get all the meals and n queries to get each meal.meal_food (n+1)... if you use the includes(:meal_food) it runs only one optimized query to get the meals with their meal food relation loaded...

Rails filtering row by column using select dropdown

I was making a travel vacation application. Searching of places is based on categories from select dropdown.
But I am not able to understand the program logic. I am able to load the content in the database. but can't filter based on certain categories.
I made a scaffold called listing and included certain parameters.
In the database it has a row of 5 columns, namely, place, description, image_url, price, category.
Now, if I create another controller, search, I am not able to load a row based on a category from the select dropdown.
Search_controller.rb
def index
#categories = Listing.find_by_sql("SELECT category FROM listings GROUP BY category").map &:category
#list = params[:category].blank? ? Listing.all : Listing.find_all_by_category(params[:category])
end
index.html.erb
<% form_tag(:action => :index) do %>
<%= select_tag "category", options_for_select(#categories) %>
<%= submit_tag "Filter" %>
<% end %>
<table>
<% #list.each do |list| %>
<tr>
<td><%= list.place %></td>
</tr>
<% end %>
</table>
It does not show the select option.
Also, I tried to do this without select form
Search_controller.rb
def index
#list = Listing.select(:category).map(&:category).uniq
end
Index.html.erb
<% #list.each do |r| %>
<%= r.place %>
<% end %>
It says: undefined method `place' for "sunny":String (where "sunny" is a category)
Basically, how do you get the row based on a certain column value. And, will the logic also apply to two select dropdowns?
I know I am close, but somethings not right. Please assist me.
Thanks a lot.
You are missing = before form_tag. Should be:
<%= form_tag(:action => :index) do %>
<%= select_tag "category", options_for_select(#categories) %>
<%= submit_tag "Filter" %>
<% end %>

rails where condition works in console, but not in web server

I am new in RoR.
The problem is, I created fully functional product categorization with Ancesrty. But now I want to be able to retrieve products that is under these subcategories.
This is my categories show controller
#category = Category.find(params[:id])
Here is categories#show view.
<b>Name of the category:</b>
<%= #category.name %>
<div class="product"
</div>
</p>
<% unless #category.children.empty? %>
<ul id="sub-menu">
<% #category.children.each do |sub1| %>
<%= link_to (sub1.name), sub1 %>
<%end%>
<%end%>
It all works fine. but now I want to add in view categories/show function that shows all products that is under that category.
I added such code.
In category/show controller
#cat_id = #category.id
#product = Product.where("category_id = ?",#cat_id)
In the categories show view I added
<td><%= #product.name %></td>
Then clicking on some subcategory where should appear few products, there just shows up Product
To check if the code is right I put in the console. There it works fine and retrieve products related to this category.
I dont understand why then code not working in webserver when I launch application ?
Could it be because of some erorr in Associations ?
Thanks !
in your controller, a more readable way is to use the plural form to indicate that you are expecting more than 1 object
#products = Product.where("category_id = ?", #cat_id)
Then in the view, just loop through these products
<% #products.each do |product| %>
<%= product.name %>
<% end %>
#product = Product.where("category_id = ?",#cat_id)
will return an array if there are any products. So you will need to loop through the array.
<% #product.each do |product| %>
<%= product.name %>
<% end %>
I accept both of the answers, But I want to suggest to use Active Record Association for this type of problems. This makes your solution easier.
If you want to fetch only one product, you can use the find_by_ helper method of the model:
#product = Product.find_by_category_id(#cat_id)
With this it will fetch the first matching product which has category_id equal to #cat_id.
If you want to fetch all the products which belong to a category, you need to fetch all the products as others suggested:
#products = Product.where(:category_id => #cat_id)
And then in the view:
<% #products.each do |product| %>
<%= product.name %>
<% end -%>

Resources