views:

116

answers:

3

I need to check, if for each item in @line_items if it is in different array say @quote_items

Controller:

def index
  @line_items = LineItem.all
  @quote_items = QuoteItem.all
end

View:

<% for line_item in @line_items %>
   <% if @quote_items.include?(line_item) %>
     line_item in quote item! 
   <% else %>
     line_item NOT in quote item! 
   <% end %>
...
<% end %>

Is there an easy way to do this? include? doesn't seem to work the way I want. Seems to just yield false for me all the the time.

+1  A: 

@line_items & @quote_items should return an array that includes the common items between them. @line_items - @quote_items return items that are in @line_items but not in @quote_items.Your code should work though, are you sure there are common items between them? Note that item equality is checked by the == operator, so you might need to provide that for your item class.

Firas Assaad
+2  A: 

You are right it will always return false because you are trying to check if the array of @quote_items has a line item object

@quote_items.include?(line_item)

which obviously will always be false because your @quote_items instance is an array of QuoteItem objects and @line_items instance is an array of LineItem object. So they are always different objects.

I think in this situation you may want to compare some common attribute of quote_item and line_item. For example if you want to compare name attribute then

quote_item_names = @quote_items.map(&:name)

and then

<% if quote_item_names.include?(line_item.name) %>
 line_item in quote item! 
<% else %>
 line_item NOT in quote item! 
<% end %>
nas
`QuoteItem` could be a superclass of `LineItem` (or vice versa), so they could actually be the same object.
Peter
Well yah, pretty much, basically, my `line_items` have id's and if the object also exists in another array (in this case `@quote_items`) I want the html output to contain an additional element, hence the view code I provided... uhh.. I think I just don't know hoe to explain myself.
Joseph Silvashy
When you instantiate / create an object then you get the object id and the object, something like #<LineItem:0x1789dc @name="queue"> for line item and like #<QueueItem:0x193ee4 @name="queue"> for queue item assuming they have only one attribute called name.So whenever you will do a comparison of these two objects it will always be false because they are not same whether you inherit one from the other. Moreover the subclass can be way different from the superclass by having its own state and behaviour in addition to inheriting all attributes and behaviour of the supper class. Makes sense ?
nas
@jpsilvashy you are creating line_object from LineObject class and quote_item from QuoteItem class. They may have same attributes and behave similarly for you but you are creating them from different class / types ie LineItem and QuoteItem hence ruby will consider them different
nas
Well yah! they are meant to be different, but I want to see if the id (literally its primary key), in the DB matches with a value in my array `@quote_items`, and specifically it's key `@quote_items.original_id`
Joseph Silvashy
nas
+1  A: 

Like it was pointed out in discussion above — it depends on which criterion you're comparing objects in 2 arrays.

  • If objects are of the same class (or the same ancestor), then include? will work.
  • If objects are different, and you only want to compare their ids (although this makes little sense), it'd be something like this:

    line_item_ids = @line_items.map(&:id) # array of just the attribute we need
    @quote_items.each do |quote_item|
      if line_item_ids.include?(quote_item.id)
        # line item with the same id found
      else
        # ...
      end
    end
    

    You can do the above with any attribute, not just id.

  • If in both cases your objects are plain strings or symbols, make sure you're converting everything to string or symbol. Sometimes I forget and comparisons end up being false.

hakunin
Excellent answer and well written! Thanks very much, worked exactly expected.
Joseph Silvashy
I wish I could mark both of you as the answer... but I gave it to Nasir, because he needs to catch up and get some points, and he answered first!
Joseph Silvashy