グルチャ

herokuのMEANからCloudinaryに画像をアップロードしよう

前提は下記の通り。
1.yeoman angular-fullstakでMEAN(MongoDB+Express+AngularJS+Node.js)アプリを作成済み
 この方法はYEOMANを使ってMEAN(MongoDB+Express+AngularJS+Node.js)を作成しようを参照すること
2.アプリをherokuにデプロイ済み
 この方法はangular-fullstackをherokuにデプロイする方法を参照すること
 
手順は下記の通り。
 

1.herokuにCloudinaryアドオンを追加

heroku toolbeltから下記コマンドを実行

heroku addons:add cloudinary --app foo

※fooはherokuのアプリ名
 

2.Gruntfile.jsに環境変数CLOUDINARY_URLを設定

herokuのConfig variablesを参照して環境変数CLOUDINARY_URLをGruntfile.jsに設定する。
下記はGruntfile.jsの例。

module.exports = function (grunt) {
  var localConfig;
  try {
    localConfig = //require('./server/config/local.env');
      {
        DOMAIN: 'http://localhost:9000',
        SESSION_SECRET: "foo-secret",

        FACEBOOK_ID: 'app-id',
        FACEBOOK_SECRET: 'secret',

        TWITTER_ID: 'app-id',
        TWITTER_SECRET: 'secret',

        GOOGLE_ID: 'app-id',
        GOOGLE_SECRET: 'secret',

        CLOUDINARY_URL: 'cloudinary://999999999999999:XXXXXXXXXXXXXXXXXXXXXXXXXXXX@xxxxxxxxx',

        // Control debug level for modules using visionmedia/debug
        DEBUG: ''
      };
  } catch(e) {
    localConfig = {};
  }

※本来環境変数は./server/config/local.env.jsに設定すれば良いはずだが、なぜかgruntが読み込んでくれないのでGruntfile.jsに直接記入している。
 

3.npmでcloudinaryをインストール

端末から下記コマンドを実行

npm install cloudinary --save

 

4.bowerでangular-file-uploadをインストール

参考文献:angular-file-upload#Yeoman with bower automatic include
端末から下記コマンドを実行

bower install ng-file-upload --save
bower install ng-file-upload-shim --save

 

5.npmでconnect-multipartyをインストール

参考文献:How to get uploaded file in Node.js Express app using angular-file-upload
connect-multipartyをインストールする。
端末から下記コマンドを実行

npm install connect-multiparty --save

 

6.bower.jsonのangular-file-uploadの読み込み順序を変更

参考文献:angular-file-upload#install
bower.jsonの依存順序を下記通りにする。
bower.jsonの依存順序を変更することでgrunt serve時にclient/index.htmlのbower管理のjavascript読み込み順序も変更される。

{
  "dependencies": {
    "ng-file-upload-shim": "~1.6.12",
    "angular": ">=1.2.*",
    "ng-file-upload": "~1.6.12"
  }
}

 

7.client側ソースコード追加

参考文献:angular-file-upload#usage
client側ソースコードを追加する。
サンプルとほぼ同じだがソースコード例を示す。
HTML例

<div ng-controller="MyCtrl">
  <input type="file" ng-file-select="onFileSelect($files)">
</div>

※scriptの読み込みはclient/index.htmlで行われる。
 
app.js

angular.module('myApp', [
  'ngCookies',
  'ngResource',
  'ngSanitize',
  'btford.socket-io',
  'ui.router',
  'ui.bootstrap',
  'pascalprecht.translate',
  'angularFileUpload'  //追加
])

 
javascript例

angular.module('myApp')
  .controller('MyCtrl', function($scope, $upload) {
    $scope.onFileSelect = function($files) {
      for (var i = 0; i < $files.length; i++) {
        var file = $files[i];
        $scope.upload = $upload.upload({
          url: 'api/myapi', // server側API例
          file: file
        }).progress(function(evt) {
          console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));
        }).success(function(data, status, headers, config) {
          console.log(data);
        });
      }
    };
  });

 

8.server側ソースコード追加

参考文献:
angular-file-upload node.js example
How to get uploaded file in Node.js Express app using angular-file-upload
Cloudinary using with node.js
server側ソースコードを追加する。
yo angular-fullstack:endpointでserverにmyapiという名前のAPIを追加した場合の例を示す。
ファイル:server/api/myapi/index.js

'use strict';

var express = require('express');
var controller = require('./myapi.controller');

var router = express.Router();

var multipart = require('connect-multiparty');
var multipartMiddleware = multipart();

router.post('/', multipartMiddleware, controller.create);

module.exports = router;

 
ファイル:server/api/myapi/myapi.controller.js

'use strict';

var fs = require('fs');
var cloudinary = require('cloudinary');

exports.create = function(req, res) {
  if(req.files.file) {
    var stream = cloudinary.uploader.upload_stream(function(result) {
      return res.send(200);
    });
    fs.createReadStream(req.files.file.path).pipe(stream);
  } else {
    return res.send(400);
  }
};

 
以上で完成。
clientで画像が選択されるたびにserver経由でcloudinaryに画像ファイルがアップロードされる。
 


Comments ( 3 )

  1. SimtterCom » 画像を縮小してからサーバーへアップロードしよう

    […] 前提条件は下記の通り。 ・環境はherokuのMEANからCloudinaryに画像をアップロードしようで作った環境を流用する。 ・画像の縮小にHTML5のcanvasを使う。 […]

  2. ジョアンReply

    貴重な情報、ありがとうございます! そのまま上記コードを使うと、エラーが発生します: TypeError: Cannot read property 'defaultEncoding' of undefined 解決策は => https://github.com/cloudinary/cloudinary_npm/commit/bd590a19601d0d938a5083064f98536f1a0d0cf0 修正前 fs.createReadStream(req.files.file.path, {encoding: 'binary'}).on('data', stream.write).on('end', stream.end); 修正後 file_reader = fs.createReadStream(req.files.file.path).pipe(stream);

    • SimtterComReply

      情報ありがとうございます。 cloudinaryのAPIが変更になってましたね。 記事を更新しました。

Leave a reply

Your email address will not be published.

Time limit is exhausted. Please reload CAPTCHA.

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>