即日起在codingBlog上分享您的技术经验即可获得积分,积分可兑换现金哦。

Rails 5 -如何上传Excel文件-教程不工作

栈溢出 Mel 28℃ 0评论
本文目录
[隐藏]

1.原始问题:Rails 5 – how to upload excel files – tutorials not working out

I am trying to upload an excel file to my Rails 5 app.

I have tried this tutorial, and this one, and this one. I can’t get any of them to work.

I have a namespaced model called:

class Randd::Field < ApplicationRecord
require 'csv'

I have tried each of these methods in my model:

  def self.import(file)
    CSV.foreach(file.path, headers: true) do | row |
        Randd::Field.create! row.to_hash
    end
  end

  def self.import(file)
    CSV.foreach(file.path, headers: true) do |row|

      randd_field_hash = row.to_hash # exclude the price field
      randd_field = Randd::Field.where(id: randd_field_hash["id"])

      if randd_field.count == 1
        randd_field.first.update_attributes(randd_field_hash)
      else
        Randd::Field.create!(product_hash)
      end # end if !product.nil?
    end # end CSV.foreach
  end # end self.import(file)

In my controller, I have:

class Randd::FieldsController < ApplicationController

def index
    @randd_fields = Randd::Field.all
end

def new
    @field = Randd::Field.new
end

def import
    Randd::Field.import(params[:file])
    redirect_to root_path, notice: "Data imported"
end

end

Notes on the controller:

  1. I don't have any strong params - which seems odd to me but none of the tutorials seem to suggest they are required.
  2. I made the above new action because I tried to make a separate form to upload the file, instead of using the index action to keep the file filed. I have tried using the new as well as using the process outlined in the tutorials in which the form field is set out in the index view. Neither approach works.

In my routes I have:

namespace :randd do
    resources :fields do 
      collection do
        post :import 
      end
    end
  end

In my form, I have:

  <%= simple_form_for [:randd, @field], multipart: true do |f| %>
      
<%= f.file_field :file %>
<%= f.button :submit %>
<% end %>

When I try using the new view to upload the file, I get an error that says:

undefined method `randd_randd_fields_path' for #<#:0x007fd5f698f430>
Did you mean?  randd_fields_path

When I try using the index view to hold the form field, I have:

<%= form_tag import_randd_fields_path, multipart: true  do |f| %>
                <%= f.file_field :file %>
             <%= submit_tag 'Import' %>
<% end %>

When I try using the index view to upload the file, I get an error that says:

undefined method `file_field' for nil:NilClass

Can anyone recommend another tutorial for how to upload an excel file to rails 5. It's possible that the ones I'm using are too old - but I can't find a better source of help.

NEXT ATTEMPT

I managed to get the form to render with the suggestion below:

<%= simple_form_for (@field), multipart: true do |f| %>

I had to define show and create actions in my fields controller in order to let this process run. I added to my randd fields controller so it now has:

class Randd::FieldsController < ApplicationController

def index
    @randd_fields = Randd::Field.all
end

def new
    @field = Randd::Field.new
end

def create
    redirect_to action: "import"
end

def show
    redirect_to action: "index"
end


def import
    Randd::Field.import(params[:file])
    redirect_to action: "index", notice: "Data imported"
end

end

When I go through the process, upload the file and submit, I can see this happening in the log:

Started GET "/images/upload/cache/presign?extension=.xls&_=142388" for ::1 at 2016-11-14 10:50:12 +1100
Started POST "/randd/fields" for ::1 at 2016-11-14 10:50:12 +1100
Processing by Randd::FieldsController#create as JS
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"8vJ7bA==", "randd_field"=>{"file"=>"{\"id\":\"04f4e0679f2a562.xls\",\"storage\":\"cache\",\"metadata\":{\"size\":165376,\"filename\":\"FOR codes.xls\",\"mime_type\":\"\"}}"}}
Redirected to http://localhost:3000/randd/fields/import
Completed 200 OK in 43ms (ActiveRecord: 0.0ms)


Started POST "/randd/fields" for ::1 at 2016-11-14 10:50:13 +1100
Processing by Randd::FieldsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"8v+bbA==", "commit"=>"Create Field"}
Redirected to http://localhost:3000/randd/fields/import
Completed 302 Found in 40ms (ActiveRecord: 0.0ms)


Started GET "/randd/fields/import" for ::1 at 2016-11-14 10:50:13 +1100
Processing by Randd::FieldsController#show as HTML
  Parameters: {"id"=>"import"}
Redirected to http://localhost:3000/randd/fields
Completed 302 Found in 29ms (ActiveRecord: 0.0ms)


Started GET "/randd/fields/import" for ::1 at 2016-11-14 10:50:13 +1100
Started GET "/randd/fields" for ::1 at 2016-11-14 10:50:13 +1100
Processing by Randd::FieldsController#show as HTML
  Parameters: {"id"=>"import"}
Redirected to http://localhost:3000/randd/fields
Completed 302 Found in 32ms (ActiveRecord: 0.0ms)


Processing by Randd::FieldsController#index as HTML
  Rendering randd/fields/index.html.erb within layouts/application
  Randd::Field Load (1.6ms)  SELECT "randd_fields".* FROM "randd_fields"
  Rendered randd/fields/index.html.erb within layouts/application (46.9ms)
  User Load (1.8ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 4], ["LIMIT", 1]]
  Setting Load (1.0ms)  SELECT  "settings".* FROM "settings" WHERE "settings"."user_id" = $1 LIMIT $2  [["user_id", 4], ["LIMIT", 1]]
  Rendered layouts/nav/_inner.html.erb (93.3ms) 
Completed 200 OK in 2773ms (Views: 2732.5ms | ActiveRecord: 4.4ms)


Started GET "/randd/fields" for ::1 at 2016-11-14 10:50:16 +1100
Processing by Randd::FieldsController#index as HTML
  Rendering randd/fields/index.html.erb within layouts/application
  Randd::Field Load (0.9ms)  SELECT "randd_fields".* FROM "randd_fields"

But -- this didn't work because the table is empty. It has no instances.

COURT3NAY'S SUGGESTION

The suggestion is that I swap the content of the import action in the fields controller to the create action. My controller now has:

class Randd::FieldsController < ApplicationController

def index
    @randd_fields = Randd::Field.all
end

def new
    @field = Randd::Field.new
end

def create
    Randd::Field.import(params[:file])
    redirect_to action: "index", notice: "Data imported"
    # @field = Randd::Field.new(randd_field_params)
    # redirect_to action: "import"
end

def show
    redirect_to action: "index"
end


# def import
#   # byebug
#   Randd::Field.import(params[:file])
#   redirect_to action: "index", notice: "Data imported"
# end

private
 def randd_field_params
  params.fetch(:randd_field, {}).permit(:title, :anz_reference)
 end

end

My form now has (i removed the import url path):

<%= simple_form_for (@field),  multipart: true do |f| %>
  <%= f.error_notification %>

  
Research Field Codes
<%= f.file_field :file %>
<%= f.button :submit %>
<% end %>

The error now says:

The action 'import' could not be found for Randd::FieldsController

The error message highlights a problem with code that I didn't write myself.

def process(action, *args)
      @_action_name = action.to_s
      unless action_name = _find_action_name(@_action_name)
        raise ActionNotFound, "The action '#{action}' could not be found for #{self.class.name}"
      end

I think its a problem though because I don't have an import action anymore. I'm supposed to have create to do the things that were in import previously (per the tutorials).

MY GUESS AT GETTING AROUND THIS:

I searched for where I was still asking for 'import'. I use it in two places, so I tried swapping 'import' for create in both.

Now, my model has:

def self.create(file)
    CSV.foreach(file.path, headers: true) do |row|

      randd_field_hash = row.to_hash # exclude the price field
      randd_field = Randd::Field.where(id: randd_field_hash["id"])

      if randd_field.count == 1
        randd_field.first.update_attributes(randd_field_hash)
      else
        Randd::Field.create! row.to_hash#(randd_field_hash)
      end # end if !product.nil?
    end # end CSV.foreach
  end # end self.import(file)

The create action in my controller has:

def create
    Randd::Field.create(params[:file])
    redirect_to action: "index", notice: "Data imported"
    # @field = Randd::Field.new(randd_field_params)
    # redirect_to action: "import"
end

This guess doesnt solve anything though. I still get an error message that says:

undefined method `path' for nil:NilClass

I also don't know what that means.

2.被采纳答案

暂无被采纳答案,请参照下面其他答案。

3.其他高票答案

3.1.第1个答案

You're really close.
You need to post to import. You're just getting fields#show

Processing by Randd::FieldsController#show as HTML
Parameters: {"id"=>"import"}

You need to post to fields#import

<%= simple_form_for (@field), url: import_fields_path, multipart: true do |f| %>

or, just use fields#create instead of redirecting. Once you post to #create the redirect will lose the params.

转载请注明:CodingBlog » Rails 5 -如何上传Excel文件-教程不工作

喜欢 (0)or分享 (0)
发表我的评论
取消评论

*

表情