繁体   English   中英

在Rails中动态创建模型的多个实例

[英]Dynamically create multiple instances of a model in rails

我有两个相关的模型“测试”和“学生”:

class Student< ActiveRecord::Base
   has_many :tests
end

class Test< ActiveRecord::Base
   belongs_to :Student
end

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

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

当单击添加测试的按钮时,我在students_controller.rb中调用一个自定义动作(以下为customAction1)。 我能想到的是动态构建并向学生的实例添加10个(作为开始)测试实例(作为开始)(在students_controller.rb的自定义动作中),呈现自定义视图(下面的addtests.html.erb),然后允许用户在该视图中为这些测试实例输入各种输入字段,最后单击创建按钮时,在students_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视图。

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

的Gemfile

gem 'cocoon'

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

车型/ 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

此表单仅使用test_attributes作为参数提交给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

我最终观看了嵌套表单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

完全按照在railscast中指定的方式修改app \\ assets \\ javascripts \\ tests.coffee和app \\ helpers \\ application_helper:

应用程序\\资产\\ JavaScript的\\ 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()

应用程序\\佣工\\ 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

上面是对我有用的完整步骤,我可以一次创建并保存一个学生的多个测试。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM