解析并将POST提交的项目数组保存为单独的单个项目

时间:2014-05-26 01:53:51

标签: ruby-on-rails ruby forms

我的用户正在提交包含多个项目的请求。无论项目如何保存到SQL数据库中,为了便于分析,我需要解析每个项目并将其保存为Excel文件(Google Drive)中的单个数据行。

换句话说,在SQL中,请求看起来像这样:{:name => "john", :email => "john@gmail.com", :items => ["a", "b", "c"],但我需要将其转换为每个项目有3行的文档,并且行中唯一不同的是项目。

  • 第1行有Name = John,Email = John @ gmail.com,Item = a
  • 第2行有Name = John,Email = John @ gmail.com,Item = b
  • 第3行有Name = John,Email = John @ gmail.com,Item = c

我下面的作品,但我想知道它是否最有效,从以下角度来看:

  1. 首先是否有更容易获得参数的方法?
  2. 是否有更简单的方法来解析和保存单个数据?
  3. 谢谢!

    模型代码

    class Request < ActiveRecord::Base
    
      serialize :items
      validate :must_have_one_item
    
      def must_have_one_item
        errors.add(:items, 'You must select at least one item') unless self.items.detect { |i| i != "0" } 
      end
    
    end
    

    查看代码

    <%= f.check_box(:items, {:multiple => true}, "#{thing}") %>
    <%= f.label(:items, "#{thing}") %>
    

    这里,thing是迭代器函数的一部分,它通过预定义的潜在项目列表来运行。

    CONTROLLER代码,有很多评论!

    class RequestsController < ApplicationController
    
      def new
        @requestrecord = Request.new
      end
    
      def create
        @requestrecord = Request.new(request_params) 
    
        if @requestrecord.save
    
          # Given model/ form code so far, the items are passed through as an array. The remaining comments uses the example: @requestrecord.items = ["water filter", "tent", "0", "0", "0"]. What happens is that "0" represents blank checkboxes
          @requestrecord.items.select! { |x| x != "0" } #removes blank checkboxes; @requestrecord.items = ["water filter", "tent"]
          num_of_requests = @requestrecord.items.count #counts number of items requested; num_of_requests = 2
    
          i = 0 
          cloned_request = Hash.new
          while i < num_of_requests do
             cloned_request[i] = Marshal.load(Marshal.dump(@requestrecord)) #creates a cloned_request[0] = @requestrecord and cloned_request[1] = @requestrecord 
             cloned_request[i].items = @requestrecord.items.slice(i) #disaggregates the items into the cloned_requests; cloned_request[0].items = "water filter",  cloned_request[1].items = "tent" 
             i += 1
          end
    
          cloned_request.each do | key, request |
              request.save_spreadsheet
          end
    
        else
          render 'new'
        end
      end
    
      private
        def request_params
          params.require(:request).permit({:items => []})
        end
    
    end
    

2 个答案:

答案 0 :(得分:2)

好的,所以这里有很多问题。

首先,尝试永远不要在数据库中存储数据数组,因为您似乎正在使用serialize :items。您可以详细了解here的原因。你应该做的是拥有一个名为Item的模型,它有自己的表。从那里,您可以使用更多模型将其与其他模型相关联,例如具有item_id和user_id属性为整数的UserItem模型。此UserItems是您的关联模型,它包含有关项目和用户如何关联的信息(即哪些用户具有哪些项目)。如果需要关联请求和项目,您也可以创建RequestItem模型。

当用户提交项目列表时,您可以从params[:request][:items]哈希中获取每个项目并使用

创建记录
params[:request][:items].each do |item|
  UserItem.create(user_id: @user.id, item_id: item.to_i)
end

请注意,它显示为item.to_i。这是因为,一旦你有了Items表,每个项目都会有一个id。一旦您更改视图以向您发送item_id(而不是项目名称),您就可以使用上述逻辑轻松地为其创建UserItem。 (使用to_i是因为大多数时间数据是作为字符串发送的,您需要将其转换为整数)。

其次,您真的应该将业务逻辑移动到适当的模型,或者至少是帮助者。作为一个原则,你的控制器应该“瘦”,你的模型应该“胖”。这有很多原因,但在我看来,最重要的原因是它使您的代码更容易测试。您可以阅读有关此here的更多信息。

答案 1 :(得分:0)

同意Enraged Camel - 我认为您可以提高create方法效率:

#app/controllers/requests_controller.rb
Class RequestsController < ApplicationController
    def create
        items = params[:request][:items]
        if items.kind_of?(Array)
            #means there are multiple array items
            for item in items do
               request = Request.new(your: item[:attribute], and: item[:another_attribute])
               request.save
            end
        else
            request = Request.new(request_params)
            request.save
        end
    end
    private

    def request_params
       request.require(request).permit(:your, :attributes)
    end
end

不要偷窃 任何人的雷声;希望你能从我发布的内容中获得更多想法!