gpt4 book ai didi

javascript - Rails 4 Angularjs Paperclip 如何上传文件

转载 作者:可可西里 更新时间:2023-11-01 02:05:11 26 4
gpt4 key购买 nike

我是使用仅提供 api 的 Rails 4 操作 angularjs 的新手。我尝试创建一个简单的 Angular 服务来上传文件。但是我使用 Paperclip 来管理文件,但我遇到了一些问题。

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

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

我的 Rails Controller

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 Controller

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"

最佳答案

经过几天的故障排除和弄清楚这两种技术的工作原理(我对这两种技术都是新手 -.-),我设法让一些东西起作用。我不知道这是否是最好的方法,但它确实有效。如果有人有任何改进,我很乐意听到。

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

  • 在 AngularJS 中创建一个指令来处理文件上传
    • 将文件编码为 base64 字符串并将其附加到 JSON 对象。
  • Rails Controller 使用 StringIO 解码 base64 字符串并将文件重新附加到参数
    • 然后我使用更新后的新参数更新或创建了模型。

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

我正在使用 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));
});
}
};
}]
};
});

带指令的 Angular 文件

<input type="file" id="fileUpload" ng-show="false" upload-image />
<img ng-src="{{userImageLink}}" ng-click="openFileWindow()" ng-class="{ hidden: !userImageLink}" >
<div class="drop-box" ng-click="openFileWindow()" ng-class=" {hidden: userImageLink}">
Click to add an image.
</div>

这会创建一个隐藏文件输入。 userImageLink 在 Controller 中设置,openFileWindow() 方法也是如此。如果用户图片存在,它会显示,否则会显示一个空白的 div,告诉用户点击上传图片。

在负责上述html代码的 Controller 中,我有以下方法:

// 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 端

在用户模型的 Controller 中,我有以下方法:

# 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/]

我认为这是相关的一切。希望这可以帮助。当我有时间的时候,我可能会把这个贴在其他地方更清楚一点。

关于javascript - Rails 4 Angularjs Paperclip 如何上传文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20521366/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com