Listing records owned by the same model? - ruby-on-rails-3

I have a simple Rails 3 application that has a number of models. A simple overview of the models I'm having trouble with is:
client model
has_many :animals
animal model
belongs_to :client
What I would to be able to do is show a list of other animals that are owned by the same client.
Something like this:
<% #client.animals.each do |animal| %>
<%= animal.AnimalName %>
<% end %>
As this is within the Animal controller, my example code won't work. Any pointers would be appreciated.
Update
To clarify, if I have the following records:
Danny (Client)
Cat (animal owned by Danny)
Dog (animal owned by Danny)
Rabbit (animal owned by Danny)
and I then went to the show view of the Dog's record, I would like a list that would show all animals that Danny owned. E.g.
Cat
Dog
Rabbit
Ideally excluding the currently viewed animal (in this case dog).
I have tried the following but it doesn't seem to work:
<% #client.animals.each do |client| %>
<%= #client.animal.AnimalName %>
<% end %>

If I understand you correctly you have #animal and want to show all the animals owned by the owner of #animal. This can be done like this:
<% #animal.client.animals.each do |animal| %>
<%= animal.AnimalName %>
<% end %>
Update:
You can just add a .where onto #animal.client.animals:
#animal.client.animals.where('id != ?', #animal.id).each ...
It's not such a good idea to do this in a view. So I would add an instance method to my Animal model:
def other_animals_with_same_owner
client.animals.where('id != ?', id)
end
With this you can do:
#animal.other_animals_with_same_owner.each ...

Related

Rails List record and count for each

I have a model called Note. Each note belongs_to :call_reason. And call_reason has_many :notes.
What I want to do in a view is display a list of call_reasons and a total count of each next to it so we can see what the most popular call reasons are.
Here's what I have so far:
dashboard_controller:
def index
#notes = Note.all
end
dashboard view:
<% #notes.each do |n| %>
<%= n.call_reason.reason %>
<% end %>
This lists all notes' call_reasons.
I'm stumbling on how to list each call_reason once with a total count next to it. What I have now just lists all the call_reasons per note which is a mess. I think I could scope this out somehow or change the instance variable but I'm having a hard time getting it right.
Any thoughts?
Since you want to list call reasons, you should start with that:
def index
#call_reasons = CallReason.all
end
Then in your view you can do this:
<% #call_reasons.each do |call_reason| %>
<%= call_reason.reason %> <%= call_reason.notes.count %>
<% end %>
Note that this will perform a query for every call reason in your database. To prevent this you can use a counter cache. Check out the section on counter cache on Rails Guides too.

Rails cache not updating properly

I am using the cache-digests gem and following the instructions as per the Railscast, it creates and reads from a cache as you would expect, but the cache does not seem to be updating properly in relation to an associated record.
When moving a listing from one category to another, the category.live_entries count stays the same for the category I move it from, but goes up for the one I move it to.
So it sounds like I need a touch: all type method so it touches the one I am moving it from as well as the one it is moving to?
_category.html.erb
<% cache category do %>
<li>
<%= link_to category.name, category %>
<% if category.live_entries > 0 %>
(<%= category.live_entries %>)
<% end %>
- <%= category.desc %>
</li>
<% end %>
category.rb
class Category < ActiveRecord::Base
has_many :listings
def live_entries
listings.where(verified: true).count
end
end
listing.rb
class Listing < ActiveRecord::Base
belongs_to :category, touch: true
Any ideas on how to tackle this?
Guess I could create a before_update callback to touch the old category - but is there a better way?
Ok just adding this as an answer - but if anyone has a better solution please feel free to share.
I just added an after_update to touch the old category:
def touch_old_category(listing)
cat = listing.category_id_was
Category.find(cat).touch if cat
end

Accessing attributes from different associated models rails 3

I am looking to get a better understanding of Active Model/Record relationships and how to call attributes dependent upon where the attributes are located (models) and where I am calling them. So for example I can access the attribute dish_name from within the recipe controller like so
def all_recipes
#recipes = Recipe.all
end
In the view
<% #recipes.each do |r| %>
<%= r.dish_name %>
<% end %>
Now say i want to access a recipe attribute from within my controller called worldrecipes and i have just written a method that returns all recipes with the same country. a country has many recipes as a relation
So my method is
def self.top_countries
joins(:recipes).
select('countries.*, count(*) AS recipes_count').
group('countries.id').
order('recipes_count DESC')
end
My controller
#worldrecipes = Country.where(:name => params[:name])
and view
<% #worldrecipes.each do |r| %>
<%= r.name %>
<% end %>
so accessing the country name attribute is easy as its in the country model and thats where my query results are being returned from (I think)...My question is how do i access the dish_name attribute from my recipe model to that links to the country name
Hope that makes sense, does anyone have a guide on how to work this out or some golden rules for this
Thank you
I think what you need is:
#country=Country.where(:name=>params[:name]).first
#worldrecipes=#country.recipes
And in the view:
<% #worldrecipes.each do |r| %>
<%= r.dish_name %>
<% end %>
This would print the dish names of the recipes of the country with name provided by params[:name]
EDIT:
Ok Let me clear this up for you :)
Your model relationship is setup such that each country has many recipes. i.e a country has many recipes.
So you have,
has_many :recipes
in country.rb and
belongs_to :country
in recipe.rb
Now when you want to access all the recipes belonging to a country, what you do is, you call country_record.recipes (country_record being the object of the country record you need).
And when you call,
Country.where(:name=>params[:name])
What you actually get is the active record object representing the COUNTRY itself and not the recipes of the country and that is why Italy was printed.
Hope this helped you.
For starters you want to make sure you have the association setup in your models:
country.rb
class Country < ActiveRecord::Base
has_many :recipes
end
recipe.rb
class Recipe < ActiveRecord::Base
belongs_to :country
end
If you haven't already done so, add a foreign_key attribute to your recipe model by running the following migration:
rails g migration add_country_id_to_recipe country_id:integer
Now that your associations are in place you can easily query for a countries respective recipes. In your controller:
#worldrecipes = Country.where(:name => params[:name])
Then in your view:
<% #worldrecipes.each do |c| %>
<% c.recipes.each do |r| %>
<%= r.dish_name %>
<% end %>
<% end %>
In regards to 'golden rules' I highly recommend you check out Association Basics. This is the go-to place for an overview of what you can do with associations.

Rails 3.2.2 Query on sub sub attribute advise

Currently have a very inefficient view partial that lists groups of users by their predicted score.
group controller
def show
#sfs_ordered = ScoreFootballSimple.order("home_score DESC, away_score ASC")
#live_games = Game.find(:all, :conditions => ['kickoff < ? AND completed != true AND game_state is NOT NULL', Time.now])
group#show (relevant section)
<% #live_games.each do |game| %>
<% #sfs_ordered.each do |sfs| %>
<% got_this_score = Array.new %>
<% game_points = nil %>
<% #group.members.each do |member| %>
<% if pred = member.prediction_set.predictions.where('game_id = ?',game.id).first %>
<% game_points = pred.points if !pred.points.nil? && pred.score_type == sfs.score_type %>
<% got_this_score << member.user.user_detail.display_name if pred.score_type == sfs.score_type %>
<% end %>
<% end %>
<% if got_this_score.count > 0 %>
<tr><td><%= sfs.home_score %>-<%=sfs.away_score%></td>
<td><% if !game_points.nil? %>
<div class="preds-show-points-div"><%= game_points %>pts</div>
<% else %>
-
<% end%></td>
<td><%= got_this_score.to_sentence %></td></tr>
<% end%>
<% end %>
<% end %>
Obviously this is loops within loops that means the that for every #sfs_ordered (round 50 records) it is iterating over every group member (for the largest group about 5000) and this means the page is taking seconds to load.
Don't flame me, this was the POC to show how it could look but it has exposed my lack of ability with ActiveRecord. Now I could go around creating a hash of users, predictions sets etc but I wondered if anyone could point me to a better way of selecting information with more precision using Rails queries.
The entity relationship is something like this
Group has many Member
Member belongs to User and PredictionSet
PredictionSet has many Prediction
Prediction belongs to Game and ScoreType
ScoreTypeSimple has one ScoreType
The predicted score is in ScoreTypeSimple - this is how I want the list organised
e.g 1:1 - Joe, Fred and Jane
1:0 - Sue, Dave and Helen
Then I want to grab the Group.member.user.name for the Group.member.prediction_set.prediction - where the prediction.game.id == game.id AND score_type == sfs.score_type
I know I can improve this by pure SQL joins and INs and build hashes but I wondered if any one could give me any pointers if there was a Rails/Ruby efficient way of doing this. I know the answer is probably out there in lambda but my ActiveRecord knowledge is stretch to the limit here!
Any help gratefully received.
Peter
You might be able to benefit from eager loading, since you're displaying all of some associated objects. This is done using the .includes method on a relation. For instance, your view works with all the members of a group, so when you fetch the group from the database (I don't see the line that does this in your code, but it probably looks something like
#group = Group.where('some condition').first
If you instead use this:
#group = Group.includes(:members => [:user]).where('some condition').first
Then loading the group, all it's members, and all their user objects is 3 database queries, rather than (in your extreme case of 5000 members) 10,001.
I'd say this is, at best, a small part of your solution, but it may help.
Edit: Here is the RailsCast on eager loading, and there's some docs about half way down this page.

How do I access an instance variable from another controller?

So I have two models & controllers. Projects and Designers.
In my designers index view, I want it to show a list of all the projects that the designer has.
However, when I do a simple query like this:
<% #projects.each do |project| %>
<tr>
<td><%= link_to 'Show', project %></td>
<td><%= link_to 'Edit', edit_project_path(project) %></td>
<td><%= link_to 'Destroy', project, :confirm => 'Are you sure?', :method => :delete %></td>
</tr>
<% end %>
From the index.html.erb in the Designers view, it gives me the following error:
NoMethodError in Designers#index
You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.each
However, when I run that EXACT code from the index.html.erb file in the projects view, it works perfectly.
So how am I able to access that controller or at least data from the view of another controller? Do I have to add a projects variable (where it queries the db) to my index object in my designers controller?
Thanks.
UPDATED TO USE A SINGLE DESIGNER RECORD
You should use associations. Add this to your models.
class Designer < ActiveRecord::Base
has_many :projects
end
class Project < ActiveRecord::Base
belongs_to :designer
end
Your view should look like this:
<% #designer.projects.each do |project| %>
<% end %>
More info on associations here:
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
Figured out one way to do it. All I had to do was add an instance variable in my designers controller:
#projects = Project.all
But...that's not very DRY. Does anyone have a more elegant 'DRY' solution, so if I want to access other variables in other controllers I can do that easily without having to re-create them in the current controller?
Thanks.
In your designers controller, you need to set the #projects instance variable to only those projects belonging to the signed in designer, correct?
You'll need something like this:
def index
#projects = Project.where(:user_id => where ever you've stored your userid)
end
I hope this helps.