Array find vs. ActiveRecord find

Hey,

So I have a Page object with a to-many relationship to PagePart like
this:

  has_many :parts, :class_name => 'PagePart', :dependent => :destroy

and due to this if I have a Page object called @page

@page.parts gives me an array of PagePart objects
I know this because if I do

logger.debug @page.parts.class

I see that the class is Array.

So now I look up the Ruby API and I find this nice find method:

Passes each entry in enum to block. Returns the first for which block
is not false. If no object matches, calls ifnone and returns its result
when it is specified, or returns nil

   (1..10).detect {|i| i % 5 == 0 and i % 7 == 0 } #=> nil
   (1..100).detect {|i| i % 5 == 0 and i % 7 == 0 } #=> 35

So, I figure I can do:

@page.parts.find { |part| part.name = "some_name" }

But noooo

apparently the correct way to do this is:

@page.parts.find_by_name( "some_name" )

according to my error messages @page.parts.find expects only one
argument and it should be an id
so it's basically find_by_id

So I would use:
@page.parts.find_by_name

But this does a fresh SQL select and gives me different PagePart
objects than exist in the @page.parts array

ahhh!!!

So, please somebody help me figure out how I can get that find method
to work on @page.parts
so that I get the objects already in the @page.parts array instead of
fresh copies of those objects from the DB.

thanks,
Jacob

Here's a code example of how I had to solve this problem. Kinda
ugly... what would be prettier?

This is the original code that did the right thing but ended up with
PagePart objects that weren't equivalent to the objects in @page.parts

        (params[:part] || {}).values.each do |v|
          array_of_page_parts = @page.parts
          if part = @page.parts.find_by_name(v[:name])
            part.attributes = part.attributes.merge(v)
            parts_to_update << part
          else
            @page.parts.build(v)
          end
        end

This is how I had to change the code in order for PagePart objects
within the loop to be exactly the same objects that are in @page.parts

        values = (params[:part] || {}).values
        @page.parts.each do |part|
          if value = values.find { |v| v[:name] == part.name}
            part.attributes = part.attributes.merge(value)
            parts_to_update << part
            values.delete(value)
            logger.debug("updating page part" + value.to_s)
          end
        end
        values.each do |value|
          logger.debug("creating page part" + value.to_s)
          @page.parts.build(value)
        end

igotimac@gmail.com wrote:

So I have a Page object with a to-many relationship to PagePart like
this:

  has_many :parts, :class_name => 'PagePart', :dependent => :destroy

and due to this if I have a Page object called @page

@page.parts gives me an array of PagePart objects
I know this because if I do

logger.debug @page.parts.class

I see that the class is Array.

It's reallly of class ActiveRecord::Associations::AssociationCollection,
but has been heavily proxied to act as an Array. One way to see this:

script/runner 'puts ActiveRecord::Associations::AssociationCollection === Page.find(:first).parts'

So now I look up the Ruby API and I find this nice find method:

Passes each entry in enum to block. Returns the first for which block
is not false. If no object matches, calls ifnone and returns its result
when it is specified, or returns nil

   (1..10).detect {|i| i % 5 == 0 and i % 7 == 0 } #=> nil
   (1..100).detect {|i| i % 5 == 0 and i % 7 == 0 } #=> 35

So, I figure I can do:

@page.parts.find { |part| part.name = "some_name" }

But noooo

apparently the correct way to do this is:

@page.parts.find_by_name( "some_name" )

according to my error messages @page.parts.find expects only one
argument and it should be an id
so it's basically find_by_id

So I would use:
@page.parts.find_by_name

But this does a fresh SQL select and gives me different PagePart
objects than exist in the @page.parts array

ahhh!!!

So, please somebody help me figure out how I can get that find method
to work on @page.parts
so that I get the objects already in the @page.parts array instead of
fresh copies of those objects from the DB.

@page.parts.to_ary.find { |part| part.name = "some_name" }

@page.parts.to_ary.find { |part| part.name = "some_name" }

this should be @page.parts.to_ary.find{|part| part.name == "some_name"}

the comparison operator is necessary for a find, if you use =, then you
will set the attribute to the value.

Chris Drappier wrote in post #738922:

@page.parts.to_ary.find { |part| part.name = "some_name" }

this should be @page.parts.to_ary.find{|part| part.name == "some_name"}

the comparison operator is necessary for a find, if you use =, then you
will set the attribute to the value.

I meet a same question,

User has_many Word has_many tag

I need the words has a tag 'fruit'.

I do this:

@User.word.find_all do | word |

  if word.tags.find_by_name('fruit')
    word.id
  end

end