Rails: finding records where attribute includes some value - ruby-on-rails

I have a "Stores" model that contains various locations. Among the attributes for each store is the the "brands" that is carries.
Example: Store1, brands: "Nike, Adidas, Polo"; Store2, brands: "Jcrew, Polo"
I want to be able to select all stores where brand contains "Adidas" (may also contain other brands)
Something along the lines of:
#search = Stores.where(brands: params[:brand])
but need it to be
#search = Stores.where(brands.include? params[:brand])
which clearly doesn't work
What's the best way to deal with this?

If brands is a string and params[:brand] contains a single brand name, you can use MySQL's LIKE function:
#search = Stores.where(['BRANDS LIKE ?', "%#{params[:brand]}%"])

You can do this with the following statement.
#search = Stores.where("brands = ?", params[:brand])
A similar example is given in Listing 11.43 of the Hardtl rails tutorial
You should also note that rails models generally are meant to have singular names, i.e. Store instead of Stores.

Related

Rails How do I find case insensitive values that are not already associated to the user?

Newbie Rails developer here so please bare with me.
I have a table called Ingredients where it contains a title field and an association to a User. A user can have many ingredients.
I want to query the database to get the ingredients that are not already available to a User.
I tried doing something like this with Rails:
#ingredients = current_user.ingredients
#community_ingredients = Ingredient.all.excluding(#ingredients).pluck(:title, :id)
But the problem is that this still returns values that are the same & only the case is different.
How can I achieve this outcome?
Try following queries.
#community_ingredients = Ingredient.includes(:user).where("users.user_id = ?", current_user.id).where(users: { id: nil } ).pluck(:title, :id)
OR
Ingredient.includes(:user).where("users.user_id = ?", current_user.id).where(ingredients: {user_id: nil } ).pluck(:title, :id)
OR
Ingredient.includes(:user).where("users.user_id = ?", current_user.id).where(users: { ingredient_id: nil } ).pluck(:title, :id)
Choose right query based on your association and feel free to suggest me so I can remove the extra one.
Most probably the first or second query will work, I strongly feel the third might not be the case.
Let's say this one is not working for you and you want to have solution based on your architecture.
#ingredients = current_user.ingredients.pluck(:title)
#community_ingredients = Ingredient.where.not("lower(title) IN (?)", #ingredients.map(&:downcase)).pluck(:title, :id)
So basically we need to convert both column value and the matching list in same case.
So we have converted to downcase.
here is how it looks in my local system, just make sure it's working that way.

CONTAIN or LIKE sql statement for ActiveRecord has_and_belongs_to_many relationship

I have 2 ActiveRecords: Article and Tag, in a many to many relationship. Basically I want to know how to select with a CONTAINS or LIKE condition, ie. to define a condition on a many to many relationship to contain a specified subset within an array.
The code structure I am trying to work out is as follows:
tag_names = ["super", "awesome", "dope"]
tags = Tag.where("name IN (?)", tag_names)
# The following is my non-working code to illustrate
# what I'm trying to do:
articles = Article.where("tags CONTAINS (?)", tags)
articles = Article.joins(:tags).where("articles.tags CONTAINS (?)", tags)
If you have different tables then you have to use joins and then specify a condition on your join:
Article.joins(:tags).where('tags.id IN ?', tag_ids)
If you want more flexibility on you queries, you could also use Arel and write something like the following:
tags = Tag.arel_table
tags_ids = Tag.where(tags[:name].matches("%#{some_tag}%"))
Article.joins(:tags).where(tagss[:id].in(tags_ids))
You can read more about matches in this answer.
I prefer Arel conditions over pure String or even Hash conditions.

rails getting attributes of associated model for many objects in one query

My title might be confusing, I wasn't sure what to write.
In rails I understand how to fetch Many Objects for One parent object
#first_user = User.first
#first_user_posts = #first_user.posts
But how can I fetch Many Objects for Many parent objects and select its attributes in one query?. I am trying to do something like that:
#many_posts = Post.all
#posts_by_user_gender = #many_posts.joins(:user).map(&:gender)
hoping it would give me an array that could look something like this:
#posts_by_user_gender => ["male", nil, "female", nil]
#I know I can do this map technique if I fetch it directly from the User model
# User.all.map(&:gender),
# but I want to start with those that posted in a specific category
# Post.where(:category_id => 1)
and then to count the males I could use the Ruby Array method .count
#males_count_who_posted = #posts_by_user_gender.count("male")
=> 1
I could always do 3 separate queries
#males_count_who_posted = #many_posts.select(:user_id).joins(:user)
.where("gender = ?", "male").count
#females_count_who_posted = ...
but I find that extremely inefficient, especially if I do the same for something like "industry" where you could have more than 3 options.
you can join model via SQL syntax
#posts_by_user_gender = #many_posts.joins("LEFT JOIN Users where users.id=posts.user_id").joins("LEFT JOIN Genders where genders.id=user.gender_id")

RoR: How to sort an array with the help of scopes

I have an array #products. Each element of the array is a hash, containing a few fields (but not all) from Product table and the corresponding values.
I have a scope descend_by_popularity in Product which allows me to sort the products based on popularity field. I'd like to sort the array #products using this scope.
What I tried:
#product_group = Array.new
#products.each do |product|
#product_group.push(Product.find(product['id']))
end
#product_group1 = #product_group.descend_by_popularity
But this gives me error:
undefined method `descend_by_popularity' for #<Array:0xb2497200>
I also want to change the sorted Product list back to the format of #products array.
Thanks
Scopes only make sense within the ActiveRecord context for requests to the database (since it is used to change the SQL query). What you did is throwing a lot of products into an array. This array then knows nothing about the scope anymore. You would have to use the scope when you create the #products object. (and it does not seem to make a lot of sense to move the result of a query into an array)
So something like
#products = Product.descend_by_popularity.where(some more stuff)
should work for you. After that you should have the records in the order defined by the scope and can then either use them directly or still push them into an array if that's what you want to do.
With the updated info from the comments it looks like maybe the best way to go would be to first collect only the Product ids from the solr response into an array and then run that as search together with your scope:
#product_group = #products.map{|product| product.id}
#result = Product.where(id: #product_group).descend_by_popularity
this should technically work, peformance is a different question. I would consider aggregating this data into the Solr document, if it doesn't change too often.
Now assuming you are only interested in the order of products as such, you could do something like this to get #products into this order:
#result.map{|r| #products.find{|p| p[:id] == r.id}
though this may slow down things a bit.
Try this: find_by_id as params
#product_group = Array.new
#products.each do |product|
#product_group.push(Product.find(params['id']))
end
and return the array of #product_group
#product_group1 = #product_group.descend_by_popularity

Ruby on Rails: where returning nil

In my app I'm obtaining a certain category, and I'm filtering the associated items based on their name.
The following code should be pretty clear:
categories = Category.where(:id => params[:category_id]).includes(:items).where("lower(items.name) like ?", "%#{params[:keywords].downcase}%")
However, if the name filter excludes all the items, the categories object returned by where is nil. Is this the expected behaviour? How can I get the category even either items exist or not?
The easiest way might be to just split the query:
#category = Category.find(params[:category_id])
#items = #category.items.where("lower(items.name) like ?", "%#{params[:keywords].downcase}%")
Based on your code it seems like category_id references only 1 category so I've changed it to singular.
You should look into doing an OUTER JOIN against the items table which will give you categories regardless of whether or not their items meet the name filter.

Resources