Rails has_many :通过简单形式的嵌套形式

Posted

技术标签:

【中文标题】Rails has_many :通过简单形式的嵌套形式【英文标题】:Rails has_many :through nested forms with simple form 【发布时间】:2020-12-13 20:58:44 【问题描述】:

我正在尝试制作一个玩家角色生成器。我有一个表格,希望能让我将技能及其值附加到角色表模型上。我做了这样的模型:

class CharacterSheet < ApplicationRecord
  has_many :character_sheet_skills, dependent: :destroy
  has_many :skills, through: :character_sheet_skills
  belongs_to :user

  accepts_nested_attributes_for :skills
end

class Skill < ApplicationRecord
  has_many :character_sheet_skills, dependent: :destroy
  has_many :character_sheets, through: :character_sheet_skills

  attr_reader :value
end

class CharacterSheetSkill < ApplicationRecord
  belongs_to :skill
  belongs_to :character_sheet
end

角色表模型包含有关玩家角色的数据,技能模型包含游戏中可用的所有技能。在 CharacterSheetSkill 中,我想存储玩家为其角色选择的技能以及设置技能值的整数字段。

打开表格时,我已经在数据库中拥有完整的技能列表。我想要做的只是创建一个角色表,其中包含所有这些具有附加值的技能。我尝试在表单中使用“fields_for”,但我无法真正让它发挥作用。现在它看起来像这样:

<%= simple_form_for [@user, @sheet] do |f| %>
    <%= f.input :name %>
    <%= f.input :experience, readonly: true, input_html: 'data-target': 'new-character-sheet.exp', class: 'bg-transparent' %>
...
    <%= f.simple_fields_for :skills do |s| %>
      <%= s.input :name %>
      <%= s.input :value %>
    <% end %>
<% end %>

如何制作该表格以便将字符表与 CharacterSheetSkills 一起保存?

【问题讨论】:

【参考方案1】:

这里一个更好的主意是使用skills 作为规范化表,您可以在其中存储技能的“主”定义,例如名称和描述。

class CharacterSheetSkill < ApplicationRecord
  belongs_to :skill
  belongs_to :character_sheet
  delegate :name, to: :skill
end

然后您使用fields_for :character_sheet_skills 在连接表上显式创建行:

<%= f.fields_for :character_sheet_skills do |cs| %>
  <fieldset>
    <legend><%= cs.name %></legend>
    <div class="field">
      <%= cs.label :value %>
      <%= cs.number_field :value %>
    </div>
    <%= cs.hidden_field :skill_id %>
  </fieldset>
<% end %>

如果您想让用户选择技能,您可以使用选择来代替隐藏字段。

当然,除非您“播种”输入,否则什么都不会显示:

class CharacterSheetController < ApplicationController
  def new
    @character_sheet = CharacterSheet.new do |cs|
      # this seeds the association so that the fields appear
      Skill.all.each do |skill|
        cs.character_sheet_skills.new(skill: skill)
      end
    end
  end

  def create
    @character_sheet = CharacterSheet.new(character_sheet_params)
    if @character_sheet.save
      redirect_to @character_sheet
    else
      render :new
    end
  end

  private
  def character_sheet_params
    params.require(:character_sheet)
          .permit(
             :foo, :bar, :baz,
             character_sheet_skill_attributes: [:skill_id, :value]
          )
  end
end

【讨论】:

代码似乎完全符合我的需要!谢谢,我可能永远不会想到那个地方的委托人。

以上是关于Rails has_many :通过简单形式的嵌套形式的主要内容,如果未能解决你的问题,请参考以下文章

Rails has_many,如何实现嵌套关联?

带有has_many的Rails嵌套表单:通过,如何编辑连接模型的属性?

使用带有 Rails 的改革 gem,我如何填充 has_many :通过嵌套模型

Rails:如何通过 has_many 进行优雅的调用

在has_many中过滤子对象:通过Rails 3中的关系

ruby-on-rails - 嵌套资源问题