1

我是Rails的初学者(刚完成Hartl的教程),而且我遇到了一些类型的关联,这些关联似乎比我更复杂一些到目前为止已经暴露。我一直在浏览谷歌和stackoverflow为我的问题的解决方案,但虽然我发现很多相关的答案,我仍然无法弄清楚如何解决我的问题。与Rails 3.2上的自定义表名的多对多关系

基本上我试图做的是实现以下关系:

ER diagram

什么,我想出了是研究一下后:

模式

# 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: "[email protected]"...) 

> john.speaks.create!(level: '6', language: '139') 

我得到:

NoMethodError: undefined method `references' for #<Class:0x007ff14c1771a0> 

我试图取代所有的“引用”与“belongs_to的”等几件事情,其中​​有许多我不知道甚至记住,但无济于事。这在我的脑海中引起了一些疑问,如:

•“引用”与“belongs_to”是否真的相同?即使在模型的情况下?我已经看到“参考”被用于迁移,但从来没有模型。

•我正确使用“class_name”吗?我对此确实没有信心。这正是我读过的所有东西之后最有意义的东西,但我还没有看到任何像这样的关联中定制的例子。

•添加这些索引有什么问题?

和好了,我不知道这里的礼仪,但我的最后一个问题是:

如何做到这一切正常?

预先感谢您!

------ 编辑 ------

我替换的关键字 “引用” 与 “belongs_to的” 无处不在。有关索引的迁移错误完全相同。当我评论索引创建线路,运行迁移,创建一个用户,然后尝试命令

> john.speaks.create!(level: 6, language: 139) 

的错误是:

ActiveModel::MassAssignmentSecurity::Error: 
Can't mass-assign protected attributes: level, language 

尽管线attr_accessible :level, :language的。

回答

1

好的。我终于设法让所有的工作都能够正常工作,我认为社区放弃未解决的问题并不是很有建设性。我的代码现在完美工作,它包括我为了允许嵌套窗体而必须添加的内容。下面是它的外观:

模式

# models/user.rb 
class User < ActiveRecord::Base 
    attr_accessible :first_name, :last_name, :email, ... , 
    :speaks_attributes, :wants_to_learn_attributes 
    # These last two attributes are necessary for nested forms 

    has_many :speaks, :class_name => "Speaks", :dependent => :destroy 
    accepts_nested_attributes_for :speaks, :allow_destroy => true # this one too 
    has_many :speaks_languages, :through => :speaks, :source => :language 

    has_many :wants_to_learn, :class_name => "WantsToLearn", :dependent => :destroy 
    accepts_nested_attributes_for :wants_to_learn, :allow_destroy => true # and this one too 
    has_many :wants_to_learn_languages, :through => :wants_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 => :want_to_learn, :source => :user 
end 

# models/speaks.rb 
class Speaks < ActiveRecord::Base 
    set_table_name 'speak' 
    attr_accessible :language, :language_id, :level 
    belongs_to :user 
    belongs_to :language 
end 

# models/wants_to_learn.rb 
class WantsToLearn < ActiveRecord::Base 
    set_table_name 'want_to_learn' 
    attr_accessible :language, :language_id 
    belongs_to :user 
    belongs_to :language 
end 

迁移

# db/migrate/20130210153328_create_speak.rb 
class CreateSpeak < ActiveRecord::Migration 
    def change 
    create_table :speak, :id => false do |t| 
     t.belongs_to :user 
     t.belongs_to :language 
     t.integer :level 

     t.timestamps 
    end 
    add_index :speak, :user_id 
    add_index :speak, :language_id 
    end 
end 


# db/migrate/20130210153342_create_want_to_learn.rb 
class CreateWantToLearn < ActiveRecord::Migration 
    def change 
    create_table :want_to_learn, :id => false do |t| 
     t.belongs_to :user 
     t.belongs_to :language 

     t.timestamps 
    end 
    add_index :want_to_learn, :user_id 
    add_index :want_to_learn, :language_id 
    end 
end 

在迁移我把 “add_index” 线内 “DEF改变” 块原因我最后一次被愚蠢地分散在外面,并分别将“user”和“language”改为“user_id”和“language_id”。这解决了它。

现在我可以创建一个用户ariel,并让他讲葡萄牙语和法语运行:

运行
> ariel.speaks.create!(language_id: 129, level: 6) 
> ariel.speaks.create!(language_id: 50, level: 4) 

然后,我可以用ariel在“说话”表中获取相关的条目:

> ariel.speaks 
=> [#<Speaks id: 1, user_id: 1, language_id: 129, level: 6, created_at: "2013-02-25 19:30:01", updated_at: "2013-02-25 19:30:01">, #<Speaks id: 4, user_id: 1, la 
nguage_id: 50, level: 4, created_at: "2013-02-26 12:37:34", updated_at: "2013-02-26 12:37:34">] 

而在 “语言” 表中的项目运行:

> ariel.speaks_languages 
=> [#<Language id: 50, iso_639_1_code: "fr", name_en: "French", name_fr: "français\n", name_pt: nil>, #<Language id: 129, iso_639_1_code: "pt", name_en: "Portugu 
ese", name_fr: "portugais\n", name_pt: nil>] 

该过程类似于wants_to_learn关联。

1

我是Rails中的引用关键字的新手,但是我在Rails指南中看到了它的迁移,但不是在类中,因此请勿在类中使用它。

因此,它与belongs_to不同,因为belongs_to用于类中,并且引用用于迁移。

创建索引时,迁移会关心类中的关联对我而言也是新的。

+0

嘿,谢谢你的快速回答。我将所有出现的“引用”都改为“belongs_to”。我编辑了添加此更改结果的问题。 – Ariel 2013-02-24 13:05:11