【问题标题】:Dynamically create multiple instances of a model in rails在 Rails 中动态创建模型的多个实例
【发布时间】:2015-08-21 16:18:13
【问题描述】:

我有两个相关的模型“Test”和“Student”:

class Student< ActiveRecord::Base
   has_many :tests
end

class Test< ActiveRecord::Base
   belongs_to :Student
end

我要做的是为学生创建未知数量的测试,即从学生的 show.html.erb 中,用户可以创建多个测试。此外,一旦创建了一组测试,用户就可以像以前一样通过学生的 show.html.erb 再次添加任意数量的测试。

请注意,创建测试不是学生创建的一部分(就像在this railscast 中一样)。学生是单独创建的,然后可以通过 app/views/students/show.html.erb 上的按钮添加多个测试。

当单击添加测试的按钮时,我正在students_controller.rb 中调用自定义操作(下面的customAction1)。我能想到的是动态构建和附加,例如 10 个(开始)测试实例到学生的实例(在 students_controller.rb 的自定义操作中),呈现自定义视图(下面的 addtests.html.erb),然后允许用户在该视图中为这些测试实例输入各种输入字段,最后当单击创建按钮时,调用 student_controller.rb 中的另一个自定义操作(下面的 customAction2)来保存(仅非空的)测试实例。

这是正确的(阅读 Rails)方法吗?由于我是 Rails 新手,请更正执行上述操作的代码:

students_controller.rb
#called when button to add tests is clicked from students/show.html.erb view:
def customAction1
    @student = Student.find(params[:student])
    10.times {@student.tests.append}
    render 'addtests'
end

addtests.html.erb
# Here I'm unable to show input fields for each of the 10 newly added tests

students_controller.rb
# Called when create button is clicked from addtests.html.erb after inputting fields for some tests
def customAction2
    @student.tests.save  # Is this correct?
    render 'show' # render show.html.erb of this student
end

如果这确实是正确的方法,请告诉我如何编写 addtests.html.erb 视图。

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-4.2


    【解决方案1】:

    您仍然可以通过学生将测试添加为更新学生而不是创建并使用cocoon gem 来帮助您处理嵌套表格,我正在考虑这样的事情

    宝石文件

    gem 'cocoon'
    

    宝石链接:https://github.com/nathanvda/cocoon

    models/student.rb

    accepts_nested_attributes_for :tests
    

    students_controller.rb

    def show
       @student = Student.find(params[:id])
       @student.tests.build #you can check here if the student has already tests you can skip this build
    end
    
    def student_params
        #add your own student parameters before the tests attributes
        params.require(:student).permit(tests_attributes: [:id, :name, :_destroy]
    end
    

    学生/show.html.haml

    = form_for @student do |f|
      = f.fields_for :tests do |builder|
        = render 'tests/test_fields', f: builder
      = link_to_add_fields 'Add Tests', f, :tests
    

    此表单将提交到students#update 操作,test_attributes 仅作为参数

    测试/_test_fields.html.haml

    -#add other test attributes that you might have
    = f.input :name
    = link_to_remove_association 'Remove Test', f
    

    【讨论】:

      【解决方案2】:

      我最终观看了嵌套表单railscast 的修订版以解决问题。步骤如下:

      students_controller.rb
      #called when button to add tests is clicked from students/show.html.erb view:
      def addTests
          @student = Student.find(params[:student])
          render 'addtests'
      end
      
      addtests.html.erb    
          <%= form_for(@student, url: {action: "realAddTests"}, method: :post) do |student_form| %>
            <% test1 = Test.new %> #to show fields for one test by default
            <%= student_form.fields_for(:tests, test1) do |f| %>
              <%= render('test_fields', f: f) %>
            <% end %>
            <br />
            <%= link_to_add_fields 'ADD MORE', student_form, :tests %><br /><br />
            <%= student_form.submit "Save", class: "btn btn-primary" %>
          <% end %>
      
      _test_fields.html.erb  #partial used above
      <fieldset>
          <%= f.label "Name" %>
          <%= f.number_field :name %>
      
          <%= f.label :date %>
          <%= f.date_field :date %>
      
          <%= f.label :time %>
          <%= f.time_field :time %>
      </fieldset>
      
      students_controller.rb
      # Called when save button is clicked in addtests.html.erb after inputting fields for some tests  
      def realAddTests
      new_tests_hash = params[:student][:tests_attributes]
                  new_tests_hash.each do |key, value|
                      new_test_attributes = value.permit(:name, :date, :time)
                      @test = Test.new(new_test_attributes)
                  end
      end
      

      修改 app\assets\javascripts\tests.coffee 和 app\helpers\application_helper 就像在 railscast 中指定的一样:

      app\assets\javascripts\tests.coffee:

      jQuery ->
          $(document).on 'click', 'form .add_fields', (event) ->
              time = new Date().getTime()
              regexp = new RegExp($(this).data('id'), 'g')
              $(this).before($(this).data('fields').replace(regexp, time))
              event.preventDefault()
      

      app\helpers\application_helper.rb:

      def link_to_add_fields(name, f, association)
              new_object = f.object.send(association).klass.new
              id = new_object.object_id
              fields = f.fields_for(association, new_object, child_index: id) do |builder|
                  render(association.to_s.singularize + "_fields", f: builder)
              end
              link_to(name, '#', class: "add_fields", data: {id: id, fields: fields.gsub("\n", "")})
          end
      

      以上是对我有用的完整步骤集,我可以一次性为一名学生创建和保存多个测试。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-08-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-23
        • 2011-08-11
        • 2021-01-05
        • 2013-10-01
        相关资源
        最近更新 更多