2010-06-14 47 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