Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Herokuで学ぶ、初めてのPerl

akiym
September 20, 2013

 Herokuで学ぶ、初めてのPerl

YAPC::Asia 2013

akiym

September 20, 2013
Tweet

More Decks by akiym

Other Decks in Technology

Transcript

  1. DQBONΛΠϯετʔϧ͢Δ $ curl -L http://cpanmin.us | ↩ perl - App::cpanminus

    ΋͘͠͸ $ curl -L http://cpanmin.us | ↩ perl - --sudo App::cpanminus
  2. $ cpanm Amon2 $ amon2-setup.pl MyApp $ carton install $

    carton exec -- plackup app.psgi εέϧτϯΛ࡞੒͢Δ
  3. $ cpanm Amon2 $ amon2-setup.pl MyApp $ carton install $

    carton exec -- plackup app.psgi ґଘϞδϡʔϧΛΠϯετʔϧ
  4. $ cpanm Amon2 $ amon2-setup.pl MyApp $ carton install $

    carton exec -- plackup app.psgi ΞϓϦΛىಈ
  5. . ├── Build.PL ├── app.psgi ├── config │ ├── development.pl

    │ ├── production.pl │ └── test.pl ├── cpanfile ├── db ├── lib │ ├── MyApp │ │ ├── DB │ │ │ ├── Row.pm │ │ │ └── Schema.pm │ │ ├── DB.pm │ │ ├── Web │ │ │ ├── Dispatcher.pm │ │ │ ├── View.pm │ │ │ └── ViewFunctions.pm │ │ └── Web.pm │ └── MyApp.pm ├── sql │ ├── mysql.sql │ └── sqlite.sql ├── static │ ├── 404.html │ ├── 500.html │ ├── 502.html │ ├── 503.html │ ├── 504.html │ ├── bootstrap │ ├── css │ │ └── main.css │ ├── img │ ├── js │ │ ├── es5-shim.min.js │ │ ├── jquery-1.10.0.min.js │ │ ├── main.js │ │ ├── micro-location.js │ │ ├── micro_dispatcher.js │ │ ├── micro_template.js │ │ ├── sprintf-0.7-beta1.js │ │ └── strftime.js │ └── robots.txt ├── t │ ├── 00_compile.t │ ├── 01_root.t │ ├── 02_mech.t │ ├── 03_assets.t │ ├── 06_jslint.t │ └── Util.pm ├── tmpl │ ├── include │ │ ├── layout.tt │ │ └── pager.tt │ └── index.tt └── xt 19 directories, 52 files
  6. . ├── Build.PL ├── app.psgi ├── config │ ├── development.pl

    │ ├── production.pl │ └── test.pl ├── cpanfile ├── db ├── lib │ ├── MyApp │ │ ├── DB │ │ │ ├── Row.pm │ │ │ └── Schema.pm │ │ ├── DB.pm │ │ ├── Web │ │ │ ├── Dispatcher.pm │ │ │ ├── View.pm │ │ │ └── ViewFunctions.pm │ │ └── Web.pm │ └── MyApp.pm ├── sql │ ├── mysql.sql │ └── sqlite.sql ├── static │ ├── 404.html │ ├── 500.html │ ├── 502.html │ ├── 503.html │ ├── 504.html │ ├── bootstrap │ ├── css │ │ └── main.css │ ├── img │ ├── js │ │ ├── es5-shim.min.js │ │ ├── jquery-1.10.0.min.js │ │ ├── main.js │ │ ├── micro-location.js │ │ ├── micro_dispatcher.js │ │ ├── micro_template.js │ │ ├── sprintf-0.7-beta1.js │ │ └── strftime.js │ └── robots.txt ├── t │ ├── 00_compile.t │ ├── 01_root.t │ ├── 02_mech.t │ ├── 03_assets.t │ ├── 06_jslint.t │ └── Util.pm ├── tmpl │ ├── include │ │ ├── layout.tt │ │ └── pager.tt │ └── index.tt └── xt 19 directories, 52 files MJC.Z"QQ8FC%JTQBUDIFSQN σΟεύονϟʔ
  7. package MyApp::Web::Dispatcher; use strict; use warnings; use utf8; use Amon2::Web::Dispatcher::Lite;

    any '/' => sub { my ($c) = @_; return $c->render('index.tt'); }; post '/account/logout' => sub { my ($c) = @_; $c->session->expire(); return $c->redirect('/'); }; 1;
  8. . ├── Build.PL ├── app.psgi ├── config │ ├── development.pl

    │ ├── production.pl │ └── test.pl ├── cpanfile ├── db ├── lib │ ├── MyApp │ │ ├── DB │ │ │ ├── Row.pm │ │ │ └── Schema.pm │ │ ├── DB.pm │ │ ├── Web │ │ │ ├── Dispatcher.pm │ │ │ ├── View.pm │ │ │ └── ViewFunctions.pm │ │ └── Web.pm │ └── MyApp.pm ├── sql │ ├── mysql.sql │ └── sqlite.sql ├── static │ ├── 404.html │ ├── 500.html │ ├── 502.html │ ├── 503.html │ ├── 504.html │ ├── bootstrap │ ├── css │ │ └── main.css │ ├── img │ ├── js │ │ ├── es5-shim.min.js │ │ ├── jquery-1.10.0.min.js │ │ ├── main.js │ │ ├── micro-location.js │ │ ├── micro_dispatcher.js │ │ ├── micro_template.js │ │ ├── sprintf-0.7-beta1.js │ │ └── strftime.js │ └── robots.txt ├── t │ ├── 00_compile.t │ ├── 01_root.t │ ├── 02_mech.t │ ├── 03_assets.t │ ├── 06_jslint.t │ └── Util.pm ├── tmpl │ ├── include │ │ ├── layout.tt │ │ └── pager.tt │ └── index.tt └── xt 19 directories, 52 files DPOpH QM 1-"$,@&/7؀ڥม਺ʹΑͬͯDPOpH͕ ੾ΓସΘΔ w खݩͰQMBDLVQͨ͠ͱ͖ʹ͸ EFWFMPQNFOU w σϓϩΠͯ͠ಈ͔͍ͯ͠Δͱ͖ʹ͸ QSPEVDUJPO
  9. use File::Spec; use File::Basename qw(dirname); my $basedir = File::Spec->rel2abs(File::Spec->catdir(dirname(__FILE__), '..'));

    my $dbpath = File::Spec->catfile($basedir, 'db', 'development.db'); +{ 'DBI' => [ "dbi:SQLite:dbname=$dbpath", '', '', +{ sqlite_unicode => 1, } ], };
  10. . ├── Build.PL ├── app.psgi ├── config │ ├── development.pl

    │ ├── production.pl │ └── test.pl ├── cpanfile ├── db ├── lib │ ├── MyApp │ │ ├── DB │ │ │ ├── Row.pm │ │ │ └── Schema.pm │ │ ├── DB.pm │ │ ├── Web │ │ │ ├── Dispatcher.pm │ │ │ ├── View.pm │ │ │ └── ViewFunctions.pm │ │ └── Web.pm │ └── MyApp.pm ├── sql │ ├── mysql.sql │ └── sqlite.sql ├── static │ ├── 404.html │ ├── 500.html │ ├── 502.html │ ├── 503.html │ ├── 504.html │ ├── bootstrap │ ├── css │ │ └── main.css │ ├── img │ ├── js │ │ ├── es5-shim.min.js │ │ ├── jquery-1.10.0.min.js │ │ ├── main.js │ │ ├── micro-location.js │ │ ├── micro_dispatcher.js │ │ ├── micro_template.js │ │ ├── sprintf-0.7-beta1.js │ │ └── strftime.js │ └── robots.txt ├── t │ ├── 00_compile.t │ ├── 01_root.t │ ├── 02_mech.t │ ├── 03_assets.t │ ├── 06_jslint.t │ └── Util.pm ├── tmpl │ ├── include │ │ ├── layout.tt │ │ └── pager.tt │ └── index.tt └── xt 19 directories, 52 files UNQM ςϯϓϨʔτ $c->render('index.tt');
  11. package MyApp::Web::Dispatcher; use strict; use warnings; use utf8; use Amon2::Web::Dispatcher::Lite;

    any '/' => sub { my ($c) = @_; return $c->render('index.tt'); }; post '/account/logout' => sub { my ($c) = @_; $c->session->expire(); return $c->redirect('/'); }; 1; SFTQPOTFΛฦ͢
  12. CREATE TABLE IF NOT EXISTS image ( id INTEGER NOT

    NULL PRIMARY KEY, filename VARCHAR(64), src TEXT, ctime INT UNSIGNED NOT NULL, UNIQUE (filename) ); TRMTRMJUFTRM
  13. CREATE TABLE IF NOT EXISTS image ( id SERIAL PRIMARY

    KEY, filename VARCHAR(64), src BYTEA, ctime INT NOT NULL, UNIQUE (filename) ); TRMQHTRM
  14. package Gyazo::DB::Schema; use strict; use warnings; use utf8; use Teng::Schema::Declare;

    base_row_class 'Gyazo::DB::Row'; table { name 'image'; pk 'id'; columns qw(id filename src ctime); }; 1; MJC(ZB[P%#4DIFNBQN
  15. use DBD::Pg; use Digest::MD5 qw/md5_hex/; post '/upload' => sub {

    my ($c) = @_; my $imagedata = $c->req->upload('imagedata') or die; # アップロードできる画像は1MB未満とする die unless $imagedata->size < 1024 * 1024; # 画像データを読み込む my $src = do { open my $fh, '<:raw', $imagedata->path or die $!; local $/; <$fh>; }; # PNGであることをシグネチャで判定する die unless $src =~ /^\x89PNG\x0d\x0a\x1a\x0a/; my $filename = md5_hex($src) . '.png'; $c->db->fast_insert('image', { filename => $filename, src => [$src, {pg_type => DBD::Pg::PG_BYTEA}], ctime => time(), }); my $url = $c->req->base . $filename; return $c->create_response(200, [], [$url]); };
  16. use DBD::Pg; use Digest::MD5 qw/md5_hex/; post '/upload' => sub {

    my ($c) = @_; my $imagedata = $c->req->upload('imagedata') or die; # アップロードできる画像は1MB未満とする die unless $imagedata->size < 1024 * 1024; # 画像データを読み込む my $src = do { open my $fh, '<:raw', $imagedata->path or die $!; local $/; <$fh>; }; # PNGであることをシグネチャで判定する die unless $src =~ /^\x89PNG\x0d\x0a\x1a\x0a/; my $filename = md5_hex($src) . '.png'; $c->db->fast_insert('image', { filename => $filename, src => [$src, {pg_type => DBD::Pg::PG_BYTEA}], ctime => time(), });
  17. use DBD::Pg; use Digest::MD5 qw/md5_hex/; post '/upload' => sub {

    my ($c) = @_; my $imagedata = $c->req->upload('imagedata') or die; # アップロードできる画像は1MB未満とする die unless $imagedata->size < 1024 * 1024; # 画像データを読み込む my $src = do { open my $fh, '<:raw', $imagedata->path or die $!; local $/; <$fh>; }; # PNGであることをシグネチャで判定する die unless $src =~ /^\x89PNG\x0d\x0a\x1a\x0a/; my $filename = md5_hex($src) . '.png'; $c->db->fast_insert('image', { filename => $filename, src => [$src, {pg_type => DBD::Pg::PG_BYTEA}], ctime => time(), }); perldoc Plack::Request::Upload
  18. post '/upload' => sub { my ($c) = @_; my

    $imagedata = $c->req->upload('imagedata') or die; # アップロードできる画像は1MB未満とする die unless $imagedata->size < 1024 * 1024; # 画像データを読み込む my $src = do { open my $fh, '<:raw', $imagedata->path or die $!; local $/; <$fh>; }; # PNGであることをシグネチャで判定する die unless $src =~ /^\x89PNG\x0d\x0a\x1a\x0a/; my $filename = md5_hex($src) . '.png'; $c->db->fast_insert('image', { filename => $filename, src => [$src, {pg_type => DBD::Pg::PG_BYTEA}], ctime => time(), }); my $url = $c->req->base . $filename; return $c->create_response(200, [], [$url]); };
  19. post '/upload' => sub { my ($c) = @_; my

    $imagedata = $c->req->upload('imagedata') or die; # アップロードできる画像は1MB未満とする die unless $imagedata->size < 1024 * 1024; # 画像データを読み込む my $src = do { open my $fh, '<:raw', $imagedata->path or die $!; local $/; <$fh>; }; # PNGであることをシグネチャで判定する die unless $src =~ /^\x89PNG\x0d\x0a\x1a\x0a/; my $filename = md5_hex($src) . '.png'; $c->db->fast_insert('image', { filename => $filename, src => [$src, {pg_type => DBD::Pg::PG_BYTEA}], ctime => time(), }); my $url = $c->req->base . $filename; return $c->create_response(200, [], [$url]); }; ΠσΟΦϜ$imagedata->pathͷ಺༰ΛಡΈࠐΉ
  20. post '/upload' => sub { my ($c) = @_; my

    $imagedata = $c->req->upload('imagedata') or die; # アップロードできる画像は1MB未満とする die unless $imagedata->size < 1024 * 1024; # 画像データを読み込む my $src = do { open my $fh, '<:raw', $imagedata->path or die $!; local $/; <$fh>; }; # PNGであることをシグネチャで判定する die unless $src =~ /^\x89PNG\x0d\x0a\x1a\x0a/; my $filename = md5_hex($src) . '.png'; $c->db->fast_insert('image', { filename => $filename, src => [$src, {pg_type => DBD::Pg::PG_BYTEA}], ctime => time(), }); my $url = $c->req->base . $filename; return $c->create_response(200, [], [$url]); }; ਖ਼نදݱͰ1/(ͷγάωνϟΛ൑ఆ
  21. die unless $imagedata->size < 1024 * 1024; # 画像データを読み込む my

    $src = do { open my $fh, '<:raw', $imagedata->path or die $!; local $/; <$fh>; }; # PNGであることをシグネチャで判定する die unless $src =~ /^\x89PNG\x0d\x0a\x1a\x0a/; my $filename = md5_hex($src) . '.png'; $c->db->fast_insert('image', { filename => $filename, src => [$src, {pg_type => DBD::Pg::PG_BYTEA}], ctime => time(), }); my $url = $c->req->base . $filename; return $c->create_response(200, [], [$url]); };
  22. die unless $imagedata->size < 1024 * 1024; # 画像データを読み込む my

    $src = do { open my $fh, '<:raw', $imagedata->path or die $!; local $/; <$fh>; }; # PNGであることをシグネチャで判定する die unless $src =~ /^\x89PNG\x0d\x0a\x1a\x0a/; my $filename = md5_hex($src) . '.png'; $c->db->fast_insert('image', { filename => $filename, src => [$src, {pg_type => DBD::Pg::PG_BYTEA}], ctime => time(), }); my $url = $c->req->base . $filename; return $c->create_response(200, [], [$url]); }; perldoc Teng
  23. # PNGであることをシグネチャで判定する die unless $src =~ /^\x89PNG\x0d\x0a\x1a\x0a/; my $filename =

    md5_hex($src) . '.png'; $c->db->fast_insert('image', { filename => $filename, src => [$src, {pg_type => DBD::Pg::PG_BYTEA}], ctime => time(), }); my $url = $c->req->base . $filename; return $c->create_response(200, [], [$url]); };
  24. # PNGであることをシグネチャで判定する die unless $src =~ /^\x89PNG\x0d\x0a\x1a\x0a/; my $filename =

    md5_hex($src) . '.png'; $c->db->fast_insert('image', { filename => $filename, src => [$src, {pg_type => DBD::Pg::PG_BYTEA}], ctime => time(), }); my $url = $c->req->base . $filename; return $c->create_response(200, [], [$url]); }; $c->create_reponse()ͰϨεϙϯεΛ࡞੒͠ ը૾ͷ63-Λฦ͢
  25. get '/{filename:.+\.png}' => sub { my ($c, $args) = @_;

    my $image = $c->db->single('image', { filename => $args->{filename}, }); if ($image) { return $c->create_response( 200, ['Content-Type' => 'image/png'], [$image->src] ); } else { return $c->res_404; } };
  26. get '/{filename:.+\.png}' => sub { my ($c, $args) = @_;

    my $image = $c->db->single('image', { filename => $args->{filename}, }); if ($image) { return $c->create_response( 200, ['Content-Type' => 'image/png'], [$image->src] ); } else { return $c->res_404; } }; ਖ਼نදݱ͕࢖͑Δ(perldoc Router::Simple) $args->{filename}Ͱड͚औΔ͜ͱ͕Ͱ͖Δ
  27. get '/{filename:.+\.png}' => sub { my ($c, $args) = @_;

    my $image = $c->db->single('image', { filename => $args->{filename}, }); if ($image) { return $c->create_response( 200, ['Content-Type' => 'image/png'], [$image->src] ); } else { return $c->res_404; } }; status, [headers], [body]
  28. get '/history' => sub { my ($c) = @_; my

    @images = $c->db->search('image', {}, { order_by => {ctime => 'DESC'}, # 降順 } ); return $c->render('history.tt' => { images => \@images, }); };
  29. get '/history' => sub { my ($c) = @_; my

    @images = $c->db->search('image', {}, { order_by => {ctime => 'DESC'}, # 降順 } ); return $c->render('history.tt' => { images => \@images, }); }; DSFOEFS ςϯϓϨʔτ໊UUaςϯϓϨʔτม਺ 
  30. [% WRAPPER 'include/layout.tt' %] <div class="row"> [%- FOR image IN

    images %] <div class="col-lg-4"> <a href="[% uri_for('/' ~ image.filename) %]"> <img src="[% uri_for('/' ~ image.filename) %]" width="360" height="360" /> </a> </div> [%- END %] </div> [% END %] UNQMIJTUPSZUU
  31. [% WRAPPER 'include/layout.tt' %] <div class="row"> [%- FOR image IN

    images %] <div class="col-lg-4"> <a href="[% uri_for('/' ~ image.filename) %]"> <img src="[% uri_for('/' ~ image.filename) %]" width="360" height="360" /> </a> </div> [%- END %] </div> [% END %] UNQMIJTUPSZUU $c->render()Ͱ౉ͨ͠ςϯϓϨʔτม਺
  32. [% WRAPPER 'include/layout.tt' %] <div class="row"> [%- FOR image IN

    images %] <div class="col-lg-4"> <a href="[% uri_for('/' ~ image.filename) %]"> <img src="[% uri_for('/' ~ image.filename) %]" width="360" height="360" /> </a> </div> [%- END %] </div> [% END %] UNQMIJTUPSZUU image.filename → $image->filename
  33. [% WRAPPER 'include/layout.tt' %] <div class="row"> [%- FOR image IN

    images %] <div class="col-lg-4"> <a href="[% uri_for('/' ~ image.filename) %]"> <img src="[% uri_for('/' ~ image.filename) %]" width="360" height="360" /> </a> </div> [%- END %] </div> [% END %] UNQMIJTUPSZUU ~จࣈ࿈݁ ςϯϓϨʔτ಺
  34. requires 'perl', '5.008001'; requires 'Amon2', '4.03'; requires 'Text::Xslate', '1.6001'; requires

    'DBD::Pg' , '2.19.3'; requires 'JSON' , '2.50'; requires 'Module::Functions' , '2'; requires 'Plack::Middleware::ReverseProxy', '0.09'; requires 'Teng' , '0.18'; requires 'Test::WWW::Mechanize::PSGI' , '0'; requires 'Time::Piece' , '1.20'; on 'configure' => sub { requires 'Module::Build', '0.38'; requires 'Module::CPANfile', '0.9010'; }; on 'test' => sub { requires 'Test::More', '0.98'; }; DQBOpMF
  35. $ heroku create --stack cedar --buildpack ↩ https://github.com/akiym/heroku-buildpack-perl.git\#carton Creating sleepy-dusk-4854...

    done, stack is cedar BUILDPACK_URL=https://github.com/akiym/heroku-buildpack-perl.git#carton http://sleepy-dusk-4854.herokuapp.com/ | [email protected]:sleepy-dusk-4854.git Git remote heroku added $ git push heroku master -----> Fetching custom git buildpack... done -----> Perl/PSGI app detected -----> Vendoring Perl Using perl 5.16.3 -----> Bootstrapping cpanm/Carton -----> Installing dependencies with Carton -----> Installing Starman -----> Discovering process types Procfile declares types -> (none) Default types for Perl/PSGI -> web -----> Compiled slug size: 20.3MB -----> Launching... done, v5 http://sleepy-dusk-4854.herokuapp.com deployed to Heroku
  36. $ heroku create --stack cedar --buildpack ↩ https://github.com/akiym/heroku-buildpack-perl.git\#carton Creating sleepy-dusk-4854...

    done, stack is cedar BUILDPACK_URL=https://github.com/akiym/heroku-buildpack-perl.git#carton http://sleepy-dusk-4854.herokuapp.com/ | [email protected]:sleepy-dusk-4854.git Git remote heroku added $ git push heroku master -----> Fetching custom git buildpack... done -----> Perl/PSGI app detected -----> Vendoring Perl Using perl 5.16.3 -----> Bootstrapping cpanm/Carton -----> Installing dependencies with Carton -----> Installing Starman -----> Discovering process types Procfile declares types -> (none) Default types for Perl/PSGI -> web -----> Compiled slug size: 20.3MB -----> Launching... done, v5 http://sleepy-dusk-4854.herokuapp.com deployed to Heroku
  37. $ heroku create --stack cedar --buildpack ↩ https://github.com/akiym/heroku-buildpack-perl.git\#carton Creating sleepy-dusk-4854...

    done, stack is cedar BUILDPACK_URL=https://github.com/akiym/heroku-buildpack-perl.git#carton http://sleepy-dusk-4854.herokuapp.com/ | [email protected]:sleepy-dusk-4854.git Git remote heroku added $ git push heroku master -----> Fetching custom git buildpack... done -----> Perl/PSGI app detected -----> Vendoring Perl Using perl 5.16.3 -----> Bootstrapping cpanm/Carton -----> Installing dependencies with Carton -----> Installing Starman -----> Discovering process types Procfile declares types -> (none) Default types for Perl/PSGI -> web -----> Compiled slug size: 20.3MB -----> Launching... done, v5 http://sleepy-dusk-4854.herokuapp.com deployed to Heroku
  38. $ heroku create --stack cedar --buildpack ↩ https://github.com/akiym/heroku-buildpack-perl.git\#carton Creating sleepy-dusk-4854...

    done, stack is cedar BUILDPACK_URL=https://github.com/akiym/heroku-buildpack-perl.git#carton http://sleepy-dusk-4854.herokuapp.com/ | [email protected]:sleepy-dusk-4854.git Git remote heroku added $ git push heroku master -----> Fetching custom git buildpack... done -----> Perl/PSGI app detected -----> Vendoring Perl Using perl 5.16.3 -----> Bootstrapping cpanm/Carton -----> Installing dependencies with Carton -----> Installing Starman -----> Discovering process types Procfile declares types -> (none) Default types for Perl/PSGI -> web -----> Compiled slug size: 20.3MB -----> Launching... done, v5 http://sleepy-dusk-4854.herokuapp.com deployed to Heroku
  39. $ heroku addons:add heroku-postgresql Adding heroku-postgresql on sheltered-earth-3211... done, v6

    (free) Attached as HEROKU_POSTGRESQL_CYAN_URL Database has been created and is available ! This database is empty. If upgrading, you can transfer ! data from another database with pgbackups:restore. Use `heroku addons:docs heroku-postgresql` to view documentation. $ heroku pg:psql HEROKU_POSTGRESQL_CYAN_URL < sql/pg.sql NOTICE: CREATE TABLE will create implicit sequence "image_image_id_seq" for serial column "image.image_id" NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "image_pkey" for table "image" NOTICE: CREATE TABLE / UNIQUE will create implicit index "image_filename_key" for table "image" CREATE TABLE
  40. $ heroku addons:add heroku-postgresql Adding heroku-postgresql on sheltered-earth-3211... done, v6

    (free) Attached as HEROKU_POSTGRESQL_CYAN_URL Database has been created and is available ! This database is empty. If upgrading, you can transfer ! data from another database with pgbackups:restore. Use `heroku addons:docs heroku-postgresql` to view documentation. $ heroku pg:psql HEROKU_POSTGRESQL_CYAN_URL < sql/pg.sql NOTICE: CREATE TABLE will create implicit sequence "image_image_id_seq" for serial column "image.image_id" NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "image_pkey" for table "image" NOTICE: CREATE TABLE / UNIQUE will create implicit index "image_filename_key" for table "image" CREATE TABLE
  41. $ heroku addons:add heroku-postgresql Adding heroku-postgresql on sheltered-earth-3211... done, v6

    (free) Attached as HEROKU_POSTGRESQL_CYAN_URL Database has been created and is available ! This database is empty. If upgrading, you can transfer ! data from another database with pgbackups:restore. Use `heroku addons:docs heroku-postgresql` to view documentation. $ heroku pg:psql HEROKU_POSTGRESQL_CYAN_URL < sql/pg.sql NOTICE: CREATE TABLE will create implicit sequence "image_image_id_seq" for serial column "image.image_id" NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "image_pkey" for table "image" NOTICE: CREATE TABLE / UNIQUE will create implicit index "image_filename_key" for table "image" CREATE TABLE
  42. $ heroku addons:add heroku-postgresql Adding heroku-postgresql on sheltered-earth-3211... done, v6

    (free) Attached as HEROKU_POSTGRESQL_CYAN_URL Database has been created and is available ! This database is empty. If upgrading, you can transfer ! data from another database with pgbackups:restore. Use `heroku addons:docs heroku-postgresql` to view documentation. $ heroku pg:psql HEROKU_POSTGRESQL_CYAN_URL < sql/pg.sql NOTICE: CREATE TABLE will create implicit sequence "image_image_id_seq" for serial column "image.image_id" NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "image_pkey" for table "image" NOTICE: CREATE TABLE / UNIQUE will create implicit index "image_filename_key" for table "image" CREATE TABLE
  43. $ heroku addons:add heroku-postgresql Adding heroku-postgresql on sheltered-earth-3211... done, v6

    (free) Attached as HEROKU_POSTGRESQL_CYAN_URL Database has been created and is available ! This database is empty. If upgrading, you can transfer ! data from another database with pgbackups:restore. Use `heroku addons:docs heroku-postgresql` to view documentation. $ heroku pg:psql HEROKU_POSTGRESQL_CYAN_URL < sql/pg.sql NOTICE: CREATE TABLE will create implicit sequence "image_image_id_seq" for serial column "image.image_id" NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "image_pkey" for table "image" NOTICE: CREATE TABLE / UNIQUE will create implicit index "image_filename_key" for table "image" CREATE TABLE