开发者

has_many :through ,self referential association

I have trouble with the self referential association, the models should give ma an array of models for the left_chunks and right_chunks methods, but I get everytime an empty array

The source

class Chunk < ActiveRecord::Base
  has_many :left_bindings, :foreign_key => "left_chunk_id",
   :class_name => "ChunkChunk",
   :dependent => :destroy
  has_many :right_chunks, :through => :left_bindings
  has_many :right_bindings, :foreign_key => "right_chunk_id",
   :class_name => "ChunkChunk",
   :dependent => :destroy
  has_many :left_chunks, :through => :right_bindings
end

class ChunkChunk < ActiveRecord::Base
 belongs_to :left_chunk, :class_name => "Chunk", :foreign_key => "left_chunk_id"
 belongs_to :right_chunk, :class_name => "Chunk", :foreign_key => "right_chunk_id"
end

Output from ./script/console

>> #first case
?> 
?> left = Chunk.new({:content => "chunk_one"}); left.save
=> true
>> right = Chunk.new({:content => "chunk_two"}); right.save
=> true
>> left.right_chunks << right
=> []
>> left.right_chunks
=> []
>> left.left_chunks
=> []
>> 
?> #second case
?> 
?> left = Chunk.new({:content => "chunk_three"}); left.save
=> true
>> right = Chunk.new({:content => "chunk_four"}); right.save
=> true
>> right.left_chunks << left
=> []
>> right.left_chunks
=> []
>> right.right_chunks
=> []

Why are the chunks not bound together ?

Database after code execution

mysql> select * from chunks;
+----+-------------+---------------------+---------------------+
| id | content     | created_at          | updated_at          |
+----+-------------+---------------------+---------------------+
|  1 | chunk_one   | 2010-02-14 12:11:22 | 2010-02-14 12:11:22 | 
|  2 | chunk_two   | 2010-02-14 12:11:22 | 2010-02-14 12:11:22 | 
|  3 | chunk_three | 2010-02-14 12:11:22 | 2010-02-14 12:11:22 | 
|  4 | chunk_four  | 2010-02-14 12:11:22 | 2010-02-14 12:11:22 | 
+----+-------------+---------------------+---------------------+

mysql> select * from chunk_chunks;
+----+---------------+----------------+---------------------+---------------------+
| id | left_c开发者_开发问答hunk_id | right_chunk_id | created_at          | updated_at          |
+----+---------------+----------------+---------------------+---------------------+
|  1 |          NULL |              2 | 2010-02-14 12:11:22 | 2010-02-14 12:11:22 | 
|  2 |             3 |           NULL | 2010-02-14 12:11:22 | 2010-02-14 12:11:22 | 
+----+---------------+----------------+---------------------+---------------------+

Any ideas ?


You don't say what version of MySQL, Ruby or Rails you are on. I just tried this with a small test application and it worked correctly. I'm using PostgreSQL 8.4.1 on OS X 10.6. I just created an empty app on Rails 2.3.5 / Ruby 1.8.7 (2009-06-12 patchlevel 174) with "rails testapp", then added two models in chunk.rb:

class Chunk < ActiveRecord::Base
  has_many :left_bindings,  :foreign_key => "left_chunk_id",
                            :class_name => "ChunkChunk",
                            :dependent => :destroy
  has_many :right_chunks,   :through => :left_bindings
  has_many :right_bindings, :foreign_key => "right_chunk_id",
                            :class_name => "ChunkChunk",
                            :dependent => :destroy
  has_many :left_chunks,    :through => :right_bindings
end

...and chunk_chunks.rb:

class ChunkChunk < ActiveRecord::Base
 belongs_to :left_chunk,  :class_name => "Chunk", :foreign_key => "left_chunk_id"
 belongs_to :right_chunk, :class_name => "Chunk", :foreign_key => "right_chunk_id"
end

...plus two migrations to add the tables, without timestamps for brevity:

class AddChunks < ActiveRecord::Migration
  def self.up
    create_table 'chunks' do | t |
      t.string :content
    end
  end

  def self.down
    drop_table 'chunk'
  end
end

...and:

class AddChunkChunks < ActiveRecord::Migration
  def self.up
    create_table 'chunk_chunks' do | t |
      t.belongs_to :left_chunk
      t.belongs_to :right_chunk
    end
  end

  def self.down
  end
end

I then ran "rake db:create", "rake db:migrate" and your console commands worked for me as follows:

PondPro:testapp adh1003$ script/console
Loading development environment (Rails 2.3.5)
>> left = Chunk.new({:content => "chunk_one"}); left.save
=> true
>> right = Chunk.new({:content => "chunk_two"}); right.save
=> true
>> left.right_chunks << right
=> [#<Chunk id: 2, content: "chunk_two">]
>> left.right_chunks
=> [#<Chunk id: 2, content: "chunk_two">]
>> left.left_chunks
=> []
>> left = Chunk.new({:content => "chunk_three"}); left.save
=> true
>> right = Chunk.new({:content => "chunk_four"}); right.save
=> true
>> right.left_chunks << left
=> [#<Chunk id: 3, content: "chunk_three">]
>> right.left_chunks
=> [#<Chunk id: 3, content: "chunk_three">]
>> right.right_chunks
=> []

The database contents after the above were:

chunk-devel=# SELECT * FROM chunks;
 id |   content   
----+-------------
  1 | chunk_one
  2 | chunk_two
  3 | chunk_three
  4 | chunk_four
(4 rows)

chunk-devel=# SELECT * FROM chunk_chunks;
 id | left_chunk_id | right_chunk_id 
----+---------------+----------------
  1 |             1 |              2
  2 |             3 |              4
(2 rows)

Given this:

  • http://blog.hasmanythrough.com/2006/4/21/self-referential-through

...and this:

  • http://blog.hasmanythrough.com/2007/10/30/self-referential-has-many-through

...I can't see anything really wrong with your original code. Perhaps the migrations aren't what you expect, perhaps there are other parts of your code you have not posted which are interfering (e.g. filters, other gems) or perhaps the ActiveRecord database adapter for MySQL isn't doing the right things in this case and/or MySQL isn't performing properly. It is a little long-winded to install PostgreSQL and use that instead of MySQL for further tests, but I think it would be worthwhile.

Just in case it proves at all useful I've uploaded the test application data here:

  • http://pond.org.uk/misc/for_messages/chunks_testapp.tar.gz

If you find out what went wrong and manage to correct it, please post a follow-up here. This will be useful if anyone encounters similar trouble in future and reads this thread while searching for a solution.


Is this a .reload problem? After you do this in the console:

right.left_chunks << left

do

right.reload

then try

right.left_chunks.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜