- 投稿日:2020-01-18T23:58:49+09:00
独学ではじめてAWS(EC2)にデプロイする方法⑩(macでNginxのインストールと設定)
Nginx
Webサーバの一種であるNginxの導入と設定を行います。
nginxは静的コンテンツ(つまりサーバ上のファイル)を高速に配信するように設計されている。
ユーザーのリクエストに対して静的コンテンツの取り出し処理を行い、そして動的コンテンツの生成をアプリケーションサーバに依頼することが可能Nginxをインストール
下記のコマンドでインストール
[ec2-user@ip-172-31-25-189 ~]$ sudo yum -y install nginxNginxの設定ファイルを編集
[ec2-user@ip-172-31-25-189 ~]$ sudo vim /etc/nginx/conf.d/rails.conf下記を貼り付ける
(ディレクトリの場所などは、自分にあった場所を指定してください)rails.confupstream app_server { # Unicornと連携させるための設定。 # アプリケーション名を自身のアプリ名に書き換えることに注意。今回であればおそらく server unix:/var/〇〇〇(アプリをまとめているディレクトリ)/〇〇〇〇〇〇<アプリケーション名>/tmp/sockets/unicorn.sock; } # {}で囲った部分をブロックと呼ぶ。サーバの設定ができる server { # このプログラムが接続を受け付けるポート番号 listen 80; # 接続を受け付けるリクエストURL ここに書いていないURLではアクセスできない server_name 18.〇〇〇.〇〇〇.〇〇(Elastic IP); # クライアントからアップロードされてくるファイルの容量の上限を2ギガに設定。デフォルトは1メガなので大きめにしておく client_max_body_size 2g; # 接続が来た際のrootディレクトリ root /var/www/〇〇〇〇〇<アプリケーション名>/public; # assetsファイル(CSSやJavaScriptのファイルなど)にアクセスが来た際に適用される設定 location ^~ /assets/ { gzip_static on; expires max; add_header Cache-Control public; } try_files $uri/index.html $uri @unicorn; location @unicorn { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_redirect off; proxy_pass http://app_server; } error_page 500 502 503 504 /500.html; }
- 3行目の<アプリケーション名> となっている箇所は、ご自身のものに変更してください。
- 11行目の<Elastic IP>となっている箇所も同様に、ご自身のものに変更してください。
- 14行目の<アプリケーション名> となっている箇所は、ご自身のものに変更してください。
Nginxの権限を変更
POSTメソッドでもエラーが出ないようにするために、下記のコマンドも実行してください。
[ec2-user@ip-172-31-25-189 ~]$ cd /var/lib [ec2-user@ip-172-31-25-189 lib]$ sudo chmod -R 775 nginxNginxを再起動して設定ファイルを再読み込み
[ec2-user@ip-172-31-25-189 lib]$ cd ~ [ec2-user@ip-172-31-25-189 ~]$ sudo service nginx restartローカルでunicorn.rb修正
listen 3000 ↓以下のように修正 listen "#{app_path}/tmp/sockets/unicorn.sock"Githubで変更点をpushしたら、本番環境でも反映させます。
ターミナル(EC2)[ec2-user@ip-172-31-25-189 ~]$ cd /var/www/アプリ名 [ec2-user@ip-172-31-23-189 <アプリ名>]$ git pull origin masterUnicornを再起動
[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ ps aux | grep unicorn ec2-user 17877 0.4 18.1 588472 182840 ? Sl 01:55 0:02 unicorn_rails master -c config/unicorn.rb -E production -D ec2-user 17881 0.0 17.3 589088 175164 ? Sl 01:55 0:00 unicorn_rails worker[0] -c config/unicorn.rb -E production -D ec2-user 17911 0.0 0.2 110532 2180 pts/0 S+ 02:05 0:00 grep --color=auto unicorn続いて、unicorn_rails master(一番上)のプロセスをkillします。
[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ kill <確認したunicorn rails masterのPID(上のコードでは17877)>unicornを起動します
[ec2-user@ip-172-31-23-189 <アプリ名>]$ RAILS_SERVE_STATIC_FILES=1 unicorn_rails -c config/unicorn.rb -E production -DブラウザからElastic IPでアクセス
https:// (Elastic IP)
これでサイトが表示されず、下記が表示されたら、、、、、、、、、
もう一度、下記をやり直してください。
Nginxの設定ファイルを編集
[ec2-user@ip-172-31-25-189 ~]$ sudo vim /etc/nginx/conf.d/rails.conf下記を貼り付ける
(ディレクトリの場所などは、自分にあった場所を指定してください)rails.confupstream app_server { # Unicornと連携させるための設定。 # アプリケーション名を自身のアプリ名に書き換えることに注意。今回であればおそらく server unix:/var/〇〇〇(アプリをまとめているディレクトリ)/〇〇〇〇〇〇<アプリケーション名>/tmp/sockets/unicorn.sock; } # {}で囲った部分をブロックと呼ぶ。サーバの設定ができる server { # このプログラムが接続を受け付けるポート番号 listen 80; # 接続を受け付けるリクエストURL ここに書いていないURLではアクセスできない server_name 18.〇〇〇.〇〇〇.〇〇(Elastic IP); # クライアントからアップロードされてくるファイルの容量の上限を2ギガに設定。デフォルトは1メガなので大きめにしておく client_max_body_size 2g; # 接続が来た際のrootディレクトリ root /var/www/〇〇〇〇〇<アプリケーション名>/public; # assetsファイル(CSSやJavaScriptのファイルなど)にアクセスが来た際に適用される設定 location ^~ /assets/ { gzip_static on; expires max; add_header Cache-Control public; } try_files $uri/index.html $uri @unicorn; location @unicorn { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_redirect off; proxy_pass http://app_server; } error_page 500 502 503 504 /500.html; }これで無事にサイトが表示されたら、完了です!
- 投稿日:2020-01-18T23:31:36+09:00
AWS(EC2)でNginxのrails.confを設定する方法
AWSのNginxを設定する際に、rails.confファイルの設定をします。
この方法の説明が意外とないので、説明していきます
Nginxの設定ファイルを編集
[ec2-user@ip-172-31-25-189 ~]$ sudo vim /etc/nginx/conf.d/rails.confrails.confファイルが開かれたら、下記の記述をします。
rails.confupstream app_server { # Unicornと連携させるための設定。 # アプリケーション名を自身のアプリ名に書き換えることに注意。 server unix:/var/〇〇〇(アプリをまとめているディレクトリ)/〇〇〇〇〇〇<アプリケーション名>/tmp/sockets/unicorn.sock; } # {}で囲った部分をブロックと呼ぶ。サーバの設定ができる server { # このプログラムが接続を受け付けるポート番号 listen 80; # 接続を受け付けるリクエストURL ここに書いていないURLではアクセスできない server_name 18.〇〇〇.〇〇〇.〇〇(Elastic IP); # クライアントからアップロードされてくるファイルの容量の上限を2ギガに設定。デフォルトは1メガなので大きめにしておく client_max_body_size 2g; # 接続が来た際のrootディレクトリ root /var/www/〇〇〇〇〇<アプリケーション名>/public; # assetsファイル(CSSやJavaScriptのファイルなど)にアクセスが来た際に適用される設定 location ^~ /assets/ { gzip_static on; expires max; add_header Cache-Control public; } try_files $uri/index.html $uri @unicorn; location @unicorn { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_redirect off; proxy_pass http://app_server; } error_page 500 502 503 504 /500.html; }3行目の<アプリケーション名> となっている箇所は、ご自身のものに変更してください。
11行目の<Elastic IP>となっている箇所も同様に、ご自身のものに変更してください。
14行目の<アプリケーション名> となっている箇所は、ご自身のものに変更してください。これで設定ができます。
- 投稿日:2020-01-18T21:58:20+09:00
ActiveRecord::AdapterNotSpecified: 'production' database is not configured. が表示された場合
アセットコンパイル時に下記を実行するが
ターミナル(EC2)[ec2-user@ip-172-31-23-189 <アプリ名>]$ rails assets:precompile RAILS_ENV=productionこの際にエラーが表示される場合がある。
エラーが出る場合
ActiveRecord::AdapterNotSpecified: 'production' database is not configured. Available: ["default", "development", "test", "database", "username", "password", "socket"]下記を修正してください
database.yamlに『 <<: *default 』を追記する
(もともとあるが、いらないだろうと思い消してしまうとエラーが表示される)config/database.ymlproduction: <<: *default # ここが抜けているはず database: <%= Rails.application.credentials.db[:database] %> username: <%= Rails.application.credentials.db[:username] %> password: <%= Rails.application.credentials.db[:password] %> socket: <%= Rails.application.credentials.db[:socket] %>追記したらpullして更新しましょう
ターミナル(EC2)[ec2-user@ip-172-31-23-189 <アプリ名>] git pull origin master再度
ターミナル(EC2)[ec2-user@ip-172-31-23-189 <アプリ名>]$ rails assets:precompile RAILS_ENV=production今度は成功するはずです
- 投稿日:2020-01-18T20:25:25+09:00
データベースのリセット方法
- 投稿日:2020-01-18T20:23:04+09:00
Can't connect to local MySQL server through socket '/tmp/mysql.sock'が表示された場合
AWSのEC2にデプロイしようとした際に、下記エラーが表示された場合の対処方法をまとめたいと思います。
『Can't connect to local MySQL server through socket '/tmp/mysql.sock'』原因
問題点としては、下記のsocketに接続できないのが問題
credentials.ymldb: database: アプリ名 username: root password: 設定したPW socket: /var/lib/mysql/mysql.sock #ここに接続ができないmysqlを再起動すると、/var/lib/mysql/mysql.sockが自動的に作成されるので、起動
Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
1) MySQLの起動確認
Mysql2::Error: Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock'というエラーが起こった場合、mysqlが起動していない可能性があります。ターミナル(EC2)sudo service mysqld start #再起動をさせたい場合は、 sudo service mysqld restart改善があるか?確認
Can't connect to local MySQL server through socket '/tmp/mysql.sock' (13)
database.ymlとcredentials.ymlの中身に漏れがないか確認をしてください
database.ymlにsocketの記述漏れがあれば、エラーがおきますcredentials.ymldb: database: アプリ名 username: root password: 設定したPW socket: /var/lib/mysql/mysql.sockconfig/database.ymlproduction: database: <%= Rails.application.credentials.db[:database] %> username: <%= Rails.application.credentials.db[:username] %> password: <%= Rails.application.credentials.db[:password] %> socket: <%= Rails.application.credentials.db[:socket] %> #ここのsocketが抜けていないか???
- 投稿日:2020-01-18T20:23:04+09:00
Can't connect to local MySQL server through socket '/tmp/mysql.sock'が表示された場合(本番環境)
AWSのEC2にデプロイしようとした際に、下記エラーが表示された場合の対処方法をまとめたいと思います。
『Can't connect to local MySQL server through socket '/tmp/mysql.sock'』原因
問題点としては、下記のsocketに接続できないのが問題
credentials.ymldb: database: アプリ名 username: root password: 設定したPW socket: /var/lib/mysql/mysql.sock #ここに接続ができないmysqlを再起動すると、/var/lib/mysql/mysql.sockが自動的に作成されるので、起動
Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
1) MySQLの起動確認
Mysql2::Error: Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock'というエラーが起こった場合、mysqlが起動していない可能性があります。ターミナル(EC2)sudo service mysqld start #再起動をさせたい場合は、 sudo service mysqld restart改善があるか?確認
Can't connect to local MySQL server through socket '/tmp/mysql.sock' (13)
database.ymlとcredentials.ymlの中身に漏れがないか確認をしてください
database.ymlにsocketの記述漏れがあれば、エラーがおきますcredentials.ymldb: database: アプリ名 username: root password: 設定したPW socket: /var/lib/mysql/mysql.sockconfig/database.ymlproduction: database: <%= Rails.application.credentials.db[:database] %> username: <%= Rails.application.credentials.db[:username] %> password: <%= Rails.application.credentials.db[:password] %> socket: <%= Rails.application.credentials.db[:socket] %> #ここのsocketが抜けていないか???
- 投稿日:2020-01-18T19:18:22+09:00
rails5.2のmaster.keyを本番環境(AWS EC2)に設定する方法
master.keyを作成していないとどうなるのか?
master.keyを本番環境で設定しておかなければ、rails db:create RAILS_ENV=productionなどを実行した際にエラーが表示される。
rails db:create RAILS_ENV=productionを実行
$ rails db:create RAILS_ENV=productionするとエラーが表示される
rails aborted! NoMethodError: Cannot load database configuration: undefined method `[]' for nil:NilClassこの'[]'はdatabase.ymlの下記が読み込めないために発生する。
database.ymlproduction: <<: *default database: <%= Rails.application.credentials.db[:database] %> username: <%= Rails.application.credentials.db[:username] %> password: <%= Rails.application.credentials.db[:password] %> socket: <%= Rails.application.credentials.db[:socket] %>'[]'は、[:database]、[:username]、[:password]、[:socket]が読み込めないことを意味している。
なぜ読み込めないのか?
credential.ymlの中身は他の人が閲覧できないように暗号化されている。
この暗号化を解除するのがmaster.key。
master.keyは扉を開ける鍵の役割をしており、鍵を使って解除しなければ、その先のデータを読み込むことができない。これは、本番環境でも同じです。
master.keyがなければ、暗号化を解除できないので、環境変数を読み込めずエラーとなる。本番環境のshared/configにmaster.keyを作成
ローカル環境にある,master.keyの中身を確認する
rails newで作成された、ローカルのmaster.keyを確認する。
$ vi config/master.keyすると下記のようにmaster.keyの中身が表示されます。
fadfdfdgaf44623535y....この表示された、master.keyの値をコピーしましょう
表示されたmaster.keyをコピーします。
これを本番環境で貼り付けていきます。本番環境でmaster.keyを作成
EC2のアプリのconfigを開きましょう
#本番環境 [ec2-user@ip-172-31-23-189 ~]$ cd /var/ここはそれぞれ違います/[アプリ名] [ec2-user@ip-172-31-23-189 <アプリ名>]$ cd configそうしたら、本番環境上でmaster.keyを作成します
[ec2-user@ip-172-31-23-189 config]$ vi master.key # ローカル環境のmaster.keyの値を入力 fsdgagaf08deg424~~~~~画像だと下記のような画面になります。
『 i 』を押すと----INSERT-----と表示がされて、文字入力ができます。
ここにコピーしたローカルのmaster.keyの値を貼り付けします。『 esc 』ボタンを押した後、:wq入力して保存します
これで本番環境でもmaster.keyが設定されています。
- 投稿日:2020-01-18T19:18:22+09:00
【rails5.2】master.keyを本番環境(AWS EC2)に設定する方法
master.keyを作成していないとどうなるのか?
master.keyを本番環境で設定しておかなければ、rails db:create RAILS_ENV=productionなどを実行した際にエラーが表示される。
rails db:create RAILS_ENV=productionを実行
$ rails db:create RAILS_ENV=productionするとエラーが表示される
rails aborted! NoMethodError: Cannot load database configuration: undefined method `[]' for nil:NilClassこの'[]'はdatabase.ymlの下記が読み込めないために発生する。
database.ymlproduction: <<: *default database: <%= Rails.application.credentials.db[:database] %> username: <%= Rails.application.credentials.db[:username] %> password: <%= Rails.application.credentials.db[:password] %> socket: <%= Rails.application.credentials.db[:socket] %>'[]'は、[:database]、[:username]、[:password]、[:socket]などの環境変数が読み込めないことを意味している。
なぜ読み込めないのか?
credential.ymlの中身は他の人が閲覧できないように暗号化されている。
この暗号化を解除するのがmaster.key。
master.keyは扉を開ける鍵の役割をしており、鍵を使って解除しなければ、その先のデータを読み込むことができない。これは、本番環境でも同じです。
master.keyがなければ、暗号化を解除できないので、環境変数を読み込めずエラーとなる。本番環境のshared/configにmaster.keyを作成
ローカル環境にある,master.keyの中身を確認する
rails newで作成された、ローカルのmaster.keyを確認する。
$ vi config/master.keyすると下記のようにmaster.keyの中身が表示されます。
fadfdfdgaf44623535y....この表示された、master.keyの値をコピーしましょう
表示されたmaster.keyをコピーします。
これを本番環境で貼り付けていきます。本番環境でmaster.keyを作成
EC2のアプリのconfigを開きましょう
#本番環境 [ec2-user@ip-172-31-23-189 ~]$ cd /var/ここはそれぞれ違います/[アプリ名] [ec2-user@ip-172-31-23-189 <アプリ名>]$ cd configそうしたら、本番環境上でmaster.keyを作成します
[ec2-user@ip-172-31-23-189 config]$ vi master.key # ローカル環境のmaster.keyの値を入力 fsdgagaf08deg424~~~~~画像だと下記のような画面になります。
『 i 』を押すと----INSERT-----と表示がされて、文字入力ができます。
ここにコピーしたローカルのmaster.keyの値を貼り付けします。『 esc 』ボタンを押した後、:wq入力して保存します
これで本番環境でもmaster.keyが設定されています。
- 投稿日:2020-01-18T19:18:22+09:00
【rails5.2】master.keyを本番環境(AWS EC2)に設定(追加作成)する方法
master.keyを作成していないとどうなるのか?
master.keyを本番環境で設定しておかなければ、rails db:create RAILS_ENV=productionなどを実行した際にエラーが表示される。
rails db:create RAILS_ENV=productionを実行
$ rails db:create RAILS_ENV=productionするとエラーが表示される
rails aborted! NoMethodError: Cannot load database configuration: undefined method `[]' for nil:NilClassこの'[]'はdatabase.ymlの下記が読み込めないために発生する。
database.ymlproduction: <<: *default database: <%= Rails.application.credentials.db[:database] %> username: <%= Rails.application.credentials.db[:username] %> password: <%= Rails.application.credentials.db[:password] %> socket: <%= Rails.application.credentials.db[:socket] %>'[]'は、[:database]、[:username]、[:password]、[:socket]などの環境変数が読み込めないことを意味している。
なぜ読み込めないのか?
credential.ymlの中身は他の人が閲覧できないように暗号化されている。
この暗号化を解除するのがmaster.key。
master.keyは扉を開ける鍵の役割をしており、鍵を使って解除しなければ、その先のデータを読み込むことができない。これは、本番環境でも同じです。
master.keyがなければ、暗号化を解除できないので、環境変数を読み込めずエラーとなる。本番環境のshared/configにmaster.keyを作成
ローカル環境にある,master.keyの中身を確認する
rails newで作成された、ローカルのmaster.keyを確認する。
$ vi config/master.keyすると下記のようにmaster.keyの中身が表示されます。
fadfdfdgaf44623535y....この表示された、master.keyの値をコピーしましょう
表示されたmaster.keyをコピーします。
これを本番環境で貼り付けていきます。本番環境でmaster.keyを作成
EC2のアプリのconfigを開きましょう
#本番環境 [ec2-user@ip-172-31-23-189 ~]$ cd /var/ここはそれぞれ違います/[アプリ名] [ec2-user@ip-172-31-23-189 <アプリ名>]$ cd configそうしたら、本番環境上でmaster.keyを作成します
[ec2-user@ip-172-31-23-189 config]$ vi master.key # ローカル環境のmaster.keyの値を入力 fsdgagaf08deg424~~~~~画像だと下記のような画面になります。
『 i 』を押すと----INSERT-----と表示がされて、文字入力ができます。
ここにコピーしたローカルのmaster.keyの値を貼り付けします。『 esc 』ボタンを押した後、:wq入力して保存します
これで本番環境でもmaster.keyが設定されています。
- 投稿日:2020-01-18T19:06:28+09:00
The asset "" is not present in the asset pipeline
assetへのパイプラインがうまくいってない時に起こるエラーです。
config/envitonments/production.rbで
config.assets.compile = trueをして、再起動してとりあえずうまく行かない時は、
<%= image_tag user.image.to_s %>みたいな記述をしていませんか。
特にbxsliderをお使いの初学者の方。
このままだとただの変数を入れているだけになるので
そういう場合は、<%= image_tag '/assets/user.jpg' %>みたいに「app/assets/images」ディレクトリに置いて呼び出すか。
refireのgemを使って呼び出せばうまく行きます。<%= f.attachment_field :image %>
- 投稿日:2020-01-18T18:47:34+09:00
独学ではじめてAWSのEC2にデプロイする方法⑨(Railsの起動)
ポートの解放
config/unicorn.rb に listen 3000 と記述しましたが、これはRailsのサーバを3000番ポートで起動するということを意味するのでした。
HTTPがつながるように「ポート」を開放する必要があります。手順
1.EC2を開く
2. 『実行中のインスタンス』を開く
3. インスタンスを選択
4. セキュリティグループの『launch-wizard-3』をクリック
5. 下記の画面が表示される
6.『 インバウンド 』を選択
7. 『 編集 』をクリック
8. 左下の『ルールの追加』をクリック
9. タイプ:「カスタムTCPルール」、プロトコルを「TCP」、ポート範囲を「3000」、送信元を「カスタム」「0.0.0.0/0」に設定
10. 画面左下の『 保存 』をクリックRailsの起動
Rails 5.1以前の場合
database.ymlに下記を追加します
config/database.yml(ローカル)production: <<: *default database: アプリ名 username: root password: <%= ENV['DATABASE_PASSWORD'] %> socket: /var/lib/mysql/mysql.sock追記が完了したら、EC2でも反映させます。
EC2とGithubは接続できているため、git pullコマンドを利用します。ターミナル(EC2)[ec2-user@ip-172-31-23-189 <アプリ名>] git pull origin masterデータベースの作成をする
ターミナル(EC2)[ec2-user@ip-172-31-23-189 <アプリ名>]$ rails db:create RAILS_ENV=production Created database '<データベース名>'アプリのディレクトリを開いてからコマンドを実行しましょう
#うまくいかない = アプリ名を指定していない [ec2-user@ip-172-31-23-189 ~( ここが指定されていない )]$ rails db:create RAILS_ENV=production Created database '<データベース名>' #アプリ名(リポジトリ)を指定しているのでちゃんと処理がされる [ec2-user@ip-172-31-23-189 <アプリ名>]$ rails db:create RAILS_ENV=production Created database '<データベース名>'rails db:migrateを実行して、migrationを完了させる。
ターミナル(EC2)[ec2-user@ip-172-31-23-189 <アプリ名>]$ rails db:migrate RAILS_ENV=productionエラーが出る場合
Mysql2::Error: Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock'というエラーが起こった場合、mysqlが起動していない可能性があります。
ターミナル(EC2)sudo service mysqld start #再起動をさせたい場合は、 sudo service mysqld restartというコマンドをターミナルから打ち込み、mysqlの起動を試してみましょう。
参考記事
Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)ユニコーンを起動
[ec2-user@ip-172-31-23-189 ~]$ cd /var/www/[リポジトリ] [ec2-user@ip-172-31-23-189 <app名>]$ bundle exec unicorn_rails -c config/unicorn.rb -E production -DRails5.2以降の場合
credentials.ymlの設定
ターミナル(ローカル)アプリ名 $ EDITOR=vim bin/rails credentials:editすると編集画面が表示されます。
しかし文字入力ができないので、
『 i 』を押して、----INSERT----モードに変更します下記を入力します。
credentials.ymldb: database: アプリ名 username: root password: 設定したPW socket: /var/lib/mysql/mysql.sockpasswordははじめてAWSでデプロイする方法⑤(EC2の環境構築、Ruby, MySQL)の『MySQLのrootパスワードの設定』で設定しています。
次に、database.ymlにcredential.ymlで設定した環境変数を記述します
config/database.ymlproduction: <<: *default database: <%= Rails.application.credentials.db[:database] %> username: <%= Rails.application.credentials.db[:username] %> password: <%= Rails.application.credentials.db[:password] %> socket: <%= Rails.application.credentials.db[:socket] %>本番環境のshared/configにmaster.keyを作成
ローカル環境にある,master.keyの中身を確認する
rails newで作成された、ローカルのmaster.keyを確認する。
$ vi config/master.keyすると下記のようにmaster.keyの中身が表示されます。
fadfdfdgaf44623535y....この表示された、master.keyの値をコピーしましょう
表示されたmaster.keyをコピーします。
これを本番環境で貼り付けていきます。本番環境でmaster.keyを作成
EC2のアプリのconfigを開きましょう
#本番環境 [ec2-user@ip-172-31-23-189 ~]$ cd /var/ここはそれぞれ違います/[アプリ名] [ec2-user@ip-172-31-23-189 <アプリ名>]$ cd shared/configそうしたら、本番環境上でmaster.keyを作成します
[ec2-user@ip-172-31-23-189 config]$ vi master.key # ローカル環境のmaster.keyの値を入力 fsdgagaf08deg424~~~~~画像だと下記のような画面になります。
『 i 』を押すと----INSERT-----と表示がされて、文字入力ができます。
ここにコピーしたローカルのmaster.keyの値を貼り付けします。『 esc 』ボタンを押した入力モードを終了
『 :wq 』入力して保存しますこれで本番環境でもmaster.keyが設定されています。
ユニコーンを起動
[ec2-user@ip-172-31-23-189 ~]$ cd /var/www/[リポジトリ] [ec2-user@ip-172-31-23-189 <app名>]$ bundle exec unicorn_rails -c config/unicorn.rb -E production -Dエラーが発生した場合
Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
Mysql2::Error: Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock'というエラーが起こった場合、mysqlが起動していない可能性があります。
ターミナル(EC2)sudo service mysqld start #再起動をさせたい場合は、 sudo service mysqld restartCan't connect to local MySQL server through socket '/tmp/mysql.sock' (13)
database.ymlとcredentials.ymlの中身に漏れがないか確認をしてください
credentials.ymldb: database: アプリ名 username: root password: 設定したPW socket: /var/lib/mysql/mysql.sockconfig/database.ymlproduction: <<: *default database: <%= Rails.application.credentials.db[:database] %> username: <%= Rails.application.credentials.db[:username] %> password: <%= Rails.application.credentials.db[:password] %> socket: <%= Rails.application.credentials.db[:socket] %> #ここのsocketが抜けていないか???サイトにアクセスしてみる
ブラウザで http://<サーバに紐付けたElastic IP>:3000/ にアクセスしてみましょう
ブラウザにCSSの反映されていない(ビューが崩れている)画面が表示されていれば成功です。アセットコンパイルする
レイアウトが崩れてしまっているでしょう。
開発中には正常に表示されていたのに、本番ではうまく表示されないのはなぜでしょうか?
これは、開発中はアクセス毎にアセットファイル(画像・CSS・JSファイルの総称)を自動的にコンパイル(圧縮)する仕組みが備わっていますが、本番モードのときにはパフォーマンスのためアクセス毎には実行されないようになっているためです。
ターミナル(EC2)[ec2-user@ip-172-31-23-189 <アプリ名>]$ rails assets:precompile RAILS_ENV=production成功した場合Yarn executable was not detected in the system. Download Yarn at https://yarnpkg.com/en/docs/install I, [2020-01-18T12:51:01.4345644 #1265] INFO -- : Writing /var/app/web-share/public/assets/member_photo_noimage_thumb-224a733c50d48aba6d9fdaded809788bbeb5ea5f6d6b8368adaebb95e58bcf53.png I, [2020-01-18T12:51:02.2615123#1265] INFO -- : Writing /var/app/appname/public/assets/application-bc071e28a78e2b63c9313afed5ad3476e00e3f0e5b12445c37214d1f1317be48.js I, [2020-01-18T12:51:02.2626434 #1265] INFO -- : Writing /var/app/appname/public/assets/application-bc071e28a78e2b63c9313afed5ad3476e00e3f0e5b12445c37214d1f1317be48.js.gz I, [2020-01-18T12:51:08.484546 #1265] INFO -- : Writing /var/app/appname/public/assets/application-8549fb9a804686e593d5c0f90a2412a39de85908e5fb58fdf6681d4b0073d891.css I, [2020-01-18T12:51:08.485454 #1265] INFO -- : Writing /var/app/appname/public/assets/application-8549fb9a804686e593d5c0f90a2412a39de85908e5fb58fdf6681d4b0073d891.css.gzエラーが出る場合
ActiveRecord::AdapterNotSpecified: 'production' database is not configured. Available: ["default", "development", "test", "database", "username", "password", "socket"]下記を修正してください
config/database.ymlproduction: <<: *default # ここが抜けているはず database: <%= Rails.application.credentials.db[:database] %> username: <%= Rails.application.credentials.db[:username] %> password: <%= Rails.application.credentials.db[:password] %> socket: <%= Rails.application.credentials.db[:socket] %>追記したら
ターミナル(EC2)[ec2-user@ip-172-31-23-189 <アプリ名>] git pull origin master再度
ターミナル(EC2)[ec2-user@ip-172-31-23-189 <アプリ名>]$ rails assets:precompile RAILS_ENV=production今度は成功するはずです
成功した場合Yarn executable was not detected in the system. Download Yarn at https://yarnpkg.com/en/docs/install I, [2020-01-18T12:51:01.4345644 #1265] INFO -- : Writing /var/app/web-share/public/assets/member_photo_noimage_thumb-224a733c50d48aba6d9fdaded809788bbeb5ea5f6d6b8368adaebb95e58bcf53.png I, [2020-01-18T12:51:02.2615123#1265] INFO -- : Writing /var/app/appname/public/assets/application-bc071e28a78e2b63c9313afed5ad3476e00e3f0e5b12445c37214d1f1317be48.js I, [2020-01-18T12:51:02.2626434 #1265] INFO -- : Writing /var/app/appname/public/assets/application-bc071e28a78e2b63c9313afed5ad3476e00e3f0e5b12445c37214d1f1317be48.js.gz I, [2020-01-18T12:51:08.484546 #1265] INFO -- : Writing /var/app/appname/public/assets/application-8549fb9a804686e593d5c0f90a2412a39de85908e5fb58fdf6681d4b0073d891.css I, [2020-01-18T12:51:08.485454 #1265] INFO -- : Writing /var/app/appname/public/assets/application-8549fb9a804686e593d5c0f90a2412a39de85908e5fb58fdf6681d4b0073d891.css.gzRailsの再起動
コンパイルが成功したら反映を確認するため、Railsを再起動します。しかし、まずは今動いているUnicornをストップします。
EC2のターミナルから以下のように入力します。「aux」と打っているのは、psコマンドのオプションです。表示結果を見やすくしてくれます。また、| grep unicornとしているのはpsコマンドの結果からunicorn関連のプロセスのみを抽出するためです。
[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ ps aux | grep unicorn ec2-user 17877 0.4 18.1 588472 182840 ? Sl 01:55 0:02 unicorn_rails master -c config/unicorn.rb -E production -D ec2-user 17881 0.0 17.3 589088 175164 ? Sl 01:55 0:00 unicorn_rails worker[0] -c config/unicorn.rb -E production -D ec2-user 17911 0.0 0.2 110532 2180 pts/0 S+ 02:05 0:00 grep --color=auto unicorn大事なのは左から2番目の列です。ここに表示されるのがプロセスのid、つまりPIDになります。
「unicorn_rails master」と表示されているプロセスがUnicornのプロセス本体です。この時のPIDは、17877となっています。[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ kill <確認したunicorn rails masterのPID>killコマンド:現在動いているプロセスを停止させるためのコマンドです
再度、プロセスを表示させ終了できていることを確認しましょう。
[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ ps aux | grep unicorn ... ec2-user 17911 0.0 0.2 110532 2180 pts/0 S+ 02:05 0:00 grep --color=auto unicorn3つあった項目が一つになっています
では、Railsを起動させましょう!
[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ RAILS_SERVE_STATIC_FILES=1 unicorn_rails -c config/unicorn.rb -E production -Dもう一度、ブラウザで http://<Elastic IP>:3000/ にアクセスしてみましょう。今度はレイアウト崩れも無くサイトが正常に表示されていることでしょう。
参考
【Rails5.2】credentials.yml.encとmaster.keyでのデプロイによる今までとの変更点
【備忘録】credentials.yml.encにdatabase設定を保存する
- 投稿日:2020-01-18T18:05:47+09:00
content_tagでmodalやリンクを表示する
はじめに
RailsでWebサービスを構築していると、フロントのコードをサーバーサイドで実装する場面ってありますよね。(あんまりないか)
Railsにはcontent_tagというメソッドが用意されていて、フロントのコードをサーバーサイドで記述することができます。content_tag
content_tagの引数は以下のように構成されています。
- 第一引数: タグ
- 第二引数: 内容
- 第三引数: クラスなどのオプション
# divタグ生成 content_tag(:div, 'hoge', class: 'fuga') # => <div class="fuga">hoge</div>modalを表示するには
modal表示のサンプルです。
hoge_helper.rbdef show_modal_button content_tag(:a, class: 'btn btn-default form-control', data: { toggle: 'modal', target: '#hoge-modal' }) do concat render 'hoge-modal' concat 'モーダル表示' endhoge/_hoge_modal.html.haml.modal.fade#hoge-modal .modal-dialog .modal-content .modal-header %h4.modal-title Title! .modal-body hogehogefugafuga .modal-footer .btn.btn-default.data{ dismiss: 'modal' } 閉じるhoge/show.html.haml... .show-modal = show_modal_button ...リンクを作成する場合
content_tagはlink_toをそのまま扱えないので、以下のように書く必要があります。
fuga_helper.rbcontent_tag(a:, class: 'fuga', href: 'https://www.hoge.fuga.com') do concat 'hoge&fugaへのリンクです!'
- 投稿日:2020-01-18T18:01:35+09:00
Ruby on Rails使用時のデバッグで便利なメソッド
今日、久しぶりに使いたくなってなかなか思い出せなかったので念のためにQiitaにも書いておく。
そこそこの規模で開発していると、自分が今みているメソッドがどこから呼ばれているか分からない時たまにありませんか?
メタプログラミング的に書かれていたりしてgrepがなかなか上手くできないケースがあります。そういう時に便利なのがrubyの
caller
メソッド
https://magazine.rubyist.net/articles/0031/0031-BackTrace.html一旦pryで止めて、callerメソッドを実行するとその前に実行されていたメソッドの歴史が表示されるので、今見ているメソッドがどこから呼ばれているかすぐにわかります。
いやー、思い出せてスッキリ。
- 投稿日:2020-01-18T17:44:16+09:00
FontAwesomeをhamlに導入する際に詰まったお話
TwitterやFacebook等のリンク用のアイコンとしてよく使われるFontAwesomeだが、今回はこれをRailsアプリケーションに導入する方法を記述していく。
FontAwesomeのサイト
https://fontawesome.com/
こちらのサイトから利用する。Proと付いているものは有料だが、それ以外であれば無料で使える。前提
RailsにFontAwesomeを導入する方法として2通りある。
gem 'font-awesome-rails'を利用するか、gem 'font-awesome-sass'を利用するか
の2種類。FontAwesomeが導入できるという点では変わらないが、違いとしては、
'font-awesome-rails'ではfa_icon, fa_stacked_iconの二種類のヘルパーメソッドが使用できるが、最新版のfont-awesome5に対応していない
'font-awesome-sass'では上記二種類のヘルパーメソッドが使えないが、最新版のfont-awesome5が利用できるという事。
エラーは出ないけど表示されないなと思ったらfont-awesome-railsでfont-awesome5のアイコンを使おうとしていた。
また、fa_iconやfa_stacked_iconを使っているのにundefined methodと怒られている場合はfont-awesome-sassを使っている、という点に気を付けよう。先に結論を言うと
gem 'font-awesome-sass'を使いましょう。新しいアイコンも使いたくなるでしょうし。
下に記述するが、fa_iconが使えないだけで他の記述で使えるので。導入手順(font-awesome-sass)
Gemfilegem 'font-awesome-sass', '~> 5.4.1'②bundle installを行う
$ bundle install #bundleでも可③application.scssに下記を追加
application.scss@import 'font-awesome-sprockets'; @import 'font-awesome';④実際に使えるかを確認する。
= icon("fas", "book")fontawesome上では
<i class="fas fa-book"></i>
と記述されており、それを上記に当て込む事で利用可能である。手順(font-awesome-rails)
一応こちらも記述する。
①下記gemをGemfileに記述する。Gemfilegem "font-awesome-rails"②bundle installを行う
ターミナル$ bundle install #bundleでも可③application.scssにて下記を追加する。
application.scss@import 'font-awesome-sprockets'; @import 'font-awesome';ここまでは同じ。使い方が先程とは異なる。
= fa_icon 'book'総評
これまではあまり深く考えてなかったが、qiitaの記事の中でもfont-awesome-sassを入れながらもfa_iconを使う記事があり、そこで少し詰まってしまった。
自分で検証しているので今回の内容に相違は恐らくないとは思うが、他にも書き方はあるのだと思う。
間違っていたらご指摘頂けたら喜んで土下座します。
- 投稿日:2020-01-18T16:27:00+09:00
Railsチュートリアル第1章で勉強をブロックしたやつ
はじめに
この記事では私がRailsチュートリアルの第1章でつまづいた所を共有します。
個人的な備忘録ですが、プログラミング学習入門で人気のRailsなのでお役に立てればうれしいです!実行環境
AWS Cloud9を使用しました。チュートリアルの手順通りに環境設定しました。
問題
rails server
を実行し、アプリケーションをブラウザで開こうとしたところ、
まったく開きませんでした...解決策
色々調べた結果、ブラウザに導入していた広告ブロックが邪魔をしていました。広告ブロックを停止するとブラウザでRailsのウェルカム画面が無事表示されました。
また、下図のような表示がずっとでていましたが、EC2を再起動すれば解決しました。
こちらの記事が参考になります。
まとめ
広告ブロックはプログラミング学習以外では非常に便利ですが、プログラミング学習するときは常時切っておくほうがよいかもしれません。
- 投稿日:2020-01-18T13:19:03+09:00
(自分用)Rails設計時(実装時)の注意点のまとめ
Railsに限らないトピックも含まれそう
- モデルとビューのどちらに実装しようか迷うときは、Decoratorパターンを検討する
- モデルの共通化
- Mix-inを使う場合は、
ActiveSupport::Concern
を利用する- STI(単一テーブル継承)
- 継承を利用して、似たようなActiveRecordモデルクラスの共通化を図る
- 継承関係にある一連のモデルクラスはすべて1つのテーブルに対応付けられる
- 各クラスのインスタンスに対応するレコードは、すべて同一のテーブルに格納される
- 対応するテーブルには
type
というカラムを用意する必要がある
- 各レコードが所属するクラス名が格納される
- https://guides.rubyonrails.org/association_basics.html#single-table-inheritance
- コントローラの共通化にMix-inを使う場合は、モジュールを
app/controllers/concerns
に配置する- ビューで使うユーティリティメソッドはカスタムヘルパーとして
app/helpers
に書く
- 全てのビューから呼べるので、「小さく作る」「具体的に命名する」点に気をつける
- コントローラとビューの間で共通的に利用したい処理は、コントローラにメソッドを定義し、それをコントローラで
helper_method
に指定することもできる- 特定のモデルに関する処理を書かないように注意し、そのような場合はモデルやDecoratorに寄せることを検討する
- (複数のモデルが絡むような)特定の処理は専用のオブジェクトを作成する
- サービスオブジェクト(サービスクラス)と呼ばれる設計パターン
- 特定の処理一つのみに専念し、小さく作るようにする
- モデルに書くべき処理をサービスに書かないように気をつける
- 投稿日:2020-01-18T12:21:57+09:00
【Rails】【Ajax】Ajax(非同期通信)でコメント編集
前回のコメント投稿と削除はremote trueをリンクボタンに設定して実装しました。
【Rails】Ajax(非同期通信)でコメント投稿、削除
今回はコメントの編集をajax関数を使用して実装していきます。注))前回からの続きです
環境
Rails 5.2.3
mysql 5.7.28
gem jquery-rails
→application.jsでrequireしておく。完成デモ
実装
機能を四つに分けて実装していきます。
1. 編集ボタンクリックでラベル非表示、コメントエリアとボタン表示
2. キャンセルボタンクリックでラベル表示、コメントエリアとボタン非表示
3. 更新ボタンクリック成功でDB更新、ラベル表示、コメントエリアとボタン非表示
4. 更新ボタンクリック失敗でエラーメッセージ表示1. 編集ボタンクリックでラベル非表示、コメントエリアとボタン表示
編集ボタン<span data-comment-id=<%= comment.id %> class="js-edit-comment-button"> <i class="fas fa-edit text-primary"></i> </span>一意のコメント<div id="js-comment-<%= comment.id %>"> <p id="js-comment-label-<%= comment.id %>"><%= comment.body %></p> <p id="js-comment-post-error-<%= comment.id %>" class="text-danger"></p> <textarea style="display: none;" id="js-textarea-comment-<%= comment.id %>" class="form-control comment-post-error"><%= comment.body %></textarea> <div id="js-comment-button-<%= comment.id %>" style="display: none;"> <button data-cancel-id=<%= comment.id %> type="button" class="btn btn-light comment-cancel-button">キャンセル</button> <button data-update-id=<%= comment.id%> type="submit" class="btn btn-success comment-update-button">更新</button> </div> </div>application.js# コメント編集エリア表示 $(function () { $(.js-edit-comment-button).on("click", function () { # ①クリックイベント const commentId = $(this).data('comment-id'); # ②一意のcomment.idを代入 const commentLabelArea = $('#js-comment-label-' + commentId); # ③一意のラベルを代入 const commentTextArea = $('#js-textarea-comment-' + commentId); # ④一意のコメントエリアを代入 const commentButton = $('#js-comment-button-' + commentId); # ⑤一意のボタンエリアを代入 commentLabelArea.hide(); # ③を非表示 commentTextArea.show(); # ④を表示 commentButton.show(); # ⑤を表示 }); });①
js-edit-comment-button
をクリックしたら中身を処理する条件定義。② data属性を使用して
data-comment-id
に設定したcomment.id
を取得。ラベル、コメントエリア、ボタンエリアの各要素をそれぞれ一意にしないとjs-edit-comment-button
をクリックした際に各コメントの全ての各要素が反応してしまいます。そのため各要素は一意にする必要があり、③~⑤で実装していくための前段階としてcomment.id
を取得しておきます。③ id属性
js-comment-label-
に、②で定義したcomment.id
を渡します。④ id属性
js-textarea-comment-
に、②で定義したcomment.id
を渡します。⑤ id属性
js-comment-button-
に、②で定義したcomment.id
を渡します。それ以下の処理がわからない方はProgate jQuery編でハンズオンできるのでやってみてください。
ただ、この①の記述だと問題点があります。後にコメントを追加した時にリロードしないと編集ボタンを押しても反応しません。これは追加されたコメントにはイベントが設定されないことが原因です。
application.js# $(.js-edit-comment-button).on("click", function () { $(document).on("click", ".js-edit-comment-button", function () {こう記述することでHTMLをスクリプト(js)で追加した後に追加要素にもイベントを設定することができます。
つまり、追加した要素の編集ボタンも動作します!変数の中身確認
application.js
の中で理解が難しいのが②の部分だと思います。
本当にcomment-id
が取得できるのか試してみます。application.js# コメント編集エリア表示 $(function () { $(.js-edit-comment-button).on("click", function () { const commentId = $(this).data('comment-id'); console.log(commentId); ・ ・ ・ }); });この状態でいくつかコメントを作って
js-edit-comment-button
をクリックしてビューの検証ツールを開いてみましょう。
command + option + iで検証ツールを開いてConsoleタブに移動するとこんな感じでクリックのたびに一意な数字が表示されていればidが取得できてるなーと確認が取れます。
2. キャンセルボタンクリックでラベル表示、コメントエリアとボタン非表示
一意のコメント<div id="js-comment-<%= comment.id %>"> <p id="js-comment-label-<%= comment.id %>"><%= comment.body %></p> <p id="js-comment-post-error-<%= comment.id %>" class="text-danger"></p> <textarea style="display: none;" id="js-textarea-comment-<%= comment.id %>" class="form-control comment-post-error"><%= comment.body %></textarea> <div id="js-comment-button-<%= comment.id %>" style="display: none;"> # キャンセルボタン↓ <button data-cancel-id=<%= comment.id %> type="button" class="btn btn-light comment-cancel-button">キャンセル</button> <button data-update-id=<%= comment.id%> type="submit" class="btn btn-success comment-update-button">更新</button> </div> </div>application.js# コメント編集エリア非表示 $(function () { $(document).on("click", ".comment-cancel-button", function () { const commentId = $(this).data('cancel-id'); const commentLabelArea = $('#js-comment-label-' + commentId); const commentTextArea = $('#js-textarea-comment-' + commentId); const commentButton = $('#js-comment-button-' + commentId); const commentError = $('#js-comment-post-error-' + commentId); commentLabelArea.show(); commentTextArea.hide(); commentButton.hide(); commentError.hide(); }); });キャンセルボタン(comment-cancel-button)をクリックしたら中身を処理する条件定義をして、中身は編集ボタンと同じような内容なので割愛します。
3. 更新ボタンクリック成功でDB更新、ラベル表示、コメントエリアとボタン非表示
ここからが今回の実装の肝であるajax関数を使った処理になります。
先に言っておくとコメント投稿と削除と同じようにremote true
を使用しても実装できますが、もっと複雑な処理の場合はajax関数を使用しての実装になるので慣れるという意味でajax関数を使用します。一意のコメント<div id="js-comment-<%= comment.id %>"> <p id="js-comment-label-<%= comment.id %>"><%= comment.body %></p> <p id="js-comment-post-error-<%= comment.id %>" class="text-danger"></p> <textarea style="display: none;" id="js-textarea-comment-<%= comment.id %>" class="form-control comment-post-error"><%= comment.body %></textarea> <div id="js-comment-button-<%= comment.id %>" style="display: none;"> <button data-cancel-id=<%= comment.id %> type="button" class="btn btn-light comment-cancel-button">キャンセル</button> <button data-update-id=<%= comment.id%> type="submit" class="btn btn-success comment-update-button">更新</button> # 更新ボタン↑ </div> </div>application.js# コメント更新ボタン $(function () { $(document).on("click", ".comment-update-button", function () { const commentId = $(this).data('update-id'); const textField = $('#js-textarea-comment-' + commentId); # ① const body = textField.val(); # ②textFieldの内容を取得 # console.log(body); $.ajax({ # ③ajax関数 url: '/comments/' + commentId, # ④comments/updateアクションにリクエスト type: 'PATCH', # ⑤HTTP通信の種類: updateアクションなので'PATCH'と記述 data: { # ⑥commentモデルのbodyカラムに変数bodyを格納 comment: { body: body } } }) }); });①までは割愛します。わからない方はもう一度記事を読み返してみてください。
②はコメントエリアの内容を変数
body
の中へ代入しています。
この下にconsole.log(body);
と記述してコメントエリアに何かしら記述して更新ボタンを押してみてください。打ち込んだ内容が検証ツールのConsoleに表示されているはずです。③からがajax関数を使った通信内容です。
④任意のアクションへのURIを記述。(今回はcomment/updateアクション)
⑥パラメーターとして送りたいデータを記述。
これで更新ボタンがクリックされたらcomments/updateアクションへパラメーターがリクエストされる状態まで記述ができました。
次はcomments_controllerでの処理に移ります。comments_controller.rbclass CommentsController < ApplicationController before_action :set_comment, only: %i[update destroy] def update # binding.pry @comment.update!(comment_params) end private def set_comment @comment = current_user.comments.find(params[:id]) end def comment_params params.require(:comment) .permit(:body) .merge(board_id: params[:board_id]) end endとりあえず
binding.pry
してここまでパラメーターきてるか確認しておきました。
さあ、やってみよう!
当然ダメですね。
まだまだやることがたくさんあります。
一つずつ潰していきます。まずレスポンスで何が返ってきてるか調べてみます。検証ツール → Network → Responseを開くと
バリデーションに失敗しました: Boardを入力してください
との表示。これは
comments_controller.rbdef comment_params params.require(:comment) .permit(:body) .merge(board_id: params[:board_id]) end
comment_params
でboard_idがパラメーターで渡ってくる想定でいるのにないんだけどどういうこと?Boardを入力してください
と怒ってるわけです。
でもコメント投稿の時点で投稿とコメントは紐づいてるから今回はboard_idいらないんだよね。というわけで、
comments_controller.rbdef update @comment.update!(comment_update_params) end # 追加 def comment_update_params params.require(:comment) .permit(:body) end新たにメソッド作っちゃいましょう。
これで再チャレンジ!ん〜〜〜
クリックしても反映されません。
リロードすると反映されるのでupdateメソッドは成功しているみたいですね。これは現段階での更新ボタンがクリックされてからのJsファイルの処理は、変数を定義して、comments/updateアクションにパラメーターをリクエストしただけなので、ラベルを表示させたり、コメントエリアを非表示にさせたりという処理を書いてないからです。
次はJsファイルにこれらの記述をしていきます。application.js# コメント更新ボタン $(function () { $(document).on("click", ".comment-update-button", function () { const commentId = $(this).data('update-id'); const textField = $('#js-textarea-comment-' + commentId); const body = textField.val(); # console.log(body); $.ajax({ url: '/comments/' + commentId, type: 'PATCH', data: { comment: { body: body } } }) # 追加 .done(function () { # ①ajax通信が成功した時の処理 const commentLabelArea = $('#js-comment-label-' + commentId); const commentTextArea = $('#js-textarea-comment-' + commentId); const commentButton = $('#js-comment-button-' + commentId); const commentError = $('#js-comment-post-error-' + commentId); # ② commentLabelArea.show(); commentLabelArea.text(???); # ③データベースにupdateされたbodyのvalueが欲しい commentTextArea.hide(); commentButton.hide(); commentError.hide(); }) # 追加 }); });①
.done
の中では、コントローラーでの処理が成功した時、この中の処理を実行する。②までは今までと同じような処理なので割愛。
③ラベルにはコメントエリアに記述した内容(body)をtextとして差し替えれば良さそう。
では③をどうやって取得すれば良いか。
これは.done
に返ってきた時、引数にcommentインスタンスを渡してもらってbody要素を取り出せば良さそうです。
なので、application.js# 変更点のみ記述 .done(function (data) { commentLabelArea.text(data.body); })こう書いたら良さそうです。
再チャレンジ!ターミナルを見に行くとステータスコード204が返ってきていた。
204エラー引用
204 No Content
訳すると内容なし。HTTPステータスコードとして204を返すのなら、その名の通りレスポンスボディーは何も返さないのが正解とのこと。
レスポンスボディーに何も入っていない?
あっ...controllerから渡してあげないとダメか。
検証ツールのResponseを見に行くと見事に空っぽでした。
一応デバックして先ほどの引数の中身を見てみます。application.js.done(function (data) { # 追加 debugger; ・ ・ ・ })上段の右側に注目、
data = undefined
となっておりdataが渡ってきていないことが確認できました。comments_controller.rbdef update @comment.update!(comment_update_params) # 追加 render @comment endこれでうまくいくかなあ...
ダメでした。この書き方だと何やらオブジェクトそのものがdataに入っているようでした。
なのでハッシュに近いjson形式にしてデータを取り出せるようにします。comments_controller.rbdef update @comment.update!(comment_update_params) render json: @comment end成功!!!
しっかりデータが入ってることが確認できました。
4.更新ボタンクリック失敗でエラーメッセージ表示
先ほどは
.done
で成功時の処理を記述しました。
失敗時には.fail
という書き方をします。application.js# .doneの処理の下に追加 .fail(function () { const commentError = $('#js-comment-post-error-' + commentId); # ①コメントエラー用の空タグ commentError.text('コメントを入力してください'); # ②空タグにメッセージを書き換える })①こちらは前もって一意のコメントに用意しておいた空のpタグです。
下記の3行目に用意してありました。一意のコメント<div id="js-comment-<%= comment.id %>"> <p id="js-comment-label-<%= comment.id %>"><%= comment.body %></p> <p id="js-comment-post-error-<%= comment.id %>" class="text-danger"></p> <textarea style="display: none;" id="js-textarea-comment-<%= comment.id %>" class="form-control comment-post-error"><%= comment.body %></textarea> <div id="js-comment-button-<%= comment.id %>" style="display: none;"> <button data-cancel-id=<%= comment.id %> type="button" class="btn btn-light comment-cancel-button">キャンセル</button> <button data-update-id=<%= comment.id%> type="submit" class="btn btn-success comment-update-button">更新</button> </div> </div>うまくいきました!!
余談 doneとfailについて
ajax関数はリクエストの成功なら
done
を、失敗ならfail
を実行するようになっていますが、この成功失敗は何をもって判断しているのか。
これはHTTPステータスコードで判断します。
全て試したわけじゃないですが、200番台ならdone
へ、400番台ならfail
へ処理が流れます。(500番台もいくつかfail
へ処理が流れました。)comments_controller.rbdef update @comment.update!(comment_update_params) render json: @comment end記事の中で使用したこのアクション内で
update!
とエクスクラメーションをつけているのはupdate
に失敗した時にfalseではなくエラーを返してほしいからです。
今回の場合は失敗すると422番のステータスコードが返っていたのでfail
へ処理が流れました。【失敗時に任意のステータスコードを返すやり方】
comments_controller.rbdef update if @comment.update(comment_update_params) render json: @comment else head :bad_request # ①ステータスコードを400番で返す end endステータスコードはHTTPレスポンスのステータス行に格納されて返ってきます。
head :hogehoge
のように記載するとhogehoge
部分に対応したステータスコードを返すことができます。
HTTPメッセージ資料:https://itsakura.com/network-http-get-post
ステータスコード資料:https://developer.mozilla.org/ja/docs/Web/HTTP/Statusまとめ
今回の実装は非常に苦労しました。
というのも今までデバックはそこまでしてこなかったですしHTTPを意識して実装もしてきませんでしたので。
今回そのあたりの知識が少しはついたかなと思います。Webの基礎的な部分の勉強でわかりやすいYouTubeチャンネルがあったので初学者の方はぜひ見てみてください!
https://www.youtube.com/channel/UCTmF42qi_LeT81fGdzoCn0w
- 投稿日:2020-01-18T11:52:15+09:00
【Rails】キャッシュされた古いページが一瞬表示されるのを避ける方法
困っていたこと
取得したパラメータによって表示したいページを変更したくて
以下のようなコントローラ設定の時、articles_controller.rbclass ArticlesController < ApplicationController def show if session[:for_article_show] == 1 render '/articles/pattern_A' elsif session[:for_article_show] == 2 render '/articles/pattern_B' end end end
session[:for_article_show]
が1の時に
pattern_A.html.erbが表示され、その後
session[:for_article_show]
が2に変更されてshowアクションが実行されると、
pattern_B.html.erb
が直接表示されると思っていました。実際は、一瞬だけ
pattern_A.html.erb
が表示され、その後すぐに
pattern_B.html.erb
の表示に切り替わりました。これでは非常に見栄えが悪く、困っていました。
原因
Rails標準gemである、turbolinksが原因でした。
turbolinksによって、
あるアクションによって描画されたページがキャッシュに存在した場合、
リクエストを送る前にまずキャッシュからプレビューを描画し、
レスポンスが返ると最新の状態を表示するようです。【参考】turbolinks github "Application Visits" 項
解決策
プレビュー機能が実行されたくないリンクを、以下タグで囲ってあげることで
ページのプレビューが表示されることがなくなりました!<div data-turbolinks="false"> <%= link_to article.title, article %> </div>
- 投稿日:2020-01-18T11:40:22+09:00
【Rails】link_toメソッドでaria-haspopup、data-toggleなどのHTML表現を入れる方法
エラー発生
Railsのlinks_toメソッドで下記のようにaria-haspopup、aria-expanded、data-toggleなどのHTML表現を入れようとしたところ、エラーが出た。
<%= link_to root_path, class: 'nav-link', data-toggle: dropdown, aria-haspopup: true, aria-expanded: false, id: header-profile do %> <%= image_tag('xxx.jpg', size: '60x60') %> <% end %>syntax error, unexpected 〇〇, expecting 〇〇
というエラーが出まくる。
構文エラーなのでどこか書き間違えがあるのかと思ったが、コードを見ても余計な文字や入れ忘れがあるように見えない。解決方法
調べて見るとlink_toの引数のハッシュとしてつける場合、キーをシングルクオテーションをつける必要がある。例えば、
data-toggle: dropdown
は'data-toggle': :dropdown
という風に書き換える。<%= link_to root_path, class: 'nav-link', 'data-toggle': :dropdown, 'aria-haspopup': :'true', 'aria-expanded': :'false', 'id': :'header-profile' do %> <%= image_tag('xxx.jpg', size: '60x60') %> <% end %>
- 投稿日:2020-01-18T07:49:17+09:00
非同期通信について初投稿
非同期通信(Ajax)とは
画面の遷移のない通信を非同期通信という。
リクエスト後にレスポンスが帰ってきた際、ブラウザが再読み込みされること無く通信が行われる通信方法で、非同期通信は英語で"Asynchronous JavaScript + XML"と表現され、略してAjax(エイジャックス)と呼ばれる。Ajaxでは、レスポンスのデータにJSONという形式が使われることが多い。
同期通信と非同期通信の違い
同期通信・・・webブラウザからサーバーにリクエストを通信しレスポンスが返ってくる時に、全ての情報を通信しているので画面が一瞬白くなり、サーバーからレスポンスが返ってくるまでは他の作業ができない
非同期通信・・・ブラウザから一部の情報をリクエストするのでそれ以外の部分は変わらないため画面が白くなることはない。そのため、サーバーからレスポンスが返ってこなくても他の作業ができる。
JSON
Java Script Object Notationの略で、データ交換を行うためのデータ記述形式の一種。Rubyのハッシュと同様、キーとバリューの組み合わせでデータを表現する形式。
例{user_name: "testさん", created_at: "2019-08-28T10:35:13.000+09:00", content: "これがJSONの形です!", image_url: null, id: 6}Ajaxでは主にJSONという型でレスポンスが行われる。この時ブラウザではJavaScriptが動作し、JavaScriptはサーバからJSON形式で返されたデータをHTMLに成形、ブラウザを書き換える。この仕組みにより、ブラウザの一部だけを更新することが可能になる。
簡単なToDoアプリで動きの確認
非同期通信 実装のポイント
1. 非同期通信ではJavaScriptを利用してリクエストを行う
非同期通信ではJavaScriptのメソッドを利用してリクエストを送る。そのため、フォーム要素のデフォルトアクションを無効にする必要がある。
またこの時、リクエストに対してのレスポンスはJSON形式で返してほしい旨をリクエストに含める。2. コントローラでJSON形式のデータを用意するよう準備
同期通信の際は特に指定せずともHTML形式のデータを返すようRailsが動いてくれる。
非同期通信をする際は、リクエストにJSON形式で返してほしい旨の情報が含まれているため、その場合の対処をコントローラのアクションに明記する必要がある。3. レスポンスするためのJSON形式のデータを準備
同期通信ではviewsディレクトリの中に○○.html.erbという形式でHTMLのファイルを準備して置くことでレスポンスとしてHTMLを返すことができた。
非同期通信の場合、JSONのデータをレスポンスとして返す必要がある。短いデータであればコントローラ内に直接書けるが、同期通信の際と同様viewsフォルダの中にJSON形式のファイルを準備することもできる。この時のファイル名は、○○.json.jbuilderという形式になる。4. JavaScriptでレスポンスを受け取り、HTMLを操作してToDoを追加
同期通信におけるレスポンスはHTML形式であり、受け取ったHTMLを描画するためにブラウザは一度リロードされる。
対して非同期通信では、ページがリロードされることはなく代わりに、レスポンスとして帰ってきたJSONのデータを利用してHTMLを操作する。
JSONのデータはユーザーが投稿したToDoのデータなので、これをToDoリストの一番後ろに付け加えるようJavaScriptを書く。respond_to
Railsのコントローラーで利用できる respond_to というメソッドは、「リクエストがHTMLのレスポンス求めているのか、それともJSONのレスポンス求めているのか」を条件に条件分岐してくれる。
例respond_to do |format| format.html { render ... } # この中はHTMLリクエストの場合に呼ばれる format.json { render ... } # この中はJSONリクエストの場合に呼ばれる endHTMLを返す場合は、該当するビューを呼びその中でデータを生成していたが、JSONを返す場合はRubyのハッシュをrenderメソッドの引数として渡すだけでJSONに変換される。以下のようにコントローラーから直接データを返すことができる。こちらは、renderというメソッドに{json: { id: @user.id, name: @user.name }}というハッシュを引数として渡している。
例respond_to do |format| format.json { render json: { id: @user.id, name: @user.name } } endJSONでレスポンスできるようにする
todos_controller.rbdef create @todo = Todo.create(todo_params) respond_to do |format| format.html { redirect_to :root } format.json { render json: @todo} end endJavaScriptを記載して送信時に要素を取得する
Ruby on Railsでは、アプリケーション作成時にjquery-railsというgemをインストールし、assetsディレクトリ以下のapplicaton.jsファイルで//= require jqueryこのように記述することでjQueryを読み込んでいる。
todo.jsというファイルをassets/javascripts以下に作成する。非同期通信でリクエストを行う
処理の流れ
- フォームの送信が行われた時にAjaxによる非同期通信を始める
- フォームに入力された値を取得する
- Ajaxを行う記述をする
- TodosコントローラのcreateアクションにてTodoの保存を行う
- 処理後にjsonを返す
- 非同期通信の終了後に受け取ったjsonを利用してHTMLを構築する
- 4で構築したHTMLをViewに差し込む
todo.js$(function() { $('.js-form').on('submit', function(e) { e.preventDefault(); var todo = $('.js-form__text-field').val(); # jQueryで非同期通信を行うための記述。 $.ajax({ type: 'POST', url: '/todos.json', data: { todo: { content: todo } }, dataType: 'json' }) #非同期が成功したときに行う処理 .done(function(data) { var html = $('<li class="todo">').append(data.content); $('.todos').append(html); $('.js-form__text-field').val(''); }) #非同期が失敗したときの処理 .fail(function() { alert('error'); }); }); });
- 投稿日:2020-01-18T07:01:35+09:00
Rails Tutorial 第一章でつまづいたところと参考URL(簡易メモ)
○所要時間
とりあえず一読 → 2:30(現在合計2:30)
一読後手を動かして → 4:00(現在合計4:00)
合計6:30・cloud9初期設定迷う
→初期設定から変更なしでOK
参考URL:https://note.com/yutsuku/n/ncb752afcc61f・rails server 起動できない(rails serverが弾かれる)
javascriptをダウンロード(具体的には、vi Gemfile→最後に「gem 'therubyracer'」を追記)
参考URL:http://yso15.hatenablog.com/entry/2015/03/21/225843かつ、cd ~/environment/hello_app でディレクトリ の移動後、rails serverを起動。
・rais serverってどうやって開けば(確認すれば)いいの?
ページの表示方法は以下
0.画面上部tools→preview(これ以外下記参考URL引用)
1. $ rails serverでサーバを起動する(上記の結果でOK)
2. 画面上部Preview → Preview Running Application をクリック
3. cloud9上にブラウザが表示されるので、アドレスバーの右にあるボタンをクリック
4. ページが表示される。
参考URL:https://qiita.com/iwato/items/c70eeb87f944043ba356・Gitでユーザを確認する方法
git config --global --list
Gitユーザを切り替える方法
XXXXのところは自分のユーザ名とメールアドレスに置き換えてください。
git config --global user.name XXXXX
git config --global user.email xxxx@xxxx.xxx
参考URL:http://javatechnology.net/service/git-config-global-list-user/・git公開鍵のbitbucketへの登録
1.公開鍵が作成されているか確認する
$ cat ~/.ssh/id_rsa.pub
2.公開鍵を作成する
$ cd ~/.ssh
$ ssh-keygen
(ssh-keygenでAWS上の/var/lib/jenkins/.sshに公開鍵、秘密鍵を作るでした。)
参考URL:https://teratail.com/questions/48406→ssh key imageなるもの(The key's randomart image)ができてこれは使えなかった→cat id_rsa.pubで確認すると、ssh-rsaで始まるものが出てきて、これはbitbucketでsshkeyとして使えた。
参考URL:https://note.com/yutsuku/n/ncb752afcc61f・bitbucket登録後、Bitbucketへのリポジトリ追加とリポジトリへのプッシュ
$ cd ~/environment/hello_app(この移動大事)(要はhello_appのマスターブランチで以下コマンドを行うということ)
$ git remote add origin git@bitbucket.org:アカウント名/hello_app.git
$ git push -u origin master
参考URL:https://note.com/yutsuku/n/ncb752afcc61f・$ bundle install --without production
→"Gemfile could no locate"のエラー
→hello_app(master)に移動して実行
- 投稿日:2020-01-18T00:37:52+09:00
ruby 2.7.0 + Rails 5.2.4 + mysql 5.7.28 でDocker開発環境を構築する備忘録
流れ
- Dockerfileを作成
- docker-compose.ymlを作成
- Gemfile,Gemfile.lockを作成
- イメージ・コンテナの作成
- Rails初期設定
- Githubにリモートリポジトリ作成
ディレクトリ構成
application_root/ - Dockerfile - docker-compose.yml - Gemfile - Gemfile.lock - その他Railsアプリケーションファイル群Dockerfileを作成
application_root下に下記のファイルを作成
# イメージのベースラインにRuby2.7.0を指定 FROM ruby:2.7.0 # Railsに必要なパッケージをインストール RUN apt-get update -qq && apt-get install -y build-essential nodejs RUN gem install bundler # ルートディレクトリを作成 RUN mkdir /app # 作業ディレクトリを指定 WORKDIR /app # ローカルのGemfileとGemfile.lockをコピー COPY ./Gemfile /app/Gemfile COPY ./Gemfile.lock /app/Gemfile.lock # Gemのインストール実行 RUN bundle install # カレントディレクトリの内容をコピー COPY . .docker-compose.ymlを作成
同様に下記のファイルを作成。
DBはmysqlで、ローカルにデータストアを設けて永続化している。# docker-compose.ymlフォーマットのバージョン指定 version: '3' services: # Railsコンテナ定義 web: # Dockerfileを使用してイメージをビルド build: . # ポート3000が来たらrailsサーバーが応答 command: bundle exec rails s -p 3000 -b '0.0.0.0' # ローカルのsrcをコンテナにマウント volumes: - .:/app ports: - 3000:3000 # dbコンテナが先に起動するよう設定 depends_on: - mysql tty: true stdin_open: true # MySQLコンテナ定義 mysql: # mysqlを使用してコンテナ作成 image: mysql:5.7.28 volumes: # データストアからマウント - ./tmp/mysql:/var/lib/mysql # コンテナ内の環境変数を定義 environment: # mysqlのルートユーザーのパスワード設定 MYSQL_ROOT_PASSWORD: password ports: - "3306:3306" restart: alwaysGemfile,Gemfile.lockの作成
以下のコマンドでGemfileを作成。
bundle init下記のように編集。
# frozen_string_literal: true source "https://rubygems.org" git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } gem "rails", "~> 5.2.4"Gemfile.lockは空で作成しておく。
touch Gemfile.lockイメージ・コンテナの作成
Railsプロジェクトを作成する。
docker-compose run web rails new . --force --database=mysqlDockerイメージを作成する。(で合っているよね?)
docker-compose build作成されたイメージを確認できる。
コンテナはまだない。# イメージのリスト docker image list # 動作しているコンテナ一覧 docker psここまでがうまくいかなかった時は削除してやり直す。
docker rm -f [container_id] docker rmi -f [image_id]いよいよコンテナを立ち上げる。
-dをつけるとデーモン実行できるが、ログを見たいのでそのまま実行。docker-compose upRails初期設定
config/database.ymlのpassword, hostを編集する。
default: &default adapter: mysql2 encoding: utf8 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root password: password # docker-compose.ymlに記載したパスワード host: mysql # docker-compose.ymlに記載したホスト名コンテナ内に入って、DBを作成する。
docker exec -it [container_name] bash rake db:create下記URLで動作が確認できる。
http://localhost:3000Github設定(ついでに)
Githubアカウントは作ってある前提で・・・
まずはSSHキーを作成。もうある場合は不要。
内容をGithubの設定から、SSH keysにアップロードする。ssh-keygen -t rsa cat .ssh/id_rsa.pubあとはリモートリポジトリのSSHアドレスを設定してPush。
# ユーザー名の設定 git config --global user.name [ユーザー名] # リモートリポジトリの設定 git remote add origin git@github.com:xxxxxxxx/xxxxxxxxx.git # アプリケーションの初期状態をPush git add -A git commit -m "create application" git push origin master