brad
brad

Reputation: 1695

removing objects from an array during a loop

I am trying to filter the results of an user search in my app to only show users who are NOT friends. My friends table has 3 columns; f1 (userid of person who sent request), f2 (userid of friend who received request), and confirmed (boolean of true or false). As you can see, @usersfiltered is the result of the search. Then the definition of the current user's friend is established. Then I am trying to remove the friends from the search results. This does not seem to be working but should be pretty straight forward. I've tried delete (not good) and destroy.

def index

#THIS IS THE SEARCH RESULT

@usersfiltered = User.where("first_name LIKE?", "%#{params[:first_name]}%" )

#THIS IS DEFINING ROWS ON THE FRIEND TABLE THAT BELONG TO CURRENT USER

@confirmedfriends = Friend.where(:confirmed => true)
friendsapproved = @confirmedfriends.where(:f2 => current_user.id)
friendsrequestedapproved = @confirmedfriends.where(:f1 => current_user.id)

#GOING THROUGH SEARCH RESULTS
@usersfiltered.each do |usersfiltered|

  if friendsapproved.present?
    friendsapproved.each do |fa|
      if usersfiltered.id == fa.f1
 #NEED TO REMOVE THIS FROM RESULTS HERE SOMEHOW
          usersfiltered.remove
      end
    end
  end
#SAME LOGIC
  if friendsrequestedapproved.present?
    friendsrequestedapproved.each do |fra|
      if usersfiltered.id == fra.f2
          usersfiltered.remove
      end
    end
  end

  end

end

Upvotes: 1

Views: 1304

Answers (2)

Peter Alfvin
Peter Alfvin

Reputation: 29399

While I agree that there may be better ways to implement what you're doing, I think the specific problem you're facing is that in Rails 4, the where method returns an ActiveRecord::Relation not an Array. While you can use each on a Relation, you cannot in general perform array operations.

However, you can convert a Relation to an Array with the to_a method as in:

@usersfiltered = User.where("first_name LIKE?", "%#{params[:first_name]}%" ).to_a

This would then allow you to do the following within your loop:

usersfiltered.delete(fa)

Upvotes: 1

lurker
lurker

Reputation: 58244

I would flip it around the other way. Take the logic that is loop-invariant out of the loop, which gives a good first-order simplification:

approved_ids = []
approved_ids = friendsapproved.map { |fa| fa.f1 } if friendsapproved.present?
approved_ids += friendsrequestedapproved.map { |fra| fra.f2 } if friendsrequestedapproved.present?
approved_ids.uniq!  # (May not be needed)
@usersfiltered.delete_if { |user| approved_ids.include? user.id }

This could probably be simplified further if friendsapproved and friendsrequestedapproved have been created separately strictly for the purpose of the deletions. You could generate a single friendsapproval list consisting of both and avoid unioning id sets above.

Upvotes: 1

Related Questions