Rails include with multiple tables - ruby-on-rails-3.1

Please anyone help me:
Using Rails I developed an application.
My models look like this:
class Score < ActiveRecord::Base
belongs_to :song
belongs_to :user
end
class Song < ActiveRecord::Base
has_one :gsong
has_many :scores
end
class Gsong < ActiveRecord::Base
belongs_to :song
end
class user < ActiveRecord::Base
has_many :scores
end
And my ScoresController:
class scoresController < ApplicationController
def index
id = current_user.id
#scores = score.where(:user_id => id)
render :json => {
:scores => #scores.as_json(:include => {:gsong => { :include => { :song => { :only => [:title, :album]}}, :only => [:artwork]}}, :only => [:song_id, :score]),
}
end
It's working fine functionally, But it's making too many queries in the database like below:
score Load (0.1ms) SELECT `scores`.* FROM `scores` WHERE `scores`.`user_id` = 3
Gsong Load (0.1ms) SELECT `gsongs`.* FROM `gsongs` WHERE `gsongs`.`id` = 8 LIMIT 1
Song Load (0.1ms) SELECT `songs`.* FROM `songs` WHERE `songs`.`id` = 8 LIMIT 1
Gsong Load (0.1ms) SELECT `gsongs`.* FROM `gsongs` WHERE `gsongs`.`id` = 2 LIMIT 1
Song Load (0.1ms) SELECT `songs`.* FROM `songs` WHERE `songs`.`id` = 2 LIMIT 1
Gsong Load (0.1ms) SELECT `gsongs`.* FROM `gsongs` WHERE `gsongs`.`id` = 1 LIMIT 1
Song Load (0.1ms) SELECT `songs`.* FROM `songs` WHERE `songs`.`id` = 1 LIMIT 1
Gsong Load (0.1ms) SELECT `gsongs`.* FROM `gsongs` WHERE `gsongs`.`id` = 11 LIMIT 1
Song Load (0.1ms) SELECT `songs`.* FROM `songs` WHERE `songs`.`id` = 11 LIMIT 1
Gsong Load (0.1ms) SELECT `gsongs`.* FROM `gsongs` WHERE `gsongs`.`id` = 12 LIMIT 1
Song Load (0.1ms) SELECT `songs`.* FROM `songs` WHERE `songs`.`id` = 12 LIMIT 1
Gsong Load (0.1ms) SELECT `gsongs`.* FROM `gsongs` WHERE `gsongs`.`id` = 23 LIMIT 1
Song Load (0.1ms) SELECT `songs`.* FROM `songs` WHERE `songs`.`id` = 23 LIMIT 1
How can I fetch all this data with single or two queries like:
Gsong Load (0.1ms) SELECT `gsongs`.* FROM `gsongs`
Song Load (0.3ms) SELECT `songs`.* FROM `songs` WHERE `songs`.`id` IN (8,2,1,11,12,23)

I would look into using ActiveModel serializers. I think you'll find it will make complex JSON like this a breeze
There's a great Screencast on it at
http://railscasts.com/episodes/409-active-model-serializers

Related

How to get table structure in oracle with constraints?

using
DBMS_METADATA.GET_DDL('TABLE','PERSON') from DUAL
is not working. how to get the meta details of whole schema?
In SQL Developer, simply run
ddl person
We'll run the DBMS_METADATA pl/sql block for you.
You can shape the DDL being generated by using the SET DDL command.
Then you can see what we're doing down here in the Log panel.
select DBMS_METADATA.GET_DDL('TABLE', OBJECT_NAME, OWNER)
from all_objects
where owner = :OWNER
and object_name = :NAME
and object_type = 'TABLE'
union all
select dbms_metadata.GET_DEPENDENT_DDL('COMMENT', TABLE_NAME, OWNER)
from (
select table_name, owner
from all_col_comments
where owner = :OWNER
and table_name = :NAME
and comments is not null
union
select table_name, owner
from sys.all_TAB_comments
where owner = :OWNER
and table_name = :NAME
and comments is not null
)
union all
select DBMS_METADATA.GET_DDL('INDEX', INDEX_NAME, OWNER)
from (
select index_name, owner
from sys.all_indexes
where table_owner = :OWNER
and table_name = :NAME
and generated = 'N'
minus select index_name, owner
from sys.all_constraints
where owner = :OWNER
and table_name = :NAME
)
union all
select dbms_metadata.GET_DDL('TRIGGER', trigger_name, owner)
from all_triggers
where table_owner = :OWNER
and table_name = :NAME
Disclaimer: I'm a product manager at Oracle, SQL Developer is one of those products I am responsible for.

Oracle script for getting results and update a table column in the same time

I would like your help for creating a script for getting results and in the same time updating a field in my table if necessary.
In my application, I have persons (table PERSON) who create REQUESTS (table REQUEST). A person is active when she has created a request during the last 3 years. I have created a field (ACTIVE - default value: 1) in the table PERSON in order to know if the person is still active.
I create a query for retrieving the number of requests for each person (Total request number, active request, inactive request):
-- PERSONS List with number of request for each person and RE_ACTIVE field
SELECT p.id,
p.lastname || ' ' || p.firstname personname,
p.company,
p.active,
(SELECT count(*)
FROM request req
WHERE req.personid = p.id) total_request_nb,
(SELECT count(*)
FROM request reqact
WHERE reqact.personid = p.id
AND reqact.requestdate > add_months(trunc(sysdate, 'YYYY'), -36)) nb_active_requests,
(SELECT count(*)
FROM request reqinact
WHERE reqinact.personid = p.id
AND reqinact.requestdate < add_months(trunc(sysdate, 'YYYY'), -36)) nb_inactive_requests,
CASE
WHEN EXISTS (SELECT *
FROM request reqreact
WHERE reqreact.personid = p.id
AND reqreact.requestdate > add_months(trunc(sysdate, 'YYYY'), -36))
THEN 1
ELSE 0
END re_active
FROM person p;
This script is working. I would like to update the field ACTIVE when the person is active (with the previous result). For instance:
UPDATE PERSON p SET ACTIVE =
CASE WHEN (
(SELECT count(*)
FROM request reqreact
WHERE reqreact.personid = p.id
AND reqreact.requestdate > add_months(trunc(sysdate, 'YYYY'), -36)) > 0
)
THEN 1
ELSE 0
END
I would like to know if it's possible to do that in the same script? Hence I could know how many updates have been done, failed, ... in once query.
Thanks you in advance for your help
You want a WHERE EXISTS condition with a correlated subquery :
UPDATE PERSON p
SET p.ACTIVE = 1
WHERE EXISTS (
SELECT 1
FROM request reqreact
WHERE reqreact.personid = p.id
AND reqreact.requestdate > add_months(trunc(sysdate, 'YYYY'), -36)
)
If there is no match in the subquery, the UPDATE in the outer query will not happen.
If you want to set to 1 or 0 depending on the result of the subquery :
UPDATE PERSON p
SET p.ACTIVE = CASE
CASE
WHEN EXISTS (
SELECT 1
FROM request reqreact
WHERE reqreact.personid = p.id
AND reqreact.requestdate > add_months(trunc(sysdate, 'YYYY'), -36)
)
THEN 1
ELSE 0
END

What is the conceptual difference between User.first.followers.count and User.first.followers.to_a.count?

The two Active Record queries: User.first.followers.count and User.first.followers.to_a.count evaluate to the following SQL queries respectively:
[4] pry(main)> User.first.followers.count
User Load (0.2ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]]
(0.3ms) SELECT COUNT(*) FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."follower_id" WHERE "relationships"."followed_id" = ? [["followed_id", 1]]
=> 4
[5] pry(main)> User.first.followers.to_a.count
User Load (0.1ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]]
User Load (0.1ms) SELECT "users".* FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."follower_id" WHERE "relationships"."followed_id" = ? [["followed_id", 1]]
=> 4
How are they conceptually different?
This question came up in an exercise question at the end of section 14.1 in The Rails Tutorial
He gives the following hint:
Hint: Suppose that the user had a million followers.

Why does my JOIN still trigger n+1 selects in active record?

PortfolioEngine::Portfolio Load (0.3ms) SELECT "portfolio_engine_portfolios".* FROM "portfolio_engine_portfolios" INNER JOIN "portfolio_engine_items" ON "portfolio_engine_items"."portfolio_id" = "portfolio_engine_portfolios"."id" ORDER BY portfolio_engine_portfolios.sort_index ASC, portfolio_engine_portfolios.sort_index ASC, portfolio_engine_items.sort_index ASC
PortfolioEngine::Item Load (0.2ms) SELECT "portfolio_engine_items".* FROM "portfolio_engine_items" WHERE "portfolio_engine_items"."portfolio_id" = 2 ORDER BY portfolio_engine_items.sort_index ASC, sort_index asc
PortfolioEngine::Item Load (0.3ms) SELECT "portfolio_engine_items".* FROM "portfolio_engine_items" WHERE "portfolio_engine_items"."portfolio_id" = 3 ORDER BY portfolio_engine_items.sort_index ASC, sort_index asc
PortfolioEngine::Item Load (0.2ms) SELECT "portfolio_engine_items".* FROM "portfolio_engine_items" WHERE "portfolio_engine_items"."portfolio_id" = 1 ORDER BY portfolio_engine_items.sort_index ASC, sort_index asc
The n+1 is triggered by looping through each portfolio's items.
class Portfolio < ActiveRecord::Base
has_many :items,
order: "portfolio_engine_items.sort_index asc",
autosave: true,
inverse_of: :portfolio
default_scope :order => 'portfolio_engine_portfolios.sort_index ASC'
end
class Item < ActiveRecord::Base
belongs_to :portfolio
belongs_to :client
has_many :images,
order: "sort_index ASC",
autosave: true,
inverse_of: :item
end
I have no idea, why this happens....
#portfolios = PortfolioEngine::Portfolio.
joins(:items).
order("portfolio_engine_portfolios.sort_index ASC, portfolio_engine_items.sort_index ASC").
all
Have you tried includes instead of joins?

Rails too many queries?

Just doing some Rails and noticed that when displaying 30 products on a single page using #products.each do it appears as though there are a lot of queries going on in the background, see below for my console output. Is this right or am I reading this entirely wrong?
Category Load (0.1ms) SELECT "categories".* FROM "categories" WHERE ("categories"."name" = 'bras') LIMIT 1
Product Load (28.0ms) SELECT "products".* FROM "products" WHERE ("products".category_id = 48)
Brand Load (0.2ms) SELECT "brands".* FROM "brands" WHERE ("brands"."id" = 408) LIMIT 1
Category Load (0.1ms) SELECT "categories".* FROM "categories" WHERE ("categories"."id" = 48) LIMIT 1
Merchant Load (0.1ms) SELECT "merchants".* FROM "merchants" WHERE ("merchants"."id" = 2) LIMIT 1
Rendered products/_product.html.erb (16.9ms)
CACHE (0.0ms) SELECT "brands".* FROM "brands" WHERE ("brands"."id" = 408) LIMIT 1
CACHE (0.0ms) SELECT "categories".* FROM "categories" WHERE ("categories"."id" = 48) LIMIT 1
CACHE (0.0ms) SELECT "merchants".* FROM "merchants" WHERE ("merchants"."id" = 2) LIMIT 1
Rendered products/_product.html.erb (1.8ms)
CACHE (0.0ms) SELECT "brands".* FROM "brands" WHERE ("brands"."id" = 408) LIMIT 1
CACHE (0.0ms) SELECT "categories".* FROM "categories" WHERE ("categories"."id" = 48) LIMIT 1
CACHE (0.0ms) SELECT "merchants".* FROM "merchants" WHERE ("merchants"."id" = 2) LIMIT 1
Rendered products/_product.html.erb (1.5ms)
CACHE (0.0ms) SELECT "brands".* FROM "brands" WHERE ("brands"."id" = 408) LIMIT 1
CACHE (0.0ms) SELECT "categories".* FROM "categories" WHERE ("categories"."id" = 48) LIMIT 1
CACHE (0.0ms) SELECT "merchants".* FROM "merchants" WHERE ("merchants"."id" = 2) LIMIT 1
Rendered products/_product.html.erb (1.5ms)
CACHE (0.0ms) SELECT "brands".* FROM "brands" WHERE ("brands"."id" = 408) LIMIT 1
CACHE (0.0ms) SELECT "categories".* FROM "categories" WHERE ("categories"."id" = 48) LIMIT 1
CACHE (0.0ms) SELECT "merchants".* FROM "merchants" WHERE ("merchants"."id" = 2) LIMIT 1
Rendered products/_product.html.erb (1.5ms)
CACHE (0.0ms) SELECT "brands".* FROM "brands" WHERE ("brands"."id" = 408) LIMIT 1
CACHE (0.0ms) SELECT "categories".* FROM "categories" WHERE ("categories"."id" = 48) LIMIT 1
CACHE (0.0ms) SELECT "merchants".* FROM "merchants" WHERE ("merchants"."id" = 2) LIMIT 1
Rendered products/_product.html.erb (1.5ms)
CACHE (0.0ms) SELECT "brands".* FROM "brands" WHERE ("brands"."id" = 408) LIMIT 1
CACHE (0.0ms) SELECT "categories".* FROM "categories" WHERE ("categories"."id" = 48) LIMIT 1
CACHE (0.0ms) SELECT "merchants".* FROM "merchants" WHERE ("merchants"."id" = 2) LIMIT 1
Rendered products/_product.html.erb (1.5ms)
CACHE (0.0ms) SELECT "brands".* FROM "brands" WHERE ("brands"."id" = 408) LIMIT 1
CACHE (0.0ms) SELECT "categories".* FROM "categories" WHERE ("categories"."id" = 48) LIMIT 1
CACHE (0.0ms) SELECT "merchants".* FROM "merchants" WHERE ("merchants"."id" = 2) LIMIT 1
Rendered products/_product.html.erb (1.5ms)
CACHE (0.0ms) SELECT "brands".* FROM "brands" WHERE ("brands"."id" = 408) LIMIT 1
CACHE (0.0ms) SELECT "categories".* FROM "categories" WHERE ("categories"."id" = 48) LIMIT 1
CACHE (0.0ms) SELECT "merchants".* FROM "merchants" WHERE ("merchants"."id" = 2) LIMIT 1
Rendered products/_product.html.erb (1.7ms)
CACHE (0.0ms) SELECT "brands".* FROM "brands" WHERE ("brands"."id" = 408) LIMIT 1
CACHE (0.0ms) SELECT "categories".* FROM "categories" WHERE ("categories"."id" = 48) LIMIT 1
CACHE (0.0ms) SELECT "merchants".* FROM "merchants" WHERE ("merchants"."id" = 2) LIMIT 1
Rendered products/_product.html.erb (1.4ms)
CACHE (0.0ms) SELECT "brands".* FROM "brands" WHERE ("brands"."id" = 408) LIMIT 1
CACHE (0.0ms) SELECT "categories".* FROM "categories" WHERE ("categories"."id" = 48) LIMIT 1
CACHE (0.0ms) SELECT "merchants".* FROM "merchants" WHERE ("merchants"."id" = 2) LIMIT 1
Rendered products/_product.html.erb (1.5ms)
CACHE (0.0ms) SELECT "brands".* FROM "brands" WHERE ("brands"."id" = 408) LIMIT 1
CACHE (0.0ms) SELECT "categories".* FROM "categories" WHERE ("categories"."id" = 48) LIMIT 1
CACHE (0.0ms) SELECT "merchants".* FROM "merchants" WHERE ("merchants"."id" = 2) LIMIT 1
Rendered products/_product.html.erb (1.4ms)
CACHE (0.0ms) SELECT "brands".* FROM "brands" WHERE ("brands"."id" = 408) LIMIT 1
CACHE (0.0ms) SELECT "categories".* FROM "categories" WHERE ("categories"."id" = 48) LIMIT 1
CACHE (0.0ms) SELECT "merchants".* FROM "merchants" WHERE ("merchants"."id" = 2) LIMIT 1
Rendered products/_product.html.erb (1.5ms)
CACHE (0.0ms) SELECT "brands".* FROM "brands" WHERE ("brands"."id" = 408) LIMIT 1
CACHE (0.0ms) SELECT "categories".* FROM "categories" WHERE ("categories"."id" = 48) LIMIT 1
CACHE (0.0ms) SELECT "merchants".* FROM "merchants" WHERE ("merchants"."id" = 2) LIMIT 1
Rendered products/_product.html.erb (1.5ms)
CACHE (0.0ms) SELECT "brands".* FROM "brands" WHERE ("brands"."id" = 408) LIMIT 1
CACHE (0.0ms) SELECT "categories".* FROM "categories" WHERE ("categories"."id" = 48) LIMIT 1
CACHE (0.0ms) SELECT "merchants".* FROM "merchants" WHERE ("merchants"."id" = 2) LIMIT 1
Rendered products/_product.html.erb (1.6ms)
CACHE (0.0ms) SELECT "brands".* FROM "brands" WHERE ("brands"."id" = 408) LIMIT 1
CACHE (0.0ms) SELECT "categories".* FROM "categories" WHERE ("categories"."id" = 48) LIMIT 1
CACHE (0.0ms) SELECT "merchants".* FROM "merchants" WHERE ("merchants"."id" = 2) LIMIT 1
Rendered products/_product.html.erb (1.5ms)
CACHE (0.0ms) SELECT "brands".* FROM "brands" WHERE ("brands"."id" = 408) LIMIT 1
CACHE (0.0ms) SELECT "categories".* FROM "categories" WHERE ("categories"."id" = 48) LIMIT 1
CACHE (0.0ms) SELECT "merchants".* FROM "merchants" WHERE ("merchants"."id" = 2) LIMIT 1
Rendered products/_product.html.erb (1.5ms)
CACHE (0.0ms) SELECT "brands".* FROM "brands" WHERE ("brands"."id" = 408) LIMIT 1
CACHE (0.0ms) SELECT "categories".* FROM "categories" WHERE ("categories"."id" = 48) LIMIT 1
CACHE (0.0ms) SELECT "merchants".* FROM "merchants" WHERE ("merchants"."id" = 2) LIMIT 1
Rendered products/_product.html.erb (1.5ms)
CACHE (0.0ms) SELECT "brands".* FROM "brands" WHERE ("brands"."id" = 408) LIMIT 1
CACHE (0.0ms) SELECT "categories".* FROM "categories" WHERE ("categories"."id" = 48) LIMIT 1
CACHE (0.0ms) SELECT "merchants".* FROM "merchants" WHERE ("merchants"."id" = 2) LIMIT 1
Rendered products/_product.html.erb (1.5ms)
CACHE (0.0ms) SELECT "brands".* FROM "brands" WHERE ("brands"."id" = 408) LIMIT 1
CACHE (0.0ms) SELECT "categories".* FROM "categories" WHERE ("categories"."id" = 48) LIMIT 1
CACHE (0.0ms) SELECT "merchants".* FROM "merchants" WHERE ("merchants"."id" = 2) LIMIT 1
Rendered products/_product.html.erb (1.6ms)
CACHE (0.0ms) SELECT "brands".* FROM "brands" WHERE ("brands"."id" = 408) LIMIT 1
CACHE (0.0ms) SELECT "categories".* FROM "categories" WHERE ("categories"."id" = 48) LIMIT 1
CACHE (0.0ms) SELECT "merchants".* FROM "merchants" WHERE ("merchants"."id" = 2) LIMIT 1
Rendered products/_product.html.erb (1.4ms)
CACHE (0.0ms) SELECT "brands".* FROM "brands" WHERE ("brands"."id" = 408) LIMIT 1
CACHE (0.0ms) SELECT "categories".* FROM "categories" WHERE ("categories"."id" = 48) LIMIT 1
CACHE (0.0ms) SELECT "merchants".* FROM "merchants" WHERE ("merchants"."id" = 2) LIMIT 1
Rendered products/_product.html.erb (1.5ms)
CACHE (0.0ms) SELECT "brands".* FROM "brands" WHERE ("brands"."id" = 408) LIMIT 1
CACHE (0.0ms) SELECT "categories".* FROM "categories" WHERE ("categories"."id" = 48) LIMIT 1
CACHE (0.0ms) SELECT "merchants".* FROM "merchants" WHERE ("merchants"."id" = 2) LIMIT 1
Rendered products/_product.html.erb (1.5ms)
CACHE (0.0ms) SELECT "brands".* FROM "brands" WHERE ("brands"."id" = 408) LIMIT 1
CACHE (0.0ms) SELECT "categories".* FROM "categories" WHERE ("categories"."id" = 48) LIMIT 1
CACHE (0.0ms) SELECT "merchants".* FROM "merchants" WHERE ("merchants"."id" = 2) LIMIT 1
Rendered products/_product.html.erb (2.0ms)
CACHE (0.0ms) SELECT "brands".* FROM "brands" WHERE ("brands"."id" = 408) LIMIT 1
CACHE (0.0ms) SELECT "categories".* FROM "categories" WHERE ("categories"."id" = 48) LIMIT 1
CACHE (0.0ms) SELECT "merchants".* FROM "merchants" WHERE ("merchants"."id" = 2) LIMIT 1
Rendered products/_product.html.erb (1.4ms)
CACHE (0.0ms) SELECT "brands".* FROM "brands" WHERE ("brands"."id" = 408) LIMIT 1
CACHE (0.0ms) SELECT "categories".* FROM "categories" WHERE ("categories"."id" = 48) LIMIT 1
CACHE (0.0ms) SELECT "merchants".* FROM "merchants" WHERE ("merchants"."id" = 2) LIMIT 1
Rendered products/_product.html.erb (1.5ms)
CACHE (0.0ms) SELECT "brands".* FROM "brands" WHERE ("brands"."id" = 408) LIMIT 1
CACHE (0.0ms) SELECT "categories".* FROM "categories" WHERE ("categories"."id" = 48) LIMIT 1
CACHE (0.0ms) SELECT "merchants".* FROM "merchants" WHERE ("merchants"."id" = 2) LIMIT 1
Rendered products/_product.html.erb (1.5ms)
CACHE (0.0ms) SELECT "brands".* FROM "brands" WHERE ("brands"."id" = 408) LIMIT 1
CACHE (0.0ms) SELECT "categories".* FROM "categories" WHERE ("categories"."id" = 48) LIMIT 1
CACHE (0.0ms) SELECT "merchants".* FROM "merchants" WHERE ("merchants"."id" = 2) LIMIT 1
Rendered products/_product.html.erb (1.6ms)
CACHE (0.0ms) SELECT "brands".* FROM "brands" WHERE ("brands"."id" = 408) LIMIT 1
CACHE (0.0ms) SELECT "categories".* FROM "categories" WHERE ("categories"."id" = 48) LIMIT 1
CACHE (0.0ms) SELECT "merchants".* FROM "merchants" WHERE ("merchants"."id" = 2) LIMIT 1
Rendered products/_product.html.erb (1.5ms)
CACHE (0.0ms) SELECT "brands".* FROM "brands" WHERE ("brands"."id" = 408) LIMIT 1
CACHE (0.0ms) SELECT "categories".* FROM "categories" WHERE ("categories"."id" = 48) LIMIT 1
CACHE (0.0ms) SELECT "merchants".* FROM "merchants" WHERE ("merchants"."id" = 2) LIMIT 1
Update: Sorry I am specifically talking about the CACHE lines, do these mean these queries are not run everytime?
CACHE (0.0ms) SELECT "brands".* FROM "brands" WHERE ("brands"."id" = 408) LIMIT 1
CACHE (0.0ms) SELECT "categories".* FROM "categories" WHERE ("categories"."id" = 48) LIMIT 1
CACHE (0.0ms) SELECT "merchants".* FROM "merchants" WHERE ("merchants"."id" = 2) LIMIT 1
Here is the code from the product partial:
<h3><%= product.product_name %></h3>
<img src="<%= product.image %>" align="right" alt="<%= product.product_name %>" height="200" />
<p><%= truncate(product.product_description, :length => 300, :omission => "...") %></p>
<p><%= product.price %></p>
<p>Brand: <%= product.brand.brand_name %></p>
<p>Category: <%= product.category.category_name %></p>
<p>Merchant: <%= product.merchant.merchant_name %></p>
<p>More information</p>
<hr />
You might want to eager load your products/merchants/etc
#product = Product.find(conditions, :include => {:category, :brand, :merchant})
(I don't know your relations so use as needed)
EDIT in regards to your cache question, no those queries aren't run against the server, but you should definitely look into eager loading so you don't have unnecessary querying going on
For more details see the following
http://rails-bestpractices.com/posts/29-fix-n-1-queries
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html <- See Eager loading
Those CACHEd queries are only run once but you still want to join them in initially. In your controller, you will want to do #products = Product.all(:include => [:brand, :category, :merchant])
Also, it is a little bit expensive to repeatedly render a small partial. I have had better luck making the partials themselves loop over the collection:
products/_products.html.erb
<% products.each do |product| %>
<h3><%= product.product_name %></h3>
<img src="<%= product.image %>" align="right" alt="<%= product.product_name %>" height="200" />
<p><%= truncate(product.product_description, :length => 300, :omission => "...") %></p>
<p><%= product.price %></p>
<p>Brand: <%= product.brand.brand_name %></p>
<p>Category: <%= product.category.category_name %></p>
<p>Merchant: <%= product.merchant.merchant_name %></p>
<p>More information</p>
<hr />
<% end %>

Resources