【问题标题】:creating a record with a has many through association通过关联创建记录有很多
【发布时间】:2023-01-12 18:40:14
【问题描述】:

我想在创建记录时创建与另一个模型的关联。

这些模型通过关联使用 has_many。

楷模

食谱

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

季节

class Season < ApplicationRecord
    has_many :recipe_seasons
    has_many :recipes, through: :recipe_seasons
end

食谱季节

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

创建食谱后,我希望使用新创建的食谱的 ID 将默认值 @month 插入到表 recipe_seasons 的记录中。

形式

<%= 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_seasons 中,使用在食谱上创建的 id 作为表 recipe_seasons 上的 recipe_id。现在,我将对用于 season_id 的@month 的值进行硬编码。

【问题讨论】:

    标签: ruby-on-rails activerecord associations


    【解决方案1】:

    你实际上在这里过度和过度复杂化了。您的 RecipeSeason 类中不需要任何内容​​,除了:

    class RecipeSeason < ApplicationRecord
      belongs_to :recipe
      belongs_to :season
    end
    

    自 Rails 5 起,存在验证默认添加到 belongs_to 关联。您不需要嵌套属性来分配关联项。

    通常,在处理连接表时,您不需要显式创建连接模型,因为它们是通过关联隐式创建的:

    def create
      @recipe = Recipe.new(recipe_params)
      # Always check if the record was valid and saved
      if @recipe.save 
        redirect_to recipes_path, status: :created
        flash[:notice] = I18n.t("recipe.created")
      else
          render :new
      end
    end
    
    def recipe_params
      params.require(:recipe)
            .permit(:name, :published, season_ids: [])
    end
    
    <%= form_with(model: :recipe) do |form| %>
      <%= form.collection_select :season_ids, Season.all, :id, :name %>
    <% end %>
    

    这使用由 has_many :seasons, through: :recipe_seasons 创建的设置器,并将自动创建/删除 recipe_seasons 表中的行。

    你唯一需要的时候明确地创建中间模型时,它不仅用作简单的连接表和该表的传递属性。例如,如果您有一个订单,并且您想将产品连同数量一起添加到订单中:

    # order.products << @product won't let us pass a quantity
    order.line_items.create(
      product: @product,
      quantity: 
    )
    

    那是嵌套属性真正变得相关的时候。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-07-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多