tag:crieit.net,2005:https://crieit.net/tags/Rails/feed
「Rails」の記事 - Crieit
Crieitでタグ「Rails」に投稿された最近の記事
2022-01-17T18:48:17+09:00
https://crieit.net/tags/Rails/feed
tag:crieit.net,2005:PublicArticle/17942
2022-01-17T18:28:45+09:00
2022-01-17T18:48:17+09:00
https://crieit.net/posts/inyoo-jp
「引用」をいい感じに展開してくれるサービス「inyoo.jp」をリリースしました
<p><a href="https://crieit.now.sh/upload_images/c582b9550ad9d33818f4e53305ff22bd61e53b56e38dc.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/c582b9550ad9d33818f4e53305ff22bd61e53b56e38dc.png?mw=700" alt="image" /></a></p>
<p><a target="_blank" rel="nofollow noopener" href="https://inyoo.jp/">inyoo.jp</a> は「引用」をいい感じに展開してくれる短縮 URL サービスです。</p>
<p>ウェブの記事などを読んでいて、文章の一部を SNS に「引用」をしたくなったとき、該当箇所を選択して右クリックから「選択箇所へのリンクをコピー」して、</p>
<p><a href="https://crieit.now.sh/upload_images/67935bf49b91593abd392ee7c82d06f561e5354a51b5b.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/67935bf49b91593abd392ee7c82d06f561e5354a51b5b.png?mw=700" alt="image" /></a></p>
<p>このリンクの URL を <a target="_blank" rel="nofollow noopener" href="https://inyoo.jp/">inyoo.jp</a> のトップページのフォームに貼り付けて「引用を作成」を押します。</p>
<p><a href="https://crieit.now.sh/upload_images/884882a729245b2440210c3229a7c2f061e5356a09fbf.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/884882a729245b2440210c3229a7c2f061e5356a09fbf.png?mw=700" alt="image" /></a></p>
<p>作成された「引用」を Twitter や Facebook などにシェアすると、こんな感じで引用部分のテキストが画像でいい感じに展開されます!</p>
<p><a href="https://crieit.now.sh/upload_images/79a6e1024aa7241cac2bc45fe29eeeca61e5358281ca9.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/79a6e1024aa7241cac2bc45fe29eeeca61e5358281ca9.jpg?mw=700" alt="image" /></a></p>
<p>ちなみにこのリンクは開くとページが自動的にスクロールされて、引用の該当箇所がハイライトされるようになっています。説明を読んだだけだと何がなんだか分からないかなと思いますので、ぜひ試しに使ってみてくださいね!</p>
<p><a href="https://crieit.now.sh/upload_images/a19f82238ceb31dc74ef1f732740713461e535b70842f.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/a19f82238ceb31dc74ef1f732740713461e535b70842f.png?mw=700" alt="image" /></a></p>
<p>また、Google Chrome 以外のブラウザや、スマートフォンからの利用方法など、詳しい使い方は <a target="_blank" rel="nofollow noopener" href="https://inyoo.jp/">トップページ</a> の「使い方」に詳しく書いてありますので、そちらをご参照ください。</p>
<h2 id="ここまで読んでくれた方へ"><a href="#%E3%81%93%E3%81%93%E3%81%BE%E3%81%A7%E8%AA%AD%E3%82%93%E3%81%A7%E3%81%8F%E3%82%8C%E3%81%9F%E6%96%B9%E3%81%B8">ここまで読んでくれた方へ</a></h2>
<p>ぜひ試しに <a target="_blank" rel="nofollow noopener" href="https://inyoo.jp/">inyoo.jp</a> を使ってみてください!!</p>
<p>ご意見や不具合の報告、フィードバックや改善の要望など、何かありましたら Twitter で <a target="_blank" rel="nofollow noopener" href="https://twitter.com/inyoo_jp">@inyoo_jp</a> までメンションか DM をお願いします!また、いいねやコメント、SNS での共有などをしていただけると今後の励みになります。</p>
<p>よろしくお願いします!!!</p>
inyoo.jp
tag:crieit.net,2005:PublicArticle/17310
2021-05-30T20:49:14+09:00
2021-05-30T20:49:14+09:00
https://crieit.net/posts/rails-database-url
📝 Rails で config/database.yml よりも ENV['DATABASE_URL'] の設定が優先される話
<p>MySQL を利用する Rails プロジェクトを起動しようとしたところ、下記のエラーが発生しました。</p>
<pre><code class="bash">bin/rails s
# データベースアダプターには mysql2 を選択している状態なのに postgresql で接続しようとしている
Error loading the 'postgresql' Active Record adapter. Missing a gem it depends on? pg is not part of the bundle. Add it to your Gemfile. (LoadError)
</code></pre>
<pre><code class="yml"># config/database.yml ファイルの中身一部抜粋
# mysql2 をデータベースアダプターとして利用しているため、
# PostgreSQL 接続のための pg ライブラリの追加を求めるエラーが発生しているのは何かおかしい。。
default: &default
adapter: mysql2
#...
</code></pre>
<p>何でや、、と思い Rails のドキュメントを読んでいた所、公式サイトに <a target="_blank" rel="nofollow noopener" href="https://edgeguides.rubyonrails.org/configuring.html#connection-preference"><code>Connection Preference</code> に関する記述</a>を見つけました。</p>
<blockquote>
<p>Since pool is not in the ENV['DATABASE_URL'] provided connection information its information is merged in. Since adapter is duplicate, the ENV['DATABASE_URL'] connection information wins.</p>
</blockquote>
<p>どうやら <code>config/database.yml</code> と <code>ENV['DATABASE_URL']</code> の両方が設定されている場合、設定値に重複がある項目については <code>ENV['DATABASE_URL']</code> の値が優先されるようでした。</p>
<p>今回は <code>DATABASE_URL</code> に下記の PostgreSQL URL が設定されてしまっていたため、<code>config/database.yml</code> では MySQL を利用していたのにも関わらず、データベースアダプターに PostgreSQL が使われてしまっていたようです。</p>
<pre><code class="bash">env | grep DATABASE_URL
# 環境変数 DATABASE_URL に PostgreSQL の URL が設定されている
DATABASE_URL=postgresql://user:password@localhost:5432/something_development
</code></pre>
<p>そのため、<code>DATABASE_URL</code> の中身を空にすることで、本来の意図通りに <code>config/database.yml</code> の設定を反映させることができました。</p>
<pre><code class="bash"># 筆者は fish を利用しているので set -e で環境変数を空にした
set -e DATABASE_URL
# 何も出力されないことを確認し DATABASE_URL が空であることを確認する
env | grep DATABASE_URL
# Rails サーバーが正常に起動するか再度確認する
bin/rails s
#...
# 無事アプリケーションサーバーが起動すること確認できれば OK
=> Booting Puma
=> Rails 6.0.3.6 application starting in development
=> Run `rails server --help` for more startup options
Puma starting in single mode...
* Version 4.3.7 (ruby 2.6.1-p33), codename: Mysterious Traveller
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://127.0.0.1:3000
* Listening on tcp://[::1]:3000
Use Ctrl-C to stop
</code></pre>
<p>今回はたまたま別プロジェクトでゴニョゴニョ作業をしていた名残で環境変数 <code>DATABASE_URL</code> が設定されてしまっていて、かつそのままの流れで Rails プロジェクトで作業していたため遭遇してしまいました。。</p>
<p>ローカル環境で変数を設定する際は <a target="_blank" rel="nofollow noopener" href="https://github.com/direnv/direnv">direnv</a> や <a target="_blank" rel="nofollow noopener" href="https://www.dotenv.org/">dotenv</a> 等を利用して極力手動では環境変数をいじらないようにしようと思いました (所感)</p>
<h2 id="参考リンク"><a href="#%E5%8F%82%E8%80%83%E3%83%AA%E3%83%B3%E3%82%AF">参考リンク</a></h2>
<ul>
<li><a target="_blank" rel="nofollow noopener" href="https://edgeguides.rubyonrails.org/configuring.html#connection-preference">Configuring Rails Applications — Ruby on Rails Guides</a></li>
</ul>
nikaera
tag:crieit.net,2005:PublicArticle/17083
2021-05-10T22:06:08+09:00
2021-05-10T22:06:08+09:00
https://crieit.net/posts/Web-60992fc0523c1
遅延ロードさせてWebアプリを高速化する
<h1 id="遅延ロードとは"><a href="#%E9%81%85%E5%BB%B6%E3%83%AD%E3%83%BC%E3%83%89%E3%81%A8%E3%81%AF">遅延ロードとは</a></h1>
<p>基本的にwebアプリは表示するデータを読み込んでからページを表示します。<br />
しかしそれだと重いデータを取得・表示する場合、ページの表示速度が落ちて重たい動作になります。<br />
なので先に軽い部分だけを読み込みそのページに移動してから重いデータを読み込むことで<br />
すべてを表示するまでの時間は変わらない(むしろ少し落ちる)がページの移動速度を大幅に上げることができます。<br />
体感上はかなりサクサクした動作になります。</p>
<p>↓ツイッターの遅延ロード<br />
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480294/8197e1ec-d086-b08d-7b45-197e323945a8.png" alt="スクリーンショット 2021-05-10 192747.png" /></p>
<h1 id="実装"><a href="#%E5%AE%9F%E8%A3%85">実装</a></h1>
<pre><code class=":gemfile">gem 'render_async'
</code></pre>
<p>を書きbundle</p>
<p>次にrenderを書き直します。</p>
<p>変更前:</p>
<p>```erb:index.html<br />
<%= render "data", posts:@posts %></p>
<pre><code><br />これを
```erb:index.html
<%= render_async data_path %>
or
<%= render_async data_user_path(@user) %>
</code></pre>
<p>このようにする。</p>
<p>次にルーティング</p>
<pre><code class="ruby:routes">get "data", to: "posts#data", as: "data"
#↓パラメーターが必要な場合
get "data_user/:id", to: "posts#data_user", as: "data"
</code></pre>
<pre><code class="ruby:controller"> def index
#@posts = Post.all
end
def data
@posts = Post.all
render partial: "data", locals: {posts:@posts}
end
def data_user
@user = User.find_by(name: params[:id])
@posts = @user.posts.all
render partial: "data_user", locals: {posts:@posts}
end
</code></pre>
<p>最後はレイアウトに</p>
<p>```erb:application.html.erb<br />
<%= content_for :render_async %></p>
<pre><code><br />を追加。
これだけで遅延ロードが完成します。
![スクリーンショット 2021-05-10 192747.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480294/e7e53d4b-7114-b09c-cf2e-a54ec754d08c.png)
# turbolinksを使用している場合
このままだと時々表示されない場合があります。
</code></pre>
<p><%= render_async data_path, html_options: { 'data-turbolinks-track': 'reload' } %></p>
<pre><code>html_options: { 'data-turbolinks-track': 'reload' }を追加して
config/initializersにrender_async.rbを作りましょう
```render_async.rb
RenderAsync.configure do |config|
config.turbolinks = true # Enable this option if you are using Turbolinks 5+
end
</code></pre>
<h1 id="jqueyを使う"><a href="#jquey%E3%82%92%E4%BD%BF%E3%81%86">jqueyを使う</a></h1>
<p>kaminariやjscrollで無限スクロールなどを実装している場合、これをしないと動きません。</p>
<p><code>config/initializers/render_async.rb
RenderAsync.configure do |config|
config.jquery = true
end</code></p>
<h1 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h1>
<p>遅延ロードって大きなサービスだと結構使われているのに日本語の情報が少なくて困ったので書きました。<br />
体感上の動作速度がかなり変わるのでぜひやってみてください。</p>
<h3 id="宣伝"><a href="#%E5%AE%A3%E4%BC%9D">宣伝</a></h3>
<p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480294/99c8f13e-2fe8-0d28-1117-338115e937a0.png" alt="453789.png" /></p>
<p><a target="_blank" rel="nofollow noopener" href="https://ammot.net/">https://ammot.net/</a></p>
<p>AmmotというSNSを作りました。<br />
文字数制限が6000字まで、画像・動画・PDF・音声は同時に10個まで投稿可能な自由なSNSです。<br />
マークダウンにも対応しているので皆さん大好きなソースコードもきれいに載せれます。<br />
ぜひ使ってみてください。</p>
<p>僕のツイッターアカ<br />
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/yamada1531">https://twitter.com/yamada1531</a></p>
山田悠
tag:crieit.net,2005:PublicArticle/16845
2021-04-14T20:37:19+09:00
2021-04-14T20:37:19+09:00
https://crieit.net/posts/SNS-Ammot
制限の少ない自由なSNS ~Ammot~
<h1 id="初めに"><a href="#%E5%88%9D%E3%82%81%E3%81%AB">初めに</a></h1>
<p>この度<a target="_blank" rel="nofollow noopener" href="https://ammot.net/">Ammot</a>というwebアプリを開発しました。<br />
「制限の少ない自由な投稿を」がコンセプトで文字数が6000字まで、画像・動画・PDF・音声は同時に10個まで投稿可能です。<br />
「ツイッターは文字数制限がきつい、ただfacebookは実名制だしデザインがごちゃごちゃでいや」<br />
という声を聴いたので作ってみました。</p>
<p><a target="_blank" rel="nofollow noopener" href="https://ammot.net/">https://ammot.net/</a></p>
<p>qiitaのほうでも宣伝したのでよかったら見てください(ちょい違う内容です。)<br />
<a target="_blank" rel="nofollow noopener" href="https://qiita.com/UTOG/items/d5e6194aaa31b54e97c9">https://qiita.com/UTOG/items/d5e6194aaa31b54e97c9</a></p>
<h1 id="どんなサービスか"><a href="#%E3%81%A9%E3%82%93%E3%81%AA%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%81%8B">どんなサービスか</a></h1>
<p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480294/48b63235-f2b6-ac69-bc72-8c61cd41d877.png" alt="453789.png" /></p>
<p>↑これがログイン後のトップです。フォローしたユーザーの投稿がHOMEに流れて、<br />
サイドバーにはおすすめの投稿と現在人気のタグを表示しています。</p>
<p>文字数制限が6000字まで、画像・動画・PDF・音声は同時に10個まで投稿可能です。</p>
<p>先ほどサイドバーにおすすめを表示していると書きましたが<br />
実はサイドバーはおすすめ機能などなくランダムで表示してるだけです。。。<br />
おすすめ機能(レコメンド)を実装できなかったというのもありますが、僕自身レコメンド機能が結構嫌いなんですよね。同じ、似たようなものばかり出てきて飽きてきますしたまには普段と全く違うものを見たい時もあるでしょう。<br />
だからタイムライン(home)には好きな投稿が流れるようになっていてサイドバーは完全ランダムにしました。</p>
<h3 id="ツイッターのいやなとこ"><a href="#%E3%83%84%E3%82%A4%E3%83%83%E3%82%BF%E3%83%BC%E3%81%AE%E3%81%84%E3%82%84%E3%81%AA%E3%81%A8%E3%81%93">ツイッターのいやなとこ</a></h3>
<p>文字数制限<br />
編集ができない(個人的にめちゃ嫌)</p>
<h3 id="facebookのいやなとこ"><a href="#facebook%E3%81%AE%E3%81%84%E3%82%84%E3%81%AA%E3%81%A8%E3%81%93">facebookのいやなとこ</a></h3>
<p>制限はないがデザインがぐちゃぐちゃ<br />
実名制はなんかいやだ</p>
<p>この二つSNSの問題を解決するのがAmmotです。</p>
<h1 id="工夫した点"><a href="#%E5%B7%A5%E5%A4%AB%E3%81%97%E3%81%9F%E7%82%B9">工夫した点</a></h1>
<h4 id="無料プランにこだわった"><a href="#%E7%84%A1%E6%96%99%E3%83%97%E3%83%A9%E3%83%B3%E3%81%AB%E3%81%93%E3%81%A0%E3%82%8F%E3%81%A3%E3%81%9F">無料プランにこだわった</a></h4>
<p>こういうものはバズらない限り、すぐには成功しません。使用者が全くいなくても1年は公開しようと思います。<br />
でも使用者がいないのに月数百円も取られるの馬鹿馬鹿しいじゃないですか。だからドメイン以外はすべて無料です。<br />
ただherokuの無料プランだとドメインを設定できないのでCloudflareを使い設定しました。</p>
<p>参考記事:<br />
<a target="_blank" rel="nofollow noopener" href="https://qiita.com/serinuntius/items/f7f08b2221f5ad068f5d">https://qiita.com/serinuntius/items/f7f08b2221f5ad068f5d</a></p>
<p>しかし、やはりSNSは速度が非常に重要なので少しだけ批判を受けました。自分はもう少しユーザーと投稿が増えてきたら有料のサーバーにしようと思います。</p>
<h4 id="デザインとUIにこだわった(つもり)"><a href="#%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%81%A8UI%E3%81%AB%E3%81%93%E3%81%A0%E3%82%8F%E3%81%A3%E3%81%9F%EF%BC%88%E3%81%A4%E3%82%82%E3%82%8A%EF%BC%89">デザインとUIにこだわった(つもり)</a></h4>
<p>フィットスクロール?だったり投稿画面のポップアップだったり<br />
今まで使ってこなかった手法を使ってみました。<br />
自己満になってるかもしれない</p>
<p>ちなみにデザインを参考にしたサイトは<a target="_blank" rel="nofollow noopener" href="https://www.tumblr.com/">tumblr</a>です。<br />
比べればまぁまぁ似てると思います。</p>
<h4 id="機能性"><a href="#%E6%A9%9F%E8%83%BD%E6%80%A7">機能性</a></h4>
<p>最初にも書きましたが画像・動画・PDF・音声の投稿とプレビュー機能を実装しました。<br />
これにはいろんな記事がありましたが</p>
<p>まともに動きかつ一番簡単でコードもシンプルなこの記事を参考にするのをお勧めします。<br />
<a target="_blank" rel="nofollow noopener" href="https://qiita.com/0thefool/items/5af0f17f0075e7e0e013">https://qiita.com/0thefool/items/5af0f17f0075e7e0e013</a></p>
<h4 id="マークダウン"><a href="#%E3%83%9E%E3%83%BC%E3%82%AF%E3%83%80%E3%82%A6%E3%83%B3">マークダウン</a></h4>
<p>他SNSとの差別化も含めマークダウンに対応しました。<br />
文字の大きさやフォント?も自由に変えれます。</p>
<h1 id="使用した技術"><a href="#%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%9F%E6%8A%80%E8%A1%93">使用した技術</a></h1>
<p>rails6<br />
ruby2.7<br />
postgresql<br />
heroku free<br />
aws s3</p>
<pre><code>gem 'ridgepole'
gem 'slim-rails'
gem 'html2slim'
gem 'pry-rails'
gem 'devise'
gem 'kaminari'
gem 'activeadmin'
gem 'rack-attack'
gem 'rails-i18n'
gem 'devise-i18n'
gem 'devise-i18n-views'
gem 'carrierwave'
gem 'rmagick'
gem 'rinku'
gem 'fog-aws'
gem 'dotenv-rails'
gem 'omniauth-google-oauth2'
gem 'omniauth-rails_csrf_protection'
gem 'redcarpet'
gem "rouge"
gem 'redis-rails'
#一部抜いてます
</code></pre>
<h1 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h1>
<p>今回の開発は今までやらなかったことにめちゃ挑戦できたので楽しかったです<br />
苦手なjquery・javascriptもプレビュー機能のおかげでちょっとわかった気がしてます。</p>
<p>文字数制限や実名制で不便を感じたことのある人はぜひAmmot使ってください!お願いします。</p>
<p>↓URL<br />
<a target="_blank" rel="nofollow noopener" href="https://ammot.net/">https://ammot.net/</a></p>
<p>↓僕のAmmotのアカウント<br />
<a target="_blank" rel="nofollow noopener" href="https://ammot.net/user/yamada">https://ammot.net/user/yamada</a></p>
<p>↓僕のツイッターのアカウント<br />
<a target="_blank" rel="nofollow noopener" href="https://twitter.com/yamada1531">https://twitter.com/yamada1531</a></p>
山田悠
tag:crieit.net,2005:PublicArticle/16139
2020-10-18T18:32:30+09:00
2020-10-18T18:32:30+09:00
https://crieit.net/posts/51666379560ed175bbb7725cb5f01193
プログラムコードを販売できるサービスまとめ
<p>今回はプログラムコードを販売できるサービスをまとめました。</p>
<h2 id="code-sell"><a href="#code-sell">code-sell</a></h2>
<p><a target="_blank" rel="nofollow noopener" href="https://www.code-sell.net/">code-sell</a><br />
<a href="https://crieit.now.sh/upload_images/58040fa19563696175b43776ee552c375f8c097ec198c.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/58040fa19563696175b43776ee552c375f8c097ec198c.png?mw=700" alt="image" /></a><br />
宣伝です...。僕が1週間くらい前に作ったサービスです。なるべく簡単に販売・購入できるようにしました。<br />
いま僕が今まで作ったwebアプリのコードをすべて無料で公開しています。</p>
<h2 id="piecex"><a href="#piecex">piecex</a></h2>
<p><a target="_blank" rel="nofollow noopener" href="https://piecex.com">piecex</a><br />
<a href="https://crieit.now.sh/upload_images/7ee158079f977ed09bd1f41679bf02bf5f8c09672c2d1.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/7ee158079f977ed09bd1f41679bf02bf5f8c09672c2d1.png?mw=700" alt="image" /></a><br />
おそらく一番メジャーで人気のあるサービスです。<br />
AIを搭載していて最適な価格がわかるそうです。</p>
<h2 id="osadasoft"><a href="#osadasoft">osadasoft</a></h2>
<p><a target="_blank" rel="nofollow noopener" href="https://www.osadasoft.com/support/source/">osadasoft</a><br />
コード一つ一つが高額です</p>
<h3 id="補足"><a href="#%E8%A3%9C%E8%B6%B3">補足</a></h3>
<p><a target="_blank" rel="nofollow noopener" href="https://www.source-gene.com/sg/top.do">sourcegene</a><br />
は登録ができませんでした。最新のコードも2018年なのでおそらくサービス終了しているんだと思います。</p>
<h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2>
<p>今回はプログラムコードを販売できるサービスをまとめてみました。とりあえずいえるのは<br />
<a target="_blank" rel="nofollow noopener" href="https://www.code-sell.net/">code-sell</a>使ってください。</p>
山田悠
tag:crieit.net,2005:PublicArticle/15902
2020-05-20T02:16:14+09:00
2020-05-20T02:16:14+09:00
https://crieit.net/posts/zsh-Rails-server-IPv6
zsh上で、Rails serverの外部からのIPv6接続を許可したい場合の、オプションの書き方
<p> zsh上で、Rails serverの外部からのIPv6接続を許可したい場合は、</p>
<p><code>bin/rails server -b \[::]</code></p>
<p>と書く必要があります。なぜかと言うと、<code>[</code>が組み込みコマンドと解釈されてしまうためで、エスケープが必要だからのようです。<br />
なお、bashでは普通に、</p>
<p><code>bin/rails s -b [::]</code></p>
<p>で大丈夫でした。<br />
また、IPv6の接続許可を行えば、自動的にIPv4でも接続できるようになりました。この辺は要調査ではありますが。</p>
真田 保
tag:crieit.net,2005:PublicArticle/15885
2020-05-01T22:32:30+09:00
2020-05-01T22:32:30+09:00
https://crieit.net/posts/Rails
Railsでモーダルの出し分けを管理する
<p>Railsでモーダルの表示処理をまとめて衝突しないように管理する方法を紹介します。</p>
<h1 id="背景"><a href="#%E8%83%8C%E6%99%AF">背景</a></h1>
<p><a target="_blank" rel="nofollow noopener" href="https://tsukulink.net/">ツクリンク</a>を運営する中でモーダルが少しづつ増え、衝突することがあったためモーダルの優先順位を付け、衝突しないよう実装をしました。</p>
<h1 id="実装"><a href="#%E5%AE%9F%E8%A3%85">実装</a></h1>
<h2 id="前提"><a href="#%E5%89%8D%E6%8F%90">前提</a></h2>
<p>以下の3つのモーダルがあるとします。</p>
<ul>
<li>A: 初回ログインで出すモーダル(全ページ)</li>
<li>B: 特定のユーザーにだけお知らせを出すモーダル(全ページ)</li>
<li>C: 特定のページで出すモーダル(Posts#show)</li>
</ul>
<h2 id="コードサンプル"><a href="#%E3%82%B3%E3%83%BC%E3%83%89%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB">コードサンプル</a></h2>
<p>全ページに出すモーダルはApplicationControllerで該当ユーザーか判断しモーダルに必要な情報をセットします。</p>
<pre><code class="ruby"># controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_action :set_modal_A
before_action :set_modal_B
def set_modal_A
return if cookies['modal_A'].present? # 表示済みなら何もしない
if is_first_signed_in? # 初回ログインか?
@modal_A = { title: '表示に必要な情報など' }
end
end
def set_modal_B
return if cookies['modal_B'].present? # 表示済みなら何もしない
if show_notice? # お知らせを出すユーザーか?
@modal_B = true
end
end
end
</code></pre>
<p>Viewごとに出るモーダルは <code>provide</code> でモーダルをセット</p>
<pre><code class="ruby"># views/posts/show.html.erb
<% provide :modal, render('modal/C') %>
</code></pre>
<p>レイアウトのView(もしくはそれに準ずるパーシャル)でモーダルの出し分けを行います。<br />
ifの上位にあるものが優先され、モーダルが複数renderされるのを防いでいます。</p>
<pre><code class="ruby"># views/layouts/application.html.erb
<% if yield(:modal).present? %>
<%= yield(:modal) %>
<% elsif @modal_B.present? %>
<%= render 'modal/B' %>
<% elsif @modal_A.present? %>
<%= render 'modal/A' %>
<% end %>
</code></pre>
<p>各モーダルのViewでは表示を管理するCookieを保存するなどの処理をしています。</p>
<pre><code class="ruby"># views/modal/A.html.erb
<% cookies.permanent['modal_A'] = { value: true, expires: 1.day } %>
<div class="modal">お知らせだよ!</div>
</code></pre>
あっきー💃
tag:crieit.net,2005:PublicArticle/15661
2019-12-31T22:28:48+09:00
2019-12-31T22:38:26+09:00
https://crieit.net/posts/Workdiary
作業日誌アプリ「Workdiary」説明書
<p><a target="_blank" rel="nofollow noopener" href="https://workdiary-al.herokuapp.com/diaries">Workdiary</a></p>
<p>初めて制作してきたWEBアプリです。<br />
日記とその日にやったワークの登録を行う作業日誌アプリで、農作業を想定していますがどんなジャンルの作業でも(おそらく)使えるような内容になっています。</p>
<p>GitHubリポジトリは<a target="_blank" rel="nofollow noopener" href="https://github.com/Massasquash/workdiary">こちら</a></p>
<p>初アプリとはいえ未完の部分が多く、クオリティ的には課題が山積み。<br />
お時間のある時になんとなくいじってみてもらえたら嬉しいです。</p>
<h2 id="アプリの使用イメージ"><a href="#%E3%82%A2%E3%83%97%E3%83%AA%E3%81%AE%E4%BD%BF%E7%94%A8%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8">アプリの使用イメージ</a></h2>
<p>自身の農作業の記録を目的として制作してみました。<br />
勉強の記録などに使ってもいいかもしれません。</p>
<p><strong>(1)やった作業を入力する</strong><br />
農作業をやっていて、一段落ついた休憩時とかその日家に帰ってお酒飲みながらでも、スマホをポチポチやってその日にやった作業内容を登録。この時にメモしておきたい数量や機械のセッティング内容などを簡単に入れておきます。</p>
<p><strong>(2)必要なときに調べる</strong><br />
その後「このセッティングって前回どうしていたっけ?」という時に、スマホをポチポチやって以前に入力した内容を確認します。</p>
<p>特徴としては「テンプレート機能」というものをつけてみました。<br />
作業内容の定型文(テンプレート)をユーザーが事前に作っておくことで、やった作業の記録を簡単に記録できるようにしています。</p>
<h2 id="アプリの使い方"><a href="#%E3%82%A2%E3%83%97%E3%83%AA%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9">アプリの使い方</a></h2>
<h3 id="(1)サインアップ・ログイン"><a href="#%EF%BC%88%EF%BC%91%EF%BC%89%E3%82%B5%E3%82%A4%E3%83%B3%E3%82%A2%E3%83%83%E3%83%97%E3%83%BB%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3">(1)サインアップ・ログイン</a></h3>
<p><a href="https://crieit.now.sh/upload_images/80efe1f337b04eeaa51d2e04ff6c3f175e0b4af496652.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/80efe1f337b04eeaa51d2e04ff6c3f175e0b4af496652.png?mw=700" alt="スクリーンショット 2019-12-19 21.05.58.png" /></a></p>
<ul>
<li>サンプルアカウントでログインしてみてください。</li>
<li>初期値でフォームにサンプルアカウントが入っているのでそのまま「ログイン」をクリックすると入れます。</li>
<li>任意のメールアドレスとパスワードでユーザー登録(サインアップ)することもできます。</li>
<li>メールアドレスは架空のものでOKです。現状の設定では実際にメールは届きません。</li>
</ul>
<h3 id="(2)ナビゲーションバー"><a href="#%EF%BC%88%EF%BC%92%EF%BC%89%E3%83%8A%E3%83%93%E3%82%B2%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%83%90%E3%83%BC">(2)ナビゲーションバー</a></h3>
<p><a href="https://crieit.now.sh/upload_images/ce91611997d4568e6aa485feea173edb5e0b4b49a8daf.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/ce91611997d4568e6aa485feea173edb5e0b4b49a8daf.png?mw=700" alt="スクリーンショット 2019-12-19 21.31.17.png" /></a></p>
<p>ログインしたら画面上部にナビゲーションバーが登場し、アイコンをクリックすると画面遷移します。左から、</p>
<ul>
<li>ダイアリー一覧:ダイアリーとワークを一覧表示します。</li>
<li>ワーク一覧:ワークをカテゴリごとに一覧表示します。(未実装)</li>
<li>検索:日記・ワークを文字列検索できます。(未実装)</li>
<li>編集:カテゴリとテンプレートを編集できます。</li>
<li>アカウント:ログイン状況の確認とログアウトができます。</li>
</ul>
<h3 id="(3)メインページ(「日記一覧」画面)"><a href="#%EF%BC%88%EF%BC%93%EF%BC%89%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8%EF%BC%88%E3%80%8C%E6%97%A5%E8%A8%98%E4%B8%80%E8%A6%A7%E3%80%8D%E7%94%BB%E9%9D%A2%EF%BC%89">(3)メインページ(「日記一覧」画面)</a></h3>
<p><a href="https://crieit.now.sh/upload_images/ddad0c60cdc43af96d4c9f997dffd83a5e0b4b7792edb.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/ddad0c60cdc43af96d4c9f997dffd83a5e0b4b7792edb.png?mw=700" alt="スクリーンショット 2019-12-19 21.16.18.png" /></a></p>
<p>ログインしたら最初にこの画面が表示されます。<br />
ここでは既に登録された「日記」と「ワーク」が一覧で表示され、それらの作成もできるこのアプリのメインページになります。</p>
<p><strong>日記の作成</strong><br />
- 「ダイアリーを書く」から今日の日記を投稿します(画像では「日記を書く」)。<br />
- 投稿できる日付は今日に限らず過去でも未来でもプルダウンで選択できます。<br />
- ダイアリーは日付あたり1つのみ作成できます。</p>
<p><strong>ワークの作成</strong><br />
- ダイアリーを作ったら、そのダイアリーに紐づいたワークが作成できるようになります。日付の横にある「ワークの追加から作成します。<br />
- カテゴリ、作業名、作業内容を入力して登録します(写真はフォームのみで未実装)。</p>
<p><strong>その他</strong><br />
・ダイアリー一覧の日付をクリックすると日記の詳細画面に映ります<br />
・登録したダイアリー・ワークの編集と削除もできます<br />
・「メモする」をクリックすると、ワークに対してメモを1つ追加することができます。後から気づいた点を追記したい場合などに活用できます。</p>
<h3 id="(4)「カテゴリ」について"><a href="#%EF%BC%88%EF%BC%94%EF%BC%89%E3%80%8C%E3%82%AB%E3%83%86%E3%82%B4%E3%83%AA%E3%80%8D%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6">(4)「カテゴリ」について</a></h3>
<p>ワークに対してカテゴリを登録しておくことで、後からカテゴリごとにワークを一覧表示できるようにするものです。</p>
<ul>
<li>ワーク入力時に「カテゴリ」をプルダウンで選択します。</li>
<li>事前に「+カテゴリ追加」から自分でカテゴリを作っておく必要があります(画面遷移します)。</li>
<li>ナビゲーションバーの「編集」ページでカテゴリを編集・削除することができます。</li>
<li>カテゴリを削除したら、該当するワークからはカテゴリが外れてしまいます。</li>
</ul>
<h3 id="(5)「テンプレート」について"><a href="#%EF%BC%88%EF%BC%95%EF%BC%89%E3%80%8C%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88%E3%80%8D%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6">(5)「テンプレート」について</a></h3>
<p>ワーク入力時にテンプレートを選択することで作業内容に定型文を入力できます。例えば「決まった一連のワークがあって、その作業内容の定型文を作っておいて数値のみ変えて登録する」といった活用なんかを想定しています。</p>
<ul>
<li>ワーク入力時に「テンプレート」をプルダウンで選択するとその下の作業内容フォームにテンプレートの内容が自動で入力されるので、それを書き換えるなどして投稿することができます。</li>
<li>事前に「+テンプレート追加」から自分でテンプレートを作っておく必要があります(画面遷移します)。</li>
<li>ナビゲーションバーの「編集」ページでテンプレートを編集・削除することができます。</li>
</ul>
<p>↓テンプレートをプルダウンリストで選択すると……<br />
<a href="https://crieit.now.sh/upload_images/b9b27dd4ad30bed38c15c67f5a3802785e0b4ba361dc5.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/b9b27dd4ad30bed38c15c67f5a3802785e0b4ba361dc5.png?mw=700" alt="スクリーンショット 2019-12-19 22.56.16.png" /></a></p>
<p>↓このように作業内容のフォームに反映されます<br />
<a href="https://crieit.now.sh/upload_images/0db1f94ffb5a331cdefc136d18611c6a5e0b4bb5d66b0.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/0db1f94ffb5a331cdefc136d18611c6a5e0b4bb5d66b0.png?mw=700" alt="スクリーンショット 2019-12-19 22.56.24.png" /></a></p>
<h3 id="(6)ログアウト"><a href="#%EF%BC%88%EF%BC%96%EF%BC%89%E3%83%AD%E3%82%B0%E3%82%A2%E3%82%A6%E3%83%88">(6)ログアウト</a></h3>
<p>ナビゲーションバーの「アカウント」ページよりログアウトできます。</p>
<p>......以上、最低限のアプリの説明書でした。</p>
<h2 id="開発に使用したスキル"><a href="#%E9%96%8B%E7%99%BA%E3%81%AB%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%9F%E3%82%B9%E3%82%AD%E3%83%AB">開発に使用したスキル</a></h2>
<p>言語とフレームワーク<br />
- HTML, CSS<br />
- Ruby, Ruby on Rails<br />
- 一部、Javascript, JqueryでAjax化</p>
<p>開発環境等<br />
- AWS cloud9<br />
- Heroku</p>
<p>またRailsで使った主なgemとしては<br />
- Bootstrap4(デザイン)<br />
- Font Awesome (アイコン使用)<br />
- Devise(ログイン機能)</p>
<p>デザイン周りはほぼBootstrapを活用しています。<br />
一部機能にjQueryを使用してAjax化していますが、ちゃんと理解して使えていないというのが正直なところ。<br />
ログイン機能のメール認証に関しては実際の認証は外した状態です。</p>
<h2 id="今後の実装予定と課題"><a href="#%E4%BB%8A%E5%BE%8C%E3%81%AE%E5%AE%9F%E8%A3%85%E4%BA%88%E5%AE%9A%E3%81%A8%E8%AA%B2%E9%A1%8C">今後の実装予定と課題</a></h2>
<p>制作期間が間延びしてしまいモチベーション的にも厳しくなってきたので、これで一区切りして次に移ろうと考えてますが、やはり未消化でモヤモヤする部分もあります。</p>
<ul>
<li>ワーク一覧表示画面、検索画面の作成</li>
<li>(完了!)パンくずリストをつける</li>
<li>(完了!)アラートメッセージの表示方法と日本語化</li>
<li>ワーク登録時に写真を追加できるようにする</li>
<li>ワーク登録時のカテゴリ・テンプレート新規作成をモーダルウィンドウで入力しやすくする</li>
<li>日付をカレンダーから選べるようにする</li>
</ul>
<p>この辺りは時間を見つけてもうちょっと取り組んでいきます。<br />
また公開したことによって細かい部分で自分で気付けなかった問題やバグが出てくると思うので、そういったデバッグ作業から今後の学びにしていきたいと思います。</p>
<p>例えば現状でも、ダイアリーやワークの登録に文字数制限をかけておいたりすべきかなーとか、UI的にダイアリーやワークの作り方がわかりづらいなーとか手間がかかるなーとか、色々見えてきますね。</p>
<p>今回一度公開することで、友人に見せてみることができたのが良かったです。何人かに見てもらったのですが、皆さんまずは「どう使えばいいかわからない」と口を揃えて言っていただけます。。。<br />
これを実感するだけでも公開した意味があったなーと感じます。</p>
<p>このアプリは僕の処女作としてしばらく公開を続けてみて、いろんな方にサンドバッグにしていただきたい所存です。<br />
とはいえぜひお手柔らかにお願いします!(よわい)</p>
Massa
tag:crieit.net,2005:PublicArticle/15621
2019-12-18T23:02:34+09:00
2019-12-18T23:02:34+09:00
https://crieit.net/posts/Rails6-Ruby
Rails6 ビューファイルにRubyのコード書く時の<% %>と<%= %>の違い
<h1 id="<% %>と<%= %>の違い"><a href="#%26lt%3B%25+%25%26gt%3B%E3%81%A8%26lt%3B%25%3D+%25%26gt%3B%E3%81%AE%E9%81%95%E3%81%84"><% %>と<%= %>の違い</a></h1>
<ul>
<li>: この中に書いたコードは表示されない。変数定義やif文などの記載に使う。</li>
<li>: この中に書いたコードは表示される。ビューファイル上に変数の値を表示したい時などに使用する</li>
</ul>
miriwo: 19年7月7日からQiita毎日投稿中!
tag:crieit.net,2005:PublicArticle/15607
2019-12-14T11:44:05+09:00
2019-12-14T14:25:38+09:00
https://crieit.net/posts/Rails-Bootstrap-Ajax
【Rails】Bootstrapを導入したらAjaxが機能しなくなっていたお話
<h2 id="参考にしたサイト"><a href="#%E5%8F%82%E8%80%83%E3%81%AB%E3%81%97%E3%81%9F%E3%82%B5%E3%82%A4%E3%83%88">参考にしたサイト</a></h2>
<ul>
<li>参考1<br />
<a target="_blank" rel="nofollow noopener" href="https://qiita.com/yusaku_/items/33f09999e403f7a2d2df">【Rails】 jQueryが動作しない時の対処法 (読み込む順番に気をつけないといけない) - Qiita</a></li>
<li><p>参考2<br />
<a target="_blank" rel="nofollow noopener" href="https://macoblog.com/jquery-saishin/#h-anker11">【2019年版】jQuery最新の読み込みスクリプト「コピペOK+裏技」 | マコブログ</a></p></li>
<li><p>今回の自作Railsアプリはこちら。<br />
<a target="_blank" rel="nofollow noopener" href="https://workdiary-al.herokuapp.com/">Workdiary</a><br />
<a target="_blank" rel="nofollow noopener" href="https://github.com/Massasquash/workdiary">GitHub - Massasquash/workdiary</a></p></li>
</ul>
<h2 id="はじめに"><a href="#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB">はじめに</a></h2>
<h2 id="1.起こったこと"><a href="#%EF%BC%91%EF%BC%8E%E8%B5%B7%E3%81%93%E3%81%A3%E3%81%9F%E3%81%93%E3%81%A8">1.起こったこと</a></h2>
<p>Railsアプリで、Ajax(jQuery)を使用した機能を作っていてしばらく上手く動いていたのですが、Bootstrapを導入してjavascript周りをいじってから機能しなくなっていました。</p>
<h2 id="2.解決策"><a href="#%EF%BC%92%EF%BC%8E%E8%A7%A3%E6%B1%BA%E7%AD%96">2.解決策</a></h2>
<p>とても簡単なことで、HTMLファイルの<code>head</code>タグ内に記述すべき<code>jQuery CDN</code>(<code>script</code>タグ)の位置が間違っていたのが原因でした。<br />
さらにこの<code>jQuery CDN</code>(<code>script</code>タグ)と<code>javascript_include_tag</code>の順番がこの通りになっていることが大事なようです。(<a target="_blank" rel="nofollow noopener" href="https://qiita.com/yusaku_/items/33f09999e403f7a2d2df">参考リンク1</a>)</p>
<p><strong>app/views/layouts/application.html.erb</strong></p>
<pre><code><head>
・
・
・
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
</head>
</code></pre>
<h2 id="3.解説・補足"><a href="#%EF%BC%93%EF%BC%8E%E8%A7%A3%E8%AA%AC%E3%83%BB%E8%A3%9C%E8%B6%B3">3.解説・補足</a></h2>
<p>bootstrapを導入する際に、<code>body</code>タグの一番下に<code>jQuery CDN</code>(<code>script</code>タグ)を移動してしまっていたのが原因のようです。<br />
記述する位置には気をつけましょう!</p>
<h3 id="修正のためやってみたこと"><a href="#%E4%BF%AE%E6%AD%A3%E3%81%AE%E3%81%9F%E3%82%81%E3%82%84%E3%81%A3%E3%81%A6%E3%81%BF%E3%81%9F%E3%81%93%E3%81%A8">修正のためやってみたこと</a></h3>
<ul>
<li>Javascriptファイルが読み込まれているか確かめる</li>
</ul>
<p>このAjaxを使用している部分は「フォーム入力時にプルダウンでテンプレートを選択 → 選択されたテンプレートの中身がフォームに自動入力される」という機能なのですが、<br />
まずはjavascriptが正常に読み込まれていないのかと思い、<br />
試しに「プルダウンを選択した時に選択されたテンプレートがアラートで表示される」ように、呼び出されるjavascriptに<code>alert(template_id)</code>を記述してみたところ、しっかりとアラートが出てきました。<br />
javascriptは機能しているようです。</p>
<ul>
<li>Ajax(jQuery)が機能しているか確かめる</li>
</ul>
<p>次に、Ajaxで渡されるはずのtemplatesコントローラーの<code>get_body</code>アクションが処理されているかを調べました。適当な行に<code>raise params.inspect</code>と入れることで、その箇所でエラーが発生するはずです。<br />
ところがプルダウンリストを選択してもエラーは発生せず、フォームにも何も反映されません。<br />
Ajaxが機能せず、目的のコントローラーのアクションに渡っていないことがわかりました。<br />
javascriptは読み込まれていても、Ajaxが動作しない。<br />
つまりjQueryの読み込みが上手くいってなさそうで、調べてみると(<a target="_blank" rel="nofollow noopener" href="https://qiita.com/yusaku_/items/33f09999e403f7a2d2df">参考リンク1</a>)にたどり着いた経緯です。</p>
<h3 id="用語"><a href="#%E7%94%A8%E8%AA%9E">用語</a></h3>
<ul>
<li>jQuery CDN</li>
</ul>
<p>という単語が出てきましたが、(<a target="_blank" rel="nofollow noopener" href="https://macoblog.com/jquery-saishin/#h-anker11">参考リンク2</a>)によると、<br />
jQueryを使うには、jQuery本体をダウンロードして読み込む方法と、CDNを経由して使う方法の2種類があるようです。後者の方が、jQueryをダウンロードする必要がなく、今回のようにHTMLファイルの<code>head</code>タグ内に以下のような<code>sqript</code>タグを貼り付けるだけでjQueryが動作するようになります。</p>
<pre><code> <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
</code></pre>
<ul>
<li>SDN</li>
</ul>
<p>これが概念としてまだイマイチ理解できませんでした。<br />
宿題とします。</p>
<h2 id="MEMO"><a href="#MEMO">MEMO</a></h2>
<p>参考までに該当部分のコードを晒しておきます。<br />
(色々余計なコードもそのままにしていると思うので、初心者の方は参考にしないでください…)</p>
<p><strong>app/views/layouts/application.html.erb</strong></p>
<pre><code><head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<title>Workdiary</title>
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
</head>
</code></pre>
<p><strong>app/assets/javascripts/application/js</strong></p>
<pre><code>function changeTemplate(val){
var template_id = val;
// alert(template_id)
$.ajax({
url: "/templates/get_body",
type: "GET",
data: {
template_id: template_id
}
})
}
</code></pre>
<p><strong>app/controllers/concerns/templates_controller.rb</strong></p>
<pre><code> def get_body
template = Template.find(params[:template_id])
@template_body = template.body
respond_to do |format|
format.js
end
end
</code></pre>
Massa
tag:crieit.net,2005:PublicArticle/15427
2019-09-26T22:08:54+09:00
2019-09-26T22:08:54+09:00
https://crieit.net/posts/React-PWA-Rails-GraphQL-RPG
React PWA + Rails GraphQLで作ったポモドーロRPGに使った技術やその選定理由を書いてみた
<p>先日、『<a target="_blank" rel="nofollow noopener" href="https://www.g-g-g-g.games">g4</a>』というポモドーロ+RPGなサービスをリリースしました。</p>
<p>そのサービスで使った技術について聞かれることがあったので残しておきます。</p>
<h1 id="どんなサービス?"><a href="#%E3%81%A9%E3%82%93%E3%81%AA%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%3F">どんなサービス?</a></h1>
<p>ポモドーロ・タイマーを使い25分間集中すると経験値をもらえ、その経験値でレベルが上がる。<br />
って言う感じのやつです。</p>
<p><a target="_blank" rel="nofollow noopener" href="https://www.g-g-g-g.games">https://www.g-g-g-g.games</a></p>
<p><a target="_blank" rel="nofollow noopener" href="https://www.g-g-g-g.games"><a href="https://crieit.now.sh/upload_images/4857e38ac110f7f2ccb9a3a6c9851f425d8c46a290533.jpeg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/4857e38ac110f7f2ccb9a3a6c9851f425d8c46a290533.jpeg?mw=700" alt="https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_51402_6c1fef60-9f24-2233-821b-1b4b16575e21.jpeg" /></a></a></p>
<h2 id="こんな特徴があります。"><a href="#%E3%81%93%E3%82%93%E3%81%AA%E7%89%B9%E5%BE%B4%E3%81%8C%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82">こんな特徴があります。</a></h2>
<ul>
<li>ポモドーロ・タイマーやRPG的なUIはリッチで動きがある</li>
<li>現在のステータスをOGP画像にしてシェアできる</li>
<li>上昇する能力値や覚えるスキルは登録した文章を解析して決まる</li>
</ul>
<h1 id="構成はこんな感じ"><a href="#%E6%A7%8B%E6%88%90%E3%81%AF%E3%81%93%E3%82%93%E3%81%AA%E6%84%9F%E3%81%98">構成はこんな感じ</a></h1>
<p><a href="https://crieit.now.sh/upload_images/a91960cfcbabfe4677662c7e3a35b9225d8c468610acb.jpeg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/a91960cfcbabfe4677662c7e3a35b9225d8c468610acb.jpeg?mw=700" alt="https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_51402_1f7797cd-59e5-b556-2afe-b0a964acd0ac.jpeg" /></a></p>
<h2 id="フロントエンドの選定理由"><a href="#%E3%83%95%E3%83%AD%E3%83%B3%E3%83%88%E3%82%A8%E3%83%B3%E3%83%89%E3%81%AE%E9%81%B8%E5%AE%9A%E7%90%86%E7%94%B1">フロントエンドの選定理由</a></h2>
<p>フロントエンドはSSRしたReactアプリをfly.ioにおいています</p>
<h3 id="[React]"><a href="#%5BReact%5D">[React]</a></h3>
<p>自分は過去に仕事でNuxt.jsや生Vue.jsを使ったことがあり、個人ではExpoやNext.jsでReactにも触っていました。</p>
<p>今回Reactを選択した理由は以下です。</p>
<ul>
<li>型が欲しかった。Typescriptを使いたかった</li>
<li>Reactのほうが書いていて楽しい(個人の感想です)
<ul>
<li>React Hooksめっちゃいい</li>
</ul></li>
<li>Apolloを使うならVueよりReactのほうが色々揃っている</li>
</ul>
<h3>[<a target="_blank" rel="nofollow noopener" href="https://fly.io">fly.io</a>]</h3>
<p>SSRするためにNode.jsをホスティングするやつが欲しかったので選定。<br />
<a target="_blank" rel="nofollow noopener" href="https://mizchi.hatenablog.com/entry/2019/02/21/235403">mizchiさんのブログ</a>で知り、面白そうだなと思ったのがきっかけ。<br />
べつにfirebase hostingでもよかったですが、以下が決め手</p>
<ul>
<li>firebase hosting同様初期導入費用がほぼ0</li>
<li>CDN</li>
<li>キャッシュコントロール</li>
<li>svgを使ったOGP画像の生成ができる</li>
</ul>
<p>特に、</p>
<blockquote>
<p>svgを使ったOGP画像の生成ができる</p>
</blockquote>
<p>に有用性を感じて選定したんですが、現時点ではカスタムフォントと日本語への対応が十分でなく、別途Cloud Runを使うことになってしまっています(後述)<br />
(サポートに聞いたらリポジトリ教えてもらったので(OSS)対応できるようなら自分で対応してなげたいなぁ)</p>
<h5 id="キャッシュコントロールもよい"><a href="#%E3%82%AD%E3%83%A3%E3%83%83%E3%82%B7%E3%83%A5%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%AB%E3%82%82%E3%82%88%E3%81%84">キャッシュコントロールもよい</a></h5>
<p>キャッシュの操作も面白くて、<br />
g4の公開用ページではAPIからもらった結果をキャッシュして、キャッシュがあればそれをそのまま返すということをしています。</p>
<p>これによってAPIサーバーへの負荷はかなり低くなってると思います。<br />
APIサーバー側からは、データ更新時にfly.ioのキャッシュを削除する操作をしていて、データが更新されるまではfly.ioはキャッシュを使い続けてます。</p>
<p>この辺のAPIが普通に使いやすくて簡単にかけるのでめっちゃ良きです。</p>
<h5 id="fly.io良いよ"><a href="#fly.io%E8%89%AF%E3%81%84%E3%82%88">fly.io良いよ</a></h5>
<p>fly.io自体ははデプロイも早いし、導入コストも安いので<a target="_blank" rel="nofollow noopener" href="https://zeit.co">now</a>とかと並べて、手軽にNode.jsをホスティングするための選択肢にしてもいいんじゃないかなって思います。</p>
<h3 id="Next.jsを選ばなかった理由"><a href="#Next.js%E3%82%92%E9%81%B8%E3%81%B0%E3%81%AA%E3%81%8B%E3%81%A3%E3%81%9F%E7%90%86%E7%94%B1">Next.jsを選ばなかった理由</a></h3>
<p>SSRする予定ではありましたが、OGPだけ生成できればいいなというレベルだったので、通常のReactアプリで作りました。<br />
なるべく継続開発するため、アップデートの手間と依存を減らしたかったのも少しある</p>
<h3 id="[PWA]を選定した理由"><a href="#%5BPWA%5D%E3%82%92%E9%81%B8%E5%AE%9A%E3%81%97%E3%81%9F%E7%90%86%E7%94%B1">[PWA]を選定した理由</a></h3>
<p>最初は、<a target="_blank" rel="nofollow noopener" href="https://expo.io">Expo</a>で作ろうかと思っていました。</p>
<p>もともとSPAでアプリっぽいUIを作る仕事を受けたときに、Nuxt.js + Firebaseで作り、マルチブラウザ対応が辛いと思った経験がありました。</p>
<p>RNならその辺いい感じに作れるかもと思って<a target="_blank" rel="nofollow noopener" href="https://shwld.net/seicho-release/">みんなの成長</a> というアプリでExpoを試しみて、使い勝手が良い事までは確認してました。</p>
<p>ただ今回はモバイルより、デスクトップアプリのほうが欲しいということに気づき、<br />
Electronで作りやすかったり、PWAならそのままインストールもできちゃうのでWebでいいかなって思いPWAにしました。</p>
<p>なのでマルチブラウザ辛いは解決してないです。<br />
ここは個人開発なので修行と割り切って本業に生かしていきます。<br />
Safari対応が結構めんどいけど、ユーザー多くて無視できない...</p>
<p>マルチブラウザと言っても、現状Chrome、Safari以外はほぼ無視してまっす。</p>
<h3>[<a target="_blank" rel="nofollow noopener" href="https://www.apollographql.com">Apollo Client (react-apollo)</a>]</h3>
<p>これもSPAでアプリっぽいUIを作る仕事で、Nuxt.js + Firebaseで作ったときに、Firebaseのデータベース(このときはrealtime database使ってた)をフロントに反映するのが辛くて、同じようにREST APIも辛いだろうなと思って、GraphQLに手をだしたのがきっかけでした。</p>
<p>GraphQLだけでもすごく良いのですが、Apollo Clientがいいのはキャッシュコントールで、<br />
クエリ毎にキャッシュを優先するかサーバーを優先するかを選択できます。</p>
<p>また、キャッシュがあれば再取得しないなどを簡単に書けたり、とにかくこれはSPAのベストプラクティスだなって感じの実装をシンプルに書けます。</p>
<p>Mutationするとキャッシュが書き換わったりするのもめっちゃ良き</p>
<p>正直この辺のこと考えながらSPA実装するのってかなり大変じゃない?ってか大変だった<br />
アプリライクなUIのSPAならApollo Client使おうぜ!</p>
<p>こいつのおかげでこれまたAPIサーバーの負荷はまあまあ抑えられてそうです。</p>
<h2 id="[Firebase Auth, Storage]について"><a href="#%5BFirebase+Auth%2C+Storage%5D%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6">[Firebase Auth, Storage]について</a></h2>
<p>バックエンドはRailsですが、APIサーバー作るのに正直Deviseとか使いたくないです(完)</p>
<p>Twitter連携やら諸々簡単なので選ばない理由がない。<br />
Auth0は選択肢に入るけど今回GCPなのでGoogleでまとめられるし、そこまで込み入った認証必要ないしでこれにしました。</p>
<p>Storageは別に何でもよかったですが、Firebase Authの認証ユーザー単位での権限指定が楽なので使い勝手は良いです。</p>
<h2 id="デザインについて"><a href="#%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6">デザインについて</a></h2>
<p>g4のデザインはレスポンシブのヘルパーとして<a target="_blank" rel="nofollow noopener" href="https://github.com/twbs/bootstrap/blob/master/dist/css/bootstrap-grid.css">bootstrap-grid</a>だけ使わせてもらってます。<br />
めっちゃ便利なのでおすすめ。</p>
<p>それ以外はcss全部自分で書いてます。</p>
<p>コンポーネントファーストで作成しており、Atomic Designの粒度で、<a target="_blank" rel="nofollow noopener" href="https://storybook.js.org">Storybook</a>作ってコンポーネントを作ってる感じです。<br />
Storybookは割とぶっ壊れやすかったり、他のビルド設定と競合とか重複したり、辛みもありますが、<a target="_blank" rel="nofollow noopener" href="https://storybook.js.org/docs/testing/structural-testing/">storyshots</a>によるスナップショットの差分確認ができるのと、テストの安心感があるので、無いと無いで不安ではあります。</p>
<h2 id="バックエンドの選定理由"><a href="#%E3%83%90%E3%83%83%E3%82%AF%E3%82%A8%E3%83%B3%E3%83%89%E3%81%AE%E9%81%B8%E5%AE%9A%E7%90%86%E7%94%B1">バックエンドの選定理由</a></h2>
<h3>[<a target="_blank" rel="nofollow noopener" href="https://graphql-ruby.org">graphql-ruby</a> & Ruby on Rails]</h3>
<p>Apollo Clientの項で書きましたが、GraphQLを使うことは決まっていました。<br />
GraphQLをマネージドでホスティングしてくれるやつを探したりしたんですが、普段Railsエンジニアなので慣れてるからテストとかも書きやすいしRailsでいっかで、graphql-rubyにしました。</p>
<p>Railsにするとランニングコストは割とかかるんですが、今回は個人開発のメインに据えて長く継続開発したいを目的にしてたので、<br />
稼働してないものにお金払うみたいなことにならない想定(自分が使い続ける)で、コストかける覚悟はしました。</p>
<p>graphql-rubyは仕事でも使ってるので、今後も押していきたい存在。</p>
<h3 id="[GCP/App Engine]"><a href="#%5BGCP%2FApp+Engine%5D">[GCP/App Engine]</a></h3>
<p>App Engineについては<a target="_blank" rel="nofollow noopener" href="https://qiita.com/shwld/items/e86ee3f642c7857dd56e">こちらの記事</a>で書きました。</p>
<p>要約するとHerokuでも良かったけど、使ってみたかったのでGCPにした。です。</p>
<h2 id="[GCP/Natural Language API]"><a href="#%5BGCP%2FNatural+Language+API%5D">[GCP/Natural Language API]</a></h2>
<p>便利。Azureとかにもありますが、今回はGoogle統一で行きました。くらいの選定理由</p>
<h2 id="[GCP/Cloud Run]について"><a href="#%5BGCP%2FCloud+Run%5D%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6">[GCP/Cloud Run]について</a></h2>
<p>Cloud Runは今回使う予定は全くありませんでした。</p>
<p>今利用している理由としては、</p>
<ul>
<li>fly.ioでOGPを生成できるとふんでいたができなかった。</li>
<li>とりあえず手っ取り早くカスタムしたDockerimageでfry.ioをあまりお金をかけずに使えるとこはないか。</li>
</ul>
<p>からの、Cloud Run。</p>
<p>中身は日本語とフォントをインストールした普通のNodeイメージに<br />
fly.ioのサーバーを単純に乗っけて起動しているだけです。(プレビルドして実行したいがやり方が分からずdevサーバー起動しているのでなんとかしたい。誰かやり方知りませんか。)</p>
<p>なので、いずれはfly.ioだけでできるようして、Cloud Runをやめたいです。</p>
<h4 id="Cloud Run超便利"><a href="#Cloud+Run%E8%B6%85%E4%BE%BF%E5%88%A9">Cloud Run超便利</a></h4>
<p>そんな理由で使い始めましたが、驚くくらい簡単かつ手軽にカスタムDockerイメージが使えるので、Cloud Runめっちゃ便利です。<br />
今後活用していきたい。</p>
<h2 id="おわりに"><a href="#%E3%81%8A%E3%82%8F%E3%82%8A%E3%81%AB">おわりに</a></h2>
<p>割と構成的にはガチよりになりました。<br />
自分の技術力総動員してる感じなのでテンション上がってめっちゃ楽しい!</p>
<p>g4の運用を支える技術についても今後書いていきたいです。</p>
<p>みんなでレベル上げしましょう!</p>
<p><a target="_blank" rel="nofollow noopener" href="https://www.g-g-g-g.games">https://www.g-g-g-g.games</a></p>
<p><a target="_blank" rel="nofollow noopener" href="https://www.g-g-g-g.games"><a href="https://crieit.now.sh/upload_images/4857e38ac110f7f2ccb9a3a6c9851f425d8c46a290533.jpeg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/4857e38ac110f7f2ccb9a3a6c9851f425d8c46a290533.jpeg?mw=700" alt="https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_51402_6c1fef60-9f24-2233-821b-1b4b16575e21.jpeg" /></a></a></p>
shwld
tag:crieit.net,2005:PublicArticle/15291
2019-07-31T22:46:21+09:00
2019-08-02T10:12:22+09:00
https://crieit.net/posts/spec-Time-zone-now
月末だけ失敗するspecテストと対策(テストを時刻に依存させるな運動)
<p>この記事で言う現在時刻というのは、例えばTime.zone.nowとか、Date.current, Date.todayのような、今日とか現在時刻、をとってくるメソッドのことです。<br />
railsではtimezoneの扱いを大事にするため、Time.nowじゃなくてTime.zone.nowを使う、みたいなノウハウがありますが、今回の話はそれとは関係がありません。<br />
specテストにおいて、そういう「現在時刻に関するメソッド」を安易に使うと、「特定の日だけ落ちるテスト」「特定の時間だけ落ちるテスト」になりやすいのでやめよう、という話。</p>
<h1 id="例えばこんなケース"><a href="#%E4%BE%8B%E3%81%88%E3%81%B0%E3%81%93%E3%82%93%E3%81%AA%E3%82%B1%E3%83%BC%E3%82%B9">例えばこんなケース</a></h1>
<blockquote>
<p>渡されたdateに対して、その月の残りの日付を配列で返す関数 remaining_days_of_month を作ります。例えば 1/28が渡されたら、<strong><em>[29,30,31]</em></strong> を返します。31日だと、残りの日付はないので <strong><em>[]</em></strong> です</p>
</blockquote>
<p>コーディングテストに良さそうな題材ですね。これをどうにかして実装したとして、この関数に対するspecテストを考えましょう。</p>
<p>「これ、引数に渡したその日は含まれないのよね」</p>
<pre><code class="ruby">it 'not contains the day' do
expect(remaining_days_of_month(Time.zone.today)).not_to include Time.zone.today.day
end
</code></pre>
<p>「で、その次の日から始まる、と」</p>
<pre><code class="ruby">it 'contains next day' do
expect(remaining_days_of_month(Time.zone.today)).to include Date.tomorrow.day
end
</code></pre>
<p>いろいろつっこみどころはあるかと思いますが、話の都合で、これがコードレビューを通ったことにしましょう。テストはなにか書いてあればOKという職場、あるでしょ?</p>
<h1 id="月末の悲劇"><a href="#%E6%9C%88%E6%9C%AB%E3%81%AE%E6%82%B2%E5%8A%87">月末の悲劇</a></h1>
<p>月末の夜、リリースに向けてコードを書く職場で悲鳴が上がります。<br />
「なんかテスト落ちてるぞ!」<br />
「Aくん、rspec落ちてるから確認して」</p>
<p>AくんはCircleCIで落ちた箇所を確認します。おかしいな。こんなところ触ってないのに、これ一体何なんだろう...触ったこともないところだから全然わからん...これぼく関係ないんじゃないの?だからテストって嫌いなんだ...</p>
<h1 id="問題"><a href="#%E5%95%8F%E9%A1%8C">問題</a></h1>
<p>簡単な例なので大半の方は気づいていると思いますが、問題のコードはこれです。</p>
<pre><code class="ruby">it 'contains next day' do
expect(remaining_days_of_month(Time.zone.today)).to include Date.tomorrow.day
end
</code></pre>
<p>このコード、通常はテストが通りますが、月末最終日に限り、Time.zone.todayはその月、Date.tomorrowは翌月を指すようになるのでテストが失敗します。</p>
<p>この一行なら誰だってわかるけど、これ10行くらい書いた中に埋め込まれると結構わからなくなるのです....</p>
<h1 id="対策"><a href="#%E5%AF%BE%E7%AD%96">対策</a></h1>
<p>よく言われる対策は「TimeCop / TimeHelpersを使って時間を固定する」です。</p>
<p>ですが、正直この程度のことにそんな大道具持ち出すのもどうなのよ、そういうことしていると、今度は開放し忘れて別の箇所で悲劇を引き起こすんじゃないの?</p>
<p>ぼくがすすめている対策は、「rspecで現在時刻は使わない」です。</p>
<p>例えば今回のテストはどう書くのが正解だったのか。</p>
<pre><code class="ruby">describe 'remaining_days_of_month' do
it 'contains remaining days' do
let(:date) { Date.new(2019, 1, 28) }
expect(remaining_days_of_month(date)).to match_array [29, 30, 31]
end
end
</code></pre>
<p>テスト日付を固定します。そうすると答えもおのずから決まるから、includeじゃなくてmatch_arrayで確認することができる。</p>
<p>そもそも、テストを実施する日によってテスト内容が変わる時点でおかしいですよね。specテストに書いたコードにバグがあっても、specテストをspecテストすることはできないのだから、テストは可能な限りシンプルなロジックであるべきで、Time.zone.nowみたいに値が変わるものを使うのは良くないことです。</p>
<h1 id="よくある反論"><a href="#%E3%82%88%E3%81%8F%E3%81%82%E3%82%8B%E5%8F%8D%E8%AB%96">よくある反論</a></h1>
<p>よくある反論は、「現在時刻使っておけばいろんな日付が試せるから潜在バグを洗い出せるよ」です。</p>
<p><strong>甘えるんじゃねえ!</strong></p>
<p>その潜在バグとやらが自分の手元で見つかるのならともかく、わけのわからんタイミングで爆発して始末させられる方の身にもなってください。</p>
<p>境界値が不安なのであれば、自分でテストを書きましょう</p>
<pre><code class="ruby"> it 'contains remaining days' do
let(:date) { Date.new(2019, 1, 28) }
expect(remaining_days_of_month(date)).to match_array [29, 30, 31]
end
it 'return empty at the end of the month' do
let(:date) { Date.new(2019, 1, 31) }
expect(remaining_days_of_month(date)).to match_array []
end
</code></pre>
<h1 id="使っても良いケース"><a href="#%E4%BD%BF%E3%81%A3%E3%81%A6%E3%82%82%E8%89%AF%E3%81%84%E3%82%B1%E3%83%BC%E3%82%B9">使っても良いケース</a></h1>
<p>メソッド内に現在時刻が使われている場合、テスト側も現在時刻を使わざるを得ないケースがあります。<br />
例えば、「今日以降の日付を配列で返す関数」のような場合です。</p>
<p>ただこの場合でも、こういう実装にしてあれば、現在時刻を使わなくてもテストすることができます。</p>
<pre><code class="ruby"># 指定された日以降の日付を配列で返す. 省略すると当日が使われる
def remaining_days_of_month(date = Time.zone.today)
:
</code></pre>
<p>この辺の実装の工夫について、下記が詳しいです。</p>
<p><a target="_blank" rel="nofollow noopener" href="https://techlife.cookpad.com/entry/2016/05/30/183947">「現在時刻」を外部入力とする設計と、その実装のこと</a></p>
<p>で、いろいろな事情によりそこまでやれない場合に、TimeHelpersで時間を固定した上で、Time.zone.now/Time.zone.todayを使うのは仕方ないかなあ、という感じですね。<br />
specテストにおいて、固定しないTime.zone.now/Time.zone.todayを使ってよい場面は存在しません。</p>
<h1 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h1>
<p>現在時刻を使うことによって、月末だけ失敗するrspecバグを埋め込むパターンを説明しました。</p>
<p>いくつかのrailsプロジェクトを渡り歩いていて、このルールはあたりまえのように守られているところもあれば、どんなに説明してもご理解いただけないところもあったりして苦労しています。<br />
この記事を示すことで誰でもわかってもらえるようになるといいなあ。</p>
daisuke furukawa
tag:crieit.net,2005:PublicArticle/15167
2019-06-25T23:08:27+09:00
2019-06-25T23:08:27+09:00
https://crieit.net/posts/Ruby-on-Rails
僕が今までやったRuby on Railsの勉強
<p>僕がプログラミングを初めて<strong>1年と9ヶ月</strong>ほど経ちました。</p>
<p>ほぼ<strong>独学</strong>でこれまで勉強してきましたが、途中で挫折する人も多いかと思います。</p>
<p> </p>
<p>少しでも挫折する人を減らせるよう、参考になるか分かりませんが自分が今までやってきたプログラミングの勉強方法を紹介させて頂きます。</p>
<p> </p>
<p>とは言っても、実は結構昔にプログラミングスクールに2週間ほど通ったことがあります。</p>
<p>でもそのとき「<strong>あっ、これ無理だ。</strong>」と思いすぐ挫折しました。</p>
<p>※決してプログラミングスクールが良くないわけではありません。質問した時は丁寧に教えてくれました。僕の理解力の問題です(笑)</p>
<p> </p>
<p>そこからだいぶ期間が空いて、その2週間で学んだことの<strong>98%は忘れてしまっていましたが</strong>、どうしても作りたいサービスがあったため、プログラミングの勉強を開始しました。</p>
<p> </p>
<p>まずは<strong>ドットインストール</strong>でHTMLとCSSの勉強を始めました。</p>
<p><a target="_blank" rel="nofollow noopener" href="https://dotinstall.com/">ドットインストール</a></p>
<p> <br />
HTMLはなんとなーくわかった気がしましたが、CSSはよくわからないまま動画を観ていました。</p>
<p>とりあえずHTMLとCSSの動画をそれぞれ2周した後、次はドットインストールで「<strong>Ruby入門</strong>」の動画を観てみました。</p>
<p> </p>
<p>Rubyを選んだ理由は特になく、その当時たまたま出会ったプログラマーの方に「<strong>web系のサービス作りたいんだったらRubyが良いよ</strong>」と言われたのでそのまま鵜呑みにしてRubyの勉強を始めました。</p>
<p><a target="_blank" rel="nofollow noopener" href="https://dotinstall.com/lessons/basic_ruby_v3">ドットインストール Ruby入門</a></p>
<p> <br />
HTMLやCSSの動画もそうですが、1つの動画が全て3分以内に収められているため、全部で26個の動画がありますがサクッと一気に観れました。</p>
<p>ただ、<strong>後半はさっぱり分けもわからず「とりあえず観る」</strong>といった感じで進めていたのを覚えています。Ruby入門の動画も分からないなりになんとか2周しました。</p>
<p> </p>
<p>ドットインストールでHTML、CSS、Rubyをそれぞれ学んだ後は<strong>Progate</strong>でHTML、CSS、Rubyをそれぞれ1周しました。</p>
<p><a target="_blank" rel="nofollow noopener" href="prog-8.com">Progate(プロゲート)</a></p>
<p>Progateは前に自分が書いたコードも使いながら次に進んでいくため、ローププレイングゲームをやっているみたいで面白かったです。</p>
<p><strong>ただ、どのコースも後半につれて訳分かんなくなってました(笑)</strong></p>
<p> </p>
<p>次にRuby on Railsというフレームワークを使うとwebサービスが作れるとネットにいっぱい書いてあったので、Railsの勉強を始めました。</p>
<p>まずはプログラミング初心者御用達のドットインストールで「Ruby on Rails5入門」の動画を2周しました。</p>
<p><strong>Railsに関しては始めから何が何だかちんぷんかんぷんでした。</strong></p>
<p><a target="_blank" rel="nofollow noopener" href="https://dotinstall.com/lessons/basic_rails_v3">ドットインストール Ruby on Rails5入門</a><br />
</p>
<p>最近になってようやく慣れましたが、ドットインストールの動画って3分に収めているからかめっちゃ早くないですか?</p>
<p>最初の頃はその早さについていけず、何度も動画を戻して繰り返し観てました。</p>
<p> </p>
<p>その後にまたまたプログラミング初心者御用達のProgateにてRuby on Rails5コースに取り掛かりましたが、<strong>後半は難しすぎてやめました(笑)</strong></p>
<p> </p>
<p>その頃に初めてプログラミングに関する本である「<strong>Ruby on Rails4 アプリケーションプログラミング</strong>」を買いました。 </p>
<p><a target="_blank" rel="nofollow noopener" href="https://www.amazon.co.jp/exec/obidos/ASIN/4774164100/hatena-blog-22/">Ruby on Rails4アプリケーションプログラミング</a><br />
※今は最新版の「Ruby on Rails5 アプリケーションプログラミング」も発売されています。</p>
<p> <br />
後にこの本は僕にとってかなり神的な本になったのですが、その頃の僕にとっては訳が分からず、すぐ読むのをやめてしまいました。</p>
<p> <br />
その後、Railsを学ぶなら「<strong>Railsチュートリアル</strong>」が良いとネットに書いてあったので、Railsチュートリアルを始めました。</p>
<p> <br />
<a target="_blank" rel="nofollow noopener" href="https://railstutorial.jp/">Ruby on Rails チュートリアル:実例を使って Rails を学ぼう</a><br />
</p>
<p>ただ、本での勉強は理解しにくいと感じていたので(今は本での勉強めっちゃ大事だと感じてます!)、Railsチュートリアルの動画が販売されていたので、その動画を購入して勉強しました。</p>
<p><a target="_blank" rel="nofollow noopener" href="https://railstutorial.jp/trial">解説動画お試しプラン - Railsチュートリアル</a></p>
<p>動画の価格が<strong>29,800円(税別)</strong>なので、決して安くはなかったですが、結果的にこの動画は僕にとって神動画になりました!</p>
<p>この動画を観てやっと<strong>RubyとRailsの違いをようやく少しだけですが理解できました。</strong>(それまでRubyとRailsがそれぞれ何なのかすらよくわかってなかった...)</p>
<p> </p>
<p>ただ、ProgateのRailsコースを途中で挫折する僕です。</p>
<p>神的な解説のおかげで前半部分はなんとなく理解できましたが、<strong>当然後半は訳わからず、「コードをコピペして分からんけど動いた」みたいなことをしてました。テストはもちろん書いてません!(笑)</strong></p>
<p> </p>
<p>Railsチュートリアルを訳分からないなりになんとか2周した後に、当時UdemyにRailsを使ってAirbnbみたいなサービスを作ってみる動画があり、評判がよかったためそれを見て勉強しました。</p>
<p> </p>
<p><strong>結果的にその動画は今までRailsを勉強してきた中で一番役に立った神動画でした!</strong></p>
<p>Progateやドットインストールで勉強した後、「<strong>一からどのようにサービスを作ったら良いか分からない問題</strong>」に必ずプログラミング初心者にはぶち当たると思うのですが、</p>
<p>その動画はrails newから実際の現場でどのようにサービスを作っていくか丁寧に説明してくれていました。</p>
<p>現在ではUdemyから削除されているのですが、今になってもまたもう一回観てみたいと思う動画です。</p>
<p> </p>
<p><strong>ただ、神動画でも僕の理解力の低さには勝てません(笑)</strong></p>
<p>動画の後半はかなり難しい内容になってきて、最後の方はお得意の「<strong>コピペしてなんか分からんけど動いた</strong>」みたいなことばかりやってました。</p>
<p> </p>
<p>それで何とかその動画も全て見終わった後、出版のサービス(サービス名は<strong>nospri</strong>といいます)を作ってみたいと考えていたので、そのサービスの制作に取り掛かりました。</p>
<p><a target="_blank" rel="nofollow noopener" href="www.nospri.com">無料で紙の本を出版できるサービス</a></p>
<p><strong>途中100回くらい挫折しそうになりましたが</strong>、どうしてもサービスを作りたかったので気合いで何とか分からないなりに<strong>4ヶ月</strong>くらいかけて作りました。</p>
<p> </p>
<p>この出版サービスを作っている時に、Javascriptも勉強しないとまずいと思い、サービスを制作しながらとりあえず<strong>jQueryの勉強もしてました。</strong></p>
<p> </p>
<p>ちなみに、サービスの中でHerokuのH12 Error( 30 second timeout )を回避する為に、Ajaxを使って大容量データファイルをAmazon S3に直接送信する機能があるのですが、そこが僕にとって特に難しく泣きそうになったのは良い思い出です。。。</p>
<p> </p>
<p>出版サービスを完成させた後、改めて前に購入していた「<strong>Ruby on Rails4 アプリケーションプログラミング</strong>」を読んでみたのですが、<strong>知識の点と点が繋がるとはまさにその時のこと</strong>で、Railsについての理解度が今まで<strong>2%くらいだったのがやっと5%くらいまで上がったと思います(笑)。</strong></p>
<p> </p>
<p>そこから本での勉強も大事だと言うことに気づき、RubyとRails、jQueryに関する様々な本を書いました。</p>
<p>それぞれ僕にとって一番よかった本は以下の通りです。</p>
<p> </p>
<p>RubyはRuby界隈で有名な伊藤淳一さんが書いた「<strong>プロを目指す人のためのRuby入門 言語仕様からテスト駆動開発・デバッグ技法まで</strong>」</p>
<p><a target="_blank" rel="nofollow noopener" href="https://www.amazon.co.jp/exec/obidos/ASIN/4774193976/hatena-blog-22/">プロを目指す人のためのRuby入門 言語仕様からテスト駆動開発・デバッグ技法まで (Software Design plusシリーズ)</a><br />
<br />
</p>
<p>Railsはすでに紹介済みの「Ruby on Rails4 アプリケーションプログラミング」の最新版にあたる「<strong>Ruby on Rails5 アプリケーションプログラミング</strong>」 </p>
<p><a target="_blank" rel="nofollow noopener" href="https://www.amazon.co.jp/exec/obidos/ASIN/4774188832/hatena-blog-22/">Ruby on Rails5 アプリケーションプログラミング</a><br />
</p>
<p> jQueryは「<strong>Web制作の現場で使うjQueryデザイン入門[改訂新版] </strong>」</p>
<p><a target="_blank" rel="nofollow noopener" href="https://www.amazon.co.jp/exec/obidos/ASIN/4048913913/hatena-blog-22/">Web制作の現場で使うjQueryデザイン入門[改訂新版] </a></p>
<p> <br />
<br />
今ではjQueryは古く、ReactやVue.js等のモダンなフレームワークを使うケースが多いため、今から必ずしもjQueryを学ぶ必要はないんじゃないかと思います。(じゃあ、RubyよりもPythonやGo勉強した方が良いんじゃないの?とかは言わないで...)</p>
<p> </p>
<p>RubyやRails、jQuery等の本を10冊くらい読んで勉強した後に、webのメディアサイトを作ってみたくなり、僕は京都が大好きなので、京都の鴨川に関する記事を誰でも投稿することができるwebメディアサイト(サービス名は「<strong>鴨川へ行こう</strong>」)を1ヶ月くらいで作りました。</p>
<p> <br />
<a target="_blank" rel="nofollow noopener" href="https://www.kamogawa-go.com/">鴨川へ行こう | 京都鴨川のあらゆる情報を発信するサイト</a></p>
<p> </p>
<p>2つ目のサービスを作ってやっとここでRuby on Railsへの理解度が<strong>7%くらいまで上がりました!</strong></p>
<p>ここから絵本を投稿できるサービスを作ったり、感謝の気持ちをポイントに変えて自由に送り合うことができるサービスを作ったり、小さいのも合わせると全部で5個くらいサービスを作りましたが、公開までに至りませんでした。</p>
<p> </p>
<p>原因は1つです。</p>
<p><strong>デザインセンスがないからです。</strong>服はほぼユニクロで買う僕にデザインのセンスなんてあるわけありません。<strong>ってかCSS書くのがめんどいです。。。</strong></p>
<p> </p>
<p>ただ、今となっては最低限CSS書いて、いくつかのサービスは「<strong>公開しとけばよかった</strong>」と思っています。なので今後ちょこちょこデザイン整えて、公開できるまでもっていきたいです。</p>
<p> </p>
<p>一方、サービスの公開まではいきませんでしたが、そこでポイント機能やフォロー・フォロワー機能、stripeを使った決済機能など、いろんなサービスで応用できそうなスキルを何となく学ぶことはできたのでまあ良い面もありました。。。</p>
<p> </p>
<p>今年に入ってから僕が今までで一番時間をかけて初心者向けのクラウドソーシングサービスを作りました。(サービス名は<strong>novice</strong>、日本語で「初心者」という意味です。)</p>
<p><a target="_blank" rel="nofollow noopener" href="https://novice-work.com/">novice | 失敗しても大丈夫! 初心者・未経験者のためのクラウドソーシングサービス</a></p>
<p>何とかリリースまでもっていきましたが、今まで発信等を全然していなかった為、<strong>全然ユーザーが増えません。よかったらTwitterフォローしてください(笑)</strong></p>
<p><a target="_blank" rel="nofollow noopener" href="https://twitter.com/leavescomic1">@leavescomic1</a></p>
<p><strong>発信力が弱小な人にとってやっぱりto C向けのサービスは難しいですね。。。</strong></p>
<p>今後は情報を発信しつつ、UXの面でも超絶使いにくいところが山ほどあるので、そこらへんを徐々に直していこうと思います。</p>
<p> </p>
<p>あと、プログラミングを勉強してサービスを作るのもいいけど、<strong>作ったサービスを広めることにも注力した方が良いと今はひしひしと思います。</strong>僕はサービスを作っただけで満足していたから今かなり痛い目にあってる。(前から痛い目に遭ってばっかりだけど。)</p>
<p> </p>
<p>まあ、今までめちゃくちゃ小規模でくだらないサービスも含めて全部で<strong>8個</strong>くらいサービスを作ってきましたが、ようやくRailsのことを<strong>9%くらい理解できるようになりました。</strong></p>
<p>何とか今年中に10%くらい理解できるよう頑張りたいです(笑)</p>
<p> </p>
<p>また、Swiftを勉強してiOSアプリリリースして、友達に自慢したいです。プログラミングやってない人から見たら、クソみたいなアプリでも自分のアプリがAppleストアに載ってるだけですごいと思ってくれるじゃないですか!?</p>
<p> </p>
<p>色々書きましたがとにかくまとめると、プログラミングの勉強で一番大事なのは「<strong>情熱</strong>」だと思います。(なんじゃそりゃ。。。)</p>
<p>もっとがんばります。はい。。。</p>
Naoki Mizutani
tag:crieit.net,2005:PublicArticle/14941
2019-04-21T22:51:18+09:00
2019-04-23T09:27:29+09:00
https://crieit.net/posts/JobLv-BLOG
JobLvマネージャーをリリースした話
<h1 id="作ったサイトの紹介"><a href="#%E4%BD%9C%E3%81%A3%E3%81%9F%E3%82%B5%E3%82%A4%E3%83%88%E3%81%AE%E7%B4%B9%E4%BB%8B">作ったサイトの紹介</a></h1>
<p>今回作ったサイトは、こちら。<br />
「<a target="_blank" rel="nofollow noopener" href="https://joblv-manager.herokuapp.com/">JobLvマネージャー</a>」です。</p>
<p>自分のJob(職業)を管理、LvUpをしながら、<br />
Twitterと連携(現時点では、名前変更)することが出来ます。</p>
<p><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118481/24d49170-feba-5d5b-c900-aabce0268d16.png" alt="image" /></p>
<h1 id="作ろうと思ったキッカケ"><a href="#%E4%BD%9C%E3%82%8D%E3%81%86%E3%81%A8%E6%80%9D%E3%81%A3%E3%81%9F%E3%82%AD%E3%83%83%E3%82%AB%E3%82%B1">作ろうと思ったキッカケ</a></h1>
<p>Twitterで繋がったユーザーさんが、名前の後ろに「〇〇Lv1」みたいなのをつけているのを見て思いつきました。<br />
いつの間にか、こっそりLvアップしていたり、新しいものに変わっていたり。<br />
そういう遊び心に興味が湧いて、この仕組みをもっと簡単に、管理や変更ができるようにしたサービスを作ってみたいと思ったのが始まりです。</p>
<h1 id="ストックすることの大切さと、一歩踏み出す大切さ"><a href="#%E3%82%B9%E3%83%88%E3%83%83%E3%82%AF%E3%81%99%E3%82%8B%E3%81%93%E3%81%A8%E3%81%AE%E5%A4%A7%E5%88%87%E3%81%95%E3%81%A8%E3%80%81%E4%B8%80%E6%AD%A9%E8%B8%8F%E3%81%BF%E5%87%BA%E3%81%99%E5%A4%A7%E5%88%87%E3%81%95">ストックすることの大切さと、一歩踏み出す大切さ</a></h1>
<p>これをタイトルした理由は、本システム、3日(時間だと8時間)で作りました。<br />
内容からして、これが早いのかわかりませんが、これだけの時間でサービスリリースまでいけたのは、</p>
<ul>
<li>Railsのおかげ</li>
<li>素材サイト様のおかげ</li>
<li>API(Twitter)のおかげ</li>
<li>今まで色々プロダクトを作ったおかげ(機能のより集め(コピペ))</li>
</ul>
<p>Railsを使うと、簡単のWebシステムが作れます。<br />
いろんなGemが用意されています。<br />
規約にそえば、簡単に作れます。</p>
<p>素材サイト様、画像にアイコンにフォントまで、いろんなものが無料で使えます。<br />
いつもありがとうございます!</p>
<p>API使えば、別のシステムの機能を自分のもののように使えます。どんどん使いましょう!</p>
<p>新しいもの、面白そうなものがあったら、とりあえず触ってみましょう!<br />
形にならなくても問題ありません。いつか使える時が来ます。ストックしておきましょう。<br />
最新の技術だからと追いかけて、サービスリリースする必要も無いと思います。<br />
触ってみてストックする事が大事。</p>
にゅ〜ぶる
tag:crieit.net,2005:PublicArticle/14909
2019-04-09T22:21:31+09:00
2019-04-19T09:16:52+09:00
https://crieit.net/posts/800-Twitter-Negomo
誰でも新卒年収800万宣言できる、Twitter就活サービス「Negomo(ネゴモ)」をリリースした。【個人開発】
<p>「Twitter就活の促進」をテーマにしたサービス「<a target="_blank" rel="nofollow noopener" href="https://negomo.me">Negomo(ネゴモ)</a>」をリリースしました!</p>
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">自分が欲しい報酬額をツイートしてTwitter就活できるサービス「Negomo(ネゴモ)」を作ってみました!下のような画像がツイートできます。Twitterアカウントで利用できるのでぜひ使ってみてください!<a target="_blank" rel="nofollow noopener" href="https://t.co/JRXFe8lHov">https://t.co/JRXFe8lHov</a><a target="_blank" rel="nofollow noopener" href="https://twitter.com/hashtag/Negomo?src=hash&ref_src=twsrc%5Etfw">#Negomo</a> <a target="_blank" rel="nofollow noopener" href="https://twitter.com/hashtag/RT%E6%8B%A1%E6%95%A3%E3%81%8A%E9%A1%98%E3%81%84%E3%81%97%E3%81%BE%E3%81%99?src=hash&ref_src=twsrc%5Etfw">#RT拡散お願いします</a></p>— TaKO8Ki (@takoyaki3160) <a target="_blank" rel="nofollow noopener" href="https://twitter.com/takoyaki3160/status/1114776315847004160?ref_src=twsrc%5Etfw">April 7, 2019</a></blockquote>
<p>Twitterアカウントで利用できるので、もしよかったら使ってみてください!</p>
<h1 id="リリースしたサービス"><a href="#%E3%83%AA%E3%83%AA%E3%83%BC%E3%82%B9%E3%81%97%E3%81%9F%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9">リリースしたサービス</a></h1>
<p><a target="_blank" rel="nofollow noopener" href="https://negomo.me">Negomo(ネゴモ) - もっとTwitter就活しよう!</a></p>
<h1 id="サービスの概要"><a href="#%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%81%AE%E6%A6%82%E8%A6%81">サービスの概要</a></h1>
<p>「Negomo(リンク)」は、自分が欲しい報酬額をツイートしてTwitter就活できるサービスです。</p>
<p>何か技術を身につけている人が、Twitterで欲しい報酬額(時給・年収)を積極的にアピールすることで、適切な報酬をもらえることを理想としています!<br />
もちろん、エンジニア以外の方も大歓迎です!</p>
<p>こんな感じのツイートができます。</p>
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">京都でWEB系のインターン探してます!! <a target="_blank" rel="nofollow noopener" href="https://t.co/JRXFe8lHov">https://t.co/JRXFe8lHov</a> <a target="_blank" rel="nofollow noopener" href="https://twitter.com/hashtag/Negomo?src=hash&ref_src=twsrc%5Etfw">#Negomo</a> <a target="_blank" rel="nofollow noopener" href="https://twitter.com/hashtag/Twitter%E5%B0%B1%E6%B4%BB?src=hash&ref_src=twsrc%5Etfw">#Twitter就活</a></p>— TaKO8Ki (@takoyaki3160) <a target="_blank" rel="nofollow noopener" href="https://twitter.com/takoyaki3160/status/1114806623942262784?ref_src=twsrc%5Etfw">April 7, 2019</a></blockquote>
<p>参考:<a target="_blank" rel="nofollow noopener" href="https://negomo.me/about">Negomo(ネゴモ)とは</a></p>
<h2 id="追記"><a href="#%E8%BF%BD%E8%A8%98">追記</a></h2>
<ul>
<li><p>単位で「兆」を選ぶことができるようになりました!</p></li>
<li><p>時給・月収・年収によって画像の色を変えたほうが見やすいというアドバイスをいただいたので、そのように仕様を変更しました!<br />
既に画像を作成されている場合は、金額を変えて編集していただくと色が変わります。</p></li>
</ul>
<p><img width="995" alt="スクリーンショット 2019-04-09 15.46.36.png" src="https://qiita-image-store.s3.amazonaws.com/0/285624/b2f41851-a590-3827-14ed-d74303dfe7e2.png"></p>
<h1 id="デザイン"><a href="#%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3">デザイン</a></h1>
<p>デザインは<a target="_blank" rel="nofollow noopener" href="https://speakerdeck.com/">SpeakerDeck</a>を参考にしました!</p>
<h3 id="トップページ"><a href="#%E3%83%88%E3%83%83%E3%83%97%E3%83%9A%E3%83%BC%E3%82%B8">トップページ</a></h3>
<p><img src="https://qiita-image-store.s3.amazonaws.com/0/285624/80f72c3a-d77b-d45f-1ff0-7f9b937d80a2.png" alt="image" /></p>
<h3 id="画像作成ページ"><a href="#%E7%94%BB%E5%83%8F%E4%BD%9C%E6%88%90%E3%83%9A%E3%83%BC%E3%82%B8">画像作成ページ</a></h3>
<p><a target="_blank" rel="nofollow noopener" href="https://gyazo.com/f5cbe5ee14262aa3025254bae37c6ef7"><img src="https://i.gyazo.com/f5cbe5ee14262aa3025254bae37c6ef7.gif" alt="Image from Gyazo" /></a></p>
<p>アピールポイントのフォームの高さは可変的になっていて、コンパクトになるように心がけました。また、ポートフォリオなどのURLが入力された場合は、自動的にリンクに変換されるようになっています。</p>
<h3 id="画像表示ページ"><a href="#%E7%94%BB%E5%83%8F%E8%A1%A8%E7%A4%BA%E3%83%9A%E3%83%BC%E3%82%B8">画像表示ページ</a></h3>
<p><img src="https://qiita-image-store.s3.amazonaws.com/0/285624/1079aace-eedc-0f02-2549-a342a3dca654.png" alt="image" /></p>
<p>作成した画像をクリックすることでツイートできるようになっています。<br />
アピールポイントの欄では、どれがリンクでどれが普通の文字列なのか分かりやすくするようにしました。</p>
<h1 id="使用した技術"><a href="#%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%9F%E6%8A%80%E8%A1%93">使用した技術</a></h1>
<ul>
<li><p>Ruby・Ruby on Rails</p>
<ul>
<li><a target="_blank" rel="nofollow noopener" href="https://github.com/csquared/IMGKit">IMGKit</a>(HTMLから画像をレンダリングできるgem)</li>
<li><a target="_blank" rel="nofollow noopener" href="https://github.com/bgarret/google-analytics-rails">google-analytics-rails</a>(google analyticsが簡単に導入できるgem)</li>
<li><a target="_blank" rel="nofollow noopener" href="https://github.com/0sc/activestorage-cloudinary-service">activestorage-cloudinary-service</a>(Active StorageとCloudinaryを繋げるgem)</li>
</ul></li>
<li><p>JavaScript・jQuery</p></li>
<li><a target="_blank" rel="nofollow noopener" href="https://cloudinary.com/">Cloudinary</a><br />
画像を保存するストレージです。Herokuのアドオンとして利用できるので非常やりやすかったです。Active Storageと連携させて利用しています。</li>
<li>Git・GitHub</li>
<li>Postgresql</li>
<li><a target="_blank" rel="nofollow noopener" href="https://jp.heroku.com/">Heroku</a><br />
今の所Hobbyプランを利用しています。</li>
<li><a target="_blank" rel="nofollow noopener" href="https://github.com/TaKO8Ki/wkhtmltopdf-buildpack">build pack</a><br />
画像を作る部分の実装で利用しました。</li>
<li>アイコン<br />
アイコンは、相変わらずフリー画像にお世話になってます。</li>
</ul>
<h1 id="苦労した点"><a href="#%E8%8B%A6%E5%8A%B4%E3%81%97%E3%81%9F%E7%82%B9">苦労した点</a></h1>
<p>今回苦労したのは、画像生成の部分です。<br />
コードとしては下のような感じで、 HTMLから画像をレンダリングする<a target="_blank" rel="nofollow noopener" href="https://wkhtmltopdf.org/">wkhtmltoimage</a>をRailsで利用できるようになるgem、IMGKitを利用しています。<br />
ローカルでは比較的簡単に動かすことができましたが、Heroku上で動かすのに少し時間がかかりました。<br />
最終的に、build packを使うのが一番良さそうだと分かったので、元からあったbuild packのレポジトリをforkして少し自分用にカスタマイズして使いました。</p>
<p><a target="_blank" rel="nofollow noopener" href="https://github.com/TaKO8Ki/wkhtmltopdf-buildpack">wkhtmltoimageをHerokuで使うためのbuild packカスタマイズ版</a></p>
<p>画像作成部分のコード</p>
<div>
```ruby
def create_image
Tempfile.create(["#{@profile.id}", '.png'], :encoding => 'ascii-8bit') do | file |
file.write(IMGKit.new(get_html, quality: 20, width: 800).to_png)
file.rewind
@profile.image.attach(io: file, filename: "q_#{@profile.id}.png", content_type: "image/png")
end
end
def get_html
<<~HTML
<!DOCTYPE html>
<html>
<head>
<link href="http://fonts.googleapis.com/earlyaccess/notosansjp.css">
<meta charset="UTF-8">
<style>
@charset "UTF-8";
html {
font-family: sans-serif;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
body {
width: 800px;
margin: 0;
background: #eee;
font-family: 'Noto Sans JP', sans-serif;
}
.q-frame {
width: 100%;
background-color: #fff;
padding: 25px 25px 10px 25px;
}
.q-frame .q-body {
vertical-align: middle;
text-align: center;
height: 220px;
width: 750px;
font-size: 2.6em;
background-color: white;
padding: 1.3em;
border-radius: 3px;
display: table-cell;
vertical-align: middle;
background-image: url(#{assets_image_url('negomo_background.png')});
background-size: 100% 100%;
background-repeat: no-repeat;
background-position: 50%;
box-shadow: 0.5px 3.5px 10px 0px #ccc;
}
.q-frame .q-icon {
font-size: 2.2em;
padding: 5px 0px 0px 0px;
margin: 0px;
color: #333;
border-radius: 5px;
}
.q-frame .q-icon img {
width: 150px;
margin-top: 7px;
}
span.word {
font-size: 75px;
font-weight: bold;
color: #7d7458;
}
span.description {
font-size: 30px;
font-weight: 100;
color: #545454;
line-height: 45px;
display: block;
margin-top: 10px;
font-weight: bold;
width: 650px;
overflow-wrap: break-word;
word-wrap: break-word;
margin: 0 auto;
}
</style>
</head>
<body>
<div class="q-frame">
<div class="q-body">
<span class="word">#{@profile.adjust_money_style}</span><br>
<span class="description">#{@profile.title}</span>
</div>
#{}
<div class="q-icon">
#{assets_image_tag('negomo.png').html_safe}
</div>
</div>
</body>
</html>
HTML
end
```
</div>
<h1 id="リリースする上で心がけたこと"><a href="#%E3%83%AA%E3%83%AA%E3%83%BC%E3%82%B9%E3%81%99%E3%82%8B%E4%B8%8A%E3%81%A7%E5%BF%83%E3%81%8C%E3%81%91%E3%81%9F%E3%81%93%E3%81%A8">リリースする上で心がけたこと</a></h1>
<h3 id="アイデアを形にするスピード"><a href="#%E3%82%A2%E3%82%A4%E3%83%87%E3%82%A2%E3%82%92%E5%BD%A2%E3%81%AB%E3%81%99%E3%82%8B%E3%82%B9%E3%83%94%E3%83%BC%E3%83%89">アイデアを形にするスピード</a></h3>
<p>少しずつWEBサービスを作ることにも慣れてきたので、自分が思いついたアイデアを形にするスピードを意識するようにしました。それでも、このサービスを作るのに1週間ほど費やしてしまったので、まだまだだなと感じます。</p>
<h3 id="ユーザーにとって分かりやすいサービスかどうか"><a href="#%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%81%AB%E3%81%A8%E3%81%A3%E3%81%A6%E5%88%86%E3%81%8B%E3%82%8A%E3%82%84%E3%81%99%E3%81%84%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%81%8B%E3%81%A9%E3%81%86%E3%81%8B">ユーザーにとって分かりやすいサービスかどうか</a></h3>
<p>今までも「ユーザーにとって分かりやすいサービス作り」を意識するようにはしてきましたが、イマイチ分かりやすさを追求できていないように感じていました。特に、非エンジニアの人に使ってもらうとなると非常に難しいと感じます。<br />
そのため、今回は、大まかに言えば「画像をツイートできるだけのサービス」というシンプルな設計にしました。</p>
<h1 id="最後に"><a href="#%E6%9C%80%E5%BE%8C%E3%81%AB">最後に</a></h1>
<p>タイトルに「誰でも新卒年収800万宣言できる」と書きましたが、最近、<a target="_blank" rel="nofollow noopener" href="https://twitter.com/komi_edtr_1230?s=17">コミさん</a>という技術的に強い方が新卒年収800万円芸なるものを行なって、話題になっているのを1フォロワーとして眺めていました。エンジニアだけでなく、他の分野にもコミさんのように優れた人材はたくさん居られると思うので、その方達がTwitterなどを利用して、しっかりといい待遇を受けられるようになればいいなと思います。<br />
僕もその方達に加われるように頑張っていきます!<br />
また、このサービスをきっかけに、もっとTwitter就活が当たり前になれば嬉しいです。</p>
<p>ここまで読んでいただきありがとうございました!</p>
<p><strong>もしよろしければ、いいねボタンを押していただけたら嬉しいです!</strong></p>
<p>Negomo、ぜひ使ってみてください!!</p>
<p><a target="_blank" rel="nofollow noopener" href="https://negomo.me">Negomo(ネゴモ) - もっとTwitter就活しよう!</a></p>
<h1 id="参考"><a href="#%E5%8F%82%E8%80%83">参考</a></h1>
<ul>
<li><a target="_blank" rel="nofollow noopener" href="https://blog.takuchalle.dev/post/2018/12/06/rails_use_wkhtmltoimage/">Rails で質問箱っぽい画像を作るのに wkhtmltoimage を使った</a></li>
<li><a target="_blank" rel="nofollow noopener" href="https://razorjack.net/wkhtmltopdf-on-heroku-evaluating-different-installation-options/">wkhtmltopdf on Heroku: evaluating different installation options</a></li>
</ul>
TaKO8Ki
tag:crieit.net,2005:PublicArticle/14622
2018-12-03T23:42:44+09:00
2018-12-13T10:34:17+09:00
https://crieit.net/posts/SP-12
SP☆12参考表(地力表)支援サイト を支える技術
<h1 id="SP☆12参考表(地力表)支援サイト を支える技術"><a href="#SP%E2%98%8612%E5%8F%82%E8%80%83%E8%A1%A8%28%E5%9C%B0%E5%8A%9B%E8%A1%A8%29%E6%94%AF%E6%8F%B4%E3%82%B5%E3%82%A4%E3%83%88+%E3%82%92%E6%94%AF%E3%81%88%E3%82%8B%E6%8A%80%E8%A1%93">SP☆12参考表(地力表)支援サイト を支える技術</a></h1>
<p>この記事はcrieitでの <a href="https://crieit.net/advent-calendars/2018/technology">個人開発サービスに用いられている技術 Advent Calendar 2018</a> の9日目の記事です。<br />
昨日は<a href="https://crieit.net/users/ckoshien">ckoshien</a>さんの<a href="https://crieit.net/posts/0431d68ab5279f65797e41cfc18a0eb5">野球リーグスコア管理システムに用いている技術について</a>という記事でした。<br />
明日は<a href="https://crieit.net/users/tRiaeZ1">iotas𓆡創作支援アプリ運営中𓅬</a>さんの記事です!</p>
<h2 id="SP☆12参考表(地力表)支援サイト とは"><a href="#SP%E2%98%8612%E5%8F%82%E8%80%83%E8%A1%A8%28%E5%9C%B0%E5%8A%9B%E8%A1%A8%29%E6%94%AF%E6%8F%B4%E3%82%B5%E3%82%A4%E3%83%88+%E3%81%A8%E3%81%AF">SP☆12参考表(地力表)支援サイト とは</a></h2>
<p>ゲームセンター等でプレイできるbeatmania IIDXというゲームの成長支援サイトです。<br />
2014年11月に開発を開始し、運用を始めて4年ほど経過しました。<br />
現時点で登録者数は9200人ほどで、GAのマンスリーアクティブユーザは11k人ほどです。</p>
<p>beatmania IIDXは音ゲーと呼ばれるジャンルのゲームで、楽曲に難易度が設定されています。<br />
楽曲の難易度はおおまかに言うと☆1から☆12までに分類されます。</p>
<p>この分類はシングルプレイ(SP)、ダブルプレイ(DP)といったモードごとに存在しているのですが、本サイトではその中でもSPの☆12についてだけ取り扱ってます。</p>
<p>なお、このサイトはGitHub上でpublic repositoryとして<a target="_blank" rel="nofollow noopener" href="https://github.com/8398a7/abilitysheet">公開しています</a>。<br />
参考になったらスターをいただけるとモチベーションになります。</p>
<h3 id="なぜSP☆12だけなのか"><a href="#%E3%81%AA%E3%81%9CSP%E2%98%8612%E3%81%A0%E3%81%91%E3%81%AA%E3%81%AE%E3%81%8B">なぜSP☆12だけなのか</a></h3>
<p>ここではゲーム性の説明を行います。<br />
技術的な話を知りたい方はスキップしてもらって構いません。</p>
<p>SP☆12は現時点で(未解禁のものも含めると)300曲を超えています。<br />
そして他の難易度帯と比較すると☆12は易しい曲と難しい曲の難易度差が最も激しくなっています。<br />
☆12に挑戦し始めの人は噂程度に「この曲は☆12の中でも難しいと言われている気がする…」という選曲判断が必要になってきます。<br />
公式にも指標に近いものがあるのですが、割とあてにならないという背景もあります。<br />
※ 人によって得意不得意分野があるため参考表も万人に当てになるわけではないです</p>
<p>また、☆12の攻略には長い時間が必要になります。<br />
自身の例ですと、1つのゴールであろう皆伝という最上位段位の取得に☆12触り始めから1年以上の時間が必要でした。<br />
皆伝という段位は☆12の中でも上位の難しさに位置している楽曲で構成されるコースのため、簡単な☆12からスタートし、段階を踏んで難しい☆12もクリアできるようになる必要があります。</p>
<p>私の元々の開発モチベーションとしては、このステップをモチベを維持しつつ「続けていける」ようにすることでした。<br />
そのため自分がプレイしているSPであり、皆伝を取得するのに避けられない☆12を対象としたサイトを作り始めました。</p>
<p>スタート地点としてはPHPで簡易的な☆12参考表サイトを作成していました。<br />
このサイトは知人等にインターナルに利用してもらっていたのですが、需要がありそうということで公開を前提に作り直し始めたのが2014年11月です。</p>
<h2 id="採用している技術たち"><a href="#%E6%8E%A1%E7%94%A8%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B%E6%8A%80%E8%A1%93%E3%81%9F%E3%81%A1">採用している技術たち</a></h2>
<p>ざっくりと書くと、</p>
<ul>
<li>サーバ
<ul>
<li>[email protected]</li>
<li>Sidekiq</li>
<li>[email protected]</li>
</ul></li>
<li>フロント
<ul>
<li>[email protected]</li>
<li>React/Redux</li>
<li>ImmutableJS</li>
</ul></li>
<li>インフラ
<ul>
<li>さくらVPS(2コア、4GB、SSD 50GB)</li>
<li>(ローカル環境のみ)k8s対応</li>
<li>nginx</li>
<li>god</li>
<li>mackerel</li>
<li>BigQuery(アクセスログ解析)</li>
</ul></li>
</ul>
<p>といった形になっています。<br />
AWS/GCP等も検討したことはあるのですが、VPSと比較すると月額コストが跳ね上がるため見送っています。</p>
<h3 id="技術的な解説"><a href="#%E6%8A%80%E8%A1%93%E7%9A%84%E3%81%AA%E8%A7%A3%E8%AA%AC">技術的な解説</a></h3>
<p>はじめてRailsを使って作成したアプリだったことによるイマイチコードがいたるところに点在しています。<br />
合間を見て少しずつ改善はしているものの既にユーザが利用していると変更しにくい部分があり、手がつけにくいところもあります。<br />
特にRailsのroutes.rbの記法の修正は既にブックマークをしているユーザへの影響を考えると変更しにくいです。</p>
<p>一度ルーティングの変更をリダイレクトサポートをしながら変更したことがあったのですが、1年半ほどそのページを開くとリダイレクトしつつnoticeでブックマークの変更を促していたにも関わらず、いざサポートを切るとdead linkを参照してしまう方は想像より多かったのを記憶しています。</p>
<p>技術的な要素でいうと、「いたって普通なRailsアプリ」をメインポリシーとして作成しています。<br />
特殊なことをいろいろと行うと、その分メンテナンスコストも上がるため極力Rails Wayに乗っておこうという精神です。<br />
メインで開発し続けているサービスなら多少の獣道も選択としてはありですが、社会人が片手間に行う分には大衆に乗っかるほうが楽でした。</p>
<p>最近まではフロントエンドとの連携に自作のgem使ったりしながら特殊なことをしていたのですが、<br />
そのあたりはwebpackerに乗り換え、スタンダードRailsへの変身しました。<br />
(この変身コストはとても大きかったです。。)</p>
<h4 id="webpacker 4.0.0.pre.3"><a href="#webpacker+4.0.0.pre.3">webpacker 4.0.0.pre.3</a></h4>
<p>webpackerのstable releaseとしては3系ですが、このプロジェクトでは4系を利用しています。<br />
理由としては最新のts-loaderを使いたかったためです。</p>
<p>ts-loaderの最新を利用するためにはwebpack4系である必要があるのですが、stable releaseのwebpackerではwebpack3系までしか対応していなかったためです。</p>
<p>webpackerを採用した理由としては「現在はRailsの中でそれが主流」という理由以上のことはありません。<br />
疎なwebpackインテグレーションを自作しても良かったのですが、メンテナンスを続けるモチベが持てなさそうなので敬遠しました。<br />
実際使ってみると細かいところで不満はあるものの、トータル的には体感は悪くないという印象を受けました。</p>
<p>webpackerでは下記のように少しだけ設定を変えています。</p>
<pre><code class="javascript">process.env.NODE_ENV = process.env.NODE_ENV || 'production'
const environment = require('./environment')
module.exports = environment.toWebpackConfig()
module.exports.devtool = 'source-map'
</code></pre>
<p>といった設定にしてproductionでは devtoolの <code>nosources-nource-map</code> を <code>source-map</code> に置き換えていることです。<br />
source-map自体を切る修正を入れる人が多そうな印象ですが、自分の環境ではあえて設定しています。<br />
理由はsentryでのエラートラッキングが快適になるためです。</p>
<p><a href="https://crieit.now.sh/upload_images/caa3aa2a085238231a7bef714bcb36675c05373413280.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/caa3aa2a085238231a7bef714bcb36675c05373413280.png?mw=700" alt="sentry-source-map.png" /></a><br />
このような形でエラー部分の元ソースコードを表示することができます。<br />
また <code>raven-for-redux</code> というnpmを利用することでそのときのactionやstateの状態までわかります。</p>
<p>そのエラーになるまでのactionの履歴<br />
<a href="https://crieit.now.sh/upload_images/381f2f4536d46c0c6f9e9aea4a1af9e05c0537bbb3cf5.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/381f2f4536d46c0c6f9e9aea4a1af9e05c0537bbb3cf5.png?mw=700" alt="action-history.png" /></a></p>
<p>そのエラーが出たときのクライアント側のstate<br />
<a href="https://crieit.now.sh/upload_images/4debee22b3854b335cf6daf70a0d43f95c0537eb5e318.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/4debee22b3854b335cf6daf70a0d43f95c0537eb5e318.png?mw=700" alt="reducer.png" /></a></p>
<p>OSSなので特にこのサービスに関しては隠蔽する必要はないのですが、mapファイルはsentryサーバ以外からアクセスできないようにしています。<br />
自前でsentryを立てているので特定IPからのアクセスは弾くようになっています。</p>
<pre><code class="nginx">location ^~ /packs/ {
gzip_static on;
set $response_file 1;
if ($request_uri ~ 'map$') {
set $response_file 0;
}
if ($remote_addr = 'xxx.xx.xxx.xxx') {
set $response_file 1;
}
if ($response_file = '0') {
return 403;
}
}
</code></pre>
<p>typescriptに置き換えてからまだ一度もエラーが出ていなかったため、この画面は意図的にエラーを仕込んで発生させました…w</p>
<p>今のところ、webpacker4系に対する不具合は踏んでおらず問題なく運用できています。</p>
<h4 id="react-rails"><a href="#react-rails">react-rails</a></h4>
<p>Reactとのつなぎ込みにはreact-railsというgemを利用しています。<br />
react_on_railsというgemのほうが多機能なのですが、相容れないところがありreact-railsを採用することにしました。</p>
<p>react_on_railsのほうが優れている点としてはrailsContextというオブジェクトが付与されており、<br />
この中にtimezone/localeなどを始めとした開発者がほしいであろうメタ情報が入っています。<br />
またRailsにxhrリクエストをする際にcsrf-tokenをheaderにセットするAPIも用意されています。</p>
<p>ただcomponentをrenderするためのhookに <code>turbolinks:render</code> を利用しており、このhookではページがチャタるケースがあったため、採用しませんでした。</p>
<p>react-railsはreact_on_railsと比べると非常にシンプルで、コンポーネントをrenderする以上のサポートはあまりないようです。<br />
ただそれを行ってくれるだけで自分の要件的には十分だったため、採用しています。<br />
react-railsではcomponentをrenderするhookに <code>turbolinks:load</code> を採用しています。</p>
<p>チャタるとは何かをもう少しわかりやすく言うと、一瞬古いページが表示された後に新しいページが表示される現象のことを指しています。<br />
<a href="https://crieit.now.sh/upload_images/1e989a869fadcebc92d18312745796605c05397505626.gif" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/1e989a869fadcebc92d18312745796605c05397505626.gif?mw=700" alt="chattering.gif" /></a></p>
<p>コンテンツが一瞬表示される->白くなる->再度表示されるというループになっていることがわかると思います。<br />
一瞬表示された後と再度表示された後でAPIリクエストが2回走ってしまうという問題やUXの観点から許容できない、という判断になりました。</p>
<p>上記はturbolinks的には「仕様」の挙動です。<br />
<a target="_blank" rel="nofollow noopener" href="https://github.com/turbolinks/turbolinks#full-list-of-events">GitHub - turbolinks/turbolinks: Turbolinks makes navigating your web application faster</a> から抜粋すると以下のように書かれています。</p>
<blockquote>
<p><code>turbolinks:render</code>fires after Turbolinks renders the page. This event fires twice during an application visit to a cached location: once after rendering the cached version, and again after rendering the fresh version.</p>
</blockquote>
<p>react_on_railsのgem自体にはissueを投げてみたのですが、少し私の想像を超えた範疇の問題があるらしく、今回はreact-railsを採用することにしました。</p>
<h4 id="ts-routes"><a href="#ts-routes">ts-routes</a></h4>
<p>Railsとフロントの繋ぎ込みには <a target="_blank" rel="nofollow noopener" href="https://github.com/bitjourney/ts_routes-rails">GitHub - bitjourney/ts_routes-rails: Exports Rails URL helpers to TypeScript, inspired by js-routes</a> というgemを利用させていただきました。<br />
似たようなgemにjs-routesと呼ばれるものがあり、そちらを採用していたのですがts化にあたって載せ替えを行っています。<br />
パラメタ不足などの不正なルーティングに関して検知しやすくなるため、tsとrailsを組み合わせるならお薦めです。</p>
<h4 id="Sidekiq"><a href="#Sidekiq">Sidekiq</a></h4>
<p>兄弟サイトのIST(Iidx Score Table)からのデータ取り込みを始めとした外部サービスの連携や定期処理(sidekiq-cron)などに利用しています。</p>
<p>先述した通り☆12の譜面はかなり数が多く、1年を通して「解禁」され数が増え続けていきます。<br />
これらを全て人手によって捕捉し続けるのはコストが高い、と感じ1日に1回IST側のデータを利用して新規の☆12が解禁されたら自動追加するようにしています。<br />
ただ☆12の中での難易度自体は議論によって決められるもののため、難易度が決定した後の反映処理は人手で行っています。</p>
<p>当サイトはVPS1台で運用しているので、バックアップ等の日次処理も必要になってきます。<br />
これらの処理もSidekiq側に任せています。<br />
<a target="_blank" rel="nofollow noopener" href="https://github.com/8398a7/abilitysheet/blob/master/lib/service_dumper.rb">abilitysheet/service_dumper.rb at master · 8398a7/abilitysheet · GitHub</a> というlibを作り、</p>
<ul>
<li>DBのdump(pg_dump)</li>
<li>carrierwaveで保存された画像等の収集</li>
</ul>
<p>を行った後にtar.gzに固めてS3に送る処理です。<br />
これらの処理をjobにして朝の5時過ぎに行うようにしています。<br />
また、手元でproduction環境の再現を行いたいときにもS3からデータを取ってきています。</p>
<p>運用しているいくつかのサービスは全てこのような形でバックアップを取っており、いつVPSが死んでしまってもすぐにサービスを復旧できるようにしています。</p>
<h4 id="CI"><a href="#CI">CI</a></h4>
<p>CircleCIを使ってテストを行っています。<br />
テストフレームワークはrspecでjs部分のテストはjest等では書いていません。<br />
代わりにsystem specとしてchromedriverを利用したE2Eで担保しています。<br />
昔に書いたコードなので、コントローラ系のspecも多いですがこのあたりも粛清したいところです…w</p>
<p>system specではjsを使うところ使わないところで以下のように条件分岐を書いています。<br />
systemであっても <code>js: true</code> でないところは <code>rack_test</code> で行うようにしているところと、<code>NO_HEADLESS</code> という環境変数を定義して実行するとchromeが実際に立ち上がるようにしています。</p>
<pre><code class="ruby"> config.before(:each, type: :system) do |example|
if example.metadata[:js]
if example.metadata[:iphone6]
display_size = [375, 667]
args = %w[--headless --disable-gpu --user-agent=iPhone]
else
display_size = [1920, 1080]
args = %w[--headless --disable-gpu]
end
args.shift if ENV['NO_HEADLESS']
caps = Selenium::WebDriver::Remote::Capabilities.chrome(chromeOptions: { args: args })
driven_by :selenium, screen_size: display_size, options: { desired_capabilities: caps }
else
driven_by :rack_test
end
end
</code></pre>
<p>実行する際には <code>NO_HEADLESS=true bundle exec rspec spec/systems</code> といったコマンドで実行します。<br />
spec内に <code>binding.pry</code> を仕込むことでElementも触れるのでspecがうまくいかないときの不具合調査などに利用しています。</p>
<p><a href="https://crieit.now.sh/upload_images/99997c2f5ff8b294ccd760ab48ea0c1b5c0a992fc4512.gif" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/99997c2f5ff8b294ccd760ab48ea0c1b5c0a992fc4512.gif?mw=700" alt="e2e.gif" /></a></p>
<h4 id="運用サポート"><a href="#%E9%81%8B%E7%94%A8%E3%82%B5%E3%83%9D%E3%83%BC%E3%83%88">運用サポート</a></h4>
<p>死活監視にはmackerelとgodを利用しています。<br />
<a target="_blank" rel="nofollow noopener" href="https://mackerel.io">Mackerel(マカレル): 新世代のサーバ管理・監視サービス</a> はSaaS型のサービスでプロセスが死んでいるか生きているかの監視もできます。</p>
<p>死活監視の肝としては <a target="_blank" rel="nofollow noopener" href="http://godrb.com/">God - A Process Monitoring Framework in Ruby</a> を採用しています。<br />
sidekiq/puma/redis/postgresql/nginxなどのサービス継続に必要なプロセスは全てgodに監視させています。<br />
再起動時などにもgodに任せて起動させているため、再起動するとサービスが落ちたままになっているということもないです。</p>
<p>特にsidekiqは知らない間にメモリの使いすぎでプロセスが落ちていることもあったため、godに監視させて死んでいたら起こすようにするのは精神的安定感が増し増しでした。<br />
デプロイには <code>capistrano</code> を採用していますが、こいつはsidekiqのgod監視とやや相性が悪いです。<br />
pumaと違ってgraceful restart時にプロセスがいない瞬間ができてしまうため、<br />
capistranoがsidekiqを起こすのとgodがsidekiqを起こすのが衝突してしまい、二重でsidekiqが起動してしまうケースが有るためです。<br />
capistranoと併用する場合は素直にcapではsidekiq:stopだけして起こすのはgodに任せたほうが良いという感覚を持っています。<br />
<a target="_blank" rel="nofollow noopener" href="https://github.com/8398a7/abilitysheet/blob/master/config/deploy.rb#L53">abilitysheet/deploy.rb at master · 8398a7/abilitysheet · GitHub</a></p>
<h4 id="k8s"><a href="#k8s">k8s</a></h4>
<p>k8sもローカル環境での動作自体はサポートしています。<br />
VPSを2台所持しているため、2台でなんとか運用できないか検討していたのですが、結局2台では割と厳しいということと、<br />
capistranoに代わるデプロイツールを自作し、メンテし続けるコストを払える自信がなかったため見送りました。</p>
<p>一通りproductionとしてローカル環境で動作させるところまでは確認しているのでrailsでのk8sに参考にしたい方はどうぞ。<br />
<a target="_blank" rel="nofollow noopener" href="https://github.com/8398a7/abilitysheet/tree/master/kubernetes">abilitysheet/kubernetes at master · 8398a7/abilitysheet · GitHub</a><br />
ただ運用もしていないコードなので穴はたくさんあると思います…</p>
<h4 id="BigQuery"><a href="#BigQuery">BigQuery</a></h4>
<p>nginxのアクセスログをfluentd経由でBigQueryに投げるようにしています。<br />
SSDで容量が厳しく、割と細かめにログを削除しているため後でまとめて見るためにBigQueryを利用しています。</p>
<p>元々はS3に置いてAthenaで集計していたのですが、BigQueryのほうがいろいろと捗りそうなので移管しました。<br />
<a target="_blank" rel="nofollow noopener" href="https://github.com/kaizenplatform/fluent-plugin-bigquery">GitHub - kaizenplatform/fluent-plugin-bigquery</a> というプラグインを利用させていただき、bqにログを送っています。</p>
<p>主にARのconnection poolがタイムアウトになっていたり、急激な負荷によるアラートの調査などに使っていたりします。<br />
railsユーザであればnginxのltsvログに <code>'request_id:$sent_http_x_request_id\t'</code> を追加しておくことで、調査が捗ることがあるためおすすめします。<br />
nginxのログから問題のrequest_idがわかればproduction.logをrequest_idでgrepすることで該当行のログに辿り着きやすくなります。</p>
<h3 id="おまけ IE対応"><a href="#%E3%81%8A%E3%81%BE%E3%81%91+IE%E5%AF%BE%E5%BF%9C">おまけ IE対応</a></h3>
<p>最近webpackerベースのreactにリプレースを行っていたのですが、その際に困った問題と解決した手法についても記載しておきます。</p>
<p><code>tsconfig.json</code> ではtargetをes5としていましたが、babel-polyfillを仕込み忘れていたことが1点目です。<br />
記法自体はes5まで落としてくれるのですが、polyfillがないと <code>Promise</code> などがIEにはないため正常に動作しません。<br />
polyfillの入れ方に関しては、headerに <code>https://cdn.polyfill.io/v2/polyfill.min.js</code> を追加するのがおすすめです。<br />
ブラウザのUAを見て必要なpolyfillを行ってくれます。<br />
試しにIEで見ると結構な量をpolyfillしてくれますが、最新版のchromeではほぼ空であることが確認できると思います。<br />
自分でbundleすると配布するjsファイルが巨大化するため、cdn経由で入れることにしました。</p>
<p>2点目はes5にトランスパイルされていないライブラリを利用してしまっていることでした。<br />
query-stringというライブラリで<a target="_blank" rel="nofollow noopener" href="https://github.com/sindresorhus/query-string/blob/master/index.js#L31">query-string/index.js at master · sindresorhus/query-string · GitHub</a>の行でアローファンクションを使っているのですが、これがIEだと解釈できないという問題です。<br />
webpackerのbabel-loaderはexcludeで <code>node_modules</code> が指定されているため、使っているライブラリまではes5にトランスパイルされません。<br />
よくよくドキュメントを見るとレガシーブラウザは5系を使え(最新は6系)ということが記載されていたので、5系を利用することで解決しました。</p>
<p>当初は上記2点の問題がわからぬまま、IEでは見れないといった声が上がっていたため、最初の対応としてはelectronでサイトをラップしたexeを配布していました。<br />
それには<a target="_blank" rel="nofollow noopener" href="https://github.com/jiahaog/nativefier#readme">GitHub - jiahaog/nativefier: Make any web page a desktop application</a>というライブラリを利用したのですが、幅広くの場面で役に立つので困ったら利用してみてください。</p>
<h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2>
<p>今回はSP☆12参考表(地力表)支援サイト を支える技術をご紹介しました。<br />
他にもいくつかサービスがありご紹介したい技術もあったのですが、割と長くなってしまったので今回はこのような形で締めたいと思います。</p>
<p>サービスを運用している方の参考になれば幸いです。</p>
<p><a target="_blank" rel="nofollow noopener" href="https://github.com/8398a7/abilitysheet">GitHub - 8398a7/abilitysheet: This app is ability sheet for beatmania iidx music of level 12.</a></p>
<p>P.S. 作者は2018年5月に念願の冥ハードを成し遂げ、ゆるふわ離脱モードに突入しました。</p>
8398a7
tag:crieit.net,2005:PublicArticle/14583
2018-10-24T18:26:18+09:00
2018-10-31T07:39:37+09:00
https://crieit.net/posts/IT-OKWorks
「日本最大のIT系フリーランス案件/求人検索サービス」として「OKWorks」をリリース
<p>さて、早速ですが、一週間ほど前に「<strong>日本最大のIT系フリーランス案件/求人検索サービス</strong>」として<br />
「<strong>OKWorks</strong>」をリリースしました。今回は、そちらのお知らせと、技術情報として、ソースコードを公開しておりますので、ご笑覧いただけるとうれしいです。</p>
<h2 id="リリースしたサービス"><a href="#%E3%83%AA%E3%83%AA%E3%83%BC%E3%82%B9%E3%81%97%E3%81%9F%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9">リリースしたサービス</a></h2>
<p>日本最大のIT系フリーランス案件/求人検索サービス「OKWorks」<br />
<a target="_blank" rel="nofollow noopener" href="https://www.okworks.me/">https://www.okworks.me/</a><br />
<img src="https://qiita-image-store.s3.amazonaws.com/0/304536/c3ec601f-03e6-5711-d1e1-84209f251698.png" alt="screenshot.png" /></p>
<h2 id="なにができるのか"><a href="#%E3%81%AA%E3%81%AB%E3%81%8C%E3%81%A7%E3%81%8D%E3%82%8B%E3%81%AE%E3%81%8B">なにができるのか</a></h2>
<p>IT系のフリーランス案件をサイト横断的に探すことができます。独自に案件を獲得するのではなく、インターネットから情報を収集し、集約しデータを提供することで、日本最大級の情報量を誇るフリーランス案件サービスです。</p>
<h2 id="なぜ作ったのか?"><a href="#%E3%81%AA%E3%81%9C%E4%BD%9C%E3%81%A3%E3%81%9F%E3%81%AE%E3%81%8B%EF%BC%9F">なぜ作ったのか?</a></h2>
<p>開発者は、フリーランスのエンジニアとして働いています。企業様から直接ご相談をうけたり、つながりのある受託企業からの案件をプロジェクト的に受けております。一部、WEBメディアも運営し、そちらからの収益もあります。</p>
<p>そんな中で、エンジニアとしてのフリーランス案件が流れてくるメールマガジンをいくつか購読しています。そこから、案件をうけるということはないのですが、自分のスキルの相場観を把握する手段として活用しています。こんな好条件の案件が出てくるなら、まだ大丈夫だな・・・ということです。</p>
<p>さて、日々の楽しみである、案件チェックですが、フリーランス案件を提供する会社が続々と登場しているなとは、肌感で感じていました。Prosheetさん、Midworksさん、ITプロパートナーズさんなど・・・大小含めれば、いまでは数十社はこの事業をやっているのではないでしょうか。</p>
<p>さて、そうなってくると、アグリゲーションの出番です。各社のサイトを集約し、より便利で大規模なフリーランス案件の検索サービスを作りたいと思いました。</p>
<h2 id="どうやって作ったのか"><a href="#%E3%81%A9%E3%81%86%E3%82%84%E3%81%A3%E3%81%A6%E4%BD%9C%E3%81%A3%E3%81%9F%E3%81%AE%E3%81%8B">どうやって作ったのか</a></h2>
<p>フリーランスエンジニア2人のチームで、約3週間で開発をしました。なるべく早くリリースすることを目標に、下記の構成で開発しています。今回は、技術的な新規性を全く考慮していません。それよりも、「フリーランス案件が市場で伸びている、それを集約することは面白くない?」というアイデアを実現することを優先しました。</p>
<p>言語 Ruby<br />
フレームワーク Rails<br />
デザインフレームワーク Bootstrap<br />
サーバー Heroku<br />
DB MySQL</p>
<p>うーん、仕事で使っているのもありますが、RailsとHerokuの組み合わせで開発するのは、本当に早いな・・・と改めて感じました。プッシュしたらデプロイされるというのは、まるで魔法ですね・・・w</p>
<h2 id="苦労したこと"><a href="#%E8%8B%A6%E5%8A%B4%E3%81%97%E3%81%9F%E3%81%93%E3%81%A8">苦労したこと</a></h2>
<p>仕事でやっているから、ということもあり、あんまりなかったですね。イッシューを淡々と潰し、リリースまでこぎつけました。</p>
<h2 id="作ってみての感想"><a href="#%E4%BD%9C%E3%81%A3%E3%81%A6%E3%81%BF%E3%81%A6%E3%81%AE%E6%84%9F%E6%83%B3">作ってみての感想</a></h2>
<p>サイトが広く一般的に使われるには、まだまだなのですが、作った本人がドックフーディング的に毎日チェックしてしまうサービスになっており、その点で作ってよかったなと思っています。</p>
<p>こんな良い案件あんのw こんな糞案件誰がやるのwww</p>
<p>みたいな発見があります。とても楽しいです。</p>
<h2 id="今後については"><a href="#%E4%BB%8A%E5%BE%8C%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E3%81%AF">今後については</a></h2>
<p>まず長期的に、IT系のフリーランスの仕事の流動性向上に貢献したいという思いがあります。ラップトップがあれば働ける反面、案件を獲得するためには、営業や調整、交渉などめんどうなことがたくさんあります。一方、企業では人材不足が加速しています。このギャップを埋めることができれば、IT系人材はもっと働ける、もっと稼げる、もっと社会に貢献できると思いますし、企業では新しいプロジェクトをもっともっと推進していくことができるでしょう。</p>
<h2 id="OKWorksのソースコード公開について"><a href="#OKWorks%E3%81%AE%E3%82%BD%E3%83%BC%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%89%E5%85%AC%E9%96%8B%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6">OKWorksのソースコード公開について</a></h2>
<p>下記内容で、ソースコードを公開させていただきます。</p>
<p>【公開内容】<br />
Rails 5.2.1を用いて書かれたアプリケーション。DBはMySQLを利用。</p>
<p>【公開URL】<br />
<a target="_blank" rel="nofollow noopener" href="https://github.com/okworks-dev/okworks_public">https://github.com/okworks-dev/okworks_public</a></p>
<p>【利用方法】<br />
GitHub上で読んでいただくか、forkなどをして触っていただけれればと思います。該当ディレクトリに移動した後に、下記コマンドを叩いていただければ初期設定が完了いたします。</p>
<p><code>bundle install && rake db:create && rake db:migrate && rake db:seed</code></p>
<p>【注意事項】<br />
・著作権を放棄したり、OSSとして開発を行っていくというわけではありません。あくまでも、学習用コンテンツとしてご利用ください。<br />
・本ソースコードの全部または一部を利用して、同種のサービスを公開することは禁止させていただきます。<br />
・公開に当たりAPI KEYなど、秘匿情報は削除しております。<br />
・また、秘匿情報の漏れなどを防ぐために、アップデートを行うつもりはありません。10/22時点のソースコードとなります。</p>
<p>いろいろややこしく恐縮ですが、ぜひお楽しみいただければと思います。</p>
<p>質問などについては、<a target="_blank" rel="nofollow noopener" href="https://twitter.com/codeq_official?lang=ja">公式ツイッターアカウント</a>にて受け付けています!できる限り返信させていただきます。</p>
<h2 id="読みどころ"><a href="#%E8%AA%AD%E3%81%BF%E3%81%A9%E3%81%93%E3%82%8D">読みどころ</a></h2>
<p>試行錯誤しながら作っているので、ぐちゃぐちゃなところもありますが、下記の点は「へー」といっていただけるかと思います。</p>
<p>・クローラー<br />
app/controllers/concerns 以下に求人サイトから情報を取得するクローラーをおいてあります。</p>
<p>crawler.rb - 各サイトごとのクローラーを管理するクラス<br />
site_crawlers以下 - 各サイト別のクローラー</p>
<p>各サイトごとに、スクレイピング方法が異なるので、そこに対応するのが一番時間がかかりました。</p>
<p>・コントローラー</p>
<p>コントローラーが肥大化しないように、できる限りモデルにロジックを隠蔽する、helperにメソッドを切り出しています。比較的、コントローラーがスッキリ書けているのでは?と思っています。</p>
<p>・hamlの利用とpartialの多用</p>
<p>hamlを使うことでコード量を劇的に減らすことができますし、構造が見やすくなります。slimを使わない理由は、slimは、簡素化しすぎていて、個人的には逆に読みづらいからです。</p>
<p>また、複数人で開発していることもあるので、コンポーネントをできる限りpartialに切り出すことで、再利用しやすく、デバッグも容易になりました。</p>
<p>といったところは、読んでいただいて面白いかと思います。また、開発環境で、動かして触っていただくのも面白いかと思います!</p>
<h2 id="みなさんぜひ使ってみてください、シェアしてください!"><a href="#%E3%81%BF%E3%81%AA%E3%81%95%E3%82%93%E3%81%9C%E3%81%B2%E4%BD%BF%E3%81%A3%E3%81%A6%E3%81%BF%E3%81%A6%E3%81%8F%E3%81%A0%E3%81%95%E3%81%84%E3%80%81%E3%82%B7%E3%82%A7%E3%82%A2%E3%81%97%E3%81%A6%E3%81%8F%E3%81%A0%E3%81%95%E3%81%84%EF%BC%81">みなさんぜひ使ってみてください、シェアしてください!</a></h2>
<p>OKWorks(オーケーワークス)をよろしくおねがいします😋<br />
<a target="_blank" rel="nofollow noopener" href="https://www.okworks.me/">https://www.okworks.me/</a></p>
OKWorks@ツイッター転職応援中