创建两个has_many :through记录

4
我有模型。
class Question < ActiveRecord::Base
  WEIGHTS = %w(medium hard easy)

  belongs_to :test
  has_many :answers, :dependent => :destroy
  has_many :testing_questions
end

class Testing < ActiveRecord::Base
  belongs_to :student, :foreign_key => 'user_id'
  belongs_to :subtest
  has_many :testing_questions, :dependent => :destroy
  has_many :questions, :through => :testing_questions
end

当我试图在创建测试时将问题绑定到测试上时:
>> questions = Question.all
...
>> questions.count
=> 3
>> testing = Testing.create(:user_id => 3, :subtest_id => 1, :questions => questions)
  Testing Columns (0.9ms)   SHOW FIELDS FROM `testings`                              
  SQL (0.1ms)   BEGIN                                                                
  SQL (0.1ms)   COMMIT                                                               
  SQL (0.1ms)   BEGIN                                                                
  Testing Create (0.3ms)   INSERT INTO `testings` (`created_at`, `updated_at`, `user_id`, `subtest_id`) VALUES('2010-05-18 00:53:05', '2010-05-18 00:53:05', 3, 1)                                                                                                                                                        
  TestingQuestion Columns (0.9ms)   SHOW FIELDS FROM `testing_questions`                                                                                     
  TestingQuestion Create (0.3ms)   INSERT INTO `testing_questions` (`question_id`, `created_at`, `updated_at`, `testing_id`) VALUES(1, '2010-05-18 00:53:05', '2010-05-18 00:53:05', 31)                                                                                                                                  
  TestingQuestion Create (0.4ms)   INSERT INTO `testing_questions` (`question_id`, `created_at`, `updated_at`, `testing_id`) VALUES(2, '2010-05-18 00:53:05', '2010-05-18 00:53:05', 31)                                                                                                                                  
  TestingQuestion Create (0.3ms)   INSERT INTO `testing_questions` (`question_id`, `created_at`, `updated_at`, `testing_id`) VALUES(3, '2010-05-18 00:53:05', '2010-05-18 00:53:05', 31)                                                                                                                                  
  TestingQuestion Create (0.3ms)   INSERT INTO `testing_questions` (`question_id`, `created_at`, `updated_at`, `testing_id`) VALUES(1, '2010-05-18 00:53:05', '2010-05-18 00:53:05', 31)                                                                                                                                  
  TestingQuestion Create (0.3ms)   INSERT INTO `testing_questions` (`question_id`, `created_at`, `updated_at`, `testing_id`) VALUES(2, '2010-05-18 00:53:05', '2010-05-18 00:53:05', 31)                                                                                                                                  
  TestingQuestion Create (0.3ms)   INSERT INTO `testing_questions` (`question_id`, `created_at`, `updated_at`, `testing_id`) VALUES(3, '2010-05-18 00:53:05', '2010-05-18 00:53:05', 31)                                                                                                                                  
  SQL (90.2ms)   COMMIT                                                                                                                                      
=> #<Testing id: 31, subtest_id: 1, user_id: 3, created_at: "2010-05-18 00:53:05", updated_at: "2010-05-18 00:53:05">

有6个SQL查询并且测试问题中创建了6条记录。为什么呢?

你的 TestingQuestion 模型长什么样? - nathanvda
5个回答

2
我已经创建了一个非常简单的示例来处理您的示例:

我已经创建了一个非常简单的示例来处理您的示例:

class Question < ActiveRecord::Base
  has_many :testing_questions
end

class Testing < ActiveRecord::Base
  has_many :testing_questions
  has_many :questions, :through => :testing_questions
end

class TestingQuestion < ActiveRecord::Base
  belongs_to :question
  belongs_to :testing
end

然后我只需要执行以下操作,就不会创建重复记录:

Loading development environment (Rails 2.3.5)
>> q1 = Question.new
=> #<Question id: nil, title: nil, ask: nil, created_at: nil, updated_at: nil>
>> q1.title = "Dit is de eerste vraag"
=> "Dit is de eerste vraag"
>> q2 = Question.new
=> #<Question id: nil, title: nil, ask: nil, created_at: nil, updated_at: nil>
>> q2.title = "Dit is de tweede vraag"
=> "Dit is de tweede vraag"
>> q1.save
=> true
>> q2.save
=> true
>> tt = Testing.new
=> #<Testing id: nil, name: nil, description: nil, action: nil, created_at: nil, updated_at: nil>
>> tt.questions
=> []
>> tt.name = "Test1"
=> "Test1"
>> tt.questions << q1
=> [#<Question id: 1, title: "Dit is de eerste vraag", ask: nil, created_at:   "2010-05-18 19:40:54", updated_at: "2010-05-18 19:40:54">]
>> tt.questions << q2
=> [#<Question id: 1, title: "Dit is de eerste vraag", ask: nil, created_at: "2010-05-18 19:40:54", updated_at: "2010-05-18 19:40:54">, #<Question id: 2, title: "Dit is de tweede vraag", ask: nil, created_at: "2010-05-18 19:40:59", updated_at: "2010-05-18 19:40:59">]
>> tt.testing_questions
=> []
>> tt.save
=> true
>> tt.testing_questions
=> [#<TestingQuestion id: 1, question_id: 1, testing_id: 1, extra_info: nil, created_at: "2010-05-18 19:41:43", updated_at: "2010-05-18 19:41:43">, #<TestingQuestion id: 2, question_id: 2, testing_id: 1, extra_info: nil, created_at: "2010-05-18 19:41:43", updated_at: "2010-05-18 19:41:43">]
>>

实际上这与你所拥有的完全相同,除了测试问题(你没有展示)。这能帮到你吗?


我看到你的例子里一切都没问题。TestingQuestion模型和你的完全一样...但是我绑定相关记录到测试的方式不同。我试图在创建Testing时进行绑定。 - Antiarchitect
是的,但这不应该有任何影响,只有在保存时才会创建TestingQuestion。我假设在您的示例中编写Testing.create,您仍然需要显式调用save。对吗?我需要这样做。我正在针对Rails 2.3.5进行测试。另外:我看到我的TestingQuestion有一个id,这是不必要的。 - nathanvda

0

首先可能存在的问题是您的连接表命名

testing_questions

Rails 期望联结表的名称是按字母顺序连接两个表名的结果。
question_testings

我知道,但是有 has_many :testing_questions, :dependent => :destroy 和 has_many :questions, :through => :testing_questions。我认为这已经足够确定中间表了。 - Antiarchitect
我认为尽管如此,您仍需使用 set_table_name 来使用传统的表命名方式。 - tommasop
这不是真的:表名是从模型名称派生出来的。如果模型名称是TestingQuestion,则表名将为testing_questions。使用:through,您可以明确指定联接表模型的名称。 - nathanvda

0

从表结构来看,这是两个表之间的has_and_belongs_to_many关系,这里不需要使用has_many和through选项,因为您的连接表不会有一个模型(除了id之外没有其他列)。无需为连接表创建模型。

因此,我建议像这样更改您的模型

<br>
class Question < ActiveRecord::Base<br>
  WEIGHTS = %w(medium hard easy)
  belongs_to :test<br>
  has_many :answers, :dependent => :destroy<br>
  has_and_belongs_to_many :question_testings 
end

class Testing < ActiveRecord::Base
belongs_to :student, :foreign_key => 'user_id' belongs_to :subtest has_and_belongs_to_many :question_testings end

请将您的表名更改为 question_testings。

请查看此链接以了解更多信息 http://guides.rubyonrails.org/association_basics.html#choosing-between-has-many-through-and-has-and-belongs-to-many


我不想使用过时的has_and_belongs_to_many,我想使用has_many :through。更改方案或类似的东西可能是问题的解决方案,但问题已经解决,现在我想知道为什么Rails这样做。 - Antiarchitect
你能告诉我在控制台中显示 SQL 查询的宝石或插件是哪个吗?你可不可以分享一下你的解决方案? - Vamsi
我不记得确切的内容,但请尝试将此文件添加到您的主目录中:http://gist.github.com/405733 - Antiarchitect
@antiarchitect:在控制台中记录日志,可以通过将此代码添加到~/.irbrc文件中来完成。所有项目都将具有该功能。如果ENV包含('RAILS_ENV')&&!Object.const_defined?('RAILS_DEFAULT_LOGGER'); 需要“logger”; RAILS_DEFAULT_LOGGER = Logger.new(STDOUT); 结束; - Ram on Rails React Native

0

不看Rails源代码或尝试,我建议尝试从Question类中删除“has_many:testing_questions”或在那里添加一个has_many ...:through。现在Rails只与连接表有关系,而不是从那一侧的“真正”目标。

连接表的名称在这里不应该引起任何问题。


0

你的questions数组包含3个项目。当你创建一个Testing实例并指定使用:questions => questions来创建它时,它将把它们添加到questions关系中,但由于这个关系是通过另一个关系进行的,所以它们必须先添加到另一个关系中,结果导致它们被插入两次。通常,你会有一些其他模型来表示连接表,这样你就可以在Questions表中插入3条记录,同时在TestingQuestions连接表(has_many:through)中也插入3条记录。

在我看来,这似乎是你定义TestingQuestions模型的问题,你没有展示它。例如,它是否指向与Questions模型相同的表?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接