如何在创建Recipe记录时自动生成has_many through关联的RecipeSeason数据
解决has_many through关联下创建Recipe时自动生成关联记录的问题
需求说明
在创建Recipe记录的同时,自动在recipe_seasons表插入一条关联记录:
recipe_id使用新生成的Recipe的IDseason_id采用硬编码的@month值(此处固定为1)
现有代码
模型代码
Recipe模型
class Recipe < ApplicationRecord attribute :name attribute :published has_many :ingridients, dependent: :destroy has_many :instructions, dependent: :destroy has_many :recipe_seasons has_many :seasons, through: :recipe_seasons accepts_nested_attributes_for :recipe_seasons validates_presence_of :name end
Season模型
class Season < ApplicationRecord has_many :recipe_seasons has_many :recipes, through: :recipe_seasons end
RecipeSeason模型
class RecipeSeason < ApplicationRecord belongs_to :recipe belongs_to :season validates_presence_of :recipe validates_presence_of :season accepts_nested_attributes_for :season end
控制器代码
def new @month = 1 @recipe = Recipe.new @recipe.recipe_seasons.build(season_id: @month).build_recipe end def create @recipe = Recipe.new(recipe_params) @recipe.save redirect_to recipes_path flash[:notice] = I18n.t("recipe.created") end private def recipe_params params.require(:recipe) .permit(:name, :published, recipe_seasons_attributes:[:recipe_id, :season_id ]) end
表单代码
<%= form_with(model: @recipe) do |f| %> <%= f.label :name %> <%= f.text_field :name, required: true %> <%= f.label :published %> <%= f.check_box :published, class: "form-control", placeholder: "Tick if done" %> <%= f.submit %> <% end %> <%=link_to t("back"), recipes_path %>
解决方案
提供两种实现方式,按需选择:
方式一:手动创建关联记录(更直接)
这种方式无需修改表单,直接在Recipe保存后创建关联:
- 调整控制器
new方法:
def new @month = 1 @recipe = Recipe.new end
- 修改控制器
create方法:
def create @month = 1 @recipe = Recipe.new(recipe_params) if @recipe.save # 自动创建关联记录 @recipe.recipe_seasons.create(season_id: @month) flash[:notice] = I18n.t("recipe.created") redirect_to recipes_path else # 处理保存失败的情况,渲染表单页面 render :new end end
- 简化参数白名单:
private def recipe_params params.require(:recipe).permit(:name, :published) end
方式二:使用嵌套属性(通过表单传递)
这种方式利用Rails嵌套属性特性,通过隐藏字段传递season_id:
- 调整控制器
new方法:
def new @month = 1 @recipe = Recipe.new # 预构建关联,用于生成表单字段 @recipe.recipe_seasons.build(season_id: @month) end
- 修改表单,添加嵌套隐藏字段:
<%= form_with(model: @recipe) do |f| %> <%= f.label :name %> <%= f.text_field :name, required: true %> <%= f.label :published %> <%= f.check_box :published, class: "form-control", placeholder: "Tick if done" %> <!-- 添加隐藏字段传递season_id --> <%= f.fields_for :recipe_seasons do |rs_form| %> <%= rs_form.hidden_field :season_id, value: @month %> <% end %> <%= f.submit %> <% end %> <%= link_to t("back"), recipes_path %>
- 调整参数白名单:
private def recipe_params params.require(:recipe) .permit(:name, :published, recipe_seasons_attributes: [:season_id]) end
无需允许
recipe_id,嵌套属性会自动将新创建的Recipe ID赋值给关联记录
模型注意事项
- Recipe模型已正确配置
has_many :recipe_seasons和accepts_nested_attributes_for :recipe_seasons,无需修改 - RecipeSeason模型的
validates_presence_of :recipe和:season会自动满足:通过关联创建时recipe_id自动填充,season_id由硬编码提供
内容的提问来源于stack exchange,提问作者cinameng
相关产品推荐
相关产品推荐

