更新附加属性中的has_many,:通过使用关系的Rails [英] Updating extra attributes in a has_many, :through relationship using Rails

查看:98
本文介绍了更新附加属性中的has_many,:通过使用关系的Rails的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经成功地建立了一个多一对多以下机型之间的关系

I've managed to set up a many-to-many relationship between the following models

  • 字符
  • 技能
  • PlayerSkills

PlayerSkills,现在,有一个属性的技能通常不会有:水平

PlayerSkills, right now, has an attribute that Skills don't normally have: a level.

该机型是这个样子(编辑以简洁):

The models look something like this (edited for conciseness):

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

所以没有什么太花哨的车型... 该控制器也很基本的,在这一点上...这是pretty的很多股票更新操作。

So nothing too fancy in the models... The controller is also very basic at this point... it's pretty much a stock update action.

我在寻找要修改的形式是字符#编辑。 现在,它呈现了一系列复选框从字符添加/删除技能。 这是伟大的,但使用的has_many的整点:通过被跟踪级别以及

The form I'm looking to modify is characters#edit. Right now it renders a series of checkboxes which add/remove skills from the characters. This is great, but the whole point of using has_many :through was to track a "level" as well.

下面是我到目前为止有:

Here is what I have so far:

- 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。

After it renders "skill.name", I need it to print a text_field that updates player_skill.

的问题,当然,是player_skill可能或可能不存在! (具体取决于该箱子是当您加载的形式已经打勾!)

The problem, of course, is that player_skill may or may not exist! (Depending on if the box was already ticked when you loaded the form!)

这是我读过的一切,的has_many:通过是伟大的,因为它可以让你把关系本身作为一个实体......但我完全不知所措,如何处理实体以这种形式

From everything I've read, has_many :through is great because it allows you to treat the relationship itself as an entity... but I'm completely at a loss as to how to handle the entity in this form.

和往常一样,提前任何及所有感谢帮助您可以给我!

As always, thanks in advance for any and all help you can give me!

推荐答案

我,到目前为止,有固定的我是有这个问题...

I, so far, have fixed the problem I was having...

这实际上是相对简单的,一旦我了解了嵌套的属性!

It was actually relatively straight forward once I learned about nested attributes!

下面是新的人物模型!

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

和更新操作的字符控制器,轻度改变:

And the update action for the character controller was mildly changed:

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

的原因被,这两个部分已经由pre_update动作处理的,因此它们不需要通过update_attributes的再次处理,这被称为后

The reason being, those two portions are already handled by the pre_update action, therefore they don't need to be handled again by update_attributes, which gets called later.

的观点是相对简单的。在许多一对多复选框仍然是相同的,但是我没有添加新的文本框!

The view was relatively straight forward. the Many-to-Many checkboxes are still the same, I did however add the new textboxes!

- @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 = [] )中的人物模型,否则它不正确设置的顺序。

In essence, the reason I have to blank out skill_ids (skill_ids = []) in the Characters model is because otherwise it improperly sets the order.

在本质上,我加所有技能。
更新的水平,使用文本框。
然后重置技能,以用户实际检查(这将删除任何未使用的技巧。)

In essence, I add all the skills.
Update the levels, using the text-boxes.
Then reset the skills to what the user actually checked (which will delete any unused skills.)

我不觉得这是最大的解决方案 - 事实上,它的感觉相当的hackish给我。 因此,如果任何人想附和更好,更快地可能/更优雅的解决方案,随时!

I don't feel this is the greatest solution - in fact it feels rather hackish to me. So if anybody else wants to chime in with a better, possibly faster/more elegant solution, feel free!

否则,我希望这可以帮助别人......因为修改的连接表的附加属性(不给连接表自己的控制器/视图)是一个真正的痛苦!

Otherwise, I do hope this helps someone else... because modifying the extra attributes on the join table (without giving the join table its own controller/views) was a real pain!

这篇关于更新附加属性中的has_many,:通过使用关系的Rails的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆