rails 4 how to use where and where in condition simultaneously - ruby-on-rails

I have the following query
model = (1,2,3,4)
#posts = Post.where(category_id: id, product_model_id: model)
My above query is justing taking the 1 from model how can i use where in condition over here
Edit-1
This piece of code works but I don't feel this as a good code right?
#posts = Post.where("category_id = ? and product_model_id in (#{model})", id)
Edit-2
If I use
#posts = Post.where("category_id = ? and product_model_id in (?)", id, model)
Throwing error as
invalid input syntax for integer: "15,16" because my input is like this
select * from posts where category_id=5 and product_model_id in ('15,16')
How to correct it then..

model_ids = model.split(",").map(&:to_i)
#posts = Post.where(category_id: id, product_model_id: model_ids)
or
model_ids = model.split(",").map(&:to_i)
#posts = Post.where("category_id = ? AND product_model_id IN (?)", id, model_ids)

According to the rails guide, you can pass in an array to where and it should understand that you want to use IN. See the guide here: http://guides.rubyonrails.org/active_record_querying.html#subset-conditions
I'm a little confused by your syntax, since model = (1, 2, 3, 4) doesn't look like valid array syntax.
Relevant part of the guide:
Client.where(orders_count: [1,3,5])

You could use arel, but I'd just do something like:
#posts = Post.where("category_id = ? AND product_model_id IN (?)", id, model)

Related

How to use .where NULL in Ruby on Rails

I have items in a table that have :parent_id that are empty to signify it being a main category. I was wondering how to iterate over these using .where (if that's even the right method to call).
Here's my controller:
def new
#title = 'New Post';
#post = Post.new
#categories = BlogCategory.all
#cat_zero = BlogCategory.where(:parent_id NULL)
#cat_one = BlogCategory.where(parent_id: 1)
#cat_two = BlogCategory.where(parent_id: 2)
#cat_three = BlogCategory.where(parent_id: 3)
#cat_four = BlogCategory.where(parent_id: 4)
end
The rest works fine, it's just that NULL isn't working. (The relationship between BlogCategory and Post have been made.)
I have tried doing these, but with no fortune (and a few other versions of these):
#cat_zero = BlogCategory.where(:parent_id == NULL)
#cat_zero = BlogCategory.where(:parent_id.nil?)
Thanks for the help!
The spelling you're looking for is:
#cat_zero = BlogCategory.where(parent_id: nil)
It's just the same as the spelling for other values, only using nil.

Relation passed to #or must be structurally compatible. Incompatible values: [:references]

I have two queries, I need an or between them, i.e. I want results that are returned by either the first or the second query.
First query is a simple where() which gets all available items.
#items = #items.where(available: true)
Second includes a join() and gives the current user's items.
#items =
#items
.joins(:orders)
.where(orders: { user_id: current_user.id})
I tried to combine these with Rails' or() method in various forms, including:
#items =
#items
.joins(:orders)
.where(orders: { user_id: current_user.id})
.or(
#items
.joins(:orders)
.where(available: true)
)
But I keep running into this error and I'm not sure how to fix it.
Relation passed to #or must be structurally compatible. Incompatible values: [:references]
There is a known issue about it on Github.
According to this comment you might want to override the structurally_incompatible_values_for_or to overcome the issue:
def structurally_incompatible_values_for_or(other)
Relation::SINGLE_VALUE_METHODS.reject { |m| send("#{m}_value") == other.send("#{m}_value") } +
(Relation::MULTI_VALUE_METHODS - [:eager_load, :references, :extending]).reject { |m| send("#{m}_values") == other.send("#{m}_values") } +
(Relation::CLAUSE_METHODS - [:having, :where]).reject { |m| send("#{m}_clause") == other.send("#{m}_clause") }
end
Also there is always an option to use SQL:
#items
.joins(:orders)
.where("orders.user_id = ? OR items.available = true", current_user.id)
You can write the query in this good old way to avoid error
#items = #items.joins(:orders).where("items.available = ? OR orders.user_id = ?", true, current_user.id)
Hope that helps!
Hacky workaround: do all your .joins after the .or. This hides the offending .joins from the checker. That is, convert the code in the original question to...
#items =
#items
.where(orders: { user_id: current_user.id})
.or(
#items
.where(available: true)
)
.joins(:orders) # sneaky, but works! 😈
More generally, the following two lines will both fail
A.joins(:b).where(bs: b_query).or(A.where(query)) # error! 😞
A.where(query).or(A.joins(:b).where(bs: b_query)) # error! 😞
but rearrange as follows, and you can evade the checker:
A.where(query).or(A.where(bs: b_query)).joins(:b) # works 😈
This works because all the checking happens inside the .or() method. It's blissfully unaware of shennanigans on its downstream results.
One downside of course is it doesn't read as nicely.
I ran into the same issue, however the code was defined in a different place and was very difficult to change directly.
# I can't change "p"
p = Post.where('1 = 1').distinct # this could also be a join
And I needed to add an or statement to it
p.or(Post.where('2 = 2'))
The following code won't raise an error, because it has distinct like the initial relationship.
p.or(Post.where('2 = 2').distinct)
The problem with it it that it only works as long as you know the relationship. It may or not have a join, or distinct.
This works regardless of what the relationship is:
p.or(p.unscope(:where).where('2 = 2'))
=> SELECT DISTINCT `posts`.* FROM `posts` WHERE ((1 = 1) OR (2 = 2))
It occurs when you try to combine two multi-active records of the same type, but one of them has a joins value or an includes value, or in your case a reference value, that the other does not.
Therefore we need to match the values between them, and I found a general way to do this without knowing the actual values in advance.
items_1 = #items.joins(:orders)
.where(orders: { user_id: current_user.id})
items_2 = #items.where(available: true)
.joins(items_1.joins_values)
.includes(items_1.includes_values)
.references(items_1.references_values)
#items = items_1.or(items_2)
just solve it!
def exec_or_statement(q1, q2)
klass = q1.klass
key = klass.primary_key
query_wrapper_1 = {}
query_wrapper_1[key] = q1
query_wrapper_2 = {}
query_wrapper_2[key] = q2
klass.where(query_wrapper_1).or(klass.where(query_wrapper_2))
end
query_1 = #items.where(available: true)
query_2 =
#items
.joins(:orders)
.where(orders: { user_id: current_user.id})
exec_or_statement(query_1, query_2)

Query Rails Postgres with array data type

So, Ive been trying to query my PostgreSQL model in Rails, but get the following error:
undefined method `id' for TransactionTemplate::ActiveRecord_Relation
My code:
#transaction_templates = TransactionTemplate.where("transaction_category_id = 1")
#transaction = Transaction.where("transaction_template_id in (?)", #transaction_templates.id)
I know that the transaction templates is an array and that there is therefor not just one ID it needs to look up, but multiple of IDs, just as I want it.
Any suggestions?
Try this:
#transaction_templates = TransactionTemplate.where("transaction_category_id = 1")
#transaction = Transaction.where("transaction_template_id in (?)", #transaction_templates.map(&:id))
If you need just ids then try:
#transaction_template_ids = TransactionTemplate.where("transaction_category_id = 1").pluck(:id)
#transaction = Transaction.where("transaction_template_id in (?)", #transaction_template_ids)
Or you have proper associations then
#transaction = Transaction.joins(:transaction_template).where("transaction_category_id = 1")

Find all records with two conditions where one condition are true and other false

I'm trying to find all associated records where two conditions are met.
I'm trying this, but it doesn't work, examples:
#students = #group.students
.includes(:attendances)
.where.not(attendances: {student_id: #ids, event_time_id: #event_id})
#students = #group.students
.includes(:attendances)
.where.not(attendances: {event_time_id: #event_id})
.where.not(attendances: {student_id: #ids})
#students = #group.students
.includes(:attendances)
.where("attendances.student_id IN (?) AND NOT attendances.event_time_id = ?", #ids, #event_id)
I want to get all the student records that exist in group and not have attendance with #event_id or have not attendance at all.
I think this might do what you want (untested), not the most elegant looking code...
exists_fragment = "SELECT 1 FROM attendances WHERE student_id = students.id"
#group.students
.joins(:attendance)
.where("attendances.event_id <> ? OR NOT EXISTS(?)", #event_id, exists_fragment)
Working solution:
#students = #group.students.includes(:attendances)
.where("attendances.event_time_id != ?", #event_id)
.references(:attendances)
#students_on = #group.students.includes(:attendances)
.where(attendances: { event_time_id: #event_id })
#students = #students - #students_on
Not sure if this is the best solution but it solves the mentioned problems
UPDATE
Less code version:
#students = #group.students
#students_exist = #group.students.includes(:attendances)
.where(attendances: { event_time_id: #event_id })
#students = #students - #students_exist

Rails Activerecord Ambiguous column name on .joins

Here is my code. It work fine if I have something in the :search field or if I have something in the :supplier field but if I have something in both i get "Ambiguous column name 'NUMBER'". Is there a way to select AS or something?
#date_from = params[:date_from] || Date.today.beginning_of_month.strftime('%m/%d/%Y')
#date_to = params[:date_to] || Date.today.strftime('%m/%d/%Y')
q = "%#{params[:search]}%"
#products = Product.where("DISCONT = ? AND NONPRODUCT = ?" ,0,0)
#products = #products.where('NUMBER like ?' ,q) if params[:search].present?
#products = #products.joins(:supplier_items).where('SUPPLIER = ?' ,params[:supplier]) if params[:supplier].present?
#products = #products.paginate(page: params[:page], per_page: 25)
Just prefix the number with the table name
For example:
#products = Product.where(:discount => 0, :nonproduct => 0)
#products = #products.where('products.number like ?', query)
I'm guessing your suppliers table and products table both have a column named "number". Honestly, you'd be best off running a migration to change the column names now (maybe supplier_num / product_num) because keeping it something as generic as "number" will likely keep causing you headaches.

Resources