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.