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