Rails 3.0 with an "or" operator in each loop

I am trying to build a query that compares two objects, and if they have the same id , the record is not retrieved. I have it:

 @channels.each do |channel| unless @guide_channels.where(:id => channel.id).exists? @dropdown_channels = @dropdown_channels.where(:id => channel.id) end end 

This creates a query, but places AND between each value, which is not what I mean. I want an "or" operator. Is there a "or where" function that I can use, or is there a better way to do this with some comparison function?

+4
source share
2 answers

The fact is that the .where() method of AR::Relation objects adds a condition to a set of conditions, which are then AND -ed together when the query is executed.

What you need to do is a query like NOT IN :

 # select all the ids for related @guide_channels # if @channels comes from a query (so it a ActiveRecord::Relation): guide_ids = @guide_channels.where(:id => @channels.pluck(:id)).pluck(:id) # use .where(:id => @channels.map {|c| c.id}) instead if @channels is just an array # then use the list to exclude results from the following. @dropdown_channels = @dropdown_channels.where("id NOT IN (?)", guide_ids.to_a) 

The first request will accumulate all identifiers for channels that have an entry in @guide_channels . The second will use the result of the first to exclude the found channels from the results for the drop-down list.

+1
source

This strange behavior is due to the lazy evaluation of ActiveRecord areas. It happens that the string

 @dropdown_channels = @dropdown_channels.where(:id => channel.id) 

It does not send a query to the database until you actually use the @dropdown_channels value, and when you do this, all states are combined into one large query, so you get AND between the conditions.

To force ActiveRecord to be loaded into scope, you can use the all scope or the first scope, for example:

 @dropdown_channels = @dropdown_channels.where(:id => channel.id).first 

This will force ActiveRecord to compute the query in place, returning the result immediately and not accumulate areas for lazy evaluation.

Another approach may be to accumulate all these channel_ids and get them later in one request, instead of making a request for each of them. This approach is more cost effective with respect to database resources. For this:

 dropdown_channels_ids = [] @channels.each do |channel| unless @guide_channels.where(:id => channel.id).exists? dropdown_channels_ids << channel.id end end @dropdown_channels = @dropdown_channels.where(:id => dropdown_channels_ids) 
0
source

Source: https://habr.com/ru/post/1443228/


All Articles