ryota21silvaの技術ブログ

Funna(ふんな)の技術ブログ

これまで学んだ技術の備忘録。未来の自分が救われることを信じて

【現代語訳】スタートアップの情報収集のすヽめ

スタートアップの情報どこにあるねん


スタートアップってリリースされている記事とかが少ないので、面白い企業を探したくても見つからないことがよくあるんですよね。

そこで「どんなメディアを使ってスタートアップを探せばいいの?」という方向けに、私がオススメするスタートアップ特化型メディア・サービスを紹介していこうと思います。
(※どんな観点でスタートアップを探すべきか?は読者の目的によって異なると思うので説明しません。その点ご了承ください)

1. STARTUP DB


startup-db.com

10,000社以上のスタートアップ・ベンチャー企業のデータと、企業家・投資家のインタビューが掲載されています。企業の登録数は圧倒的ですね。
老舗?企業、メガベンチャーとか何でも掲載されてる感じもしますが、創業1ヶ月のスタートアップの企業情報も掲載されてます。すごい。

「業界のカテゴリー」で企業を検索できます。

f:id:ryota21silva:20201210235343p:plain

「資金調達額」「従業員数」「設立年数」「サブカテゴリー」などで、詳細検索もできます。

f:id:ryota21silva:20201210235512p:plain

検索結果として、ビャビャーっと企業一覧が表示されます。

f:id:ryota21silva:20201211000026p:plain

プレスリリース、資金調達の最新情報も一覧で見れます。

f:id:ryota21silva:20201210233419p:plain

2. Startup Times


startuptimes.jp

個人的にコレが一番好きです。
スタートアップのインタビュー記事が掲載されているサイトです。とにかくスタートアップに特化してます。リリースしたばかりのサービスが取り上げられている印象です。ワクワクします。

f:id:ryota21silva:20201211001157p:plain

3. BRIDGE


thebridge.jp

「起業家と投資家を繋ぐ」テクノロジー&スタートアップ関連の話題をお届けするブログメディア。
スタートアップの資金調達、業務提携とかのニュースがよく掲載されている。

f:id:ryota21silva:20201214225949p:plain

4. TechCrunch


jp.techcrunch.com

定番のヤツ。

業界別のカオスマップも見れて便利です。EdTech、飲食インフラ、キャッシュレス、副業系サービスなどなど興味のある業界のマップを探してみましょう。

f:id:ryota21silva:20201214230728p:plain

f:id:ryota21silva:20201214231601p:plain

「TechCrunch Tokyo」「Startup Battle」というイベントもあるようです。設立3年未満のスタートアップがビジネスアイデアを持ち寄ってピッチを繰り広げるイベントで、「こんなアツい会社あるんやすげええぇぇ」ってなります。

f:id:ryota21silva:20201214230525p:plain

f:id:ryota21silva:20201214230624p:plain

5. CoralCapital


coralcap.co

こちらも有名ですね。
VCである株式会社Coral Capitalがスタートアップにまつわる情報を発信してくれています。

たとえば、「Coral Insights」の記事は日本のスタートアップ市場に関する記事や、VCはどのような観点をもとにスタートアップに出資しているのかといった話など、勉強になるものが多いです。

ベンチャー企業とスタートアップは何が違うのか? | Coral Capital

私が日本のスタートアップ投資の魅力を海外に伝えるときに話すこと | Coral Capital

f:id:ryota21silva:20201214234424p:plain

「Coral Careers」には、スタートアップキャリアイベント「Startup Aquarium」などスタートアップの転職イベントの情報が配信されてたりします。
他にもCoral Capitalの投資先スタートアップの開発環境を一覧化したマップが掲載されていたり、面白いサービスが色々あります。

f:id:ryota21silva:20201214235017p:plain

6. YOUTRUST


youtrust.jp

「転職市場に出てきづらい優秀な人材を採用できるキャリアSNS」を謳っているサービスです。
従来の転職サービスとは異なりSNSとして利用される側面を持っており、転職者や採用担当者などの呟きがタイムラインに流れているので、そこから興味を持った方に連絡を取ることができるカジュアルなイメージの強い転職サービスです。

f:id:ryota21silva:20211103191129p:plain

転職活動として利用することもできますし、企業一覧ページ には色々な企業が掲載されているので、これを見るだけでも企業探しに使えると思います。 個人的には今時の「イケてそう」なスタートアップが多いイメージです。

f:id:ryota21silva:20211103191711p:plain

7. ウメキワークス


note.com

ウメキワークスとは、個人投資家でもある梅木雄平さんが発信しているスタートアップの資金調達情報やIPO分析などの月額マガジンのことで、成長性のある選りすぐりのスタートアップの情報が多数掲載されています。
f:id:ryota21silva:20211103192818p:plain

ただし情報の質が高い分月額3,000円の購読料がかかってしまうので「ずっと課金し続けるのは厳しい、、」という方もいらっしゃると思いますし、はたまた「そんないっぱい記事見る余裕無いわ」という方もいらっしゃると思います。

そんな方におすすめのウメキワークスでの情報収拾法は、「3,000円の購読料を一度だけ支払って、スタートアップ転職おすすめ企業50選【20XX年版】高野氏監修付き(1.5万字)」だけを読むという方法です。

この「スタートアップ転職おすすめ企業50選【20XX年版】高野氏監修付き(1.5万字)」は、数あるスタートアップの中から転職におすすめの企業を50社掲載した記事となっており、以下のようなポイントから企業を選定しています。

  1. スタートアップ転職の成功≒転職先スタートアップの成功と仮定し、IPO確度がある程度高そうな企業を中心に選定
  2. とはいえレイターステージはあまり旨みがないため、シリーズA,Bを中心に選定。レイターとアーリーも含まれますが、中心はシリーズA,B
  3. 2020年度版と被りすぎても情報価値がないので、昨年と同じ企業は50社中9社に抑えた。言い換えると、その9社は2年連続の選定のため、本誌では強くオススメ
  4. ポジションはビジネスサイドメインの記載だが、エンジニアはどこでも募集していると思われるため、ピックアップしたシリーズA以降のスタートアップであればエンジニアにとっては高い確率で勝ち馬に乗りやすいと想定。同様に、コーポレート部門も大抵募集がある
  5. オススメの読み方は、見出しにあるEC/メディアなどの項目をクリックし、セクターごとのおすすめ企業とポジション一覧をまず見て、興味ある企業について読んでいく。表の赤いセルは2020年選出企業、紫のセルは高野氏オススメ企業です。

    (スタートアップ転職おすすめ企業50選【2021年版】での企業選定ポイント)

本来こちらは1記事で10,000円/の料金設定となっていますが、ウメキワークスの購読料3,000円を支払えば無料で読むことができるので、1ヶ月だけ課金をすれば優良スタートアップ50社の情報を一気に収拾できるというワケです。

時短術!! feedlyを使って複数メディアの記事を一括確認する


ここまで色々なメディア・サービスを紹介してきましたが、これだけのサイトを全部調べるのは面倒臭いですよね。

そこでオススメなのがfeedlyというサービスです。

feedly.com

feedly」とは、登録したホームページやWebメディアの情報を効率よく収集できる非常に便利なサービスです。
例えば、上記の複数メディアをfeedlyの「Start up」タグに登録しておけば、各メディアのページにアクセスすることなく、下記のように一覧化された記事から気になるものを探して読むことができます。

f:id:ryota21silva:20201215004742p:plain

feedlyの使い方は、以下の記事を見れば事足りるかと思います。

ferret-plus.com

こんなところで終わりたいと思います。
お読みいただきありがとうございました。

【備忘録】チェリー本第3章:テストを自動化する

3.1 イントロダクション

3.1.2 プログラマの3大美徳

以下の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

zshrcexport 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を削除

パスワードがマジで分からないので、もうディレクトリごと消してやれ、、!と決意。

一旦プロセスに残っているMySQLmysql.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してみると、MySQLgrepしたというプロセスしか残ってない。 MySQL自体のプロセスは止まっているということ。

$ ps aux | grep mysql
fune     32236   0.0  0.0  4278520    672 s000  S+    3:42PM   0:00.00 grep mysql

ディレクトリごと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>

docs.ruby-lang.org

範囲オブジェクト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]

www.sejuku.net

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

techracho.bpsinc.jp

qiita.com

techacademy.jp

www.rubydoc.info

マイグレーションファイルについて

マイグレーションファイルとは

データベースの設計図。
マイグレーションファイルを実行すれば、マイグレーションファイルを元に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

qiita.com

qiita.com

qiita.com

qiita.com

【Ruby】procとblock

procとblockについて

block

ブロックとは

do...end{ }のカタマリのこと。

do...endと{ }

ブロックの中の|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. ブロック引数は1つしか受け取れない。
  2. 複数の引数が存在する場合、ブロック引数は最後の引数として指定してあげる。

以下の例では、&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
実行したよ

rails-study.net

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

以下の処理は、上記の処理と同じ挙動となる。 つまり、以下の&blockblockは、上記のブロックと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"]

docs.ruby-lang.org

以下の2つは同じ意味になる。
→do...end に限らず { |object| object.published! } も同じく短く出来る!

find_each do |object|
  object.published!
end

find_each(&:published)

qiita.com

以下であれば、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