某Webアプリ、スマホアプリ開発の企業に勤めているエンジニアの日記です。主に、技術系記事や本の要約を発信します。

null byteエラーが発生したときの対処

やりたいこと

①S3から複数のZipファイルを取得

②複数のzipファイルを解凍しディレクトリ形式にする

③最終的に1つのzipファイルにしたい。

起きた問題

①でget_objectしたところ、以下のようになってしまい、②で必要なファイルパスが取得できない状況。

PK\u0003\u0004\u0014\u0000\u0000\u0000\u0000\u0000\xA1\x9AYQ\u0000\u0000\u0000

client = Aws::S3::Client.new(
    :region => 'ap-northeast-1',
    :access_key_id => '***',
    :secret_access_key => '***',
)      
@orders.each do |order|
    obj = client.get_object(
    bucket: "*",
    key: order.zip_file_name
    ).body.read  
    
    Rails.logger.debug obj.inspect
    #=> PK\u0003\u0004\u0014\u0000\u00....
end

原因

zipファイルの中身はバイナリデータ。

ダウンロードしてきたファイルの中身をobjに参照させている。.body.readという関数は、zipファイルの中身を参照する関数。なので、当然バイナリがログで出てくる。

解決策

readせずに、rubyzipのopen_bufferメソッドを使って、zipファイルを開く。 ただ、open_bufferメソッドはrubyzipの公式ドキュメントには載っていない。。。 もっと良いやり方見つけたい。

client = Aws::S3::Client.new(
    :region => 'ap-northeast-1',
    :access_key_id => '***',
    :secret_access_key => '***',
)      
@orders.each do |order|
    obj = client.get_object(
    bucket: "*",
    key: order.zip_file_name
    ).body  >> readしない!    
end

## get_objectでopenする
Zip::File.open_buffer(obj) do |zip|
    ~~
end

Railsについて初心者なりに調べてみた

ドキュメント

Ruby on Rails ガイド:体系的に Rails を学ぼう

Railsドキュメント

Railsとは

  • Rubyにより構築されたWEBアプリケーションフレームワーク
  • MVCアーキテクチャに基づいて構築されている
  • 他のフレームワークより少ないコードでアプリケーション開発ができるように考慮されている
  • それを実現するためにRailsには制約が多く存在し、慣れるまでは少し窮屈に感じることもあるかも?

Rubyの他フレームワーク

Sinatra

・軽量なフレームワークで簡潔に記述できる、最小限の労力でWebアプリケーションをすばやく作れる。 ・MVCアーキテクチャに基づいた設計ではない。 小規模開発に向き http://sinatrarb.com/

HANAMI

・バージョン1.0が2017年4月にリリースされた比較的新しいフレームワーク。 ・メモリの消費を抑えるために提供されている100以上の安定したAPIを利用できる ・応答速度などで高いパフォーマンスを発揮 長期的なメンテナンスを考え作られている https://hanamirb.org/

Ramaze

Sinatraと同様にシンプルかつ軽量で柔軟性のあるフレームワークRubyの書き方をそのまま踏襲できるようになっている http://ramaze.net/

他言語フレームワークとの比較

Web開発フレームワークのシェアと推移

Stack Overflow

image.png

djangoとlaravelがトレンド上昇している。

ruby on rails は2011年以降、下降している。

Ruby on rails のトレンド下降している要因

Twitterが、Ruby on RailsからJavaVMへ移行する理由

Twitterの膨大化したアクセスを、railsで構築されたシステムよりもJavaVMの方が速やかに処理できる。

→大規模システム開発で使われるケースが世界的に減っている。

なぜ一時期、一世を風靡したRuby on railsが、「railsはもう終わった」と言われるようになったのか?

その一部の背景を上記で説明しました。以下は具体的にかかれている記事

「Railsは終わった」と言われる理由 - Qiita

ただ日本ではスタートアップ中心に仕事がまだまだたくさんある。

例、Cookpad, Gunosy, 食べログ, Freee, Crowdworks

開発環境

  • ローカル
  • Virtual Box
  • Docker
  • Cloud9(AWS)

開発の流れ(ローカル環境)

基本的にMVCモデルの設計に沿って、ファイルを作成する。

image.pngrailsチュートリアルから抜粋

参考文献

Ruby on Railsだけじゃない!Rubyフレームワーク6選

Ruby on Rails チュートリアル:プロダクト開発の0→1を学ぼう

zipとgzipの違い

Adminerをいじっていてこれなんだ?と疑問に思ったので、さくっとメモしておきます。

zipとは

圧縮ファイルの形式で現在一番ポピュラーなもの

gzipとは

GNU Zipのこと。

GNU(グヌー、[ɡnuː] ( 音声ファイル))とはオペレーティングシステム であり、かつコンピュータソフトウェアの広範囲に渡るコレクションである。 GNUは完全にフリーソフトウェアから構成されている。 GNUは"GNU's Not Unix! "(「GNUUNIXではない」)の再帰的頭字語である。 wikipediaより https://ja.wikipedia.org/wiki/GNU#:~:text=GNU%EF%BC%88%E3%82%B0%E3%83%8C%E3%83%BC%E3%80%81%5B%C9%A1n,%E7%9A%84%E9%A0%AD%E5%AD%97%E8%AA%9E%E3%81%A7%E3%81%82%E3%82%8B%E3%80%82

それぞれの主な役割

zip

圧縮アーカイバ

※圧縮アーカイバ = 複数のファイルを一つのファイルにまとめる機能をもつ

gzip

単なる圧縮機能

ReactNative × FirestoreでiOSアプリを作成する手順とまとめ

概要

CloudFirestoreとは

Firebaseが提供している、NoSQLベースのデータベースのうちの一つ(MBaasの一つ)

RealtimeDatabase → CloudFirestoreに進化!

Q、何が改善されてる?

A、データモデルの改善、クエリ強化されている。

Firebaseの機能とデータベース

image.png

準備

Firebaseプロジェクトのセットアップ

Firebase公式ページからコンソール画面に移動して、新規アプリ作成。

プロジェクトIDとロケーションは後で変更が出来ないので、注意!

※国内向けサービスの場合、asia-northeast1(東京)or asia-northeast2(大阪)

バックエンド側のセットアップ

  • Firebase CLIをインストールする。これを使うと、Firebaseを使った開発がより効率的になる。
    npm install firebase-tools
  • デプロイを可能にするためにセットアップする。
    npm firebase login
  • Firestoreをセットアップ

    最初はテストモードで開始。

f:id:t2s-single:20201230204134p:plain

  • npmモジュールの追加
    npm install @react-native-firebase/app

iOSアプリ開発環境のセットアップ

  • CocoaPods経由でFirebaseをインストール。

    Finderで、「プロジェクト名」→「ios」→「podfile」を開く。podfile内にテキストで以下を記述する。

    target 'Project' do
      pod 'Firebase/Core'
      pod 'Firebase/Auth'
      pod 'Firebase/Firestore'
      pod 'Firebase/Functions'
    end

iosアプリにFirebaseを作成するページで以下の流れに沿って進める。

  • pod install
    cd ios/ && pod install
  • Firebase SDKのセットアップ
    npm install @react-native-firebase/app
    npm install @react-native-firebase/auth
    npm install @react-native-firebase/firestore

実装(データの操作)

  • CollectionとDocumentの取得、追加
    import firestore from '@react-native-firebase/firestore';

    // 'Users'というCollectionの、'KHarada'というDocumentを指定
    const userDocument = firestore()
      .collection('Users')
      .doc('kHarada');
        // 取得
        .get()
        // 追加
        .set()
  • AuthenticationアカウントとFirestoreドキュメントの作成

    新規登録画面で入力されたメールアドレス等をfirestoreドキュメントにぶちこむ。

    handleSubmit = async () => {
        try {
        // メールアドレス認証
          let res = await auth()
            .createUserWithEmailAndPassword(this.state.email, this.state.password)
            .catch((err) => {
              console.log(err);
            });
    
        // ドキュメント内に保存するフィールド
            let userData = {
              uid: res.user.uid,
              email: this.state.email,
            };
                    
        // userDataを保存する
            await firestore()
              .collection('users')
              .doc(res.user.uid)
              .set(userData);
              
              console.log('email login success');
              this.props.navigation.navigate('App');
          }

        } catch (e) {
          console.log(e.message);
        }
      };
  • クエリの機能と種類

    クエリを使いこなすことで、firestore内に保存されているデータを制御し、自在に操作することが可能

  • 条件制限

where

Ex, 18歳以上のみ取得したいとき

        firestore()
          .collection('Users')
          // 18歳以上のみ
          .where('age', '>=', 18)
          .get()
  • 件数制限

limit

ドキュメントの数を制限したいとき

        firestore()
          .collection('Users')
          // 18歳以上のみ
          .where('age', '>=', 18)
          // ドキュメントを20こまで
          .limit(20)
          .get()
  • 並べ替え

order By

        firestore()
          .collection('Users')
          // 降順で並べ替え
          .orderBy('age', 'desc')
          .get()
  • 特定のポイントから開始/終了

start At / end At

        firestore()
          .collection('Users')
          .orderBy('age', 'desc')
            // 18歳から30歳まで
          .startAt(18)
          .endAt(30)
          .get()

startAtでリロード後の追加データをどのポイントから取得するのか指定する。

Firestoreの課題

  • マイグレーション

    マイグレーション:ソフトウェアやシステム、データなどを別の環境に移転したり、新しい環境に切り替えたりすること。

    データのエクスポートが出来ない。バックアップする方法がない。

    (このデメリットはさほど気にならない気もする・・)

  • データベース設計

    データの形式が自由なだけあって、フィールドに書き込んだデータの型がわからなかったりする。

    チーム内でのドキュメント作成と共有が重要。

  • 検索

    ネイティブインデックスの作成やドキュメント内のテキストフィールドの検索をサポートしていないので、Algoliaという検索APIを使って、検索周りはそっちに任せる。

Firebaseでバックエンドエンジニア不在のアプリ開発 クックパッドが体感した、メリットと課題 #エンジニアHub - エンジニアHub|若手Webエンジニアのキャリアを考える!

全文検索 | Firebase

Firestoreを今まで触ってみて思ったこと

  • プロジェクトの規模にもよるが、とにかく機能が充実していて、あまり不便さを感じていない。なので、RDBの必要性が見えてこない。
  • Authenticationは多くのSNSと連携することが可能なので、モダンなプロダクトにはもってこい
  • 多くの企業が利用しているせいか、日本語の記事が多い印象。初心者に優しい。

参考ページ

Cloud Firestore | React Native Firebase

実践Firestore (技術の泉シリーズ(NextPublishing))

CodeIgniterのMVCモデル

CodeIgniterのMVCモデルの書き方をメインに書いています。

Controller

  • 静的なページを作成するためのクラスを実装したコントローラを作成する。

    作成するクラスは、system/core/Controller.php の CI_Controller クラスを継承させる。

    引数にページの名前を取る。

    そのページをロードするメソッドは、show()

    class Pages extends CI_Controller {

            public function show($page = 'home')
            {
            }

    }
  • クラスの継承
    • オーバーライド:小クラスと親クラスで同じメソッドを使用した場合、コクタスが優先され、親クラスを上書きする。
  • メソッド

    特殊な役割を持つメソッド

    • デフォルトメソッド:index()
      • 第二メソッドが空の時に実行されるメソッド
    • 再マップメソッド:_remap()
      • デフォルトメソッドより優先して呼び出される(デフォルトメソッド必要なくなる)
      • 通常のURIルーティングは無視される。
    • 出力メソッド:_output()
      • ユーザー側のブラウザにデータを返す手前で何らかの処理を行うことができる。
    • コンストラクタメソッド:クラス名と同名()
      • コントローラクラスが呼ばれた時に一度だけ実行される。
      • コントローラ内で共通で使用するライブラリなどを初期化する場合や決まった処理を毎回実行したい場合に便利。
        function __construct() {
            // 親コントローラクラスのコンストラクタを呼び出す            
            parent::__construct();
        }
  • プライベートメソッド:_任意のメソッド名()
    • URLから直接アクセスできない。
    • 以下のような書き方で、デフォルトメソッドを経由して呼び出される。
        function index() 
        {
            echo $this->_private_method();
        }

        function _private_method()
        {
            echo 'プライベートメソッドです';
        }

View

  • 特徴
    • PHP構文とHTMLタグで記述できる
    • ビュー同士の連携が可能で、階層構造をもたせることができる。
    • ヘルパーやライブラリが直接利用できる。
    • キャッシュ機能がある。
    • Smartyのような疑似変数ができる。
  • Viewの読み込み
    $this->load->view('ファイル名', データの連想配列 or オブジェクト)
    <?php 
       class Hello extends CI_Controller
       {  
            // index()メソッドの中身>>'Hello World'
          public function index() 
          { 
             echo "Hello World"; 
          }

            // about()メソッドの中身>>about.php
          public function about() 
          { 
             $this->load->view('about'); 
          }
          
       } 
    ?>
  • ループ
    • foreach構文を使って繰り返し処理を行う。
    // Controller 

    function index()
    {
        $data["title"] = "サンプル"
        $data["contents"] = array("りんご", "みかん")
        $this->load->view("ファイル名", $data);
    }
    <title><?=$title?></title>
    .
    .
    .
    <ul>
        <?php foreach($contents as $item):?>
        <li><?=$item;?></li>
        <?php endforeach;?>
    </ul>

Model

  • Modelの書き方
    <?php 
       class Model_name extends CI_Model 
       { 
          public function __construct()
          { 
             parent::__construct(); 
          } 
       } 
    ?>
  • Modelの読み込み
    • 読み込み
    // /system/application/models/read/read.phpを読み込みたいとき
    $this->load->model('read/read');
  • メソッドの実行
    $this->read->function();

CodeIgniterのデータベース接続方法

データベースへの接続

なるべく自動接続。理由は手動接続はすべてのコントローラの接続を作成する必要があるため。

  • 自動接続

    application/config/autoload.phpを使用して行う

    php $autoload['libraries'] = array('database');

  • 手動接続

    特定のコントローラのデータベース接続が必要な場合に使う。

    php $this->load->database();

PHPでの開発を始めるので、概要をまとめてみた

役割

  • HTMLを作ること
  • データを管理すること

ローカル開発環境

サーバーにアップせずにPHPが書き換えたHTMLを確認するために必要な作業

必要なインストール

  • PHP
  • Webサーバー

上記はインストールがかなり難しい。

なので、インストールをアシストしてくれる、XAMPPやMAMPを使う。

MAMPとは

MacintoshApacheMySQLPHPを省略してつなげた名前。

簡単にWeb開発環境を立ち上げられるようにするために必要なソフトウェアをパッケージ化したもの。

XAMPPとほぼ一緒。開発元が違う。

RubyPythonを使う人向け。

コードの書き方

// 最初に<?php ?> で囲う。
<?php echo 'こんにちは!';  // こんにちは!と表示される。 ?>  
<?php echo 'こんにちは!' . date('l');  // こんにちは!Mondayと表示される。
?>  

// 変数
<?php 
    $message = 'こんにちは' . date('l');
?>
<?= $message;  // こんにちは!Mondayと表示される ?>  

// 乱数
<?php 
    $n = mt_rand(1, 3)  // 1以上3以下
?>

// ファイルをインポートする
<?php 
    include('ファイル名')
// この記述だけで反映される
// 以降にHTML記述がなければ、閉じタグ不要
?>

// HTMLタグの中に文字列を記述する時
<title>
    <?= htmlspecialchars($title, ENT_QUOTES, 'UTF-8'); // 別ファイルで表示させたい値を、$titleに代入する
    ?>
    PHPのサイト
</title>

// キャスト
<?php
    $x = (string) 10;    // int型の10を、string型の'10'に変換
?>

// 変数を調査するとき
<?php 
    var_dump($x)
?>

// 連想配列(JSだとオブジェクトに近い?)
<?php 
    $hashira = [
        '水柱' => '冨岡義勇'    // key => value
    ];
    echo $hashira['水柱'];  // 冨岡義勇と表示される
    // keyはstring型かint型のみOK
?>

// 関数の定義
<?php 
    function 関数名($引数1, $引数2) {
        // 処理
        return 返り値;
    }
    関数名($実引数1, $実引数2);
?>

// アクセス修飾子
<?php 
    class Human{
    // プロパティ
        public $name;  // プロパティをクラスの外に公開する
        protected $birthday;
        private $gender;  // プロパティをクラスの外に公開しない。基本的にprivate

    // メソッド
        public function walk() {
            echo '歩く'.PHP_EOL;
        }

        public function eat() {
            echo '食べる'.PHP_EOL;
        }
    }
?>

// コンストラクタ(上の続き)
<?php 
    $human = new Human();
    $human -> eat();
    $human -> walk();
?>