【问题标题】:Ruby on rails - Create multiple records from an arrayRuby on rails - 从数组创建多条记录
【发布时间】:2016-12-20 17:38:32
【问题描述】:

我的模型@gig 有一个表格。我正在尝试一次创建多个具有相同属性的gigs,除了应该从数组中挑选的date

到目前为止,只有数组中的最后一个日期,并且只有一条记录被保存。

_form.html.erb

    <%= simple_form_for @gig , url: gigs_path do |form| %>
         <div class="create-title">
            <%= form.input :title, label: t('gig.title'), placeholder: t('placeholder.title') %>
         </div>

          bla... bla... bla....

         <p><%= t('gig.date') %> </p>
           <% if !mobile_device? %>
             <%= form.input :date, as: :string, label: false, placeholder: t('placeholder.date'), multiple: true %>
           <% else %>

                       bla... bla... bla....
    <% end %>

gig_controler.rb

    def create
      @gigdates = params[:gig][:date].split(';')
      puts @gigdates.count
        @gigdates.each do |date|
            puts date
           @gig = Gig.create(gig_params)
           @gig.date = date
         end

        if @gig.save

          redirect_to @gig
        else
          Rails.logger.info(@gig.errors.inspect)
          render 'new'
        end
      end




     def gig_params
       params.require(:gig).permit(:title, :location, :description, :date, :salary, :salary_cents, :salary_currency, :genre_ids => [])
     end

在控制器中使用puts date,我可以看到我的日期被正确地分开了。

服务器显示ROLLBACK 被调用的次数与数组中的日期一样多,然后最终的gig 正确保存。


更新 1:

我已经更改了允许创建多条记录的控制器,我只是担心如果记录保存失败时缺少重定向或消息。

def create

  @gigdates = params[:gig][:date].split(';')
    @gigdates.each do |date|
       @gig = Gig.new(gig_params)
       @gig.date = date
       @genres = Genre.where(:id => params[:choose_genres])
       @gig.genres << @genres
       @gig.save
     end

    redirect_to @gig
  end

【问题讨论】:

    标签: ruby-on-rails arrays database activerecord


    【解决方案1】:

    对于@gig_dates 数组中的每个日期,您正在使用gig_params 创建一个无效的演出。这是无效的,因为gig_paramsdate 键将是最初在表单中输入的字符串,例如"2017-01-3;2017-05-09;2017-08-01"。这是一个无效的日期,因此所有 ROLLBACKs - 您对 Gig.create 的调用都在数据库级别失败。

    让我们更深入地了解正在发生的事情:

      # EACH LOOP BEGINS
      # for each gig date:
      @gigdates.each do |date|
        # gig_params[:date] will be the whole string that was entered in the
        # form. this is an invalid date, so Gig.create will fail to save the
        # gig to the database (= ROLLBACK). 
        # so you create an gig, but it can't be saved because its date parameter
        # is invalid. you assign this invalid gig to the @gig instance
        # variable. this variable will be overwritten each time, so only the
        # last created gig is stored in @gig
        @gig = Gig.create(gig_params)
    
        # you assign that invalid gig a (valid) date (but you don't save it!)
        @gig.date = date
      end
      # EACH LOOP ENDS
    
      # Save @gig, the last created gig, using the valid date you assigned 
      # it at the end of the each loop. so now the save will work!
      if @gig.save
        redirect_to @gig
      else
        Rails.logger.info(@gig.errors.inspect)
        render 'new'
      end
    end
    

    编辑:

    处理验证的一种方法是在保存任何新演出之前检查所有新演出的有效性。为此,您可以将 each 替换为地图,这将创建一个包含新演出的数组,然后在全部保存之前检查它们是否都有效:

    def create
      gigdates = params[:gig][:date].split(';')
    
      gigs = gigdates.map do |date|
        gig = Gig.new(gig_params.merge(date: date))
        genres = Genre.where(:id => params[:choose_genres])
        gig.genres << genres
      end
    
      if gigs.all?(&:valid?) && gigs.all?(&:save)
        redirect_to gigs.first
      else
        flash[:notice] = "something went wrong"
        @gig = Gig.new(gig_params)
        render :new
      end
    end
    

    【讨论】:

    • 我已经用更新版本更新了我的问题。我现在可以保存多条记录,但没有验证或失败时闪烁消息。
    • @RobHughes 请参阅我的编辑,以获取有关如何处理验证的相当幼稚的示例。这并不理想(例如,如果所有演出都是有效的,但其中一些仍然因任何原因无法保存,则会出现不一致)。解决此问题的一种更好的方法是简化创建操作,一次只制作一个 gig,并让浏览器为每个 gig 发出单独的请求(例如,使用一点 javascript 来发送 ajax 请求)。但这超出了这个问题的范围。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-14
    • 2023-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-18
    • 2018-10-16
    相关资源
    最近更新 更多