【问题标题】:DRYing up similar code in controller methods在控制器方法中干燥类似的代码
【发布时间】:2017-02-17 12:27:42
【问题描述】:

我在控制器中有两种方法,代码非常相似。想知道我怎么能把它们弄干!他们都使用csv-importer gem 来解析 csv 文件。

sales_controller.rb

  def import_csv_test
    user_id = params[:user_id]
    import = ImportSaleCSV.new(file: params[:file]) do
      after_build do |sale|
        sale.user_id = user_id
        skip! if sale.email == nil
        skip! if sale.order_date == nil
        skip! if sale.amount == nil
      end
    end
    import.run!
    redirect_to lifecycle_grid_sales_path, notice: import.report.message
  end

  def import_ftp
    user_id = params[:user_id]
    import = ImportSaleCSV.new(path: './public/uploads/gotcha.csv') do
      after_build do |sale|
        sale.user_id = user_id
        skip! if sale.email == nil
        skip! if sale.order_date == nil
        skip! if sale.amount == nil
      end
    end
    import.run!
    redirect_to lifecycle_grid_sales_path, notice: import.report.message
  end

谢谢!

【问题讨论】:

    标签: ruby-on-rails dry


    【解决方案1】:

    我认为您可以提取一个类来完成繁重的工作。

    class ImportSaleCSVCreator
      def initialize(csv_options = {}, csv_attributes = {})
        @csv_options = csv_options
        @csv_attributes = csv_attributes
      end
    
      def build
        ImportSaleCSV.new(csv_options) do
          after_build do |sale|
            csv_attributes.each { |k, v| sale.public_send("#{k}=", v) }
            skip! if sale.email.nil? || sale.order_date.nil? || sale.amount.nil?
          end
        end
      end
    
      private
    
      attr_reader :csv_options, :csv_attributes
    end
    
    class Controller
      def import_csv
        import = ImportSaleCSVCreator.new({ file: params[:file] }, { user_id: params[:user_id] })
        import.run!
      end
    
      def import_ftp
        import = ImportSaleCSVCreator.new({ path: './gotcha.csv' }, { user_id: params[:user_id] })
        import.run!
      end
    end
    

    确保检查通过的属性。特别是在处理文件、路径等时。您可能希望过滤ImportSaleCSVCreator 中的参数。

    【讨论】:

      【解决方案2】:

      您可以将两种方法都重构为一个:

      def import(hash)
        user_id = params[:user_id]
        import = ImportSaleCSV.new(hash) do
          after_build do |sale|
            sale.user_id = user_id
            skip! if sale.email == nil
            skip! if sale.order_date == nil
            skip! if sale.amount == nil
          end
        end
        import.run!
        redirect_to lifecycle_grid_sales_path, notice: import.report.message
      end
      

      然后调用它:

      import({file: params[:file]})
      import({path: './public/uploads/gotcha.csv'})
      

      该方法似乎不属于您的控制器,因此您可能希望将其提取到某个地方。我鼓励您检查this great article 并将您的方法提取到全新的服务对象中。

      【讨论】:

      • 是的,这似乎是唯一的区别。
      • 这看起来很棒,谢谢!我会直接在我的 sales_controller.rb 中定义导入方法吗?并这样称呼它? def import_csv_test import({file: params[:file]}) end
      • 是的,你可以这样做。似乎该方法不应该存在于您的控制器中。所以你可能需要在其他地方提取它。最好的选择是具有单个公共方法call(与import 方法完全相同)和几个私有方法(如果需要)的服务类。因此,在您的控制器中,您将能够创建该服务的实例并在其上调用 call 方法。我会用一些有用的链接来编辑我的答案。
      • 再次感谢,感谢您的帮助。我醒来后会检查一下。不错的个人资料哈哈...
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多