Rails 4 Selecting uniq objects related AR CollectionProxy - ruby-on-rails

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

Related

Can i cache a parent in 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)

How do I select only the associated objects in a Rails "where" query?

I have a model Category, which has_many Products, and a Product in turn has_many Categories. When a user searches for a Category, I'd like to return the products of the matching Categories without losing my Arel object. Here's what I have so far:
Category.where("upper(title) like ?", search_term.upcase).map {|category| category.products}.flatten
This does the trick of returning the products, but of course what I have is an array and not Arel. I can get as far as adding an :includes(:products) clause, so I do indeed get the products back but I still have them attached to their categories. How do I adjust my query so that all I get back is an Arel that only addresses products?
If it is products that you want then you should probably start with the Product object when you are searching. For example ,you could do it like this:
Product.joins(:categories).where("upper(categories.title) like ?", search_term.upcase)
The reason I use joins instead of includes is that joins will perform an INNER JOIN instead of LEFT OUTER JOIN which is what you need to only return the products that are actually associated with the found categories.
To make it a little more elegant you could wrap it all up in a scope in your Product model like this:
# In Product.rb
scope :in_categories_like, Proc.new{ |search_term|
joins(:categories).where("upper(categories.title) like ?", search_term.upcase)
}
# In use
#products = Product.in_categories_like(params[:search_term])

rails mongoid criteria find by association

I'm trying to find a record by associated username which is included in a belongs_to relation, but it's not working.
Articles belong to Users
Users have many articles
Article.where(user_id: someid) works fine, but I'd like to use the username as reference which is stored in the Users table.
Article.includes(:user).where(:username => "erebus")
Article.includes(:user).where("user.username" => "erebus")
I also have identity_map_enabled: true
Article.includes(:user).inclusions returns the relation details
Doesn't work, what am I not understanding?
You have to keep in mind that there are no joins in mongodb. In relational dbs, includes forms a join query and you can use columns from both the tables in query. However due to absence of joins in mongodb, same is not possible.
In mongoid, includes just saves a bunch of db calls. It fetches and stores the associated records in identity map for fast retrieval, but still while querying, one query can only deal with one collection.
If you need articles based on user names, I would suggest following work around:
user_ids = User.where(username: 'erebus').only(:_id).map(&:_id)
articles = Article.where(:user_id.in => user_ids)
You can make it little shorter from what rubish suggested:
user_ids = User.where(username: 'erebus').pluck(:id)
articles = Article.where(:user_id.in => user_ids)
Or one liner:
articles = Article.where(:user_id.in => User.where(username: 'erebus').pluck(:id))

How to Average Multiple Columns in Rails

I have the following objects: Products, Ratings, and Users. I am trying to filter and select a number of Products that the User owns (through a has_many :through relationship with UserProducts) and average a certain column the Ratings table that matches their User ID and the correct Product ID.
So, my function is something along these lines:
def find_rating(criteria)
product = self.products.find(:all, :conditions => ["criteria = ?", criteria])
rating = self.ratings.where("product_id = ?", product).average(:overall)
end
I think that I'm going about this the wrong way, because I'm trying to find a product_id by passing an entire array of data consisting of multiple products. But, I think of using a more traditional loop and that seems convoluted. Can someone point me in the right direction for solving this problem? Thanks!
If product is a single entry, as it appears to be in your code, I would do this:
rating = self.products.find_by_criteria(criteria).ratings.average(:overall)
If it's an array of products, this method may help you: http://apidock.com/rails/ActiveRecord/Batches/ClassMethods/find_each

Find all objects with broken association

I have two models in my rails app with a has many and belongs to association.
Category has many items and Item belongs to category.
These models are associated in the normal way through a category_id column in the Item model.
I'm looking for a quick way of finding all elements in the database with broken associations.
i.e. find all categories that exist with no associated items and items that exist with no associated category.
For example, if I have an item with a category_id of 7, but the category with id 7 has been deleted then this would be considered broken.
For your example, to find items with category_id's for categories which don't exist any more:
Item.where('NOT EXISTS (SELECT * FROM categories where category.id = item.category_id)')
You might want to look at this as well:
A rake task to track down missing database indexes (not foreign keys though, but indexes): https://github.com/eladmeidar/rails_indexes
A very effective way is using find_by_sql to let the database do the heavy lifting:
uncategorized_items = Item.find_by_sql("select * from items where category_id IS NULL")
Another way is a named scope:
class Item < ActiveRecord::Base
scope :uncategorized, where(:category_id => nil) # rails 3
# or...
named_scope :uncategorized, :conditions => 'category_id IS NULL'
end
These are just a couple of ideas. I assume that once you've found these broken associations you plan to fix them, right? You might want to use validates_associated in both models if it's important to you that this not happen again.
You can use find_by_sql and a left outer join to find all the items in one table but not another. Here, I use a downloads table and an image_files table (I've only included the SQL):
SELECT d.*, d.image_file_id
from downloads as d
LEFT OUTER JOIN image_files as i
ON i.id = d.image_file_id
WHERE d.image_file_id IS NULL

Resources