- 投稿日:2019-08-04T23:32:51+09:00
RubyのRailsをMySQLでHerokuにあげてみた
今までの麻雀アプリは一人でずっとやるだけだったので、
もう少しデータ的なのを集められるようになりたいなーと思って
ちょっと改良しました。https://rubymahjong.herokuapp.com/
みんなのあがり回数とあがりまでの平均ツモ数を表示できるようにしました!
◇開発言語
ruby 2.6.3
◇サーバーサイドフレームワーク
ruby on rails 5.2.3
◇フロントエンドフレームワーク
Vue.js
◇データベース
MySQL
◇開発OS
mac
◇IDE
vscode
◇ソース管理
GitHub
◇アプリケーションプラットフォーム
Heroku忘れないうちにRuby On Railsのインストール手順とかまとめておきます。
Ruby On Railsのインストール
まぁ、Railsのインストール手順とかは色々記事があるのでそれを見ればできます。
自分はRails Girls ガイドを見ながら環境を作りました。(Girlじゃないけど)基本的にはRails Girls ガイドの通りに作業を進めればいいんですが、
Homebrewのインストールがうまく行きませんでした。
brew doctor を実行してエラーがないか確認したところ11:05:46 Users $ brew doctor Please note that these warnings are just used to help the Homebrew maintainers with debugging if you file an issue. If everything you use Homebrew for is working fine: please don't worry or file an issue; just ignore this. Thanks! Warning: "config" scripts exist outside your system or Homebrew directories. `./configure` scripts often look for *-config scripts to determine if software packages are installed, and which additional flags to use when compiling and linking. Having additional scripts in your path can confuse software installed via Homebrew if the config script overrides a system or Homebrew-provided script of the same name. We found the following "config" scripts: /Library/Frameworks/Python.framework/Versions/3.7/bin/python3.7-config /Library/Frameworks/Python.framework/Versions/3.7/bin/python3.7m-config /Library/Frameworks/Python.framework/Versions/3.7/bin/python3-config 11:05:52 Users $と大量のWarningが…。
原因ですが、「-config」ファイルにPathが通っているとWarningが発生するみたいです。
envコマンドで環境設定確認すると、確かにPythonのPathが通ってますね。11:12:40 Users $ env | grep PATH PATH=/Users/itoutoshiya/.rbenv/shims:/Library/Frameworks/Python.framework/Versions/3.7/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin以下のサイトを参考に、
PathからPythonを除外してbrewコマンドを実行するエイリアスを作成しました。
参考:https://www.task-notes.com/entry/20141223/1419324649alias brew="env PATH=${PATH/\/Library\/Frameworks\/Python.framework\/Versions\/3.7\/bin:/} brew"コンソールを再起動してbrew doctorを再実行。
11:22:47 ~ $ brew doctor Your system is ready to brew.これでHomebrewのインストールはうまくできました!
残りのソフトは、Rails Girls ガイドの通りに実装できました。
MySQLのインストール
MySQLのインストール手順も参考になる記事はたくさんありますね。
自分は以下のサイトが分かりやすかったので参考にさせてもらいました。
https://qiita.com/fuku_tech/items/a380ebb1fd156c14c25bbrew install mysqlrailsプロジェクト作成
必要なものは全部インストールできたので、早速
mysqlを利用するRailsプロジェクトを作成します。
といっても、さすがRails。コマンド一つだけですぐにできます。rails new ./ -d mysql適当なフォルダにて上記コマンドを実行すればOKです。
VScodeにてコンソールを表示し、上記コマンドを実行すれば必要なファイルが勝手に作成されます。config/database.ymlを確認すると、ちゃんとMySQLを使う設定になってますね!
んで、早速Railsの起動コマンド「rails server」を実行。
デフォルトだと地球儀の絵がTOPページに表示されるはず。
うーん失敗。ただ、以下のメッセージからするに、mysqlに接続できていない感じ。
Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)というか、そもそもsqlサーバーを起動していないので、そりゃDB接続できないよってエラー出ますよね。
ということで、以下コマンドを実行してsqlサーバーを起動。mysql.server startうん。sqlサーバーは起動できたみたいです。
じゃぁもう一度Railsを起動し画面を確認!
まぁ、エラーになるよね。今回のエラー原因は以下の通り。Unknown database 'project_development'project_developmentってデータベースがないよーってい言ってますね。
project_developmentは、config/database.ymlで設定している
データベースですね。
mySqlにログインしようとしてもproject_developmentはないからエラーになりますね。
まぁ、project_developmentを作ってないので当たり前ですね。なので、project_developmentを作ります。
ただ、これもRailsを利用して作成することができます。
以下コマンドを実行するだけ!rails db:createはい!できましたー。
じゃぁもう一度Railsを起動し画面を確認!地球の絵!
見慣れた画像が表示されました!
とりあえず、これで環境面は一通りできました!テーブル作成
今回は、上がりまでにかかった自摸の回数をテーブルに記録させていきたいと思います。
Railsのコマンドを実行すると、テーブルやそのテーブルにアクセスするための機能(プログラムファイル)
も自動でできます。rails generate scaffold WonCount name:string wonCount:integerですが、上記コマンドだけだと肝心のテーブル自身は作成されません。
マイグレーションを実行する必要があります。
と言っても難しいことは何もしません。
以下コマンドを実行するだけです。rails db:migrate参考:https://www.sejuku.net/blog/14229
ここまでくれば、後はあがりまでの自摸数をDBに登録するAPIを実装するだけです。
Herokuへのデプロイ
ローカル環境ではうまく出来たので、早速インターネットに公開したいと思います。
サーバーは、またHerokuを使います。便利ですね、PaaS。
参考:http://arfyasu.hatenablog.com/entry/2016/01/11/035101
https://devcenter.heroku.com/articles/rails4#logging-and-assetsrails_12factor
rails_12factorというのをHeroku上で利用できるように設定します。
rails_12factorは、Herokuでのログを見れるようにするgem(Rubyのライブラリ)です。
Gemfileに以下記述を追加するだけでOKです。group :production do gem 'rails_12factor' endProcfile作成
Procfileを作成し、Heroku上での起動コマンドを記述します。
以下記述だけでOK。web: bundle exec rails server -p $PORTHerokuにアップ
はい。ここまで出来たらHerokuにアップします。
HerokuGitにアップする方法もありますが、
自身のGitHubにアップしたプロジェクトを利用します。んで、プロジェクトアップロード後にWebサイトを確認。
はい。失敗〜。
Herokuのログを見ます。コマンドプロンプトから以下コマンドを実行〜。heroku logs --tail --app rubymahjong※「rubymahjong」は、Herokuにアップしたプロジェクト名です。
Mysql2::Error::ConnectionError (Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)):MySQLに接続出来なくてエラーになってますね。
HerokuにMySQLのDB作成
MySQLを利用するにはHerokuにクレジットカードの情報を登録する必要があります。
クレジットカードの登録だけなら無料です。(2019/08/04現在)クレジットカード登録後、コマンドプロンプトから以下コマンドを実行しMySQLが利用できるようにcleardbアドオンをインストールします。
参考:https://www.yuta-u.com/programing/rails/heroku-mysql-2heroku addons:create cleardb:ignite --app rubymahjongHeroku上の「Overview」を見ると、MySQLがアドオンされたことが分かりますね。
以下コマンドを実行してコンフィグを確認しても、MySQLが追加されたことが分かります。
heroku config --app rubymahjongCLEARDB_DATABASE_URLに、デプロイ用のDB接続情報が記載されています。
CLEARDB_DATABASE_URL: mysql://bfc76098d1b006:90049602@us-cdbr-iron-east-02.cleardb.net/heroku_c287fee3253ccb2?reconnect=trueこの情報をDATABASE_URLとして設定します。
ただし、Railsのgemでインストールしているのがmysql2のため、
mysqlではなくmysql2に変更して設定します。heroku config:set DATABASE_URL=mysql2://bfc76098d1b006:90049602@us-cdbr-iron-east-02.cleardb.net/heroku_c287fee3253ccb2?reconnect=true --app rubymahjong変更後、またコンフィグを確認してみます。
【変更後】
heroku config --app rubymahjong
DATABASE_URLが追加されてますね!ActiveRecord::StatementInvalid (Mysql2::Error: Table 'heroku_c287fee3253ccb2.won_counts' doesn't exist: SHOW FULL FIELDS FROM `won_counts`):won_countsテーブルがなくてエラーになってますね。
テーブル作成はマイグレーションですね。以下コマンドを実行!
heroku run rails db:migrate --app rubymahjongなんか出来てる感じですね!
早速ブラウザから画面を確認してみます。
できました!
きちんとあがり回数をDBに登録し、その結果を出力出来てます!Herokuって便利ですねー。
Rails+MySQLってかなりのWebサービスで利用されてそうで、
その環境が簡単に作れると色々なことが出来て夢が広がりますね!
今回のプログラムは以下GitHubにあげてます。
https://github.com/kph7m/rubymahjong
- 投稿日:2019-08-04T22:35:53+09:00
未経験が現場iOSアプリ開発で出会うRuby関連
どうもみなさんこんにちはiOS青二才です。
未経験でiOS開発現場に入ると、思いの外今まで頑張って技術をあげてきた
Swift以外にも様々なものに出会い自分の知見・技術レンジが狭いことに気付きます。
現場に入る前も幅広く開発をしてる人は出会うことがあったり使用したりの経験があると思いますが、私はそんなことはなかったので、「あれ、rubyさん介入してるやんなんやこれ」ってなった物のメモをおきます。Ruby
- 日本産のスクリプト言語
- Webサイト制作に使用
- Webアプリ制作に使用
- スマホアプリ開発に使用
- サーバーサイド開発に使用
まずiOSアプリ開発とRubyとの関係性と知る
色々と掘り下げる前に、iOSアプリ開発に置いての
Rubyとの関係性を知るべきだと思いました。
Rubyという言語の一部の特徴は上にあげたものたちですが、サーバーサイド側の処理を担うことが多々あります。
ここでまず一つ、「開発に置いてサーバー連携はrubyで、、、」という繋がり1が生まれます。
そしてMacにはデフォルトでRubyが導入されているのですが、サーバー側処理とか個人開発で使わなきゃ出会いないよね、と思っていたのですがところがどっこい。実は触れてました。以下で説明する
gemですが、実はCocoapodsをインストールする際に使用していたんですね。最近は既存のプロジェクトを改修したりすることばかりで、新規でインストールする機会を逃していたので完全に忘れていました。
よくよく調べてみるとCocoapodsはRubyで実装されているらしく、インストールはRuby経由ということになります。ライブラリ / パッケージ
プロジェクトの
readmeをみるとgem installとかbundle installとかそういうのを見かけることがあります。
調べてみると、gemとはRubyGemsが公開しているRubyのパッケージ管理ツール。とかいろんなところで説明されています。正直、意味がすんなり入ってこなかったので調べました。まずここで一つはっきりさせておきたいのが
ライブラリ = パッケージ
ということです。
初歩的なことかとは思いますが、新しいものを理解するときに事前に脳内にある知識と説明を照らし合わせたときに少しでも差異があると混乱を招きますので、この際にはっきりさせました。iOS開発で使用する
CocoapodsCarthageはライブラリ管理ツールと認識していたので、パッケージ管理?また違うもの?っとなってしまったのでここで認識を共通化させたかった次第です。
以下の説明では、同等のものと認識してください。
なおここではライブラリという言葉で統一化します。Gem
RubyGemsが提供するRuby用のライブラリ管理ツールRubyにおいてgemとはライブラリのこと(太郎さん、花子さんを人間と呼ぶ感じ)- ターミナルにて
gemコマンドで使用gemコマンドにてビルド、アップロード、ダウンロード、インストールを行うgemfilegemfile.lockというのが作成されるので、gemfile内にライブラリを記載して使用まず
RubyGemsですが、これはそもそものgemを使用できる環境、または管理するシステムです。これを
gemを使用するにはまずそれ自体のインストールから始めます。丁寧なreadmeの場合はだいたいプロジェクトをビルドするまでのフローが書いてあると思いますので、それに従ってください。こいつが
SwiftでいうCocoapodsなどの管理ツールに該当するのではと思います。参考
https://ja.wikipedia.org/wiki/RubyGems
https://qiita.com/sumyapp/items/5ec58bf3567e557c24d7bundler
gemの依存関係とバージョンを管理するためのツール。との説明が多いですがこの表現も紐解くと
bundlerもgemの一つ- 複数の
gemの使用の間で生まれるgemA version1 と gemB version1が上手く動作しない、というのを管理して解消してくれる。gemfilegemfile.lockに準拠して管理gemの管理をするgem、それがbundlerということになります。
bundlerを入れましたら、基本的にはbundle installなどbundlerを介してgem達のインストールを行うのが良いとされているようです。参考
https://qiita.com/oshou/items/6283c2315dc7dd244aef
https://techacademy.jp/magazine/19840rbenv
rbenvは、複数のRubyのバージョンを管理してくれて、かつプロジェクトごとのRubyのバージョンを指定して使うことができるツールです。Rubygemsがライブラリ管理ツールだとしたら、こちらはRuby管理ツールとでもいうんですかね。Homebrewなどでインストールして使います。
rbenvでRubyのバージョン操作等を行うことがあるかどうかわわかりませんが、だいたいgembundlerとセットで使用されていることが多いはずです。
ちなみアールベンブとかアールビーエンブという呼び方をするそうです。まとめ
登場したのは以下のもの達
rbenv-Rubyのバージョンを管理gem(RubyGems)-Rubyのライブラリ管理ツールbundler-gem(ライブラリ)の一つで、gemの相互性などの管理をするiOSアプリ開発で
Rubyを扱っていた場合ほぼほぼこれらを導入しているケースが多いのかなと思います。
Rubyも完璧にする!というのもまた先が長い話になるので、チーム開発規模のプロジェクトに介入する際は最低限入れておくべき部分かなと感じました。という訳で、知見を広げるいい経験でした。ビルドの際、何かライブラリ系のエラーにエンカウントした場合はこの辺にも何か原因があるのでは、という発想をもてるようにもなったかと思うのでとてもいい機会だったと思います。
- 投稿日:2019-08-04T20:24:32+09:00
『レストラン検索アプリ』の制作過程
はじめに
今回自作アプリを作るのでその過程を残しておきます。(備忘録)
現在制作中なので随時更新されていきます。目次
※別記事をアップしたら随時更新していきます
アプリ概要
●使用する技術
今回はRails+mysql+heroku+bootstrapでアプリを作っていきます。
AWSと迷いましたが、チーム開発でAWSを触っていたので省略してherokuを使います。
もし時間があれば、AWSに移すかもしれません。●解決したい事とアプリへの想い
アプリを作ったキッカケは、ミシュランや食べログなど様々な観点の評価軸をもつサイトがあるが、200店舗程実際に食べてみて、どれも当てにならないと思っていました。(勿論個人の好みもあります)
いつもレストランに行ってトライアンドエラーを繰り返す中で、一番信用出来る情報源は、食通や料理人が美味しいと言うお店だと思いました。
なので私が知っている限りですが、それを紹介できるアプリを作ろうと思ったのがきっかけです。
しかし問題として、私自身美味しいお店を広めたくありません!過去好きなお店が突然点数アルゴリズムが変わったとか
なんとかで、予約が取れなくなる苦い経験を何度かしています。(お店側も結構似た想い持ってるところが多いです、、、)
なので、今回は質問に答えて、それに当てはまる1店舗だけを紹介するという形にしました。拘りも出せて一石二鳥です。
●実装内容
内容としては
・DBにレストラン情報と別テーブルでカテゴリーidを保存しておく。
・質問に答えて貰って、該当のカテゴリーidを持つレストランを表示する。の二点が最低機能で追加機能を入れるなら、
・ユーザー登録機能の実装
・ユーザーが1店舗だけオススメのレストランを登録できる。
・レストラン検索機能
です。
レストランをカテゴリー分けして、表示しようかなと思いました。
別テーブルに保存する事で、カラムを増やせばカテゴリーを増やせるので、後々質問が多様化してカテゴリーの種類が増えた時に困らないかなと思ったのでこの様な仕様にしました。
ユーザー投稿を導入すると、どうしても検索されるレストランの質が落ちてしまう問題があるので、1ユーザー1店舗に
する事で質を保とうとしました。
またユーザーが投稿出来る様になる事で、私の秘蔵情報を公開する必要がなくなる為、レストラン検索機能を追加したいと思います。まとめ
現状最低機能までを3日で考えています。
またアプリが完成した段階でまとめを書いていきたいと思います
- 投稿日:2019-08-04T19:41:03+09:00
Docker for Windowsでrubyファイルを実行する
docker run -it --rm --name ruby -v D:/ユーザー名/workspace/foo_dir:/myapp -w /myapp ruby:2.5 bashエディタでの編集内容は自動的に反映されるので、コンテナのbashからrubyファイルを実行
各オプションとか
-it bash コンテナのbashに入って操作
--rm 終了時にコンテナを削除(終了したコンテナが溜まっていくので)
--name コンテナの名前を指定
-v ボリュームをマウント(各々のPCのディレクトリ構成に合わせる)
-w Docker内のワーキングディレクトリを指定
- 投稿日:2019-08-04T18:36:14+09:00
seedsファイルで西暦テーブルを作りたい
前記事で下の画像のミニアプリを実装しようとした際、optionタグ用に1900年から2019年までのレコードを作ろうとして七転八倒したので共有します。
seeds.rbっていうぐらいだからruby式が使えます
qiita seedデータの投入方法
【Rails入門】seedの使い方まとめ | 侍エンジニア塾ブログ(Samurai Blog)
seedsファイルのデータ投入方法について検索すると出てくる上記のリンクでは下記のようなコードを紹介しています。(例)seeds.rb2019.times do |number| Year.create(year: number) endyearsテーブルのyearカラムに0~2019年までのデータを入れるというコードです。
しかし、このコードだと0年からレコードが作られてしまいます。
僕は、ずっとこの式じゃないとデータ投入ができないという固定観念があったので、これでどうやって1900年からだけ入れればいいんだと悩みました。
しかし、seeds.rbでは普通のruby式が使えるので以下のコードでいけます(正解)seeds.rbnum = 1900 while num < 2020 Year.create(year: num) num += 1 endこれでもいけます
(正解)seeds.rb2019.times do |number| Year.create(year: number) if number >= 1900 end干支も一緒に登録する
話はミニアプリに戻りますが、当初は以下のコードでユーザーの選んだ年に対してリアクションを返そうとしていました。
js$(function(){ $(".daigo-main__year__select").on("change", function(){ //optionタグを選択すると発火 var ment = $(this).val();//値を入手 if (ment % 12 == 0) { $(".demon").text("あなたは申年ですね。これが").fadeIn(4000, function(){ $(".demon2").text("メンタリ○ムです").fadeIn(2000);//値 ÷ 12のあまりが0なら申年 }); } else if (ment % 12 == 1) { $(".demon").text("あなたは酉年ですね。これが").fadeIn(4000, function(){ $(".demon2").text("メンタリ○ムです").fadeIn(2000);//値 ÷ 12のあまりが1なら酉年 }); } else if (ment % 12 == 2) { $(".demon").text("あなたは戌年ですね。これが").fadeIn(4000, function(){ $(".demon2").text("メンタリ○ムです").fadeIn(2000);//値 ÷ 12のあまりが2なら戌年 }); } }); }); . . . .書くのがだる過ぎて干支をテーブルに登録できないか考えました。
テーブルに保存していれば下記のコードを全ての干支で使いまわせますからね。(正解)js$(function(){ $(".daigo-main__year__select").on("change", function(){ var ment = $(this).val(); $(".demon").text("あなたは"+ ment +"年ですね。これが").fadeIn(4000, function(){ $(".demon2").text("メンタリ○ムです").fadeIn(2000); }); }); });それを可能にしたのが以下のコードです。
seeds.rbnum = 1900 zyuunishi = ["申", "酉", "戌", "亥", "子", "丑", "寅", "卯", "辰", "巳", "午", "未"] while num < 2020 Year.create(year: "#{num}", eto: "#{zyuunishi[num % 12]}") num += 1 end配列の中の要素は
配列名[番号]で入手することができます。それを利用してjQuery側で行なっていた干支の仕分けを自動でしてくれるというわけです。完成!
- 投稿日:2019-08-04T17:09:07+09:00
rails config/routes.rbの基本
1. root
あるドメイン名(例えばlocalhost:3000)でアクセスしたら、指定したcontroller, action, viewに従いブラウザに表示する。
ひとつのドメインに対して一つのrootのみconfig/routes.rbRails.application.routes.draw do root 'users#index' endview : users/index.html.erb
controller : Users
action : index
url欄の表示 : localhost:3000
root_path = 'localhost:3000'
(root_pathは変数として使える)urlを打ち込みブラウザに表示するまでの流れ1 「localhost:3000」をurlで検索する 2 config/routes.rbから該当するcontroller, action, viewを読み込む 3 読み込んだcontroller(Users), action(index)で「@name='hoge'」が入る 4 読み込んだviewでcontroller, actionで設定した「@name」をブラウザ上で表示させる 1 「localhost:3000」 2 __________________ | | controller : Users |root 'users#index'| → action : index | | view : users/index.html.erb |__________________| config/routes.rb 3 _____________ | | |def index | | @name='hoge'| → @name = 'hoge' |end | | | |_____________| app/controllers/users_controller.rb 4 ____________ |<%= @name %>| | | | | | | | | |____________| app/views/users/index.html.erb ____________ | hoge | | | | | | | | | |____________| ブラウザ上の表示結果2. get
指定したview,controller,actionに従いブラウザに表示する。
rootと違い、urlの表示が「ドメイン名/???」となり、???を変えれば複数の設定が可能config/routes.rbRails.application.routes.draw do get '/index', to: 'users#index' endview : users/index.html.erb
controller : Users
action : index
url欄の表示 : localhost:3000/index
index_path = 'localhost:3000/index'
(index_pathは変数として使える)urlを打ち込みブラウザに表示するまでの流れ(ドメインの後ろに「/???」がつく所などがrootと異なる)1 「localhost:3000/index」をurlで検索する 2 config/routes.rbから該当するcontroller, action, viewを読み込む 3 読み込んだcontroller(Users), action(index)で「@name='hoge'」が入る 4 読み込んだviewでcontroller, actionで設定した「@name」をブラウザ上で表示させる 1 「localhost:3000/index」 2 _______________________________ | | controller : Users |get '/index', to: 'users#index'| → action : index | | view : users/index.html.erb |_______________________________| config/routes.rb 3 _____________ | | |def index | | @name='hoge'| → @name = 'hoge' |end | | | |_____________| app/controllers/users_controller.rb 4 ____________ |<%= @name %>| | | | | | | | | |____________| app/views/users/index.html.erb ____________ | hoge | | | | | | | | | |____________| ブラウザ上の表示結果3. post
「form_for」などでdbに新規データを保存する時に使う。(違う事を言っているかもしれません)
config/routes.rbRails.application.routes.draw do get '/users/new', to: 'users#new' post '/users', to: 'users#create' endapp/controllers/users_controller.rbclass UsersController < ApplicationController def new @user = User.new end def create user = User.new(user_params) #dbはUserテーブルでカラムがname(string), age(integer)を用意しておく user.save #本当はdbに保存する前に色々と値が正しいのかチェックしたいが今回は省略する end private def user_params params.require(:user).permit(:name, :age) end end endapp/views/users/new.html.erb<%= form_for @user do |f| %> <%= f.label :名前 %> <%= f.text_field :name %> <%= f.label :年齢 %> <%= f.number_field :age %> <%= f.submit "新規作成" %> <% end %>form_forなどでdbに新規データを保存するまでの流れ1 「localhost:3000/users/new」に移動 2 config/routes.rbから該当するgetのcontroller, action, viewを読み込む 3 getなどでform入力画面に移動(newメソッドで「@user」を作成、viewで使用する) 4 「form_for」などでフォームにデータを入力しsubmitボタンを押す(「@user」にデータを入れて投げる) 5 config/routes.rbから該当するpostのcontroller, action, (view)を読み込む 6 読み込んだcontroller(Users), action(create)に従い、投げられた「@user」データをdbに保存する 1 「localhost:3000/users/new」 2 _________________________________ | | controller : Users |get '/users/new', to: 'users#new'| → action : new | | view : users/new.html.erb |_________________________________| config/routes.rb 3 _______________ | | |def new | | @user=User.new| → @user = User.new |end | | | |_______________| app/controllers/users_controller.rb __________________ |form_for | |上を参照 | ← @user = User.new |name: | |age: | | | |__________________| app/views/users/new.html.erb 4 __________________ |form_for | |上を参照 | |name:'yamada taro'| |age:105 | → @user.name = 'yamada taro' | | @user.age = 105 |__________________| app/views/users/new.html.erb 理解していないのだが、form_forで飛ぶurlはデフォルトだと'localhos:3000/users'になるのかな 一応form_forのオプションでurlを指定も出来る。 今回は理解が出来ていないが、app/views/users/new.html.erbのform_forで飛ぶ先は'localhost:3000/users'という事で進める。 5 _________________________________ | | controller : Users |post '/users', to: 'users#create'| → action : create | | view : users/new.html.erb |_________________________________| config/routes.rb 6 _______________ | | |def create | | 上を参照 | ← @user.name = 'yamada taro' |end | @user.age = 105 | | |_______________| app/controllers/users_controller.rb ↓ @user.name = 'yamada taro' @user.age = 105 ____↓_____ | / / / / /| |/ / / / / | | / / / / /| |/ / / / / | |_/_/_/_/_/| db4. patch
dbにあるデータを変更し保存する
5. delete
dbにあるデータを削除する
- 投稿日:2019-08-04T16:17:59+09:00
Railsのビューテンプレートで使うcontent_forとyieldっぽいものを、Ruby標準のERBだけを使って自作する
まえおき
完全に自分用メモ。
80%くらい同じだけど20%くらい中身が異なるDockerfileを量産したかったので、Dockerfile.base.erbFROM <%= yield(:base_image) || 'debian:buster' %> RUN apt-get update && apt-get -y install ... RUN ... RUN ... <%= yield(:additional_install) %> USER user RUN git clone ... RUN ... ENV ... <%= yield(:additional_install_for_user) %> RUN ... RUN ... CMD ["/bin/bash", "start_server.sh"]ruby2.6/Dockerfile.binding.erb<% content_for(:base_image, 'ruby:2.6-buster') %> <% content_for(:additional_install) do %> RUN apt-get install libxslt-dev libsqlite-dev <% end %>みたいな感じのことをやりたかった。
ただ、Railsを入れるほどではないので、Rails非依存で(Ruby標準のERBだけで)サクッと自作できないかなと考えた話。
※ 結果だけを知りたい方は「まとめ」のところに一気にどうぞw
Railsの実装を参考にしてみる
content_forはどういう定義になっているかをちらっと見ると、
/actionview/lib/action_view/helpers/capture_helper.rbdef content_for(name, content = nil, options = {}, &block) if content || block_given? if block_given? options = content if content content = capture(&block) end if content options[:flush] ? @view_flow.set(name, content) : @view_flow.append(name, content) end nil else @view_flow.get(name).presence end end (中略) def content_for?(name) @view_flow.get(name).present? endテンプレートのバインディングの方で使われる
content_for(:key)は、単純に@view_flow[:key]的な場所に値を入れているだけだ。app/views/layouts/application.html.erb などテンプレート側は
yieldを使うだけなので、ブロックを何らかの形で渡してるんだろう。
https://medium.com/rubyinside/disassembling-rails-template-rendering-2-a99214c6fde8
あたりに詳しく説明があるが、template.render {|*name| ... }みたいな感じでブロックを渡しているらしい。複雑なことをしない、自分だけの yield, content_for の要件
今回の自分の用途では
- yieldは必ず1つのキーを指定される
- content_forは必ず1つのキーを指定され、valueもしくはブロックで値が指定される
- content_forを書くファイルには、content_for以外の内容は書かない
という、仕様を削ぎ落とした版のyield/content_forがあればよい。
この程度であれば、Ruby標準のERBでできそうだ。
実コードでいうと
冒頭で書いた
Dockerfile.base.erbruby2.6/Dockerfile.binding.erbを読み込んで、以下のようなRubyスクリプトでいい感じに ruby2.6/Dockerfile ができればいい。generate_dockerfile.rbrequire 'erb' def apply_template(template_erb, binding_erb) # どう書く? end template_erb = ERB.new(File.read("Dockerfile.base.erb")) # yield指定がある binding_erb = ERB.new(File.read("ruby2.6/Dockerfile.binding.erb")) # content_for指定のみがある dockerfile = apply_template(template_erb, binding_erb) File.write("ruby2.6/Dockerfile", dockerfile)さて、apply_templateをどうすればいいんだ?というのがこの記事の本題。
実装するぞ
binding_erbにあるcontent_forの内容をどこかの変数に一時的に持っておく
Railsだとcapture_helper.rbで
@view_flowに保持していた。https://magazine.rubyist.net/articles/0017/0017-BundledLibraries.html をみるとなんとなく想像がつくが、ERBのバインディングはresultメソッドを叩いたその瞬間の評価コンテキストで行われる。(内部でevalをしているだけ)
なので、binding_erb.resultを呼ぶ時には、そこから見える場所にcontent_forメソッドが定義されている必要がある。すっっごい雑にやるなら、
generate_dockerfile.rbdef content_for(key, value = nil) @binding_values[key] = block_given? ? yield : value end def apply_template(template_erb, binding_erb) @binding_values = {} binding.erb.result(binding) puts @binding_values # => { "base_image" => "ruby:2.6-buster", "additional_install" => "..." } endこんな感じで、メソッドをもう1つ生やしてみるとよい。中身は、一時的なインスタンス変数にcontent_forで指定されたものをつっこむだけ。
(よいこのみんなはちゃんとクラス化して、プライベートメソッドで content_for を定義しましょう)
template_erbのyield呼び出し時に、保持していた値を入れ込む
template_erb側で
<%= yield(:hoge) %>のような指定があった際に、
@binding_values[:hoge]を入れ込むようにする必要がある。そもそもyieldってなんだっけ?というところがキモなのだが、雑に言うと「ブロックを評価せよ」という命令だ。
yielddef aaa(x) puts x, yield(:hoge) end data={hoge: 3, fuga: 4} aaa(1) do |key| data[key] end # => 1, 3
さて、今回は何にブロックを渡せばいいんだっけ?ということになるが、
template_erb.result(binding) do |key| @binding_values[key] endこれでいけるかな?と最初思ってやってみたんだけど、これではうまくいかない。
先にも書いたとおり、ERB#resultは内部的には単なるevalなので、resultを叩いた時点でブロックが見える必要がある、つまり極端に書くとyield(:hoge) #template_erb.result(binding)このyield指定でも正しく動かないといけない。
そう、正解は
generate_dockerfile.rbdef content_for(key, value = nil) @binding_values[key] = block_given? ? yield : value end def bind_to_template(template_erb) # templateの中でyieldされると、bind_to_templateに渡されたブロックが評価される template_erb.result(binding) end def apply_template(template_erb, binding_erb) @binding_values = {} binding.erb.result(binding) bind_to_template(template_erb) do |key| @binding_values[key] end endだ。
まとめ
ここまでの内容だとまとまらないので、一応クラス化しとこうと思う。
template_binder.rbrequire 'erb' class TemplateBinder def initialize(template_erb_string:, binding_erb_string:) template_erb = ERB.new(template_erb_string) binding_erb = ERB.new(binding_erb_string) evaluate_binding(binding_erb) @result = evaluate_template(template_erb) do |key| @binding_values[key] end end attr_reader :result private def content_for(key, value = nil) @binding_values[key] = block_given? ? yield.strip : value end def evaluate_binding(binding_erb) @binding_values = {} # binding_erbの中でcontent_forされたものが @binding_values に保持される binding_erb.result(binding) end def evaluate_template(template_erb) # template_erb の中でyieldされると、evaluate_templateに渡されたブロックが評価される。 template_erb.result(binding) end endこんなクラスを1つ用意しておけば、
template = 'var1=[<%= yield(:var1) %>], var2=[<%= yield(:var2)%>]' binding1 = <<~ERB <% content_for(:var1, 3) %> ERB binding2 = <<~ERB <% content_for(:var1) do %> hoge <% end %> <% content_for(:var2, :fuga) %> ERB TemplateBinder.new( template_erb_string: template, binding_erb_string: binding1 ).result # => var1=[3], var2=[] TemplateBinder.new( template_erb_string: template, binding_erb_string: binding2 ).result # => var1=[hoge], var2=[fuga]こんな感じで超簡易版 yield / content_for ができる。
- 投稿日:2019-08-04T16:07:48+09:00
本番環境でCarrierWaveでS3にアップロードした画像が表示されない時の対処
簡単なチャットアプリケーションを開発する学習で
Rails、Heroku、CarriaWave 、S3を使用して画像をアップロードした際に
以下のようになり、画像が正しく表示されませんでした
対処した時のことを忘れないように、記事を投稿したいと思います。原因を探ってみる
まずは、そもそも画像がAmazon S3の管理画面にアップロードできているのかを確認
問題なくアップロードされていました。
ファイルの記述方法は間違っていないかを確認
carrierwave.rbrequire 'carrierwave/storage/abstract' require 'carrierwave/storage/file' require 'carrierwave/storage/fog' CarrierWave.configure do |config| config.storage = :fog config.fog_provider = 'fog/aws' config.fog_credentials = { provider: 'AWS', aws_access_key_id: Rails.application.secrets.aws_access_key_id, aws_secret_access_key: Rails.application.secrets.aws_secret_access_key, region: 'ap-northeast-1' } config.fog_directory = 'バケット名' config.asset_host = 'https://s3-ap-northeast1.amazonaws.com/バケット名' endんー、カリキュラムの指示通りかけてるな
どこが悪いのかさっぱり!
解決方法
キーワードを変えながら検索をしていると同じような問題を書いてあるページを発見しました。
読んでみると、
「原因はconfig/initializers/carrierwave.rb内の、urlの指定が間違っていたからでした。以下のように asset_hostのurlの指定を修正すると、無事にストレージから画像を取得できました。」
(https://remonote.jp/rails-production-carrierwave-s3-error より引用)carrierwave.rbの書き方ミスとのこと
カリキュラムの書き方を信じるのもよくないですな
以下のようにコードを修正しましたcarrierwave.rbrequire 'carrierwave/storage/abstract' require 'carrierwave/storage/file' require 'carrierwave/storage/fog' CarrierWave.configure do |config| config.storage = :fog config.fog_provider = 'fog/aws' config.fog_credentials = { provider: 'AWS', aws_access_key_id: Rails.application.secrets.aws_access_key_id, aws_secret_access_key: Rails.application.secrets.aws_secret_access_key, region: 'ap-northeast-1' } config.fog_directory = 'バケット名' config.asset_host = 'https://s3-ap-northeast1.amazonaws.com/バケット名' #url間違い config.asset_host = 'https://バケット名.s3.amazonaws.com' #このように修正ふぅ・・なんとかなりました
最後に
いかがでしたでしょうか?
初投稿なので読みづらかったり分かりづらい点もあるかと思います。
コードの書き方は変わっていくので常に追っていかないといけないなと改めて思いました
同じエラーで悩んでいる人の助けになれたらいいなと思います参考元
「本番環境でCarrierWaveでS3にアップロードした画像が表示されない問題」の対処
https://remonote.jp/rails-production-carrierwave-s3-error
- 投稿日:2019-08-04T15:19:51+09:00
Rspecメモ
Rspecとは
RubyでBDD(振舞駆動開発)を実施するためのテストフレームワーク。
そもそもBDD(振舞駆動開発)とは
振舞とは?
ユーザーの操作によって実行されるソフトウェアの処理であり機能。
つまり、対象における「外部から見える変化」「入力・出力」「オブジェクトのメッセージ」などの「対象における何らかのイベントにひも付く外部から見える変化」であると言える。振る舞いをテストしている」とは何か
上記のような、「対象オブジェクトにおけるメソッドの組み合わせによって外部から見える変化を記述している」、「対象がどのように何をするかを記述している」、「コミュニケーションパターンを記述している」など例で言い換えると「ある人物について個々の動作を独立に説明しているけれど、その人物を特徴付ける一連の行動を説明していない」と言い換えることができる。
RSpecとMiniTestの違い
Rspecの特徴
- DSLで記述→ロジックの自由度が低い
- 学習コストが高い
- 採用している企業が多い
- 情報が豊富
- 最初からさまざまな機能が入っていて便利
MiniTestの特徴
- 純粋なRubyで記述→言語機能が使えるため自由度が高い
- 学習コストが低い
- Rails標準のテストフレームワーク
- 採用している企業が少ない
- 実行速度が早い
- 複雑なテストを行う場合、多くのプラグインが必要となる
主なテストの種類
Modelテスト
- モデルの状態が有効になっているか。
- バリデーションが効いているか。
- クラスメソッドとインスタンスメソッドの動作。
System テスト
- Rails 5.1から使用可能となった統合テスト。
- Feature テストと役割は同じだがテスト失敗時スクショを撮影するgemのインストールが不要。
- driven_byを使って、specごとにブラウザを簡単に切り替えることができる。
- テスト終了時にDBが自動的にロールバックされる
Request(結合) テスト
- ルーティングを含めたコントローラー、モデル、ビューを通したテストを行う。また、リクエストに対して正しいレスポンスが返されることを確認する。
その他のテストは利用頻度が少なかったり上記のテストに置き換えが推薦されていたりするので割愛。
コードの基本形
describe [仕様を記述する対象(テスト対象)], type: [Specの種類] do context [ある状況・状態] do before do [事前準備] end it [仕様の内容(期待の概要)] do [期待する動作] end end end
- テストを整理・分類する・・describe,context
テストコードを実行する・・before、it
before
- 何を記述しようとしているのかを記述
context
- テストの内容を「状況・状態」のバリエーションごとに分類する
it
- 期待する動作を文章と、ブロック内のコードで記述
(参考)
https://www.atmarkit.co.jp/ait/articles/1404/30/news022.htmlhttps://qiita.com/umeziro_v2/items/edd7df47a5aa378af721#_reference-e2a604932337f846bc8e
- 投稿日:2019-08-04T11:36:54+09:00
if文をunlessを用いて書き換える
「if」
if a + b > 0 puts "計算結果は0より大きいです" end「unless」
unless a + b <= 0 puts "計算結果は0より大きいです" end
- 投稿日:2019-08-04T11:16:35+09:00
rails generate react:install実行時のrun() in thread failed: inotify event queue has overflowed対応
現象
rails webpacker:installを実行するとrun() in thread failed: inotify event queue has overflowedと表示される。
app/assets/javascripts/application.jsが作成されない。環境
docker-composeでruby:2.6.3をベースに構築。
対応
方法その1.Dockerの設定を変更する。
環境設定→AdvancedのCPUs,Memory,Swapの値を増加する。
方法その2.コンテナ内のファイル以下の記述を追加しsysctl設定にロードする。
/etc/sysctl.conffs.inotify.max_user_watches = 999999 fs.inotify.max_queued_events = 999999 fs.inotify.max_user_instances = 999999以下のコマンドを実行
sudo sysctl -p補足:以下のエラーが表示される場合、privilegedでコンテナを起動する必要がある。
sysctl: setting key "fs.inotify.max_user_watches": Read-only file systemprivilegedを以下の通り記載してコンテナを起動し、再度コンテナ内でsudo sysctl -pを実行する。
docker-compose.ymlversion: '3' services: web: privileged: true結果
rails generate react:installでエラーが出ず、正しくapp/assets/javascripts/application.jsが作成される!
参考にさせていただいたサイト
https://github.com/guard/listen/wiki/Increasing-the-amount-of-inotify-watchers
https://github.com/guard/rb-inotify/issues/61
https://qiita.com/osamunmun/items/1786aac5904439522d72
- 投稿日:2019-08-04T11:07:53+09:00
rails bootstrap Paginationの基本
■ 環境
- windows 8.1
- Rails 5.1.6
- ruby 2.3.3p222 (2016-11-21 revision 56859) [i386-mingw32]
- Bundler version 1.15.3
Gemfileに以下を追加
Gemfilegem 'will_paginate', '3.1.6' gem 'bootstrap-will_paginate', '1.0.0'$ bundle update $ bundle installapp/controllers/Users_controller.rbclass UsersController < ApplicationController def index @users = User..paginate(page: params[:page], per_page: 5) #per_pageで1ページに表示可能な個数を指定できる end endapp/views/users/index.html.erb<!-- 上で設定した@usersを使い表示させる --> <% @users.each do |user| %> <p><%= link_to user.name, user %></p> <% end %> <%= will_paginate %> <!-- ↓ will_paginateを少しいじる。詳しくは参照2に行くと良い--> <% @users.each do |user| %> <p><%= link_to user.name, user %></p> <% end %> <%= will_paginate @users, previous_label: '< 前へ', next_label: '次へ >' %>参照
- 投稿日:2019-08-04T10:45:51+09:00
【Sinatra】サーバを再起動せずにコードの更新を行う
sinatraで、コードを変更した際にサーバを再起動しないとコードの変更が反映されません。面倒くさいさいですよね。
ということで、自動でコードの変更がが反映されるようにしましょう!
※参考
https://codingcast.techdrive.top/sinatra/bundler/
https://qiita.com/k-ta-yamada/items/9e35c5f8b31862267e01*windows10環境を使用しています。
Gemファイルの作成
アプリを作成しているディレクトリまで移動してください。
そこでGemファイルの作成を行います。$ bundle initでGemファイルが作成されます。
windows環境ではGemファイルは隠しファイルになってるので、隠しファイルの表示を行いましょう。
フォルダのエクスプローラの「表示」オプションから隠しフォルダの設定の変更を行うことが出来ます。表示オプションを選択後、「隠しファイル、隠しフォルダー、および隠しドライブを表示する」を選択後、OKを押します。
Gemファイルの編集
次にGemファイルの編集を行います。
Gemfile.source 'http://rubygems.org' gem 'sinatra' gem 'sinatra-reloader'sinatraとsinatraリローダーを表記しています。
アプリのファイルの編集
myapp.rbrequire 'rubygems' require 'bundler' Bundler.requireこちらの表記をアプリに対して行います。
こう記述することによって、Gemファイルに記述されている内容を持ってくることができ、require~を書かなくて済むようになります。
もう一度
bundle installを実施します。これでコードの編集時にサーバを再起動しなくても、コードの変更が自動で反映されます。
- 投稿日:2019-08-04T09:06:19+09:00
Rails ルーティングの基礎とRESTful
はじめに
Railsのルーティングについて調べましたので、まとめようと思います。
Railsのルーティングについて一気にまとめてしまうと長くなってしまいますので、
今回は
- Railsのルーティングの基礎
- RESTful
に絞りました。
ルーティングの基礎
ルーティングとは
リクエストのURLに応じて、どの処理を実行するかを決定するしくみを指します。
Railsの場合、次の手順で実行するコントローラとアクションを決定します。
- クライアントがリクエストを送る
- パスを解析し、ルート定義を検索する
- 検索されたルート定義に基づいて対応するコントローラ、アクションを呼び出す
ルーティングの設定
ルーティングの設定は/config/routes.rbに定義します。
routes.rbRails.application.routes.draw do get 'members' => 'members#index' endこれは
リクエストのURLの末尾がmembersだった場合 =>
membersコントローラのindexアクションを呼び出す
と定義しています。ルーティングとコントローラの設定例
例えば、次のコントローラとアクションを定義して
members_controller.rbclass MembersController < ApplicationController def index end end次のルーティングを定義して
routes.rbRails.application.routes.draw do get 'members' => 'members#index' end次のリクエストを送信すると
※ http://localhost:3000/の部分はホスト名で、Railsのデフォルトポートは3000です。http://localhost:3000/membersMembersコントローラのindexアクションが呼ばれます。
RESTful
Railsのルート設計
RESTの性質を持つルート設計のことをRESTfulと言います。
Railsのルート設計はRESTfulです。
※ RESTfulでないルート設計も可能です。しかしRailsにはRESTfulなルート設計が前提の機能も存在するため、注意が必要です。RESTとは
以下の原則に沿った Webサービスの設計モデルを指します。
- セッションなどの状態管理を行わない
- 情報を操作する命令が体系化されて定義・共有される
- 情報に対して汎用的な構文で一意に識別される
- 情報に、別の情報や別の状態へのリンクを含めることができる
一つ一つ具体的にまとめてみます。
セッションなどの状態管理を行わない
クライアントの送信する情報には、全てのやりとりが含まれています。
サーバはクライアントの状態を保持しません。
このようなクライアントとサーバのやりとりはステートレスと言われます。
逆に状態を保持する場合はステートフルと言われます。例としてECサイトで買い物する場合
ステートフルの場合
1. 商品Aをカートに入れる
2. 商品Bをカートに入れる
3. カート内の商品を購入ステートレスの場合
1. 商品Aをカートに入れる
2. 商品Aと商品Bをカートに入れる
3. カート内の商品を購入ステートフルの場合、サーバ側でカートに入れた商品の状態を保持しているため、クライアントは追加する商品の情報のみ送信します。
ステートレスの場合、サーバ側でカートの状態を保持していないため、クライアントは送信する情報にすべてのやりとりを含める必要があります。情報を操作する命令が体系化されて定義・共有される
なに(リソース)に対してどうするか(HTTPメソッド)でルート定義を設定すること
HTTPメソッドとはクライアントがサーバに対して出す依頼のことで、主に次のようなものがあります。
- GET:取得
- POST:作成
- PUT:更新
- PATCH:部分更新
- DELETE:削除
リソースとはユーザ情報や画像データなど、情報全般のことを指します。
例えば以下のルーティングの場合
routes.rbRails.application.routes.draw do get 'members' => 'members#index' endMembers(リソース)をGET(取得)するとルート設計しています。
情報に対して汎用的な構文で一意に識別される
すべてのリソースはURIで識別されるということです。
情報に、別の情報や別の状態へのリンクを含めることができる
ハイパーテキスト(他の文書への参照を埋め込める)を拡張したハイパーメディア(文字情報に加え、画像や音声などの情報を扱えるようにし、対応づけたもの)を使おうということです。
ハイパーメディアを用いることで、現在のアプリケーションの状態や、違う情報へのリンクなどを表現します。メリット
- ステートレスなため、サーバ側の負荷が少ない
- HTTP標準のメソッドを使用することで、一貫性のあるルートを設計できる
- URIに規則が生まれるため、アプリ開発者はリソースを管理しやすい
おわりに
RailsのルーティングとRESTfulについてまとめました。
間違っているところなどがありましたら、教えていただけるとありがたいです。

































