0

If i have a model method like:

def favoured_users
 self.followers.limit(5).order("created_at")
end

with a view block like:

<% 5.times do |i| %>
  <li><%= @user.favoured_users[i].name  %></li>
<% end %>

...would I be calling the favoured_user method five times and each time asking for the 5 users, ending up with like 25 users being called?

I'm just wondering if I should put the result of favoured_users in a variable in my controller instead:

@favoured_users = @user.followers.limit(5).order("created_at")

Would that be less calls to the server?

** EDIT **

I'm not sure if this means the value is coming from the cache, it appears it is (bcos of the CACHE, but I dont know thats what it means), but I haven't explicitly told it to, do I have to do anything to make sure it does come fro the cache:

User Load (0.6ms)  SELECT `users`.* FROM `users` INNER JOIN `relationships` ON `users`.`id` = `relationships`.`followed_id` WHERE `relationships`.`follower_id` = 1 ORDER BY full_name, created_at LIMIT 5
CACHE (0.0ms)  SELECT `users`.* FROM `users` INNER JOIN `relationships` ON `users`.`id` = `relationships`.`followed_id` WHERE `relationships`.`follower_id` = 1 ORDER BY full_name, created_at LIMIT 5
CACHE (0.0ms)  SELECT `users`.* FROM `users` INNER JOIN `relationships` ON `users`.`id` = `relationships`.`followed_id` WHERE `relationships`.`follower_id` = 1 ORDER BY full_name, created_at LIMIT 5
CACHE (0.0ms)  SELECT `users`.* FROM `users` INNER JOIN `relationships` ON `users`.`id` = `relationships`.`followed_id` WHERE `relationships`.`follower_id` = 1 ORDER BY full_name, created_at LIMIT 5
CACHE (0.0ms)  SELECT COUNT(*) FROM `users` INNER JOIN `relationships` ON `users`.`id` = `relationships`.`follower_id` WHERE `relationships`.`followed_id` = 1
User Load (0.5ms)  SELECT `users`.* FROM `users` INNER JOIN `relationships` ON `users`.`id` = `relationships`.`follower_id` WHERE `relationships`.`followed_id` = 1 ORDER BY full_name, created_at LIMIT 5
CACHE (0.0ms)  SELECT `users`.* FROM `users` INNER JOIN `relationships` ON `users`.`id` = `relationships`.`follower_id` WHERE `relationships`.`followed_id` = 1 ORDER BY full_name, created_at LIMIT 5
CACHE (0.0ms)  SELECT `users`.* FROM `users` INNER JOIN `relationships` ON `users`.`id` = `relationships`.`follower_id` WHERE `relationships`.`followed_id` = 1 ORDER BY full_name, created_at LIMIT 5
CACHE (0.0ms)  SELECT `users`.* FROM `users` INNER JOIN `relationships` ON `users`.`id` = `relationships`.`follower_id` WHERE `relationships`.`followed_id` = 1 ORDER BY full_name, created_at LIMIT 5

Is the value returning from the cache?

EDIT I'm not sure how to access the variable from my view, I have the method as per Sebi's edit and in my view I am trying to:

<% @user.favoured_followers do %>

  <li><%= @favoured.first.username unless @favoured.first.blank? %></li>
  <li><%= @favoured.second.username unless @favoured.second.blank? %></li>
  <li><%= @favoured.third.username unless @favoured.third.blank? %></li>
  <li><%= @favoured.fourth.username unless @favoured.fourth.blank? %></li>
  <li><%= @favoured.fifth.username unless @favoured.fifth.blank? %></li>

<% end %>

Nothing is being returned?

1
  • Rails does attempt to cache redundant queries per request. Those CACHE messages mean it returned a value from the cache rather than hitting the database again. It's helpful, but you're better off explicitly caching values as in Sebi's answer than depending on Rails to do it for you. Commented Feb 25, 2012 at 17:16

2 Answers 2

3

If you look in your log you'd be able to verify whether it's hitting the cache or not for each call to the function. This doesn't appear to be hitting the cache so the query to load the followers will be repeated 5 times for each user. i.e for each @user you will fire the query 5 times. So caching the value in a variable is definitely a better idea.

Edit : You could change your model method like this :

def favoured_users
    @favoured ||= self.followers.limit(5).order("created_at")
end

The @favoured variable will be created the first time this is called and then for any subsequent calls it will be returned without the query being fired.

Your view code should remain the same without any change. i.e :

<% 5.times do |i| %>
  <li><%= @user.favoured_users[i].name  %></li>
<% end %>    
Sign up to request clarification or add additional context in comments.

7 Comments

I would rather have the method in the model, how would I go about caching the value from the model?... or would I have to call the model method from the controller to set a variable?
Its better if you loop this way <% @user.favoured_users.each do |user| %> <li><%= user.name %></li> <% end %>
The reason I'm looping the way I am is that I want the 5 li tags to render even if there are only 3 users returned.
Well in that case in your favoured_users method, you could do something like @favoured_users ||= self.followers.limit(5).order("created_at")
You mean put this variable in the controller? or inside the model method?
|
0

If i have to do .. i will do below way

Inside controller

@favoured_users = @user.followers.limit(5).order(:created_at)

inside view

<% @favoured_users do |user| %>
  <li><%= user.name  %></li>
<% end %>
<% (5 - @favoured_users.count).times do%>
 <li>&nbsp;</li>
<% end %>

1 Comment

This wouldn't work how I want it to work... I need the 5 li tags to render even if the variable contains only 3 users.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.