This project is archived and is in readonly mode.

#3667 ✓wontfix
Kent T

Array of records from ActiveRecord Association does not behave as expected

Reported by Kent T | January 7th, 2010 @ 05:37 PM

From my limited experience and knowledge of Ruby on Rails, it appears that an Array can perform just like an association array when it is created from an array of associated records.
Take the following example. (Though this is simple, it illustrates the point.)


Project has_and_belongs_to_many Contracts
Contract has_and_belongs_to_many Projects

@record = Project.first
all_contracts = @record.contracts
@cts = Contracts.find(:all, :limit=>5)

@cts.each do |c|
  all_contracts << c
end

Every record that is added to the all_contracts array is actually added to the @record.contracts association. It performs like I had called @record.contracts << c
In the console I can even see the records being inserted into the database.

My solution was like this:


@record = Project.first
all_contracts = Array.new()
all_contracts = all_contracts | @record.contracts
@cts = Contracts.find(:all, :limit=>5)

@cts.each do |c|
  all_contracts << c
end

My solution does not create any join records.

Is this a feature or a bug? Did I miss some documentation some where to this effect?

Comments and changes to this ticket

  • Matt Jones

    Matt Jones January 7th, 2010 @ 07:04 PM

    • State changed from “new” to “wontfix”

    This behavior is by design - @record.contracts doesn't actually return an Array, but an instance of AssociationCollection that mostly pretends to be an array. This lets you do things like:

    @record.contracts.exists?(@some_contract)
    

    which does a specific SQL query if @record.contracts isn't loaded yet, avoiding that database overhead. It also permits you to chain named scopes onto an association (@record.contracts.some_scope) and build/create associated records (with @record.contracts.build, etc.).

    If you really want to remove all the magic, @record.contracts.to_a will do what you're looking for.

  • Kent T

    Kent T January 7th, 2010 @ 07:31 PM

    I don't wish to remove any of the magic of @record.contracts.
    However, when I instantiate an array from @record.contracts, should the array be an Array or an instance of AssociationCollection?

    Example

    all_contracts = @record.contracts

    all_contracts would be an array

    @record.contracts would be an instance of AssociationCollection

    Interestingly enough, when I printed the class of all_contracts it shows as an array, but it behaves like AssociationCollection. This is what I don't understand.

  • Matt Jones

    Matt Jones January 7th, 2010 @ 09:32 PM

    This is a common gotcha in Ruby - objects are pretty much passed around as references. An example:

    a = [1,2,3]
    b = a
    a << 4
    b # => [1,2,3,4]
    

    So in your example, all_contracts is still an instance of AssociationCollection (although it fibs in the .class method and claims to be an Array). There are some ways to tell the two apart, though - all_contracts.respond_to?(:proxy_reflection) will return true, not that one typically needs to figure out that difference in standard Rails code.

    Anyway, if you have further questions, feel free to ask on the rails-talk list to avoid cluttering up Lighthouse.

  • Rohit Arondekar

    Rohit Arondekar October 7th, 2010 @ 05:21 AM

    • Tag changed from activerecord associations, habtm to activerecord, associations, habtm

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

<h2 style="font-size: 14px">Tickets have moved to Github</h2>

The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>

People watching this ticket

Pages