【現代語訳】スタートアップの情報収集のすヽめ
スタートアップの情報どこにあるねん
スタートアップってリリースされている記事とかが少ないので、面白い企業を探したくても見つからないことがよくあるんですよね。
そこで「どんなメディアを使ってスタートアップを探せばいいの?」という方向けに、私がオススメするスタートアップ特化型メディア・サービスを紹介していこうと思います。
(※どんな観点でスタートアップを探すべきか?は読者の目的によって異なると思うので説明しません。その点ご了承ください)
1. STARTUP DB
10,000社以上のスタートアップ・ベンチャー企業のデータと、企業家・投資家のインタビューが掲載されています。企業の登録数は圧倒的ですね。
老舗?企業、メガベンチャーとか何でも掲載されてる感じもしますが、創業1ヶ月のスタートアップの企業情報も掲載されてます。すごい。
「業界のカテゴリー」で企業を検索できます。
「資金調達額」「従業員数」「設立年数」「サブカテゴリー」などで、詳細検索もできます。
検索結果として、ビャビャーっと企業一覧が表示されます。
プレスリリース、資金調達の最新情報も一覧で見れます。
2. Startup Times
個人的にコレが一番好きです。
スタートアップのインタビュー記事が掲載されているサイトです。とにかくスタートアップに特化してます。リリースしたばかりのサービスが取り上げられている印象です。ワクワクします。
3. BRIDGE
「起業家と投資家を繋ぐ」テクノロジー&スタートアップ関連の話題をお届けするブログメディア。
スタートアップの資金調達、業務提携とかのニュースがよく掲載されている。
4. TechCrunch
定番のヤツ。
業界別のカオスマップも見れて便利です。EdTech、飲食インフラ、キャッシュレス、副業系サービスなどなど興味のある業界のマップを探してみましょう。
「TechCrunch Tokyo」の「Startup Battle」というイベントもあるようです。設立3年未満のスタートアップがビジネスアイデアを持ち寄ってピッチを繰り広げるイベントで、「こんなアツい会社あるんやすげええぇぇ」ってなります。
5. CoralCapital
こちらも有名ですね。
VCである株式会社Coral Capitalがスタートアップにまつわる情報を発信してくれています。
たとえば、「Coral Insights」の記事は日本のスタートアップ市場に関する記事や、VCはどのような観点をもとにスタートアップに出資しているのかといった話など、勉強になるものが多いです。
ベンチャー企業とスタートアップは何が違うのか? | Coral Capital
私が日本のスタートアップ投資の魅力を海外に伝えるときに話すこと | Coral Capital
「Coral Careers」には、スタートアップキャリアイベント「Startup Aquarium」などスタートアップの転職イベントの情報が配信されてたりします。
他にもCoral Capitalの投資先スタートアップの開発環境を一覧化したマップが掲載されていたり、面白いサービスが色々あります。
6. YOUTRUST
「転職市場に出てきづらい優秀な人材を採用できるキャリアSNS」を謳っているサービスです。
従来の転職サービスとは異なりSNSとして利用される側面を持っており、転職者や採用担当者などの呟きがタイムラインに流れているので、そこから興味を持った方に連絡を取ることができるカジュアルなイメージの強い転職サービスです。
転職活動として利用することもできますし、企業一覧ページ には色々な企業が掲載されているので、これを見るだけでも企業探しに使えると思います。 個人的には今時の「イケてそう」なスタートアップが多いイメージです。
7. ウメキワークス
ウメキワークスとは、個人投資家でもある梅木雄平さんが発信しているスタートアップの資金調達情報やIPO分析などの月額マガジンのことで、成長性のある選りすぐりのスタートアップの情報が多数掲載されています。
ただし情報の質が高い分月額3,000円の購読料がかかってしまうので「ずっと課金し続けるのは厳しい、、」という方もいらっしゃると思いますし、はたまた「そんないっぱい記事見る余裕無いわ」という方もいらっしゃると思います。
そんな方におすすめのウメキワークスでの情報収拾法は、「3,000円の購読料を一度だけ支払って、スタートアップ転職おすすめ企業50選【20XX年版】高野氏監修付き(1.5万字)」だけを読むという方法です。
この「スタートアップ転職おすすめ企業50選【20XX年版】高野氏監修付き(1.5万字)」は、数あるスタートアップの中から転職におすすめの企業を50社掲載した記事となっており、以下のようなポイントから企業を選定しています。
- スタートアップ転職の成功≒転職先スタートアップの成功と仮定し、IPO確度がある程度高そうな企業を中心に選定
- とはいえレイターステージはあまり旨みがないため、シリーズA,Bを中心に選定。レイターとアーリーも含まれますが、中心はシリーズA,B
- 2020年度版と被りすぎても情報価値がないので、昨年と同じ企業は50社中9社に抑えた。言い換えると、その9社は2年連続の選定のため、本誌では強くオススメ
- ポジションはビジネスサイドメインの記載だが、エンジニアはどこでも募集していると思われるため、ピックアップしたシリーズA以降のスタートアップであればエンジニアにとっては高い確率で勝ち馬に乗りやすいと想定。同様に、コーポレート部門も大抵募集がある
- オススメの読み方は、見出しにあるEC/メディアなどの項目をクリックし、セクターごとのおすすめ企業とポジション一覧をまず見て、興味ある企業について読んでいく。表の赤いセルは2020年選出企業、紫のセルは高野氏オススメ企業です。
(スタートアップ転職おすすめ企業50選【2021年版】での企業選定ポイント)
本来こちらは1記事で10,000円/の料金設定となっていますが、ウメキワークスの購読料3,000円を支払えば無料で読むことができるので、1ヶ月だけ課金をすれば優良スタートアップ50社の情報を一気に収拾できるというワケです。
時短術!! feedlyを使って複数メディアの記事を一括確認する
ここまで色々なメディア・サービスを紹介してきましたが、これだけのサイトを全部調べるのは面倒臭いですよね。
そこでオススメなのが「feedly」というサービスです。
「feedly」とは、登録したホームページやWebメディアの情報を効率よく収集できる非常に便利なサービスです。
例えば、上記の複数メディアをfeedlyの「Start up」タグに登録しておけば、各メディアのページにアクセスすることなく、下記のように一覧化された記事から気になるものを探して読むことができます。
feedlyの使い方は、以下の記事を見れば事足りるかと思います。
こんなところで終わりたいと思います。
お読みいただきありがとうございました。
【備忘録】チェリー本第3章:テストを自動化する
3.1 イントロダクション
3.1.2 プログラマの3大美徳
1. 怠慢(Laziness)
全体の労力を減らすために手間を惜しまない気質。
何度も同じことをやりたくない面倒くさがりのプログラマは、自動化やDRY原則・再利用を意識してコーディングする。
2. 短気(Impatience)
コンピューターの動作が怠慢な時に感じる怒り。 挙動がおかしくなったり、処理速度が遅くなることに苛立ちを感じるプログラマは、事前にそのような問題を想定してコードを書くようにする。
3. 傲慢(Hubris)
自分の書いたプログラムは誰に見せても恥ずかしくないと胸を張れる自尊心。 傲慢なプログラマは、自分の書いたコードに責任を持ち、さらに保守性を上げるために努力する。
【備忘録】チェリー本第2章:Rubyの基礎
2.6 メソッドの定義(P.36)
メソッドの戻り値
Rubyは最後に評価された式がメソッドの戻り値になるため、return
のようなキーワードは不要。
以下のように、returnはメソッドを途中で脱出したい場合に使用することが多い。
irb(main):012:1* def greeting(country) irb(main):013:1* return '入力してください' if country.nil? irb(main):014:1* irb(main):015:2* if country == 'japan' irb(main):016:2* 'こんにちは' irb(main):017:2* else irb(main):018:2* 'hello' irb(main):019:1* end irb(main):020:0> end => :greeting irb(main):021:0> irb(main):022:0> greeting(nil) => "入力してください" irb(main):023:0> greeting('japan') => "こんにちは"
2.10 真偽値と条件分岐についてもっと詳しく
2.10.5 条件演算子(三項演算子)
式 ? 真だった場合の処理 : 偽だった場合の処理
irb(main):025:0> n = 15 irb(main):026:1* if n > 10 irb(main):027:1* '10より大きい' irb(main):028:1* else irb(main):029:1* '10以下' irb(main):030:0> end => "10より大きい"
上記の条件分岐を、条件演算子で書けば以下のような感じ。
irb(main):031:0> n = 15 irb(main):032:0> n > 10 ? '10より大きい' : '10以下' => "10より大きい"
条件演算子の結果を代入することも可能。
irb(main):033:0> n = 15 irb(main):034:0> message = n > 10 ? '10より大きい' : '10以下' irb(main):035:0> message => "10より大きい"
シンプルなif文は条件演算子ですっきり書けるかもしれないけど、複雑な条件文で使うとかえってコードの可読性が悪くなる場合もあるから注意。
2.11 メソッド定義についてもっと詳しく
2.11.1 デフォルト値付きの引数
引数なしで呼び出した場合もエラーにならない。
def メソッド(引数1 = デフォルト値1, 引数2 = デフォルト値2) # 処理 end
irb(main):036:1* def greeting(country = 'japan') irb(main):037:2* if country == 'japan' irb(main):038:2* 'こんにちは' irb(main):039:2* else irb(main):040:2* 'hello' irb(main):041:1* end irb(main):042:0> end => :greeting irb(main):043:0> greeting => "こんにちは" irb(main):044:0> greeting('china') => "hello"
2.12 その他の基礎知識
2.12.5 参照の概念を理解する
Rubyの変数にはオブジェクトそのものではなく、オブジェクトへの参照が格納されている。
ある変数をほかの変数に代入したり、メソッドの引数として渡すと、新しい変数やメソッドの引数は元の変数のオブジェクトを参照している。
どのオブジェクトを参照しているかは、object_id
メソッドを使えばわかる。
irb(main):048:0> a = 'hello' irb(main):049:0> b = 'hello' irb(main):050:0> c = b irb(main):051:0> a.object_id => 180 irb(main):052:0> b.object_id => 200 irb(main):053:0> c.object_id => 200
2.12.7 require
組み込みライブラリでない標準ライブラリやgemを利用する場合は、明示的にそのライブラリを読み込む必要がある。
自分で作成したRubyプログラム(クラスの定義など)を読み込む場合も必要。
require ライブラリ名
【環境構築】MySQLのパスワードが分からず、最終的にディレクトリごと削除して解決した話(オススメしない)。
(※2020/05のメモを記録)
はじめに
環境構築の際、MySQLのパスワードが分からず詰まったので、以下に解決まで至った流れを記していきます。 これはあくまで私の環境上の話なので、どこまで参考になるか分かりませんし、皆様のお時間を無駄にしたくはないので、最初に解決策と主に使用したコマンドを記載しておきます。
ご興味ある方は最後までご一読頂ければと思います。
解決策
- mysqlの5.7系と8系がインストールされてたから8系を削除。
- mysqlが5.7系のパスを指すように
zshrc
で設定。 - 過去にインストールしていたMySQL5.7系のパスワードが分からないから、
sudo rm -rf /usr/local/var/mysql
でディレクトリごと削除。 - 改めて
brew install mysql@5.7
を実行し、完全に新しいrootユーザーが作成されたことで、パスワード無しでログインできた。
主に使用したコマンド
MySQL
- brew uninstall mysql
- which mysql
- ps aux | grep mysql
- source ~/.zshrc
- sudo rm -rf /usr/local/var/mysql
試したこと①とりあえずログインしようとしてみる
MySQLのバージョン確認。8系が入ってる。
$ mysql --version > mysql Ver 8.0.19 for osx10.15 on x86_64 (Homebrew)
パスワードが分からない。何も覚えてねえ、、
$ mysql.server start Starting MySQL .. SUCCESS! $ mysql -u root -p > Enter password: ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO) $ mysql -u root > ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)
勿論bundle exec rails db:create
は実行できない。
$ bundle exec rails db:create Access denied for user 'root'@'localhost' (using password: NO) Couldn't create 'runteq_rails_advanced_development' database. Please check your configuration. rails aborted! Mysql2::Error::ConnectionError: Access denied for user 'root'@'localhost' (using password: NO)
$ which mysql > /usr/local/bin/mysql
試したこと②MySQL8系をアンインストールし、5.7系を使ってみる
パスワードがわからんから一旦brew uninstall mysql
してみると、8系がアンインストールされた。
which mysql
を打つとnot found
と出る。
$ brew uninstall mysql Uninstalling /usr/local/Cellar/mysql/8.0.19... (286 files, 289.2MB) $ which mysql mysql not found
ps aux
で現在実行されているプロセスを確認できる。grep
コマンドで文字列検索を行えるので、ps aux | grep mysql
を実行し、実行中のMySQLが無いか確認してみる。すると、mysqlの5.7系のプロセスが実行されている事が分かった。
whichコマンドでは5.7系が見つからなかったけど、5.7系のプロセス自体は実行されているため、mysqlと打てば5.7系のディレクトリにパスが通るよう設定する。
$ ps aux | grep mysql fune 617 0.0 0.0 4682956 2000 ?? S 30 420 1:29.79 /usr/local/opt/mysql@5.7/bin/mysqld --basedir=/usr/local/opt/mysql@5.7 --datadir=/usr/local/var/mysql --plugin-dir=/usr/local/opt/mysql@5.7/lib/plugin --log-error=ryota21.local.err --pid-file=ryota21.local.pid fune 497 0.0 0.0 4280012 8 ?? S 30 420 0:00.04 /bin/sh /usr/local/opt/mysql@5.7/bin/mysqld_safe --datadir=/usr/local/var/mysql fune 30815 0.0 0.0 4268280 636 s000 R+ 3:27PM 0:00.01 grep mysql
zshrc
にexport PATH="/usr/local/opt/mysql@5.7/bin:$PATH"
と記載。
export PATH="/usr/local/opt/mysql@5.7/bin:$PATH
source
コマンドでzshrcファイルに記載されているコマンドを実行し、パスを通す。
$ source ~/.zshrc`
which mysql
と打つと、zshrcで指定したパスを指すようになった。
$ which mysql /usr/local/opt/mysql@5.7/bin/mysql
まだpasswordを空でEnter押してもログインできない。。。
$ mysql -u root -p > Enter password: ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)
MySQL5.7系もアンインストールし、再インストールしてみる。 やっぱりパスワードが分からず、ログインできない、、😭
$ mysql.server stop Shutting down MySQL .... SUCCESS! mysqlの5.7系をアンインストール $ brew uninstall mysql@5.7 mysqlの5.7系を再インストール $ brew install mysql@5.7 mysqlを起動 $ mysql.server start mysqlにログイン $ mysql -uroot > ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO) $ mysql -u root -p > Enter password: ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
試したこと③:ディレクトリごとMySQLを削除
パスワードがマジで分からないので、もうディレクトリごと消してやれ、、!と決意。
一旦プロセスに残っているMySQLをmysql.server stop
で停止させる。
$ ps aux | grep mysql fune 32217 0.0 0.0 4278520 676 s000 S+ 3:41PM 0:00.01 grep mysql fune 32210 0.0 0.4 4681888 31748 s000 S 3:38PM 0:00.41 /usr/local/Cellar/mysql@5.7/5.7.29/bin/mysqld --basedir=/usr/local/Cellar/mysql@5.7/5.7.29 --datadir=/usr/local/var/mysql --plugin-dir=/usr/local/Cellar/mysql@5.7/5.7.29/lib/plugin --log-error=ryota21.local.err --pid-file=/usr/local/var/mysql/ryota21.local.pid fune 32111 0.0 0.0 4280120 688 s000 S 3:38PM 0:00.04 /bin/sh /usr/local/Cellar/mysql@5.7/5.7.29/bin/mysqld_safe --datadir=/usr/local/var/mysql --pid-file=/usr/local/var/mysql/ryota21.local.pid プロセスを停止する $ mysql.server stop
grepしてみると、MySQLでgrepしたというプロセスしか残ってない。 MySQL自体のプロセスは止まっているということ。
$ ps aux | grep mysql fune 32236 0.0 0.0 4278520 672 s000 S+ 3:42PM 0:00.00 grep mysql
MySQLをアンインストールする $ brew uninstall mysql@5.7 ディレクトリの中に削除してはいけないものが無いか確認しておく。 $ open /usr/local/var/mysql MySQLのディレクトリ自体を削除。 $ sudo rm -rf /usr/local/var/mysql
5.7系を再インストールしてみたら、やっとログインできた!!!
5.7系をインストール $ brew install mysql@5.7 $ mysql.server start Starting MySQL . SUCCESS! $ mysql -u root Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 2 Server version: 5.7.29 Homebrew Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>
おわりに
やっぱり環境構築は大変だと改めて実感しました。。。 いい勉強にはなったので、もっと場数踏んで、環境構築を行う速度を上げたいものですね。
参照
mergeメソッドのメモ
以下は、あるテーブルのデータと、そのテーブルの関連テーブルの外部キーを代入している。
しかし、処理が2行に分かれていて冗長。
@meal_record = current_user.meal_records.build(meal_record_params) @meal_record.food_id = params[:food_id]
mergeメソッドを使えば、かんたんに書ける。
@meal_record = current_user.meal_records.build(meal_record_params.merge(food_id: params[:food_id]))
ブロックでも書ける。
@meal_record = current_user.meal_records.build(meal_record_params) do |meal_record| meal_record.food_id = params[:food_id] end
変数の中身を確認してみる。
current_user.meal_records.build(meal_record_params) => #<MealRecord:0x00007f7fd4bf87f8 id: nil, meal_time: Sat, 31 Oct 2020 00:00:00 JST +09:00, created_at: nil, updated_at: nil, user_id: 2, food_id: nil> current_user.meal_records.build(meal_record_params.merge(food_id: params[:food_id])) => #<MealRecord:0x00007f7fd0fc4a98 id: nil, meal_time: Sat, 31 Oct 2020 00:00:00 JST +09:00, created_at: nil, updated_at: nil, user_id: 2, food_id: 84> current_user.meal_records.build(meal_record_params.merge(food_id: params[:food_id])).food Food Load (0.6ms) SELECT `foods`.* FROM `foods` WHERE `foods`.`id` = 84 LIMIT 1 ↳ (pry):27:in `create' => #<Food:0x00007f7fd0de8800 id: 84, name: "アイスクリーム", labels: ["Food", "Ice cream", "Frozen dessert", "Dish", "Dondurma", "Cuisine", "Vanilla ice cream", "Ingredient", "Sorbet", "Gelato", "Dessert", "Frozen yogurt", "Cream", "Vanilla", "Dairy"], calorie: 0, calorie_theory: "", created_at: Fri, 30 Oct 2020 21:33:27 JST +09:00, updated_at: Fri, 30 Oct 2020 21:33:27 JST +09:00>
範囲オブジェクトrange。 ..でリテラル表現
範囲オブジェクトとは
範囲オブジェクトのクラス。範囲オブジェクトは文字どおり何らかの意味での範囲を表します。数の範囲はもちろん、日付の範囲や、「"a" から "z" まで」といった文字列の範囲を表すこともできます。 docs.ruby-lang.org
範囲の開始値と範囲の終了値を「..」で繋いで書けば、範囲オブジェクトのリテラル表現になる。
range = 1..10 range.class => Range range.count => 10 range.map { |n| n * 2 } => [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
mapメソッドでループする(ついでにreject(&:blank?)とflattenを使ってる)
わざわざ空配列を用意するのダサいし、冗長。
@food_lists = [] food_labels.each do |food_label| @food_lists = Food.search_by_label(food_label) end
mapメソッドを使う。
reject(&:blank?)で配列からnilと空文字を除く。
flattenで多次元配列を一次元配列にする。
food_lists = food_labels.map do |food_label| Food.with_label(food_label) end # 空配列を削除し、多次元配列を一次元配列にする @food_lists = food_lists.reject(&:blank?).flatten
food_labels = response.responses.map do |res| res.label_annotations.map do |label| label.description end end # mapと&:を使えばシンプルに food_labels = response.responses.map do |res| res.label_annotations.map(&:description) end
マイグレーションファイルについて
マイグレーションファイルとは
データベースの設計図。
マイグレーションファイルを実行すれば、マイグレーションファイルを元にDBが作成される。
→マイグレーションファイルを作成しただけではDBに反映されない。
マイグレーションファイルを作成
rails g migration マイグレーション名
rails generate model モデル名 カラム名:型 カラム名:型
$ be rails g model ApiKey user:references access_token:string expires_at:datetime Running via Spring preloader in process 47115 invoke active_record create db/migrate/20200719073831_create_api_keys.rb create app/models/api_key.rb invoke rspec create spec/models/api_key_spec.rb invoke factory_bot create spec/factories/api_keys.rb
マイグレーションファイルを実行
dbにマイグレーションファイルの内容が反映された。
$ be rails db:migrate == 20200719073831 CreateApiKeys: migrating ==================================== -- create_table(:api_keys) -> 0.0065s -- add_index(:api_keys, :access_token, {:unique=>true}) -> 0.0020s == 20200719073831 CreateApiKeys: migrated (0.0091s) ===========================
DBに反映されているマイグレーションファイルを確認する
upと書いているファイルがデータベースに反映されているもの(マイグレーション済みということ)
$ rails db:migrate:status database: db/learning_api_development Status Migration ID Migration Name -------------------------------------------------- up 20200627072315 Sorcery core up 20200627073523 Create social profiles up 20200627074538 Create articles up 20200627075238 Create comments up 20200719073831 Create api keys
スキーマファイルで現在のDBの構造を確認する
マイグレーションファイルの内容をDBに反映されていない状態に戻す
rails db:rollbackで、最新のマイグレーションファイルをdown状態にできる。
down状態のマイグレーションファイル = データベースに反映されていない状態にあるということ。
※up状態にあるマイグレーションファイルを削除・編集することは避けよう。
rails db:rollback
be rails db:reset
全てのテーブルを dropし、"db/schema.rb"を元にテーブルの再作成を行う。レコードは空になる。
be rails db:migrate:reset
migrateとresetを両方行う。
$ be rails db:migrate:reset Dropped database 'db/runteq_curriculum_learning_api_development.sqlite3' Dropped database 'db/runteq_curriculum_learning_api_test.sqlite3' Created database 'db/runteq_curriculum_learning_api_development.sqlite3' Created database 'db/runteq_curriculum_learning_api_test.sqlite3' == 20200627072315 SorceryCore: migrating ====================================== -- create_table(:users) -> 0.0037s -- add_index(:users, :email, {:unique=>true}) -> 0.0021s == 20200627072315 SorceryCore: migrated (0.0060s) ============================= == 20200627073523 CreateSocialProfiles: migrating ============================= -- create_table(:social_profiles) -> 0.0093s == 20200627073523 CreateSocialProfiles: migrated (0.0094s) ==================== == 20200627074538 CreateArticles: migrating =================================== -- create_table(:articles) -> 0.0058s == 20200627074538 CreateArticles: migrated (0.0059s) ========================== $ rcs Running via Spring preloader in process 60310 Loading development environment in sandbox (Rails 6.0.2.1) Any modifications you make will be rolled back on exit [1] pry(main)> User.first (0.3ms) begin transaction User Load (0.5ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]] => nil
be rails db:seed
Seedファイルのデータを、テーブルのレコードに投入
$ be rails db:seed $ rcs Running via Spring preloader in process 60874 Loading development environment in sandbox (Rails 6.0.2.1) Any modifications you make will be rolled back on exit [1] pry(main)> User.first (1.7ms) begin transaction User Load (0.4ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]] => #<User:0x00007fb1841d4808 id: 1, name: "user-1", email: "user-1@example.com", crypted_password: "$2a$10$FWgdOQ7TTpcNzgGVxhRLfus46sJg8WP3DPi0yvj4U72rH7RW0PMxa", salt: "8QYWYUM7Vb-yp44eVzBP", created_at: Sun, 19 Jul 2020 08:06:58 UTC +00:00, updated_at: Sun, 19 Jul 2020 08:06:58 UTC +00:00>
Rakeタスクのメモ的な(メールの自動配信機能)
Rakeタスク
タスクファイル作成
rails g task mail_summary
タスクファイルの編集
(lib/tasks/mail_summary.rake) namespace :mail_summary do desc '公開済の記事の件数と、昨日公開された記事の件数とタイトルをメールで送信' # task :article doだとDBには接続しない task article: :environment do # mailerのメソッドを呼び出す # articles = Article.all ArticleMailer.report_summary.deliver_now end end
メールをcronjobなどから今すぐ送信したい場合は、deliver_now でいつでも実行できる。
# すぐにメール送信したい場合は#deliver_nowを使用 UserMailer.welcome(@user).deliver_now # Active Jobを使用して後でメール送信したい場合は#deliver_laterを使用 UserMailer.welcome(@user).deliver_later
一般に、非同期キュー(.deliver_laterでメールを送信するなど)はRakeタスクに書いても動きません。Rakeが終了すると、.deliver_laterがメールの処理を完了する前にインプロセスのスレッドプールを削除する可能性があるためです。この問題を回避するには、.deliver_nowを用いるか、development環境で永続的キューを実行してください。
これをdeliver_later
にすると、メールが届かなかった。
ArticleMailer.report_summary.deliver_later
講師 deliverは非推奨、deliver_nowは同期処理、deliver_laterは非同期処理 nowだと同期処理だからキューに入らないと思う もしSidekiqとかResqueのような永続化キューを使用してない場合、rakeタスクの中でdeliver_laterするとメール届かない可能性があるみたい。deliver_laterでメールの送信処理を完了する前にrakeタスクのプロセスが終わる可能性があるかららしい。
タスク一覧
rake -vT rake mail_summary:article # 公開済の記事の総記事数と、昨日公開された記事の件数とタイトルをメールで送信 rake status_update:article_status # 記事が公開待ち状態で、公開日時が過去の場合、ステータスを「公開」にする
タスク実行
rake status_update:article_status
Mailer
$ rails g mailer ArticleMailer report_summary Running via Spring preloader in process 99411 create app/mailers/application_mailer.rb create app/mailers/article_mailer.rb invoke erb create app/views/layouts/mailer.html.erb create app/views/layouts/mailer.text.erb create app/views/article_mailer create app/views/article_mailer/report_summary.html.erb create app/views/article_mailer/report_summary.text.erb
(app/mailers/application_mailer.rb) class ApplicationMailer < ActionMailer::Base default from: 'from@example.com' layout 'mailer' end
- 良い書き方
(app/mailers/article_mailer.rb) class ArticleMailer < ApplicationMailer # 共通処理を書く。 # article_mailer/report_summary.~のビューを呼び出す def report_summary(articles) @published_articles = articles.published @published_articles_yesterday = Article.published_yesterday mail(to: 'admin@example.org', subject: '公開記事の集計結果') end end
- 良くない書き方
# BAD: # @published_articles_yesterday = @published_articles.where('? <= published_at && published_at <= ?', Time.current.yesterday.beginning_of_day, Time.current.yesterday.end_of_day) # SOSO: # @published_articles_yesterday = @published_articles.where(published_at: Time.current.yesterday.all_day)
- scopeを定義
(app/models/article.rb) scope :published_yesterday, -> { where(published_at: 1.day.ago.all_day) }
# メーラーメソッドでcountしておくのもあり @published_articles_count = articles.published
(app/views/layouts/mailer.html.erb) <html> <body> <%= yield %> </body> </html>
(app/views/article_mailer/report_summary.html.erb) <p>公開済の記事数: <%= "#{@published_articles.count}" %>件</p> <% if @published_articles_yesterday.present? %> <p>昨日公開された記事数: <%= "#{@published_articles_yesterday.count}" %>件</p> <% @published_articles_yesterday.each do |article| %> <p>タイトル: <%= article.title %></p> <% end %> <% else %> <p>昨日公開された記事はありません</p> <% end %>
Letter Opener
https://github.com/ryanb/letter_opener ・実際にメールを送信するのではなく、デフォルトのブラウザでメールをプレビューする。 これにより、開発環境で実際にメールを送らずに済む。
(config/environments/development.rb) # letter_opener_webの設定 config.action_mailer.delivery_method = :letter_opener_web config.action_mailer.default_url_options = 'localhost:3000'
(app/views/password_resets/edit.html.erb) <%= form_with model: @user, url: password_reset_path(@token), local: true do |f| %> 引数の@token無しでもいけた。。。 <%=form_withmodel:@user, url:password_reset_path, local:truedo |f| %>
Whenever
config/schedule.rb # 初期設定ファイル # このファイルを使って、すべてのcronジョブを簡単に定義することができます。 # Rails.rootを使用するために必要(cronはRailsとは全く別物だから) require File.expand_path(File.dirname(__FILE__) + '/environment') # cronを実行した際のログを出力するファイルを指定 set :output, "#{Rails.root}/log/cron.log" # TODO: cronログの出力内容を記述できてないっぽい # cronを実行する環境 set :environment, :development every :minute do rake 'status_update:article_status' end every 1.day, at: '9:00 am' do rake 'mail_summary:article' end
config/schedule.rbをcron構文に変換した内容を表示してくれてるが、crontabファイルが更新されているわけではない。
$ be whenever * * * * * /bin/bash -l -c 'cd /Users/funesakisuke/workspace/runteq/332_ryota1116_runteq_learning_advanced && RAILS_ENV=development bundle exec rake status_update:article_status --silent >> /Users/funesakisuke/workspace/runteq/332_ryota1116_runteq_learning_advanced/log/cron.log 2>&1' * * * * * /bin/bash -l -c 'cd /Users/funesakisuke/workspace/runteq/332_ryota1116_runteq_learning_advanced && RAILS_ENV=development bundle exec rake mail_summary:article --silent >> /Users/funesakisuke/workspace/runteq/332_ryota1116_runteq_learning_advanced/log/cron.log 2>&1' ## [message] Above is your schedule file converted to cron syntax; your crontab file was not updated. ## [message] Run `whenever --help' for more options.
設定されているcronを確認
$ crontab -l # Begin Whenever generated tasks for: /Users/funesakisuke/workspace/runteq/332_ryota1116_runteq_learning_advanced/config/schedule.rb at: 2020-05-14 16:09:28 +0900 0 * * * * /bin/bash -l -c 'cd /Users/funesakisuke/workspace/runteq/332_ryota1116_runteq_learning_advanced && RAILS_ENV=development bundle exec rake status_update:article_status --silent >> /Users/funesakisuke/workspace/runteq/332_ryota1116_runteq_learning_advanced/log/cron.log 2>&1' # End Whenever generated tasks for: /Users/funesakisuke/workspace/runteq/332_ryota1116_runteq_learning_advanced/config/schedule.rb at: 2020-05-14 16:09:28 +0900
cronにデータを反映させる
$ bundle exec whenever --update-crontab [write] crontab file updated
OKを押す。
再度cronを確認するとデータが反映されていることがわかる
$ crontab -l # Begin Whenever generated tasks for: /Users/funesakisuke/workspace/runteq/332_ryota1116_runteq_learning_advanced/config/schedule.rb at: 2020-05-31 22:22:28 +0900 * * * * * /bin/bash -l -c 'cd /Users/funesakisuke/workspace/runteq/332_ryota1116_runteq_learning_advanced && RAILS_ENV=development bundle exec rake status_update:article_status --silent >> /Users/funesakisuke/workspace/runteq/332_ryota1116_runteq_learning_advanced/log/cron.log 2>&1' * * * * * /bin/bash -l -c 'cd /Users/funesakisuke/workspace/runteq/332_ryota1116_runteq_learning_advanced && RAILS_ENV=development bundle exec rake mail_summary:article --silent >> /Users/funesakisuke/workspace/runteq/332_ryota1116_runteq_learning_advanced/log/cron.log 2>&1' # End Whenever generated tasks for: /Users/funesakisuke/workspace/runteq/332_ryota1116_runteq_learning_advanced/config/schedule.rb at: 2020-05-31 22:22:28 +0900
cronからデータを削除する
$ bundle exec whenever --clear-crontab
【Ruby】procとblock
procとblockについて
block
ブロックとは
do...end
や{ }
のカタマリのこと。
do...endと{ }
- 改行を含む長いブロックを書く場合はdo...end
- 1行でコンパクトに書きたい場合は{ } プロを目指す人のためのRuby入門 言語仕様からテスト駆動開発・デバッグ技法まで (Software Design plusシリーズ) | 伊藤 淳一 |本 | 通販 | Amazon
ブロックの中の|i|
のi
はブロック引数と呼ばれるもの。
ブロックの中で| |
を書くことで、eachメソッドから渡された配列の要素が順番に入ってくる。
[1, 2, 3].each do |i| puts i*2 end 2 4 6 => [1, 2, 3]
[1, 2, 3].each { |a| p a } 1 2 3 => [1, 2, 3]
値を受け取らない場合は、| |
を書かなければいい。| |
を使わなければ、単に配列の要素の数だけ処理が実行される。
3.times do p 'おはよ!' end "おはよ!" "おはよ!" "おはよ!" => 3
[1, 2, 3].each { p 'おはよ' } "おはよ" "おはよ" "おはよ" => [1, 2, 3]
do...endの応用
# @meal_record = MealRecord.new(food_id: params[:food_id]) # @meal_record.meal_record_pictures = ActiveStorage::Blob.find(session[:meal_picture_id]) if session[:meal_picture_id] @meal_record = MealRecord.new(food_id: params[:food_id]) do |meal_record| meal_record.meal_record_pictures = ActiveStorage::Blob.find(session[:meal_picture_id]) if session[:meal_picture_id] end
ブロック引数
ブロック引数は引数と同じように、関数の()に入れてあげればいい。
そしてブロック引数を受け取る関数を定義するには&block
という仮引数を指定してあげるといい。この&block
でブロック引数を受け取る宣言をしているといった感じである。
注意点は、
- ブロック引数は1つしか受け取れない。
- 複数の引数が存在する場合、ブロック引数は最後の引数として指定してあげる。
以下の例では、&blockという仮引数に、puts "Hello block"
というブロックが渡されている。
def receive_block(&block) puts "受け取ったブロックを実行する" # block.callで、受け取ったブロック(puts "Hello block"のこと)を実行 block.call puts "実行したよ" end receive_block do puts "Hello block" end #出力結果 受け取ったブロックを実行する Hello block 実行したよ
proc
procとは、ブロックという処理のカタマリをオブジェクト化するためのクラスのこと。
callメソッドで呼び出せる。
hello_proc = Proc.new do 'Hello' end # 上記と同じ hello_proc = Proc.new { 'Hello' } hello_proc => #<Proc:0x00007fcbae10af50 (irb):66> hello_proc.call => "Hello"
引数を受け取る処理もできる。
proc = Proc.new do |message| puts message end proc.call("Hello proc") =>Hello proc
以下の処理は、上記の処理と同じ挙動となる。
つまり、以下の&block
とblock
は、上記のブロックとProcインスタンスの関係にあるということ。以下では、内部的に受け取ったブロックをProcインスタンス化しているのである。
def receive_block(&block) block.call end receive_block do puts "Hello block" end =>Hello block
&はブロックを表す記号であり&blockのblockはブロック引数につけた仮引数名にあたるので実は何でも良い。 つまり引数として受け取ったblockという名のブロックを、blockという名のProcインスタンスに変換しているからblock.callで実行することができる。
Rubyのブロック、ブロック引数、Proc、yieldをまとめてみた – Ruby on Rails 始めました
&:method
配列の要素1つ1つに、(&:メソッド名)
で与えられたメソッドを呼び出してくれる。
['a' ,'b'].map(&:upcase) => ["A", "B"]
以下の2つは同じ意味になる。
→do...end に限らず { |object| object.published! } も同じく短く出来る!
find_each do |object| object.published! end find_each(&:published)
以下であれば、array.map(&:メソッド名)
の(&:メソッド名)部分は、:メソッド名.to_proc.call
を省略した形。
# array.map(&:メソッド名)の記法 ['a','b'].map(&:upcase) #=> ["A", "B"] # 省略しない記法 ['a','b'].map do |string| :upcase.to_proc.call(string) end #=> ["A", "B"]
さらに例文で理解する(余計ややこしいかも)
(app/models/article.rb) class Article < ApplicationRecord enum state: { draft: 0, published: 1, publish_wait: 2 } # 公開日時が過去の日付になっている記事を取得 scope :past_publish, -> { where('published_at <= ?', Time.current) } end
(lib/tasks/status_update.rake) namespace :status_update do desc '記事が公開待ち状態で、公開日時が過去の場合、ステータスを「公開」にする' task article_status: :environment do # 公開待ち(publish_wait)の記事の中で、公開日時が過去(past_publish)になっているものがあれば、ステータスを「公開(published!で)」に変更する # `Article.publish_wait`で、enum値がpublish_waitに該当するデータを取得 @articles = Article.publish_wait.past_publish.find_each(&:published!) # 以下と同じ # @articles.each do |article| # if article.published_at.past? # article.state = :published # article.save! # end # end end end