我是 Rails 的初学者(刚刚完成 Hartl 的教程),我在处理某些类型的关联时遇到了麻烦,这些关联似乎比我迄今为止接触过的关联更复杂。我一直在 google 和 stackoverflow 上浏览我的问题的解决方案,但是虽然我找到了许多相关的答案,但我仍然不知道如何解决我的问题。
基本上我要做的是实现以下关系:
在研究了它之后,我想出的是:
楷模
# models/user.rb
class User < ActiveRecord::Base
attr_accessible :first_name, :last_name, :email …
has_many :speak, :class_name => "Speaks"
has_many :speaks, :through => :speak, :source => :language
has_many :want_to_learn, :class_name => "WantsToLearn"
has_many :wants_to_learn, :through => :want_to_learn, :source => :language
…
end
# models/language.rb
class Language < ActiveRecord::Base
attr_accessible :iso_639_1_code, :name_en, :name_fr, :name_pt
has_many :speak, :class_name => "Speaks"
has_many :users_who_speak, :through => :speak, :source => :user
has_many :want_to_learn, :class_name => "WantsToLearn"
has_many :users_who_want_to_learn, :through => :wants_to_learn, :source => :user
end
# models/speaks.rb
class Speaks < ActiveRecord::Base
set_table_name 'speak'
attr_accessible :level, :language
references :user
references :language
end
# models/wants_to_learn.rb
class WantsToLearn < ActiveRecord::Base
set_table_name 'want_to_learn'
attr_accessible :language
references :user
references :language
end
迁移
# db/migrate/20130210153328_create_speak.rb
class CreateSpeak < ActiveRecord::Migration
def change
create_table :speak do |t|
t.references :user
t.references :language
t.integer :level
t.timestamps
end
end
add_index :speak, :user
add_index :speak, :language
end
# db/migrate/20130210153342_create_want_to_learn.rb
class CreateWantToLearn < ActiveRecord::Migration
def change
create_table :want_to_learn do |t|
t.references :user
t.references :language
t.timestamps
end
end
add_index :want_to_learn, :user
add_index :want_to_learn, :language
end
当我这样做并尝试运行rake:db migrate
时,我收到以下错误:
-- add_index(:speak, :user)
rake aborted!
An error has occurred, this and all later migrations canceled:
PG::Error: ERROR: relation "speak" does not exist
: CREATE INDEX "index_speak_on_user" ON "speak" ("user")
...
如果我注释掉add_index
迁移成功运行的行,但我无法从用户创建“说话”关系。例如,如果我运行:
> john = User.new(first_name: "John", last_name: "Doe", email: "john@doe.com"...)
> john.speaks.create!(level: '6', language: '139')
我得到:
NoMethodError: undefined method `references' for #<Class:0x007ff14c1771a0>
我试图用“belongs_to”和其他一些东西替换所有“引用”,其中许多我什至不记得了,但无济于事。这在我的脑海中提出了几个疑问,例如:
• “references”真的和“belongs_to”一样吗?即使在模型的背景下?我已经看到迁移中使用了“引用”,但从未见过模型。
• 我是否正确使用了“class_name”?我真的对此没有信心。这正是我阅读完所有内容后最有意义的,但我还没有在这样的关联中看到任何自定义示例。
• 添加这些索引有什么问题?
好吧,我不知道这里的礼仪是什么,但我的最后一个问题是:
我该如何正确地做这一切?
先感谢您!
------编辑------
我到处都用“belongs_to”替换了关键字“references”。索引的迁移错误完全相同。当我评论索引创建行时,运行迁移,创建用户,然后尝试命令
> john.speaks.create!(level: 6, language: 139)
错误是:
ActiveModel::MassAssignmentSecurity::Error:
Can't mass-assign protected attributes: level, language
尽管行attr_accessible :level, :language
。