将多个参数传递给ActiveModel :: Model

时间:2013-10-17 09:12:43

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

嗨,这是我的第一篇文章。

我一直在尝试调整ruby on rails screen cast 396导入csv和excel文件中的一些代码。适应是我使用了多对多的模型,其中单词属于列表,所以连同文件细节我想传递list_id。

由于WordImport模型不是真正的模型,我认为事情变得更加困难。

我已经尝试了所有类型的排列,但已经恢复到“接近”状态。我想我想知道这是否也是最佳方法。

由于

我的表格是:

<%= form_for @word_import do |f| %>
  <% if @word_import.errors.any? %>

    <div id="error_explanation">
      <h2><%= pluralize(@word_import.errors.count, "error") %> prohibited this import from completing:</h2>
      <ul>
        <% @word_import.errors.full_messages.each do |msg| %>
          <li><%= msg %></li>
        <% end %>
      </ul>
    </div>

  <% end %>

  <%= hidden_field_tag 'list_id', @list.id %>

  <div class="field">
    <%= f.file_field :file %>
  </div>

  <div class="buttons">
    <%= f.submit "Import" %>
  </div>

我的控制器:

class WordImportsController < ApplicationController
  def new
    @word_import = WordImport.new
  end

  def create
    @word_import = WordImport.new(word_import_params)
    if @word_import.save
      redirect_to root_url, notice: "Imported words successfully."
    else
      render :new
    end
  end

  def word_import_params
    params.require(:word_import).permit(:file)
  end

private

  def correct_user
    @list = current_user.lists.find_by_id(params[:list_id])
    redirect_to root_url if @list.nil?
  end
end

模特:

class WordImport    
include ActiveModel::Model

attr_accessor :file

  def initialize(attributes = {})
    attributes.each { |name, value| send("#{name}=", value) }
  end

  def persisted?
    false
  end

  def save
    if imported_words.map(&:valid?).all?
      imported_words.each(&:save!)
      true
    else
      imported_words.each_with_index do |product, index|
        product.errors.full_messages.each do |message|
          errors.add :base, "Row #{index+2}: #{message}"
        end
      end
      false
    end
  end

  def imported_words
    @imported_words ||= load_imported_words
  end

  def load_imported_words
    @list = List.find(4) ## Would like to pass in a value from the controller
    spreadsheet = open_spreadsheet
    header = spreadsheet.row(1)
    (2..spreadsheet.last_row).map do |i|
      row = Hash[[header, spreadsheet.row(i)].transpose]
      @list.words.create(row.to_hash)
    end
  end

  def open_spreadsheet
    case File.extname(file.original_filename)
      when ".ods" then Roo::OpenOffice.new(file.path, nil, :ignore)
      when ".csv" then Roo::Csv.new(file.path, nil, :ignore)
      when ".xls" then Roo::Excel.new(file.path, nil, :ignore)
      when ".xlsx" then Roo::Excelx.new(file.path, nil, :ignore)
    else
      raise "Unknown file type: #{file.original_filename}"
    end
  end
end

1 个答案:

答案 0 :(得分:0)

解决方案是直截了当的,虽然我不确定它是否是最好的做事方式。

我在WordImport ActiveModel :: Model中创建了一个名为:list_id的att_assessor,并将list_id传递给它。然后在WordImport中找到列表并将其分配给实例变量。