Rails has_many :通过简单形式的嵌套形式
Rails has_many :through nested forms with simple form
我正在尝试制作玩家角色生成器。我有一个表格,希望能让我将技能及其价值附加到角色 sheet 模型上。我做了这样的模型:
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
角色 sheet 模型包含有关玩家角色的数据,技能模型包含游戏中可用的所有技能。在 CharacterSheetSkill 中,我想存储玩家为其角色选择的技能以及设置技能值的整数字段。
打开表格时,我已经掌握了完整的数据库技能列表。我想在形式上做的就是创建一个角色 sheet,它具有所有这些技能并具有附加值。我尝试在表单中使用“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 %>
我如何制作该表格以便将字符 sheet 与 CharacterSheetSkills 一起保存?
这里一个更好的主意是使用 skills
作为规范化 table,您可以在其中存储技能的“主要”定义,例如名称和描述。
class CharacterSheetSkill < ApplicationRecord
belongs_to :skill
belongs_to :character_sheet
delegate :name, to: :skill
end
然后您使用 fields_for :character_sheet_skills
在联接 table 上显式创建行:
<%= 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 %>
如果你想让用户 select 技能,你可以使用 select 而不是隐藏字段。
当然,除非您“播种”输入,否则不会显示任何内容:
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
我正在尝试制作玩家角色生成器。我有一个表格,希望能让我将技能及其价值附加到角色 sheet 模型上。我做了这样的模型:
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
角色 sheet 模型包含有关玩家角色的数据,技能模型包含游戏中可用的所有技能。在 CharacterSheetSkill 中,我想存储玩家为其角色选择的技能以及设置技能值的整数字段。
打开表格时,我已经掌握了完整的数据库技能列表。我想在形式上做的就是创建一个角色 sheet,它具有所有这些技能并具有附加值。我尝试在表单中使用“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 %>
我如何制作该表格以便将字符 sheet 与 CharacterSheetSkills 一起保存?
这里一个更好的主意是使用 skills
作为规范化 table,您可以在其中存储技能的“主要”定义,例如名称和描述。
class CharacterSheetSkill < ApplicationRecord
belongs_to :skill
belongs_to :character_sheet
delegate :name, to: :skill
end
然后您使用 fields_for :character_sheet_skills
在联接 table 上显式创建行:
<%= 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 %>
如果你想让用户 select 技能,你可以使用 select 而不是隐藏字段。
当然,除非您“播种”输入,否则不会显示任何内容:
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