後故障排除了幾天,搞清楚這兩種技術的工作(我是新來的兩個-.-)怎麼樣,我設法得到的東西的工作。我不知道這是否是最好的方式,但它是有效的。如果有人有任何改進,我會很高興聽到他們。
一般情況下,我做了以下內容:
- 在AngularJS創建一個指令來處理文件上傳
- 編碼的文件爲Base64字符串,並將其連接到一個JSON對象。
- 滑軌控制器解碼使用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));
});
}
};
}]
};
});
角文件與指令
<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
在控制器中設置,openFileWindow()
方法也一樣。如果用戶圖像存在,則會顯示,否則會顯示一個空格,告訴用戶點擊上傳圖像。
在控制器,其負責上面的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');
};
滑軌側
在用戶模型的控制器,我有以下方法:
# 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.r b文件會有這樣的:
### 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/]
我認爲這是一切都是相關的。希望這可以幫助。當我有時間時,我可能會更清楚地將這個帖子張貼在其他地方。
我嘗試用簡單的指令,但是當我後我的文件回形針獲得一個錯誤回形針:: AdapterRegistry :: NoHandlerError:沒有找到處理... – Pinou
你有沒有找到解決的辦法?我現在正在處理類似的情況。 – rcheuk
不,我現在放棄了 – Pinou