Can i cache a parent in rails? - ruby-on-rails

I have this code:
Business.all.limit(50).each do |business|
card = {name: business.name, logo: business.logo, category: business.category.name}
feed << card
end
In my models, Business belongs to Category, and Category has many Business
My problem is that this will query the DB 50 times, each time I want to retrieve each business' category name.
I have seen Rails cache effectively by using :include, but all examples I have seen are for child records, for example:
Category.all :include => [:businesses]
but in this case I want to cache the parent's data.

Its the same you can do by using singular model name
Business.includes(:category)

Related

Rails 4 Selecting uniq objects related AR CollectionProxy

I'm dealing with a shopping cart, which has many products in it. The products can be sold by multiple different companies. What I'm trying to do is select the companies uniquely so that I can create one order per vendor.
the hack
companies = []
#cart.products.each { |p| companies << p.company }
companies.uniq
#create order for each company
I'm not sure if #pluck is something I should be using here, but I do know that there has got to be a more efficient way of collecting my companies "uniquely". #uniq doesn't seem to be working for me, and neither does #cart.products.pluck(:company)
I have no :company_id in my Bid model, it's a has_many/has_one relationship
pluck is used for retrieving array of values in provided column like:
#cart.products.pluck(:company_id) # => [1,2,3]
For collecting companies you can do companies = #cart.products.collect(&:company).uniq

testing queries using rspec and factory_girl : Is there a better way?

I have the following classes and relationships
City has_many Cinemas
Cinemas has_many Movies
Movies has_many Ratings
Movies Has_many Genres through GenreMovie
and I want to test queries like
* Show me the all movies in NewYork
* Show me the all movies in NewYork order by the rating
* Show me the all movies in NewYork order by length_of_movie, in genre "Action"
* show me all movies in Cinema "X" order by rating, that are in Genre "SciFi"
Currently the way I am doing as below, using factory girl, and chaining a bunch of models together to have data to check against,
city = create(:city)
cinema = create(:cinema, city: city)
5.times do
movie = create(:movie, cinema: cinema, tags: ["sci fi", "action"]
3.times do
create(:rating, score: 2.3, movie: movie)
end
end
and repeating that 3-4 to generate enough data to query against but it seems so clunky.
Is there a better way ?
I normally test this using a very "minimalistic" approach:
e.g. for your first case I would create two movies, one in NY, and one outside. Your method should only return the one in NY
For the second, create three movies, both in NY, with different rating. Create them in a not logic way, so that, no matter what, they will be sorted. Check whether your method returns them in the right order
Similar for the other cases.
I would not just create 5x3 movies. Makes no sense, and only costs time...
There are several factory_girl constructs you could use to clean these up. create_list will create an array of objects, cleaning up your x.times do blocks. A with_ratings trait on your movie factory could allow you to opt in to having ratings automatically created when you create a movie (via FactoryGirl callbacks). You could even have that use a transient attribute in order to control the number and rating. So your result could look something like this:
cinema = create(:cinema)
movies = create_list(
:movie,
5,
:with_ratings,
cinema: cinema,
tags: [...],
ratings_count: 3,
ratings_value: 2.3
)
If you need access to the city, you can get it via cinema.city.
See:
transient attributes
traits

Rails 4: Displaying a table of a collection of items, sorted by various item attributes?

So I have a CareerEntry model that has the following attributes: name, job_category, company, group, location, year, full_intern, and it represents the job offers that people have received. full_intern is a string that is either "internship" or "full-time", and represents what the type of the job offer is. All CareerEntries will be created by an Admin interface, so it is essentially acting as a standalone model. This is my question: given a bunch of CareerEntry objects, I want to display a table to display on my careers page (which has an action in a PagesController).
I want the table to be sorted according to multiple attributes. I want each year to be its own section in the table, then within each year, I want the internship entries grouped together and the full-time entries grouped together. Then, within these groupings, I want each job_category to be its own section (job_categories comprise of things like 'Investment Banking,' or 'Technology.')
A very good example of what I'm going for is shown under the "2013" tab in this link.
What is the best way to go about achieving this? I know that in the careers action definition of my PagesController, I could have:
class PagesController < ApplicationController
def careers
#careerentries = CareerEntry.order(:year => :desc, :fullintern => :asc, :job_category => :asc)
end
end
But this would simply return all the entries in the order that I want, and would not allow me to place headers and dividers to separate, say, the job_categories.
Is there any easier way of achieving what I'm looking for?
Perhaps you're looking for .group_by?
Group By
From the link you gave, it looks like you want to group your results by year, like this:
#careerentries = CareerEntry.order(year: :desc, fullintern: :asc, job_category: :asc)
#entries_by_year = #careerentries.group_by { |entry| entry.year }
This gives you all the data, ordered to your specs. You can then sort through it, using the group_by method:
#entries_by_year.each do |entry|
entry.name
end
You could then work this into your table
Good reference Group posts by Year - Rails

How to sort a merged array and hash chronologically?

In a Rails 3.2 app I have a polymorphic ActivtyFeed model.
class ActivityFeed
belongs_to :user
belongs_to :feedable, polymorphic: true
end
I need to aggregate some items in the ActivityFeed index view. For example, instead of rendering separate items for each photo, I want to group photos by a date or event, and display "User uploaded x photos".
My controller looks like this:
#feed_items = #user.activity_feeds.sort_by(&:created_at)
#feed_array = []
photos = #feed_items.find_all{|f|f.feedable_type.eql?("Photo")}
#feed_items.delete_if{|f|f.feedable_type.eql?("Photo")}
#feed_array << #feed_items
grouped_photos = photos.group_by{|p| p.feedable.event_id}
#feed_array << grouped_photos
#feed_array.flatten!
Then in the views I'm using e.g.
if feed_array.class.eql?(Hash)
render grouped photo partial
elsif feed_array.feedable_type.eql?("Post")
render single post partial
etc
I'm having trouble sorting items chronologically, because the array contains a nested hash.
[#<ActivityFeed id: 7, user_id: 2, feedable_type: "Post", feedable_id: 3>, {2=>[#<ActivityFeed id 3, user_id: 4, feedable_type: "Photo", feedable_id: 6>]}]
How can I sort this array?
I've tried #feed_array.sort{|a,b| a.['created_at'] <=> b.['created_at'] } but got comparison of ActivityFeed with Hash failed
Is this the best approach, or is there a better way to go?
you can merge the array and the hash and then sort it
merged.sort {|a,b| a.method <=> b.method }
you only need to tell the sort how to sort the objects
one suggestion, instead of
#user.activity_feeds.sort_by(&:created_at)
do
#user.activity_feeds.order('created_at ASC')
that should be faster, since you already get the activities sorted from the database (if activity_feeds is a relation)
Well you need to do little bit modification to your original design.
What I would suggest is to add event to activity feed and also you need to keep the original photo to the activity feed as well.
Because, by keeping photo as a activity feed you will be able to display a single photo on your activty stream when the photo is not associated with any event. But, if every photo belongs to an event then you can remove the photo from activity feed.
Then every object will be activity feed and can be sorted easily based on created_at.
Also you don't need to extract the photos manually.
Hope this will help!

How can I write this query efficiently in Ruby on Rails?

I have three tables: Accounts, Investments, and Games. An Investment has an account_id, game_id, some statistic counters, and is created the first time an Account participates in a Game.
I want to provide a JSON list of the latest Games along with the user's Investment in that Game, like this:
[{id: 666, name: "Foobar", ..., investment: {tokens: 58, credits: 42, ...}},...]
If they have not yet participated in the game, I still want to include an Investment object with default values, so I overrode the serializable_hash function in my Game model:
# game.rb
has_many :investments
def serializable_hash(options=nil)
options ||= {}
i = investments.find_or_initialize_by_account_id options[:uid]
{:id => id, ..., :investment => i.serializable_hash}
end
However, when I run something like Game.find(list_of_ids).to_json(:uid => current_user.id), Rails does a separate query on the Investments table for each Game. I tried Game.includes(:investments).find(list_of_ids).to_json(:uid => current_user.id) but not only does that load the investments for all users, it still does a separate query for each game to find or initialize the investment object.
In short, given a list of game IDs and an account id, what's a clean way to load the associated Investment objects that exist in one query, and initialize the rest?
You want to give the list of ids to the server in one go. I use the IN operator for this:
Game.includes(:investments).where("games.id IN (?)", list_of_ids)

Resources