Rails 4 Angularjs Paperclip如何上传文件

 WenFJ 发布于 2023-02-11 14:58

我是新手用Rails 4操纵angularjs,它只提供api.我尝试创建一个简单的角度服务来上传文件.但我使用Paperclip来管理文件,我有一些问题.

首先,我不明白如何正确收集输入文件.我已经看到很多插件或胖指令来做到这一点.但我想要一个简单的指令收集我的文件并放入我的ng模型.

最后我想知道在Base64中编码我的文件是否更有效?

我的Rails控制器

class Api::EmployeesController < Api::BaseController
  def create
    employee = Employee.create(employee_params)
    if employee.save
      render json: employee
    else
     render :json => { :errors => employee.errors.full_messages }, :status => 406
     end
  end

  def employee_params
    params.require(:employee).permit(:first_name,:mobile_phone,:file)
  end
end

我的Angularjs服务

angular.module('test').factory 'Employee', ($resource, $http) ->
 class Employee
  constructor: (errorHandler) ->
  @service = $resource('/api/employees/:id',
  {id: '@id'},
  {update: {method: 'PATCH'}})
  @errorHandler = errorHandler

  create: (attrs, $scope) ->
    new @service(employee: attrs).$save ((employee) ->
      $scope.employees.push(employee)
      $scope.success = true
      $timeout (->
        $scope.success = false
      ), 3000
    ), @errorHandler

我的Angularjs控制器

angular.module('test').controller "EmployeesController", ($scope, $timeout,  $routeParams, $location, Employee) ->

$scope.init = ->
 @employeeService = new Employee(serverErrorHandler)
 $scope.employees = @employeeService.all($scope)

$scope.createEmployee = (employee) ->
  if $scope.employeeFirstName
    @employeeService.create (
      first_name: $scope.employeeFirstName
      last_name:     $scope.employeeLastName
      promotion: $scope.employeePromotion
      mobile_phone: $scope.employeeMobilePhone
      nationality: $scope.employeeNationality
      social_number: $scope.employeeSocialNumber
      born_place: $scope.employeeBornPlace
      employee_convention: $scope.employeeConvention
      employee_type: $scope.employeeType
  ), $scope
  else
    $scope.error = "fields missing"

rcheuk.. 13

经过几天的故障排除并弄清楚这两种技术是如何工作的(我对两者都不熟悉),我设法让事情变得有效.我不知道这是不是最好的方式,但它确实有效.如果有人有任何改进,我会很高兴听到他们.

一般来说,我做了以下事情:

在AngularJS中创建一个指令来处理文件上载

将文件编码为base64 String并将其附加到JSON对象.

Rails控制器使用StringIO解码base64 String并将文件重新附加到参数

然后我使用新的更新参数更新或创建了模型.

它感觉真的很迂回,所以如果有另一种方法可以做到这一点,我想知道!

我正在使用Rails 4和AngularJS,Paperclip和Restangular的最新稳定版本.

这是相关的代码:

Angularjs指令

var baseUrl = 'http localhost:port'; // fill in as needed

angular.module('uploadFile', ['Restangular']) // using restangular is optional

.directive('uploadImage', function () {
return {
 restrict: 'A',
 link: function (scope, elem, attrs) {
  var reader = new FileReader();
  reader.onload = function (e) {
    // retrieves the image data from the reader.readAsBinaryString method and stores as data
    // calls the uploadImage method, which does a post or put request to server
    scope.user.imageData = btoa(e.target.result);
    scope.uploadImage(scope.user.imagePath);
    // updates scope
    scope.$apply();
  };

  // listens on change event
  elem.on('change', function() {
    console.log('entered change function');
    var file = elem[0].files[0];
    // gathers file data (filename and type) to send in json
    scope.user.imageContent = file.type;
    scope.user.imagePath = file.name;
    // updates scope; not sure if this is needed here, I can not remember with the testing I did...and I do not quite understand the apply method that well, as I have read limited documentation on it.
    scope.$apply();
    // converts file to binary string
    reader.readAsBinaryString(file);
  });
 },
 // not sure where the restangular dependency is needed. This is in my code from troubleshooting scope issues before, it may not be needed in all locations. will have to reevaluate when I have time to clean up code.
 // Restangular is a nice module for handling REST transactions in angular. It is certainly optional, but it was used in my project.
 controller: ['$scope', 'Restangular', function($scope, Restangular){
  $scope.uploadImage = function (path) {
   // if updating user
    if ($scope.user.id) {
      // do put request
      $scope.user.put().then( function (result) {
        // create image link (rails returns the url location of the file; depending on your application config, you may not need baseurl)
        $scope.userImageLink = baseUrl + result.image_url;
      }, function (error) {
        console.log('errors', JSON.stringify(errors));
      });
    } else {
      // if user does not exist, create user with image
      Restangular.all('users')
      .post({user: $scope.user})
      .then(function (response) { 
        console.log('Success!!!');
      }, function(error) {
        console.log('errors', JSON.stringify(errors));
      });
    }
   };
 }]
};
});

带指令的角度文件



Click to add an image.

这会创建一个隐藏文件输入.所述userImageLink被设定在控制器中,因为是openFileWindow()方法.如果存在用户图像,则显示该图像,否则显示空白div,告知用户单击以上载图像.

在负责上面的html代码的控制器中,我有以下方法:

// triggers click event for input file, causing the file selection window to open
$scope.openFileWindow = function () {
  angular.element( document.querySelector( '#fileUpload' ) ).trigger('click');
  console.log('triggering click');
};

Rails Side

在用户模型的控制器中,我有以下方法:

# set user params 
before_action :user_params, only: [:show, :create, :update, :destroy]

def create
  # if there is an image, process image before save
  if params[:imageData]
    decode_image
  end

  @user = User.new(@up)

  if @user.save
    render json: @user
  else
    render json: @user.errors, status: :unprocessable_entity
    Rails.logger.info @user.errors
  end
end

def update
  # if there is an image, process image before save
  if params[:imageData]
    decode_image
  end

  if @user.update(@up)
    render json: @user
  else
    render json: @user.errors, status: :unprocessable_entity
  end
end

private 

  def user_params
    @up = params.permit(:userIcon, :whateverElseIsPermittedForYourModel)
  end

  def decode_image
    # decode base64 string
    Rails.logger.info 'decoding now'
    decoded_data = Base64.decode64(params[:imageData]) # json parameter set in directive scope
    # create 'file' understandable by Paperclip
    data = StringIO.new(decoded_data)
    data.class_eval do
      attr_accessor :content_type, :original_filename
    end

    # set file properties
    data.content_type = params[:imageContent] # json parameter set in directive scope
    data.original_filename = params[:imagePath] # json parameter set in directive scope

    # update hash, I had to set @up to persist the hash so I can pass it for saving
    # since set_params returns a new hash everytime it is called (and must be used to explicitly list which params are allowed otherwise it throws an exception)
    @up[:userIcon] = data # user Icon is the model attribute that i defined as an attachment using paperclip generator
  end

user.rb文件将具有:

### image validation functions
has_attached_file :userIcon, styles: {thumb: "100x100#"}
#validates :userIcon, :attachment_presence => true
validates_attachment :userIcon, :content_type => { :content_type => ["image/jpg", "image/gif", "image/png"] }
validates_attachment_file_name :userIcon, :matches => [/png\Z/, /jpe?g\Z/]

我认为这是一切相关的东西.希望这可以帮助.当我有时间时,我可能会在其他地方更清楚地发布这个.

撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有