Rails 5如何从父模型的视图编辑联接模型属性?

问题描述

我有一个系统,管理员可以根据他们销售的分支机构创建考试并为它们定价。因此,例如,第一分支的考试费用为5美元,而第二分支的考试费用为10美元。

我制作了一个名为ExamOffering的联接表,该表具有考试的价格,因此每个考试可以在许多分支机构以不同的价格出售,并且每个分支机构可以进行许多考试。像这样:

    class Branch < ApplicationRecord
      has_many :exam_offerings
      has_many :exams,through: :exam_offerings
    end

    class Exam < ApplicationRecord
      has_many :exam_offerings
      has_many :branches,through: :exam_offerings
    end

    class ExamOffering < ApplicationRecord
      # this class has a 'price' attribute
      belongs_to :exam
      belongs_to :branch
    end

我需要能够创建一个新的Exam并在表单中选择一个Branch以便输入价格,但是该属性不是Exam模型的一部分,而是ExamOffering连接表。我尝试了一些方法但失败了(在Exam模型中使用accepts_nested_attributes_for:exam_offerings或遍历所有分支并为控制器中的每个分支创建ExamOfferings)。这样做的“路轨方式”是什么?我认为这是一个很常见的案例,但是我没有找到适合我的案例的答案。也许这有个名字,我不知道。

它可以这样表达:创建新的考试时,我希望能够为每个现有分支机构输入价格。

谢谢。

解决方法

您想要做的是显式创建联接模型:

# config/routes.rb
resources :exam_offerings,only: [:new,:create]
class ExamOffering < ApplicationRecord
  # this class has a 'price' attribute
  belongs_to :exam
  belongs_to :branch
  accepts_nested_attributes_for :exam
  validates_associated :exam
end
# app/views/exam_offerings/new.html.erb
<%= form_with(model: @exam_offering) do |f| %>
  <div class="field" %>
    <%= f.label(:branch_id) %>  
    <%= f.collection_select(:branch_id,Branch.all,:id,:name) %>
  </div>
  <div class="field" %>
    <%= f.label(:price) %>  
    <%= f.number_field(:price) %>
  </div>
  <%= f.fields_for(:exam) do |exam_field| %>
    <div class="field" %>
      <%= exam_field.label(:foo) %>  
      <%= exam_field.text_field(:foo) %>
    </div>
  <% end %>
  <%= f.submit %>
<% end %>
class ExamOfferingsController < ApplicationController

  # GET /exam_offerings/new
  def new
    @exam_offering = ExamOffering.new
  end
 
  # POST /exam_offerings
  def create
    @exam_offering = ExamOffering.new(exam_offering_params)
    if @exam_offering.save
       redirect_to @exam_offering,notice: 'Offering Created'
    else
       render :new,notice: 'Oh No!'
    end
  end

  private

  def exam_offering_params
    params.require(:exam_offering)
          .permit(
            :branch_id,:price,exam_attributes: [:foo]
          )
  end
end

请记住,联接模型没有什么特别的-并不一定总是隐式创建它们。通常,它们实际上是商务逻辑的重要组成部分,而不仅仅是管道。

但是,实际上,如果我要构建它,我只会创建一条普通的POST /exams路线,用户可以在其中创建考试,然后让他们在此之后创建产品。如果需要,请使用AJAX使其无缝显示。

,

我最终在Exam模型中使用了accepts_nested_attributes_for,因此我不必使用其他视图来标价,所以就像这样:

class Branch < ApplicationRecord
  has_many :exam_offerings
  has_many :exams,through: :exam_offerings
end

class Exam < ApplicationRecord
  has_many :exam_offerings
  has_many :branches,through: :exam_offerings
  accepts_nested_attributes_for :exam_offerings
end

class ExamOffering < ApplicationRecord
  # this class has a 'price' attribute
  belongs_to :exam
  belongs_to :branch
end

重要的是观点。创建考试时,我需要将fields_for与新对象一起使用,但是在编辑考试时,要获取现有的exam_offerings,所以我有以下代码:

<% if exam.exam_offerings.empty? %>
  <% Branch.all.each do |branch| %>
    <%= form.fields_for :exam_offerings,@exam.exam_offerings.build do |offering| %>
      <div class="field">
        <%= offering.label "Price in #{branch.name}" %>
        <%= offering.text_field :price %>
        <%= offering.hidden_field :branch_id,value: branch.id %>
      </div>
    <% end %>
  <% end %>
<% else %>
  <%= form.fields_for :exam_offerings do |offering| %>
    <div class="field">
      <%= offering.label "Price in #{offering.object.branch.name}" %>
      <%= offering.text_field :price %>
    </div>
  <% end %>
<% end %>

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...