2010-06-14 20 views
2

我已經成功地建立了許多一對多以下車型之間的關係更新附加屬性的的has_many,:使用Rails

  • 通過人物關係
  • 技能
  • PlayerSkills

玩家技能,現在,有一個屬性,技能通常不具有:一級。

該機型是這個樣子(編輯爲簡潔起見):

class PlayerSkill < ActiveRecord::Base 
    belongs_to :character 
    belongs_to :skill 
end 

class Skill < ActiveRecord::Base 
    has_many :player_skills 
    has_many :characters, :through => :player_skills 

    attr_accessible :name, :description 
end 

class Character < ActiveRecord::Base 
    belongs_to :user 

    has_many :player_skills 
    has_many :skills, :through => :player_skills 
end 

所以沒有在模型過於花哨...... 控制器也是在這一點上是非常基本的...這是一個很值得股票更新行動。

我正在修改的表單是characters#edit。 現在它呈現一系列複選框,可以在角色中添加/刪除技能。 這很好,但是使用has_many:through的全部意義還在於跟蹤「級別」。

這是我到目前爲止有:

- form_for @character do |f| 
    = f.error_messages 
    %p 
    = f.label :name 
    %br 
    = f.text_field :name 
    %p 
    = f.label :race 
    %br 
    = f.text_field :race 
    %p 
    = f.label :char_class 
    %br 
    = f.text_field :char_class 
    %p 
    - @skills.each do |skill| 
     = check_box_tag "character[skill_ids][]", skill.id, @character.skills.include?(skill) 
     =h skill.name 
     %br 
    %p 
    = f.submit 

它呈現「skill.name」後,我需要它來打印text_field的更新player_skill。

問題當然是,player_skill可能存在也可能不存在! (取決於當你裝入表格時盒子是否已經打勾!)

從我讀過的所有東西,has_many:通過是偉大的,因爲它允許你把關係本身看作一個實體......但是,完全不知道如何處理這種形式的實體。

一如既往,在此先感謝您爲我提供的任何和所有幫助!

回答

0

我不知道答案,但在這裏就是我的想法:

對於控制器:

@character = Character.find(params[:id]) 

在視圖:

<% if @character.skills!=0 %> 
    <% for skill in @character.skills %> 
     <%=h skill.name %> 
     <%= check_box_tag(skill.name, value = "1", checked = false, options = {...}) %> 
    <% end %> 
<% end %> 

希望這將有助於!

1

我,到目前爲止,有固定的我有問題...

它實際上是相對簡單的,一旦我瞭解嵌套的屬性!

這裏是新的角色模型!

class Character < ActiveRecord::Base 
    belongs_to :user 

    has_many :player_skills 
    has_many :skills, :through => :player_skills 
    accepts_nested_attributes_for :player_skills 

    def skills_pre_update(params) 
    skills = Skill.find(:all, :order => 'id') 
    skills = skills.map do |skill| 
     skill.id 
    end 

    self.skill_ids = [] 
    self.skill_ids = skills 

    self.skill_ids.each_with_index do |skill_id, index| 
     self.player_skills[index].level = params[:character][:player_skills_attributes][index][:level] 
    end 

    self.skill_ids = params[:character][:skill_ids] 
    end 
end 

而且對於角色管理更新行動輕度改變:

@character.skills_pre_update(params) 
params[:character].delete(:player_skills_attributes) 
params[:character].delete(:skill_ids) 

其原因是,這兩個部分都已經被pre_update動作處理,因此他們並不需要處理再次通過update_attributes,稍後調用。

該觀點相對簡單。多對多複選框仍然是相同的,但是我添加了新的文本框!

- @skills.each_with_index do |skill,index| 
    = check_box_tag "character[skill_ids][]", skill.id, @character.skills.include?(skill) 
    =h skill.name 
    -ps = skill.player_skills.find_by_character_id(@character) || skill.player_skills.build 
    -fields_for "character[player_skills_attributes][]", ps do |psf| 
    =psf.text_field(:level, :index => nil) 
    =psf.hidden_field(:id, :index => nil) 

從本質上說,我要在人物模型,空出skill_ids(skill_ids = [])的原因是因爲否則不當,將訂購。

從本質上講,我添加了所有技能。
使用文本框更新級別。
然後重置技能,用戶實際檢查

我不覺得這是最大的解決方案(這將刪除任何未使用的技能。) - 事實上,它的感覺相當的hackish給我。 因此,如果任何其他人想用更好的,可能更快/更優雅的解決方案來叮噹作響,那麼請隨意!否則,我希望這可以幫助別人...因爲修改連接表上的額外屬性(不給連接表自己的控制器/視圖)是一個真正的痛苦!

+0

我想說明的是,您必須修改pre_update方法,以獲得所需的連接模型上的每個額外屬性。這顯然不理想。 – Robbie 2010-06-17 23:31:33

+0

你可以在集合上使用'fields_for'。它節省了大量的實現細節。 – hurikhan77 2010-10-10 00:42:03

+0

...和訂購問題。 – hurikhan77 2010-10-10 00:50:01