RIT Tech Blog

株式会社RITのエンジニアが知見を共有する技術ブログです。

JS/TSで特定ディレクトリ以下のモジュールをまとめてexport/importしたい

CTOの福田です

JSって書いてますがTSの話しかしませんごめんなさい

app.ts
├ modules
│  ├ a.ts
│  └ b.ts
└ ...

こんな感じのファイル構成があったときに、app.tsでmodules/aとmodules/bを使おうとすると

// modules/a.ts
export default class A {
}

// modules/b.ts
export default class B {
}


// app.ts
import A from './modules/a';
import B from './modules/b';

class App {
}

AとBを別々にimportする必要がある 2つぐらいだと問題ないけど増えてくると面倒

// app.ts
import { A, B } from './modules';

って書けると嬉しい

とりあえず一つのファイルでimportしてそこからexportしてみる

// modules/modules.ts
import A from './a';
import B from './b';

export { A, B };

// app.ts
import { A, B } from './modules/modules';

これだとmodules/modulesがダサい

index.(js|ts)ってファイルを置いておくと、親ディレクトリがimportされたときにそのファイルがimportされる(なんの仕様かはちゃんと調べてない)

// modules/index.ts
import A from './a';
import B from './b';

export { A, B };

// app.ts
import { A, B } from './modules';

index.tsでimportするモジュールをいちいち書かなきゃいけないのが面倒

// modules/a.ts
export class A {
}

// modules/b.ts
export class B {
}

// modules/index.ts
export * from './a';
export * from './b';

export * from 'xxx'でそのモジュールでexportしてるモジュールを全てexportできる ただ、default exportしてると動いてくれないのでexportにしてる

僕がやれたのはここまでなので、誰かJSとかTSのすごい人がいたら

import { A, B } from './modules';

import A from './modules/a';

ができてindex.tsを書くのが面倒じゃない良い方法あれば教えてください!

ActiveStorageでattachできるものについて調べてみた

福田です

ActiveStorage便利ですよね

railsのmodelにファイルを簡単に紐づけることができるんですが、form postされたファイルだけじゃなくてdirect uploadで発行された謎トークンとかもattachできて混乱しちゃったので、結局何がattachできるのかコード読んで調べてみました

↓はhas_oneなattachのコードです

# Associates a given attachment with the current record, saving it to the database.
#
#   person.avatar.attach(params[:avatar]) # ActionDispatch::Http::UploadedFile object
#   person.avatar.attach(params[:signed_blob_id]) # Signed reference to blob from direct upload
#   person.avatar.attach(io: File.open("/path/to/face.jpg"), filename: "face.jpg", content_type: "image/jpg")
#   person.avatar.attach(avatar_blob) # ActiveStorage::Blob object
def attach(attachable)
    blob_was = blob if attached?
    blob = create_blob_from(attachable)

    unless blob == blob_was
        transaction do
            detach
            write_attachment build_attachment(blob: blob)
        end
        blob_was.purge_later if blob_was && dependent == :purge_later
    end
end

どうやらattachは四種類の引数を受け取るようです

  • ActionDispatch::Http::UploadedFile
    • form postされたfile
  • signed_blob_id
    • ファイルそのものではなくてdirect uploadでアップロードされたファイルを表すID?
  • io
  • ActiveStorage::Blob
    • active_storage_blobsかな?
    • すでにattachされてるファイルを別のmodelに紐づけたりできそう

IOクラスのインスタンスを直接attachできるのは初めて知ったので試してみましょう

User model作って

class User < ApplicationRecord
    has_one_attached :avatar
end

適当に置いといたpngをattachしてみる

irb(main):012:0> f = File.open(Rails.root.join('storage', 'sample_avatar.png').to_s)
=> #<File:/app/storage/sample_avatar.png>
irb(main):013:0> User.first.avatar.attach(io: f, filename: 'sample_avatar.png', content_type: 'image/png')

urlを取得してみる

irb(main):023:0* include Rails.application.routes.url_helpers
=> Object
irb(main):024:0> default_url_options[:host] = "localhost:3000"
=> "localhost:3000"
irb(main):025:0> url_for User.first.avatar
  User Load (0.3ms)  SELECT  `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
  ActiveStorage::Attachment Load (1.9ms)  SELECT  `active_storage_attachments`.* FROM `active_storage_attachments` WHERE `active_storage_attachments`.`record_id` = 1 AND `active_storage_attachments`.`record_type` = 'User' AND `active_storage_attachments`.`name` = 'avatar' LIMIT 1
  ActiveStorage::Blob Load (0.4ms)  SELECT  `active_storage_blobs`.* FROM `active_storage_blobs` WHERE `active_storage_blobs`.`id` = 1 LIMIT 1
=> "http://localhost:3000/rails/active_storage/blobs/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBCZz09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--c0c210c1622d0f9c9d208352011ee63a9aa8d5f1/sample_avatar.png"

ちゃんとattachできてる

IOのインスタンスってことはopen-uriとか使ってweb上の画像とかも直接attachできるので、SNS連携で登録された時のデフォルトアバターとか設定するのに使えそうですね

tech blogはじめました & VIRECの裏側

初めまして、RIT CTOの福田(@gendaihyousyou)です。

RITにより多くの人から興味を持ってもらうために、エンジニアやデザイナーから知見を発信するtech blogを開設しました。

WEB系の技術を取り扱うことが多くなると思いますが、たまにコンサル系の記事も混じってくるかもしれません。

今回は初回ということでRITの紹介少しと現在開発中のサービスの裏側について書きます。

RITについて

会社の概要はホームページを見てもらうのが早いですが、実際にどんな仕事をしてるのかが想像しづらいかもしれないので補足してみます。

人材と仕事内容

2018年3月現在の社員数は8名で、大半がコンサルタントとして社外に常駐しています。

このブログを見てる方はおそらくエンジニアのはずで、コンサルタントの業務についてよく知らない方が多いと思う(自分が知らなかっただけかも)ので簡単に説明しておくと、

  • 何か課題を抱えている企業がコンサルタントを雇って課題の解決をお願いする
  • コンサルタントが関係各所にヒアリングを行って課題を洗い出す
  • 自身の持っている知見を駆使して解決方法を提案する

って事をやってるみたいです。知見というのは具体的には"電話での問い合わせに問題を抱えていればAmazon Connectで解決した事例がある"みたいなのですね。

なのでコンサルタントは領域によってはエンジニアよりもAWSやAzureのサービスに詳しかったりします。

エンジニアとデザイナーは基本的に自社のオフィスに常駐していて、コンサルタントが提案したソリューションを受託開発したり、社内で提案された新サービスを開発しています。

出社していたほうがコミュニケーション取りやすいので基本的には出社してますが、体調不良や家で荷物受け取らなきゃいけないみたいな時はリモートでも作業をしてます。

技術スタック

  • インフラ
  • サーバサイド
  • フロントエンド
    • TypeScript, Webpack, React(no Redux), Bootstrap, Sass
  • その他利用ツール

がメインですが、高速に開発する事を第一としているので、より良い選択肢があれば常にそれを試せるようしています。

現在開発中のサービスの裏側

現在RITではVIRECという、フリーのコンサルタントとクライアント企業をマッチングするサービスを開発しています。

普通のWEBアプリケーションなのですが、開発の特徴としては

  • Elastic Beanstalkにもろもろお任せ
  • だいたい使える限り最新のバージョンを使う
    • MySQL 5.7
    • Ruby 2.4
      • Beanstalkのプラットフォームで2.5系がまだ選べなかったので仕方なく
    • Rails 5.2
      • ユーザに紐づいた動画とか扱うのにActiveStorageをすごく使いたかったのでbeta版から使ってる
    • TypeScript 2.7
    • React 16.2
    • Webpack 4.0
  • 開発環境はdocker-composeにお任せ
  • DDD, TDDを一部採用

みたいな感じです。

バージョンに関してはこれで固定ではなく、可能な限りstable版が出ると同時ぐらいのタイミングで各々入れ替えていく事を目標にしています。

また、利用している技術スタックに関しても同様で、より良い方法があればフットワーク軽めに色々試してみる予定です。

最後に

VIRECの新機能開発やその他新サービスの開発など、開発するものは色々あるのにエンジニアの手が足りない状況です。

もしRITで働く事に興味があれば、ぜひ一度オフィスに遊びに来てください!

会社の問い合わせ用のアドレスにメール送ってもらうか僕のアカウントに連絡してもらえれば対応します!