【问题标题】:How can i attach more than one file with Carrierwave / AngularJs+RoR via Json?如何通过 Json 使用 Carrierwave / AngularJs+RoR 附加多个文件?
【发布时间】:2014-09-17 11:23:28
【问题描述】:

对不起我的英语。

现在我可以创建附有一张图片的任务,我想要更多...

我在后端有 Rails,在前端有 AngularJS。我创建了一个指令,帮助我通过 json 将图像发送到服务器。

app.directive 'uploadImage', ->
return{
  restrict: 'A'
  link:(scope,elem)->
    reader = new FileReader()
    reader.onload =(e)->
      scope.iFile = btoa(e.target.result)
      scope.$apply()

    elem.on 'change', ->
      scope.iFile=''
      file = elem[0].files[0]
      scope.iFilesize = file.size
      scope.iFiletype = file.type
      scope.iFilename = file.name
      scope.$apply()
      reader.readAsBinaryString(file)
}

在 AngularJS 中创建任务:

$scope.createTask =->
  $scope.task.iFile = $scope.iFile
  $scope.task.iname = $scope.iFilename
  $scope.task.itype = $scope.iFiletype
  baseTasks.post($scope.task).then (data)->
    $scope.tasks.unshift($scope.task)
    $scope.go('/tasks')
  ,(error)->
   # some code  

在服务器端,我有一个具有此设置的模型 Task.rb:

require 'file_size_validator' 
class Task < ActiveRecord::Base
    belongs_to :user
    belongs_to :category
    has_many :comments, as: :commentable, dependent: :destroy
    validates_presence_of :title
    validates_presence_of :text
    validates_presence_of :price
    mount_uploader :pict, ImageUploader
    validates :pict, 
    :file_size => { 
      :maximum => 0.5.megabytes.to_i 
    } 
end

和TasksController,动作创建:

    def create
    params[:task][:pict] = parse_image_data(params[:iFile]) if params[:iFile]

    @task = Task.new(task_params)

    if @task.save
      clean_tempfile
      render_with_protection @task.to_json, {status: :created, location: @task }
    else
      render_with_protection @task.errors.to_json, {status: :unprocessable_entity }
    end
  end

private

def task_params
  params.require(:task).permit(:desc, :text, :price, :title, :ed, :category_id, :pict, :user_id)
end


def parse_image_data(image_data)
  Rails.logger.info 'decoding now'
  decoded_data = Base64.decode64(image_data) 
  # create 'file' understandable by Carrierwave
  @data = StringIO.new(decoded_data)
  @tempfile = Tempfile.new('task-image')
  @tempfile.binmode
  @tempfile.write decoded_data
  @tempfile.rewind

  ActionDispatch::Http::UploadedFile.new(
    :tempfile => @tempfile,
    :content_type => params[:itype],
    :filename => params[:iname]
    )
 end

 def clean_tempfile
    if @tempfile
       @tempfile.close
       @tempfile.unlink
     end
 end

我在哪里解码图像并将其附加到 Carrierwave 需要的模型中。

所以请帮助我将多个图像附加到我的模型。 提前致谢。

【问题讨论】:

  • 我对它的工作原理有一个大概的了解。两张或多张图片加入数组或散列,然后通过 json 发送数据,然后根据载波需要配置并重新附加到服务器上的模型。

标签: ruby-on-rails json angularjs carrierwave


【解决方案1】:

您必须像这样遍历您的 uploadImage 指令中的每个图像:

reader = new FileReader()
reader.onload = (e) ->
  scope.iFile = btoa(e.target.result)
  scope.$apply()

elem.on "change", ->
  i = 0

  while i < elem.length
    x = 0

    while x < elem[i].files.length
      file = elem[i].files[x]
      scope.iFile = ""
      scope.iFilesize = file.size
      scope.iFiletype = file.type
      scope.iFilename = file.name
      scope.$apply()
      reader.readAsBinaryString file
      x++
    i++
  return

并且在您的 html 中,您的文件输入中应该有多个 true。

<input type='file' ng-mpdel='abc' multiple>

【讨论】:

  • 尝试创建另一个文件阅读器实例。从顶部删除它并在 while x &lt; elem[i].files.length 下添加内部更改
  • 好的,你在所有过程结束时调用$scope.createTask 时出错。所以最后一张图片将被创建为$scope.task.iFile = $scope.iFile 保存最后一张图片。所以你需要在你的文件循环中调用创建操作
  • 如果我这样做,我会用一张图片完成一些不同的任务,不是吗?
  • 不,每次你会得到不同的$scope.iFile所以会得到不同的文件对象。最好先试试
  • 也许我做错了,我在 plunker(script.js)plnkr.co/edit/fSWLnWIxpCiWrgZUooZf?p=catalogue 中的新指令。请参见。与新指令相同情况,数据保存但只有一张图片
【解决方案2】:

解决了。我必须创建具有多态关联的模型图像。所以我的模型是:

require 'file_size_validator' 
class Image < ActiveRecord::Base
    belongs_to :imageable, polymorphic: true
    mount_uploader :picture, PictureUploader
    validates :picture, 
    :file_size => { 
      :maximum => 0.5.megabytes.to_i 
    } 
end

class Task < ActiveRecord::Base
    belongs_to :user
    belongs_to :category
    has_many :comments, as: :commentable, dependent: :destroy
    has_many :images, as: :imageable, dependent: :destroy
end

在视图中上传图片的代码:

<input type="file" multiple accept="image/png, image/gif, image/jpeg" upload-image/>

在 @Nitin Verma 的帮助下在 angularJS 中创建指令(谢谢!)

app.directive 'uploadImage', ['Restangular',(Restangular)->
    baseImages = Restangular.all('images')
    return{
    restrict: 'A'
    link: (scope, elem)->
      elem.on 'change', ->
        i = 0
        im =[]
        filD =[]
        while i < elem.length
          x = 0
          while x < elem[i].files.length
            reader = new FileReader()
            reader.onload = (e)->
              im.push(btoa(e.target.result))
              scope.$apply()
            file = elem[i].files[x]
            scope.files = elem[0].files
            scope.iFile = ""
            filD[x]=[]
            filD[x].push(file.type)
            filD[x].push(file.name)
            scope.$apply()
            reader.readAsBinaryString file
            x++
          i++
        scope.arImages = im
        scope.fileInf = filD
        return
    }
  ]

还有我的 $scope.createTask :

$scope.createTask =->
  $scope.task.ed = $scope.edIz.name
  $scope.task.category_id = $scope.category_id.id
  $scope.task.user_id = $scope.curr.id
  baseTasks.post($scope.task).then (data)->
    $scope.taskId =data.id
    i = 0
    while i < $scope.arImages.length
      $scope.image ={}
      $scope.image.pict = $scope.arImages[i]
      $scope.image.iname = $scope.fileInf[i][1]
      $scope.image.itype = $scope.fileInf[i][0]
      $scope.image.task_id =$scope.taskId
      console.log($scope.image.task_id)
      imageRes.save( $scope.image )
      i++
    $scope.tasks.unshift($scope.task)
    $scope.go('/tasks')
  ,(error)->
    flash.error = error

我不得不使用 $resource,因为使用 Restangular 进行双重保存会挂起应用程序而不会出错。所以:

app.factory('imageRes', ['$resource', ($resource)->
    return $resource('/images/:id.json', {id: '@id'}, {
      update: {method:'PUT'},
      show: {method:'GET'},
      delete: {method:'DELETE'}

  })])

在ImagesController的服务器端,动作创建:

def create
    params[:image][:picture] = parse_image_data(params[:pict]) if params[:pict]
    @image = Image.new(image_params)
    clean_tempfile
    if @image.save

      # render_with_protection @task.to_json, {status: :created, location: @task }
      render json: @image
    else
      render_with_protection @image.errors.to_json, {status: :unprocessable_entity }
    end
  end

方法 parse_image_data 同问题描述。

如果有人知道更好的方法来解决这个问题,请写出来!

【讨论】:

    猜你喜欢
    • 2018-04-19
    • 2015-05-12
    • 2012-06-15
    • 1970-01-01
    • 1970-01-01
    • 2019-01-06
    • 2016-10-30
    • 1970-01-01
    • 2015-12-05
    相关资源
    最近更新 更多