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