使用Ruby on Rails动态生成值并根据用户输入创建多个记录

时间:2016-04-21 17:21:38

标签: ruby-on-rails ruby ruby-on-rails-4 activerecord

在我的Ruby on Rails应用程序中,我试图根据用户在表单上输入的数字动态创建n个数据库记录。为了简单起见,我将使用一本书及其章节的类比来说明我想要做的事情。下面是我的模型,属性和表格来创建一本书。

型号:

class Book < ActiveRecord::Base
  has_many :chapters
end

class Chapter < ActiveRecord::Base
  belongs_to :book
end

图书属性:
idbook_titlenumber_of_chapterscreated_atupdated_at

章节属性:
idchapter_titlecontentsbook_idcreated_atupdated_at

表单以创建新书:

<%= form_for(@book) do |f| %>
    <%= f.text_field :book_title %>
    <%= f.text_field :number_of_chapters %>

    <%= f.submit %>
<% end %> 

当用户创建图书时,他们可以输入图书的标题和图书的章节数。如果用户输入5章,那么我们需要能够动态地将5条记录插入章节表中,每个记录都有一个唯一生成的章节标题名称。

生成的章节标题可以简单如下:

 chapter1   
 chapter2   
 chapter3  
 chapter4  
 chapter5  

我在研究中找到的最接近的解决方案是创建一个嵌套的模型表单。但由于几个原因,嵌套模型形式不是理想的解决方案。我无法预测需要插入第二个模型的记录数量,它可能是几个或高达10,000个记录。加上手动数据输入该许多记录的字段值是不实际的。

我有一些我认为需要做的事情,但我需要帮助将它们捆绑在一起。

我的第一个想法是使用after_save回调来触发创建章节的方法。我会将以下内容添加到Book模型中。

after_save Chapter.generate_chapter_titles

但是从性能的角度来看,我怀疑after_save是否是最好的方法,因为我们可能一次创建数千条记录。

在章节模型中,我考虑使用以下方法根据chapter_titles创建number_of_chapters值。

def generate_chapter_titles
    1.upto(book.number_of_chapters) do |chapter|
    print "chapter%d" % chapter
end 

但现在我陷入了困境,我还没有想到如何从generate_chapter_titles获取输出并创建单独的章节db记录。同时确保新生成的章节与从中创建的书籍相关联。

非常感谢有关使此功能正常工作的任何帮助。我在发布之前试图对此进行研究,但答案仍然没有找到我。我是一个编程和Ruby noob,所以我愿意承认Ruby和Ruby on Rails API文档中的一些信息超出了我的想象。我非常感谢任何关于分解和理解我需要使其功能增加的帮助。

更新 - 最终解决方案 感谢@margo,我所要做的就是使用下面的代码更新create中的books_controller.rb方法。现在,章节将根据为number_of_chapters输入的值自动生成。

class BooksController < ApplicationController

  [...]

  def create
    @book = Book.new(book_params)

    if @book.save
      ActiveRecord::Base.transaction do
        @book.number_of_chapters.times do |n|
          Chapter.create!(book_id: @book.id, title: "Chapter #{n+1}")
        end
      end
      redirect_to @book, notice: "Book created successfully."
    else
      render 'new'
    end
  end

  [...]

end

1 个答案:

答案 0 :(得分:0)

首先,您需要在transaction中包装本书章节的创建。如果在完成之前发生错误,事务将确保保存所有章节或回滚任何提交。

您可以在books_controller中的create方法中创建所有章节。下面是一个例子,你必须填写各个部分。

在你的books_controller中

def create
  @book = Book.new(book_params)
  if @book.save 
    generate_chapters(@book)
  end
end

private
def generate_chapters(book)
  ActiveRecord::Base.transaction do
    book.number_of_chapters.times do |n|
      Chapter.create!(book_id: book.id, title: "Chapter #{n+1})"
    end
  end
end

我建议你从这种方法开始并让它运作起来。如果您要同时创建数千条记录,那么您可能需要考虑将其移至后台作业,但这是一个单独的问题。