简体   繁体   中英

Passing multiple parameters to an ActiveModel::Model

Hi this is my first post.

I have been trying to adapt some code from the ruby on rails screen cast 396 importing csv and excel files. The adaptation is that I'm using a many to many model, where words belong to lists, so along with the file details I'd like to pass a list_id.

I think things are made a little more difficult due to WordImport model not being a true model.

I've tried all sort's of permutations but have reverted back to a 'close' state. I guess I'd like to know if this is the best approach also.

Thanks

My form is:

<%= 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>

My Controller:

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

And Model:

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

The solution was straight forward although I'm not sure if its the best way of doing things.

I created an att_assessor in the WordImport ActiveModel::Model called :list_id and pass the list_id to this. then within WordImport find the list and assign it to the instance variable.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM