- 投稿日:2020-08-08T23:00:05+09:00
ページネーション機能の実装
バージョン
・ruby 2.5.7
・Rails 5.2.4.3ページネーション機能を使って1ページにつき10件だけ表示させたい
まずgemをインストール
ページネーション機能の実装には、gemの「kaminari」を使います。
まず、gemfileでkaminariを記述する。
Gemfileに追記できたら、ターミナルでbundle installを実行して、kaminariをインストールします。さらに以下のコマンドを実行
kaminariの設定ファイルを作成の為、下記を実行します。このファイル内にある数字を動かせれば1ページにつき、何件表示出来るか設定出来ます。
下記を実行して生成されるものはkaminariのデザインの修正ができます。
詳しくはこちらの記事が分かりやすかったです。
https://qiita.com/you8/items/df68aaee3010e282d1ae
viewとcontrollerをページネーション用に変更
kaminariを利用するには、利用したいviewファイルに以下のように追記します。
controllerの方もallで取得していたのを以下のように修正します。
reverse_orderを指定すると新しい順に表示されるようになります。
config/initializersフォルダのkaminari_config.rbに何件表示させたいか記入すれば完成!!
- 投稿日:2020-08-08T22:46:48+09:00
参考になるRailsのプロダクトコード(OSS)5選
はじめに
「この設計でいいのかな〜」「クラス名や変数名はこれでいいのかな〜」と思ったときに参考にできそうな、Railsで書かれたOSSを5つピックアップしました。
参考になるRailsのプロダクトコード(OSS)5選
GitLab
- GitHub: https://github.com/gitlabhq/gitlabhq
- Webサイト: https://about.gitlab.com/
- GitHubみたいな、Gitリポジトリのホスティングサービス
- 今回紹介する5つの中で、おそらく一番大規模なアプリ
RubyGems.org
- GitHub: https://github.com/rubygems/rubygems.org
- Webサイト: https://rubygems.org/
- RubyのGemを検索できるサービス
- 今回紹介する5つの中で、おそらく一番小規模でシンプル
Spree
- GitHub: https://github.com/spree/spree
- Webサイト: https://spreecommerce.org/
- BASEやSTORES、Shopifyのような、ECサイトを手軽に構築するためのサービス
- Spreeから派生したSolidusというサービスも存在している
Discourse
- GitHub: https://github.com/discourse/discourse
- Webサイト: https://www.discourse.org/
- 掲示板アプリ
OpenProject
- GitHub: https://github.com/opf/openproject
- Webサイト: https://www.openproject.org/
- RedmineやTrelloのような、プロジェクト・タスク管理ツール
さいごに
先人の知恵を借りて、きれいなコードを書けるように努めましょう?
- 投稿日:2020-08-08T20:39:46+09:00
初心者がwebpackを調べてまとめてみた
この記事について
Rails6でポートフォリオを作成していたが、webpackを理解できずに開発を進めていってたから勉強のまとめとして投稿
参考URL
https://qiita.com/kamykn/items/45fb4690ace32216ca25
https://eng-entrance.com/what-is-nodejs
https://note.com/billion_dollars/n/n596fecfdeb2e
https://qiita.com/ashketcham/items/48d64e960d436f8b6f78webpackとは
一言でまとめるとNode.jsで、サーバーサイドで動かすモジュールバンドラーツールのこと
さて、いきなり知らん単語ばかりが並んで思考が停止しそうになるぜ。
このwebpackの説明文読んだときの頭の中を表現すると、
「Node.jsって美味しいの???」
「モジュールとは・・・」ここは落ち着いて知らん単語を調べるのみ!!!!
Node.jsとは・・・
サーバサイドで動くJavaScriptのこと。Ruby やPHPなどと同じような働きをしてくれる。
このようにサーバサイドで動くJavaScriptをサーバサイドJavaScriptと呼ばれるが、その中でも代表的なのがNode.js。(他にも色々あるみたいだけどマイナーらしい。)Node.js = サーバサイドJavaScriptだと認識しておいてよさげ。
モジュールとは・・・
JavaScriptファイルなどのファイルのことをモジュールと呼ぶ。
ちなみに、webpackではCSSや画像もまとめてくれるので、それらもモジュールと呼ばれている!!
バンドラーとは
複数のモジュールを依存関係を解決して一つにまとめること。
そもそもバンドルとは、まとめられたファイルを意味する。
つまりここまでの用語を噛み砕いてwebpackを説明すると・・・
サーバサイドで動くJavaScriptで、CSS・JavaScript・画像などを1つのファイルとしてまとめるための便利なやつ!!!!(強引)
ここで疑問に感じるよね
なんでまとめる必要があるのか????
それはブラウザ/サーバー間での通信プロトコルであるHTTP/1.1の仕組みにある。
HTTP/1.1では一度に処理できるリクエストの数が限られている。そんな限られている中で、CSSや画像やらJSファイルを一つ一つリクエストしてると、処理速度が遅くなってしまう。
そこで、JSのリクエストをなるべく一つにまとめてリクエストの回数を減らすことが表示速度(パフォーマンス)を上げてやることができる。ここまででなんとなくwebpackが何なのか薄らわかってきたとこで、webpackの利点をまとめる。
webpackの良いところ
其の1:外部モジュールを簡単に利用できる。
フロントエンドの開発ではjQueryやVue.jsなどを利用することが多く、webpackではこのような外部モジュールを簡単に利用することができる。
其の2:依存関係を解決したファイルを出力できる。
複数のライブラリ等を読み込んで、それに依存しているapplication.jsに読み込むファイルがあった場合は以下のようになる
qiita.rb<!DOCTYPEhtml> <html> <head> <metacharset="utf8"/> <title>dependency</title> </head> <body> <scriptsrc="js/extra.js"></script> <scriptsrc="js/jquery.js"></script> <scriptsrc="js/mymodule.js"></script> <scriptsrc="js/main.js"></script> <scriptsrc="js/application.js"></script> </body> </html>上記のようにしてたら、読み込みが増えれば増えるほど管理が大変になってしまtたり、読み込み順を変えると上手く動かなくなったりするかもしれないという懸念がある。
そんな懸念を解決するのがwebpackさん!!!
webpackを使わなかったらjs以下等のファイルを一つ一つ記述していたが、それらをwebpackでギュッと一つにまとめてやると、記述をかなり減らして書くことができる。
qiita.rb<!DOCTYPEhtml> <html> <head> <metacharset="utf8"/> <title>dependencyresolved</title> </head> <body> <scriptsrc="js/bundle.js"></script> </body> </html>他のCSSやJSの読み込みの記述は必要なく、bundle.jsにすべてまとめられている。
まとめ
webpackはフロントエンド開発用のモジュールバンドラーのこと。
モジュールバンドラとは、複数のモジュールをまとめるツールのことであり、モジュールはJavaScriptファイルなどのこと。
つまり、webpackは複数のJavaScriptファイルなどをまとめてくれるツールのことなんやな!!!
- 投稿日:2020-08-08T19:48:29+09:00
deviseで送信されるメールを非同期処理にする方法
はじめに
railsで作ったアプリケーションにdeviseを導入していますが、会員登録時などに送信するメールを非同期処理でおこないたいと思います。
メール送信処理でエラーが発生しても画面操作が続けられることがメリットです。
今回は非同期処理にdelayed_job
を使用します。
他にはside_kiq
を使う方法もあります。前提
- deviseが使用できること。
devise-asyncのインストール
以下のgemをGemfileに追加し、
bundle install
してください。Gemfilegem 'devise-async'非同期処理を有効にするため、
devise-async.rb
を修正します。config/initializers/devise-async.rbDevise::Async.setup do |config| config.enabled = true end
queue_adapter
にdelayed_job
を指定します。config/application.rbmodule [アプリ名] class Application < Rails::Application # 省略 config.active_job.queue_adapter = :delayed_job end endMailerをカスタマイズ
以下のようにDevise::Mailerを継承したカスタマイズクラスを作成します。
必要に応じてメソッドをオーバーライドしてください。
Devise::Mailerのメソッドapp/mailers/user_mailer.rbclass UserMailer < Devise::Mailer default from: 'info@example.com' def confirmation_instructions(record, token, opts = {}) @token = token devise_mail(record, :confirmation_instructions, opts) end end
devise.rb
でカスタマイズしたMailerを指定します。config/initializers/devise.rbDevise.setup do |config| config.mailer = 'UserMailer' # 省略 enddelayed_jobのインストール
delayed_job
に関するgemをbundle install
します。Gemfilegem 'delayed_job_active_record' # デプロイ先でデーモンとして動かすのに必要 gem 'daemons'delayed_jobテーブルを作成します。
rails g delayed_job:active_record rake db:migrateJobをスタートさせます。
bin/delayed_job start正常に起動できているか確認します。
$ ps aux | grep delayed_job user 16788 0.0 2.2 4621728 183972 ?? S 2:16PM 10:24.78 delayed_job user 20824 0.0 0.0 4286716 720 s002 S+ 7:34PM 0:00.01 grep delayed_jobCapistranoによるデプロイ
Capistrano用のgemを追加し、
bundle install
します。Gemfilegem 'capistrano3-delayed-job'Capfileには以下のrequire文を追加してください。
Capfilerequire 'capistrano/delayed-job'参考
- 投稿日:2020-08-08T19:28:15+09:00
【Rails】アプリ作成の流れ⑤【SNS認証機能】
前回は
パスワード認証機能を実装しました。
目次
- SNS認証機能
SNS認証機能
- SNS認証機能はSNSに登録されているユーザー情報を取得して、自分で作ったアプリにログインさせるといった機能。
- SNSによって取得できる情報は違う。
gem 'omniauth'を使うことで実装できる。
- omniauthを使うことで、異なる形式を一つの統一された形式に変換してくれる。
【参考記事】
https://qiita.com/kazuooooo/items/47e7d426cbb33355590e
https://qiita.com/zenizh/items/94aec2d94a2b4e9a1d0b
https://qiita.com/Hassan/items/176bc2c6fd75a3e00111必要なgemの導入
Gemfilegem 'omniauth' gem 'omniauth-facebook' gem 'omniauth-twitter' gem 'omniauth-google-oauth2'ターミナル% bundle install
Omniauthに必要なカラムをUserテーブルに追加
ターミナル% rails g migration AddOmniauthToUsers provider:string uid:string % rails db:migrate
initializerにomniauthの設定
initializers/devise.rbconfig.omniauth :facebook, ENV['FACEBOOK_KEY'], ENV['FACEBOOK_SECRET'], scope: 'email', info_fields: 'email', callback_url: "#{ENV['HOST']}/users/auth/facebook/callback" config.omniauth :twitter, ENV['TWITTER_API_KEY'], ENV['TWITTER_API_SECRET'], scope: 'email', oauth_callback: "#{ENV['HOST']}/users/auth/twitter/callback" config.omniauth :google_oauth2, ENV['GOOGLE_CLIENT_ID'], ENV['GOOGLE_CLIENT_SECRET'], scope: 'email', redirect_uri: "#{ENV['HOST']}/users/auth/google_oauth2/callback"後々、秘密鍵をcredentials.ymlに変更する。
Userモデルの編集をする。
- omniauthableの追記する。
- from_omniauthを追加する。
models/user.rbclass User < ApplicationRecord devise :omniauthable, omniauth_providers: %i[facebook twitter google_oauth2] # omniauthのコールバック時に呼ばれるメソッド def self.from_omniauth(auth) where(provider: auth.provider, uid: auth.uid).first_or_create do |user| user.email = auth.info.email user.password = Devise.friendly_token[0,20] end end endルーティングを設定する
config/routes.rbdevise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }Usersコントローラにコールバック処理を実装
- app/controllers/users以下に
- omniauth_callbacks_controller.rbを作成
- そのファイルを編集
omniauth_callbacks_controller.rbclass Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController # callback for facebook def facebook callback_for(:facebook) end # callback for twitter def twitter callback_for(:twitter) end # callback for google def google_oauth2 callback_for(:google) end # common callback method def callback_for(provider) @user = User.from_omniauth(request.env["omniauth.auth"]) if @user.persisted? sign_in_and_redirect @user, event: :authentication #this will throw if @user is not activated set_flash_message(:notice, :success, kind: "#{provider}".capitalize) if is_navigational_format? else session["devise.#{provider}_data"] = request.env["omniauth.auth"].except("extra") redirect_to new_user_registration_url end end def failure redirect_to root_path end end各プラットフォーム毎に設定する
Facebook APIの導入
Facebook for Developersの「設定」→「ベーシック」
ここで「アプリID」と「app secret」が確認できる。「Facebookログイン」→「設定」→「有効なOAuthリダイレクトURI」
ここでURLを保存する。
※まだしていない。本番で利用するときは
プライバシーポリシーページを作成して、StatusをONにする。
- Twitter APIの導入 https://dev.classmethod.jp/articles/twitter-api-approved-way/#pl2
- Twitter Developerの画面右上の「申し込む」 「Twitterユーザー向けの構築ツール
- APIキーとシークレットキーを取得
- callbackurlを指定
- privacy policy
- terms of service
- permissionはread only
- Request email addresses from usersにチェックを入れる
- 新しいプロジェクトを作成
- PeopleAPI認証の有効にする
- 認証情報を作成する→「OAuthクライアントIDの作成」
- クライアントIDとクライアントシークレットをメモする まだしていない
- リダイレクトURIを設定する まだしていない
- Google+のAPIを有効にしておく
まとめ
まだ実装はできていない。
- まずはAPIの取得が大変
- APIキーとシークレットキーの管理が大変
- 投稿日:2020-08-08T19:07:38+09:00
【puma】puma4台インストールできない問題の対処法
環境
Rails 5.2, 6.0
puma 4.3.1, 4.3.4, 4.3.5など
xcode 12.0
xcodeのバージョンは$ xcodebuild -version
で確認できます。「puma4台インストールできない問題」というよりは「xcode最新版を入れているとpuma4台インストールできない問題」です。
Rails6で開発をしようとしたところ、以下のようなエラーが出てpumaのインストールができませんでした。エラー文
$ rails new new_app
$ rails new new_app …(省略) Fetching bootsnap 1.4.7 Installing bootsnap 1.4.7 with native extensions Using bundler 2.1.4 Using byebug 11.1.3 Fetching regexp_parser 1.7.1 Installing regexp_parser 1.7.1 Using xpath 3.2.0 Fetching capybara 3.33.0 Installing capybara 3.33.0 Using childprocess 3.0.0 Using ffi 1.13.1 Using jbuilder 2.10.0 Using rb-fsevent 0.10.4 Using rb-inotify 0.10.1 Using listen 3.2.1 Using method_source 1.0.0 Fetching puma 4.3.5 Installing puma 4.3.5 with native extensions Gem::Ext::BuildError: ERROR: Failed to build gem native extension. current directory: /Users/k_end/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/puma-4.3.5/ext/puma_http11 /Users/k_end/.rbenv/versions/2.6.6/bin/ruby -I /Users/k_end/.rbenv/versions/2.6.6/lib/ruby/2.6.0 -r ./siteconf20200729-76891-111jdf1.rb extconf.rb checking for BIO_read() in -lcrypto... yes checking for SSL_CTX_new() in -lssl... yes checking for openssl/bio.h... yes checking for DTLS_method() in openssl/ssl.h... yes checking for TLS_server_method() in openssl/ssl.h... yes checking for SSL_CTX_set_min_proto_version in openssl/ssl.h... yes creating Makefile current directory: /Users/k_end/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/puma-4.3.5/ext/puma_http11 make "DESTDIR=" clean current directory: /Users/k_end/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/puma-4.3.5/ext/puma_http11 make "DESTDIR=" compiling http11_parser.c compiling io_buffer.c compiling mini_ssl.c compiling puma_http11.c puma_http11.c:203:22: error: implicitly declaring library function 'isspace' with type 'int (int)' [-Werror,-Wimplicit-function-declaration] while (vlen > 0 && isspace(value[vlen - 1])) vlen--; ^ puma_http11.c:203:22: note: include the header <ctype.h> or explicitly provide a declaration for 'isspace' 1 error generated. make: *** [puma_http11.o] Error 1 make failed, exit code 2 Gem files will remain installed in /Users/k_end/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/puma-4.3.5 for inspection. Results logged to /Users/k_end/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/extensions/x86_64-darwin-17/2.6.0/puma-4.3.5/gem_make.out An error occurred while installing puma (4.3.5), and Bundler cannot continue. Make sure that `gem install puma -v '4.3.5' --source 'https://rubygems.org/'` succeeds before bundling. In Gemfile: puma run bundle binstubs bundler Could not find gem 'rails (~> 6.0.3, >= 6.0.3.1)' in any of the gem sources listed in your Gemfile. run bundle exec spring binstub --all Could not find gem 'rails (~> 6.0.3, >= 6.0.3.1)' in any of the gem sources listed in your Gemfile. Run `bundle install` to install missing gems. rails webpacker:install Could not find gem 'rails (~> 6.0.3, >= 6.0.3.1)' in any of the gem sources listed in your Gemfile. Run `bundle install` to install missing gems.$ bundle install
$ bundle install …(省略) Using bundler 2.1.4 Using byebug 11.1.3 Using regexp_parser 1.7.1 Using xpath 3.2.0 Using capybara 3.33.0 Using childprocess 3.0.0 Using ffi 1.13.1 Using jbuilder 2.10.0 Using rb-fsevent 0.10.4 Using rb-inotify 0.10.1 Using listen 3.2.1 Using method_source 1.0.0 Fetching puma 4.3.5 Installing puma 4.3.5 with native extensions Gem::Ext::BuildError: ERROR: Failed to build gem native extension. current directory: /Users/k_end/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/puma-4.3.5/ext/puma_http11 /Users/k_end/.rbenv/versions/2.6.6/bin/ruby -I /Users/k_end/.rbenv/versions/2.6.6/lib/ruby/2.6.0 -r ./siteconf20200729-77400-1d4l9f3.rb extconf.rb checking for BIO_read() in -lcrypto... yes checking for SSL_CTX_new() in -lssl... yes checking for openssl/bio.h... yes checking for DTLS_method() in openssl/ssl.h... yes checking for TLS_server_method() in openssl/ssl.h... yes checking for SSL_CTX_set_min_proto_version in openssl/ssl.h... yes creating Makefile current directory: /Users/k_end/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/puma-4.3.5/ext/puma_http11 make "DESTDIR=" clean current directory: /Users/k_end/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/puma-4.3.5/ext/puma_http11 make "DESTDIR=" compiling http11_parser.c compiling io_buffer.c compiling mini_ssl.c compiling puma_http11.c puma_http11.c:203:22: error: implicitly declaring library function 'isspace' with type 'int (int)' [-Werror,-Wimplicit-function-declaration] while (vlen > 0 && isspace(value[vlen - 1])) vlen--; ^ puma_http11.c:203:22: note: include the header <ctype.h> or explicitly provide a declaration for 'isspace' 1 error generated. make: *** [puma_http11.o] Error 1 make failed, exit code 2 Gem files will remain installed in /Users/k_end/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/puma-4.3.5 for inspection. Results logged to /Users/k_end/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/extensions/x86_64-darwin-17/2.6.0/puma-4.3.5/gem_make.out An error occurred while installing puma (4.3.5), and Bundler cannot continue. Make sure that `gem install puma -v '4.3.5' --source 'https://rubygems.org/'` succeeds before bundling. In Gemfile: puma$ gem install puma -v '4.3.5' --source 'https://rubygems.org/'
$ gem install puma -v '4.3.5' --source 'https://rubygems.org/' Building native extensions. This could take a while... ERROR: Error installing puma: ERROR: Failed to build gem native extension. current directory: /Users/k_end/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/puma-4.3.5/ext/puma_http11 /Users/k_end/.rbenv/versions/2.6.6/bin/ruby -I /Users/k_end/.rbenv/versions/2.6.6/lib/ruby/2.6.0 -r ./siteconf20200729-77587-1dqkt4f.rb extconf.rb checking for BIO_read() in -lcrypto... yes checking for SSL_CTX_new() in -lssl... yes checking for openssl/bio.h... yes checking for DTLS_method() in openssl/ssl.h... yes checking for TLS_server_method() in openssl/ssl.h... yes checking for SSL_CTX_set_min_proto_version in openssl/ssl.h... yes creating Makefile current directory: /Users/k_end/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/puma-4.3.5/ext/puma_http11 make "DESTDIR=" clean current directory: /Users/k_end/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/puma-4.3.5/ext/puma_http11 make "DESTDIR=" compiling http11_parser.c compiling io_buffer.c compiling mini_ssl.c compiling puma_http11.c puma_http11.c:203:22: error: implicitly declaring library function 'isspace' with type 'int (int)' [-Werror,-Wimplicit-function-declaration] while (vlen > 0 && isspace(value[vlen - 1])) vlen--; ^ puma_http11.c:203:22: note: include the header <ctype.h> or explicitly provide a declaration for 'isspace' 1 error generated. make: *** [puma_http11.o] Error 1 make failed, exit code 2 Gem files will remain installed in /Users/k_end/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/puma-4.3.5 for inspection. Results logged to /Users/k_end/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/extensions/x86_64-darwin-17/2.6.0/puma-4.3.5/gem_make.outその後、Rubyのバージョンを変えたりbrewのアップデートをしたりRubyを再インストールをしたりopensslを再インストールしたりしてみましたが、解消せず。
しかも、他の人に聞いてみたところ、同じバージョンでも普通にできている。pumaのバージョンを3台に下げれば動くことはわかったものの、どうにか解決したい。
対処法
結論からいうと、Xcodeの最新バージョンがpumaにエラーを投げているらしい。
以下のコマンドで解消した。$ bundle config build.puma --with-cflags="-Wno-error=implicit-function-declaration" $ bundle installfail to bundle install puma 4.3.5 or gem puma with ruby-2.6.6 on macos-10.15.6 - Stack Overflow
$ bundle config build.puma --with-cflags="-Wno-error=implicit-function-declaration" とは
とりあえずこれでうまく行ったけど、つまり何をやっているのさ?と思ったので、とりあえず自分の理解の範囲で調べてまとめました。
bundle config build.puma
$ bundle config Settings are listed in order of priority. The top value will be used. build.puma Set for the current user (/Users/k_end/.bundle/config): "--with-cflags=-Wno-error=implicit-function-declaration" path Set for your local app (/Users/k_end/workspace/personal/paranoia/.bundle/config): "vendor/bundle"pathに関しては覚えてはいないですが、
$ bundle config set path 'vendor/bundle'
でpathを設定していたのだと思います。bundlerで非推奨になった --path --binstubs - Qiita
Bundlerでビルドオプションを指定する - Qiita
--with-cflags
pumaをビルドするときには、C言語で書かれたファイルをコンパイルしている(エラーでは
compiling puma_http11.c
でこけていた)。
--with-cflags
オプションを付けることで、puma_http11.cや他のCファイルを-Wno-error=implicit-function-declaration
オプションを付けてコンパイルします。
-Wno-error=implicit-function-declaration
-Werror-implicit-function-declaration
というのが、「関数が宣言される前に使われている場合にエラーを出」すオプションらしい。そして、「これらの特定の警告オプションのそれぞれには,-Wno-で始まる警告を出力させないための否定形式があります.」ということなので、関数が宣言される前に使われている場合にエラーを出さないということです。
警告を要求/抑止するオプション - フリーソフトウェア徹底活用講座(3)今回は、
#include <ctype.h>
がされていないエラーが出ているので、それをエラーとして出力しないようにしています。結論
ということで、コンパイル時におけるエラーを発生させないようにしているだけなので、あくまでも応急処置のようなコマンドのようです。
Explicitly include ctype.h to fix compilation warning by venables · Pull Request #2314 · puma/pumaで解決しそうなので、とりあえずマージされるまでは現在のオプションを設定することでしのぎたいと思います。
- 投稿日:2020-08-08T17:59:08+09:00
RailsアプリをHerokuで公開する方法
プログラミングの勉強日記
2020年8月8日 Progate Lv.226
目標
すでにローカルで作成済みのRailsアプリケーションをHeroku上で公開する。(すでにGitHubにコードをプッシュ済み)
方法
1.Herokuに新規登録をする
Herokuの公式サイトから新規登録を行う。(無料)
2.Heroku用のデータベースをインストールする。
Gemfileを以下のように書きかえる。
Gemfile# 開発環境、テスト環境 group :development, :test do gem 'sqlite3' # sqlite3 end # 本番環境 group :production do gem 'pg' # PostgreSQL end
Gemfileを書きかえたら、反映するためにbundle install
をする。ターミナル$ bundle installデータベースの設定ファイル(
config/database.yml
)を書きかえる。config/database.yml# 変更前 production: <<: *default database: db/production.sqlite3 # 変更後 production: <<: *default adapter: postgresql encoding: unicode pool: 53.Herokuにログインする
ターミナル(私はGit Bashを利用しました)からログインする。
ターミナル$ heroku loginブラウザで以下のような画面が開く。
画面のLog Inを押すとログインすることができる。(ターミナルでも確認できる)
4.Heroku上でアプリを作成する
自分でサービス名を決めて、以下のコマンドを実行する。サービス名は、最初が文字で始まり、最後が文字または数字である必要があり、小文字、数字、ダッシュのみを含めることができる。
ターミナル$ heroku create サービス名アプリが作られていれば、
https://サービス名.herokuapp.com/
にアクセスすると以下の画面が出てくる。5.Herokuにコードをプッシュする
GitHubにコードが管理されていることが前提。
ターミナル$ git push heroku master成功すると、先ほどのURLをリロードすると以下の画面が出てくる。
ターミナル$ heroku run rails db:migrateデータベースを更新すると、先ほどのURLでサイトが表示される。
メモ(ファイルを変更した場合のコマンド)
ターミナル$ git add -A $ git commit -m "メッセージ" $ git push heroku master $ heroku run rails db:migrate データベースをリセット(初期化)する場合 $ heroku pg:reset DATABASE問題点
以上の方法で、Heroku上Railsアプリケーションを公開することができた。
しかし、carrierwaveとcloudinaryを用いて画像を投稿する機能を作成したが、この部分がうまくいかないので、もう少し試行錯誤してみようと思う。
Herokuにcloudinaruを追加するときにクレカの登録が必要みたい、、?参考文献
- 投稿日:2020-08-08T17:59:08+09:00
[無料で簡単]RailsアプリをHerokuで公開する方法
プログラミングの勉強日記
2020年8月8日 Progate Lv.226
目標
すでにローカルで作成済みのRailsアプリケーションをHeroku上で公開する。(すでにGitHubにコードをプッシュ済み)
方法
1.Herokuに新規登録をする
Herokuの公式サイトから新規登録を行う。(無料)
2.Heroku用のデータベースをインストールする。
Gemfileを以下のように書きかえる。
Gemfile# 開発環境、テスト環境 group :development, :test do gem 'sqlite3' # sqlite3 end # 本番環境 group :production do gem 'pg' # PostgreSQL end
Gemfileを書きかえたら、反映するためにbundle install
をする。ターミナル$ bundle installデータベースの設定ファイル(
config/database.yml
)を書きかえる。config/database.yml# 変更前 production: <<: *default database: db/production.sqlite3 # 変更後 production: <<: *default adapter: postgresql encoding: unicode pool: 52.5. herokuコマンドを使用する(herokuコマンドが使える人は飛ばしてOK)
herokuコマンドを使うためには、heroku toolbaltというツールをインストールする必要がある。
こちらからインストールすることができる。以下のコマンドでherokuコマンドが使えるか確認できる。(私はGit Bashで行った)
ターミナル$ heroku --version3.Herokuにログインする
ターミナル(私はGit Bashを利用した)からログインする。
ターミナル$ heroku loginブラウザで以下のような画面が開く。
画面のLog Inを押すとログインすることができる。(ターミナルでも確認できる)
4.Heroku上でアプリを作成する
自分でサービス名を決めて、以下のコマンドを実行する。サービス名は、最初が文字で始まり、最後が文字または数字である必要があり、小文字、数字、ダッシュのみを含めることができる。
ターミナル$ heroku create サービス名アプリが作られていれば、
https://サービス名.herokuapp.com/
にアクセスすると以下の画面が出てくる。5.Herokuにコードをプッシュする
GitHubにコードが管理されていることが前提。
ターミナル$ git push heroku master成功すると、先ほどのURLをリロードすると以下の画面が出てくる。
ターミナル$ heroku run rails db:migrateデータベースを更新すると、先ほどのURLでサイトが表示される。
メモ(ファイルを変更した場合のコマンド)
ターミナル$ git add -A $ git commit -m "メッセージ" $ git push heroku master $ heroku run rails db:migrate データベースをリセット(初期化)する場合 $ heroku pg:reset DATABASE問題点
以上の方法で、Heroku上Railsアプリケーションを公開することができた。
しかし、carrierwaveとcloudinaryを用いて画像を投稿する機能を作成したが、この部分がうまくいかないので、もう少し試行錯誤してみようと思う。
Herokuにcloudinaruを追加するときにクレカの登録が必要みたい、、?参考文献
挫折した人必見!HerokuでRailsアプリを公開する方法
herokuのデータベースをリセット/リストア/再構築する
HerokuにRailsアプリをデプロイする手順
- 投稿日:2020-08-08T17:29:36+09:00
Could9での環境開発 - チートシート (Rails Tutorial)
$ printf "install: --no-document \nupdate: --no-document\n" >> ~/.gemrcリスト 1.1: バージョンを指定してRailsをインストールする
$ gem install rails -v 5.1.6リスト 1.2: Railsプロジェクトで使うenvironmentディレクトリを作成する(クラウドの場合は不要)
$ cd # ホームディレクトリに移動する $ mkdir environment # 'environment' ディレクトリを作成する $ cd environment/ # 'environment' ディレクトリに移動する
- 投稿日:2020-08-08T16:44:57+09:00
docker-compose upでDBが立ち上がらない「Mysql2::Error::ConnectionError: Unknown MySQL server host 'db' (-2)」への対処法
dockerで環境構築をし、サーバーを起動しようと
docker-compose up
をすると
Mysql2::Error::ConnectionError: Unknown MySQL server host 'db' (-2)
というエラーが出てしまう。ターミナルにて、エラーログを確認すると
何かが原因でDBがシャットダウンしてしまっている模様。
privilege tables
なのでsudoで作成するユーザのテーブル?
なぜdockerでこの内容のエラーが出る?
と色々疑問に思ったが、とりあえず一度全てのvolumeを削除してみることに。解決策
①volumeのIDを調べる
$ docker volume ls DRIVER VOLUME NAME local b1d0c8467782387a61c446e1ea2aedaa745d6f120c4c6423bdc37e9005a7bd34②上記で調べた
VOLUME NAME
を用い、rmコマンドにてvolumeを削除$ docker volume rm [VOLUME NAME] # 例↓ $ docker volume rm b1d0c8467782387a61c446e1ea2aedaa745d6f120c4c6423bdc37e9005a7bd34③
docker-compose.yml
を元に、コンテナ&サーバー再起動$ docker-compose up --build $ docker-compose run web rails db:create $ docker-compose run web rails db:migrate④localhost:3000にアクセス
→ 無事エラーなく起動原因
mysqlのテーブル情報が保存される場所がvolumeなので
コンテナを削除した際にvolumeコンテナを削除しきれておらず、前回のmysqlの情報が中途半端に残っていたため
、権限不足となっていたみたいです。これ以前に何回もコンテナを作って削除して、を繰り返して試行錯誤していたため、その時の残骸でしょう...
参考にした記事
- 投稿日:2020-08-08T16:44:57+09:00
docker-compose upでDBが立ち上がらないときにやったこと
dockerで環境構築をし、サーバーを起動しようと
docker-compose up
をすると
Mysql2::Error::ConnectionError: Unknown MySQL server host 'db' (-2)
というエラーが出てしまう。ターミナルにて、エラーログを確認すると
何かが原因でDBがシャットダウンしてしまっている模様。
privilege tables
なのでsudoで作成するユーザのテーブル?
なぜdockerでこの内容のエラーが出る?
と色々疑問に思ったが、とりあえず一度全てのvolumeを削除してみることに。解決策
①volumeのIDを調べる
$ docker volume ls DRIVER VOLUME NAME local b1d0c8467782387a61c446e1ea2aedaa745d6f120c4c6423bdc37e9005a7bd34②上記で調べた
VOLUME NAME
を用い、rmコマンドにてvolumeを削除$ docker volume rm [VOLUME NAME] # 例↓ $ docker volume rm b1d0c8467782387a61c446e1ea2aedaa745d6f120c4c6423bdc37e9005a7bd34③
docker-compose.yml
を元に、コンテナ&サーバー再起動$ docker-compose up --build $ docker-compose run web rails db:create $ docker-compose run web rails db:migrate④localhost:3000にアクセス
→ 無事エラーなく起動原因
mysqlのテーブル情報が保存される場所がvolumeなので
コンテナを削除した際にvolumeコンテナを削除しきれておらず、前回のmysqlの情報が中途半端に残っていたため
、権限不足となっていたみたいです。これ以前に何回もコンテナを作って削除して、を繰り返して試行錯誤していたため、その時の残骸でしょう...
参考にした記事
- 投稿日:2020-08-08T13:47:16+09:00
form_withにselectでジャンルを選択する方法
はじめに
- Golf Gearのreview Appを作成中
- 投稿の際、Maker(Taylormade, calloway...)とClubの種類(Driver, Iron, Putter...)とFormから選んで投稿したい。
form_with実装
_form.html.erb<%= form_with(model: @gear, local: true) do |form| %> <div class="form-group"> <%= form.label :maker_id, "Maker" %> <%= form.select(:maker_id, Maker.all.map {|maker|[maker.name, maker.id] }, {prompt: "Select Maker"}, {class: "form-control"}) %> </div> <div class="form-group"> <%= form.label :club_id, "Club" %> <%= form.select(:club_id, Club.all.map {|club|[club.name, club.id] }, {prompt: "Club or Accesory"}, {class: "form-control"}) %> </div>
form.select(保存したいカラム、テーブルのデータをallで全て取得し、mapで一つずつ||に代入。:nameと:idに分ける
Controller編集
gears_controller.rbclass GearsController < ApplicationController before_action :find_gear, only: [:edit, :update] def new @gear = current_user.gears.new end def create @gear = current_user.gears.new(gear_params) if @gear.save redirect_to root_path, notice: 'Gear was successfully created.' else render 'new' end end def edit end def update if @gear.update(gear_params) redirect_to gear_path(@gear), notice: 'Gear was successfully updated.' else render 'edit' end end private def gear_params params.require(:gear).permit(:name, :description, :maker_id, :club_id, :image) end def find_gear @gear = Gear.find(params[:id]) end end
:edit
,update
の際は、どの@gear
かをfind(params[:id])
でsetする。- privateメソッドで、
:maker_id
とgear_id
を引き渡しできるように設定する。
- 投稿日:2020-08-08T12:45:07+09:00
dockerコンテナ内でrspecコマンド(自分用)
全specファイルをテストbin/rspec特定のディレクトリをテストbin/rspec spec/system
- 投稿日:2020-08-08T11:07:21+09:00
lazy_high_chartsを1.6.1にアップデートしたらCIが落ちるようになった
Railsでlazy high chartsを使っていて、最近アップデートしようとしたら、エラーが出るようになって更新できなかったので、そのときに調べたことをまとめています。
気の早いお方へ
7/29以前からlazy_high_chartsを使っていて、アップデートしたら
couldn't find file 'highcharts/highcharts' ...
というエラーが出てあれー?ってなっている方はrake highcharts:update
をしてみてください。vendor/assets/javascripts/highcharts
以下に最新のhighchartsがダウンロードされて使えるようになります。詳細
CIでエラー
dependabotが更新のプルリクを作ってくれていたんですが、CIでエラーが出ていました。
couldn't find file 'highcharts/highcharts'
と、highchartsFailure/Error: //= require highcharts/highcharts ActionView::Template::Error: couldn't find file 'highcharts/highcharts' with type 'application/javascript' Checked in these paths: /home/circleci/repo/app/assets/config /home/circleci/repo/app/assets/images /home/circleci/repo/app/assets/javascripts /home/circleci/repo/app/assets/stylesheets : :
調査
地道に前回インストールしたバージョンのコミットからの差分を見ました。
大変そうですが、実は5個しかみてません。
普段から最新のgemを使うようにしていて、ホントよかったです!それで見つけたのがこのコミットです。
内容は「gemにjsのソースをバンドルすると、本家がアップデートするたびにgemのバージョンもあげなきゃいけなくて大変だと思うので、別途利用者が個別にインストールする形をとったらどうでしょう?」というもので、最新のhighchartsを取得するrakeタスクの追加と、gem内部のjsの削除がされていました。
その後、よくよく見るとREADME.mdのインストール手順にrakeタスクの実行が追加されていました。
highchartsのインストールで解決
追加されたインストール手順の
rake highcharts:update
を実行すると、無事にhighchartsをインストールできました。場所はvendor/assets/javascripts/highcharts
です。利用しているページでグラフが表示されていることを確認して、問題ないことがわかりました。
リポジトリに登録して、解決しました。
懸念事項
今までlazy_high_chartsのアップデートでhighchartsの更新が行われていたわけですが…これが自分たちでやらなくてはならなくなってしまいました…。
どうやって忘れないようにしよう…。
おわりに
sprocketsからwebpackerに移行したいです…!
そしたらアップデート作業をdependabotに頼めるので。あとは…README.mdのblame見ればよかった。
ちゃんとREADME.mdも更新されていたので、コミットログでなくて、こちらを見たらもっと楽だったと思いました…。
- 投稿日:2020-08-08T10:33:24+09:00
【超初心者的】Railsアプリ作成 Part.3 ビューの設定
【超初心者的Railsアプリ作成】土台作り Part.2 コントローラの設定 の続きです。
コントローラを介してデータベースの中身をページに表示したり、データベースの中身を操作するための画面を作成します。MVCのVです。
ビューに関して
ビューは app/views/menus/ の配下に作成します。menusの部分は作成したモデル名の複数形です。コントローラに設定したメソッドと同じ名前でファイルを作成します。作成が必要なのは4つです。
メソッド名 ファイル名 使用用途 index index.html.erb 一覧表示画面 show show.html.erb 詳細表示画面 new new.html.erb 新規登録画面 edit edit.html.erb 編集画面 残り3つのメソッドはいずれかのビューで使用するため、専用のビューを必要としません。ボタンやリンクで呼び出します。
メソッド名 ファイル名 使用用途 create new.html.erb 作成 update edit.html.erb 更新 destroy いずれか 削除 ビューファイルの作成
app/views/menus/index.html.erb<table> <thead> <tr> <th>商品名</th> <th>値段</th> <th>説明</th> </tr> </thead> <tbody> <% @menus.each do |menu| %> <tr> <td><%= menu.name %></td> <td><%= menu.price %></td> <td><%= menu.description %></td> </tr> <% end %> </tbody> </table>app/views/menus/show.html.erb<table> <tr> <th>商品名</th> <td><%= @menu.name %></td> </tr> <tr> <th>値段</th> <td><%= @menu.price %></td> </tr> <tr> <th>説明</th> <td><%= @menu.description %></td> </tr> </table>app/views/menus/new.html.erb<%= form_with model: @menu do |form| %> <div> <%= form.label "商品名" %> <%= form.text_field :name %> </div> <div> <%= form.label "値段" %> <%= form.text_field :price %> </div> <div> <%= form.label "説明" %> <%= form.text_field :description %> </div> <div> <%= form.submit %> </div> <% end %>app/views/menus/edit.html.erb<%= form_with model: @menu do |form| %> <div> <%= form.label "商品名" %> <%= form.text_field :name %> </div> <div> <%= form.label "値段" %> <%= form.text_field :price %> </div> <div> <%= form.label "説明" %> <%= form.text_field :description %> </div> <div> <%= form.submit %> </div> <% end表示確認
ビューを作成したのでブラウザでアクセス出来るようになりました。URLは下記のとおりです。
メソッド名 ファイル名 使用用途 URL index index.html.erb 一覧表示画面 http://localhost:3000/menus show show.html.erb 詳細表示画面 http://localhost:3000/menus/1 new new.html.erb 新規登録画面 http://localhost:3000/menus/new edit edit.html.erb 編集画面 http://localhost:3000/menus/1/edit URLの数字(menus/1など)はデータベースに登録したデータのIDです。IDは自動で割り振られる番号で、登録した順に増えていきます。確認する場合はrails consoleを使用します。
ターミナル% bin/rails c
ターミナルirb(main):001:0> Menu.all Menu Load (0.6ms) SELECT "menus".* FROM "menus" LIMIT $1 [["LIMIT", 11]] => #<ActiveRecord::Relation [#<Menu id: 1, name: "ラーメン", price: 600, description: "おいしい", created_at: "2020-07-12 02:20:36", updated_at: "2020-07-12 02:20:36">Menu id: の数字がURLの1にあたります。
レイアウトテンプレート
ところで、HTMLを少し触ったことがある人ならお気づきかもしれませんが、ビューファイルには
<html>
や<body>
などのタグを書いていません。それなのにちゃんとブラウザで表示がされるのは、レイアウトテンプレートのおかげです。ビューはコントローラの機能(メソッド)を使うための見た目を”部分的”に作成するもので、ページ全体の見た目は「app/views/layouts/application.html.erb」というファイルが担っています。このファイルには
<html>
や<body>
などが書かれています。そしてこのファイルの中に、以下の行が見つけられると思います。作成したビューはこの
<%= yield %>
によって読み込まれる仕組みになっています。app/views/layouts/application.html.erb<%= yield %>たとえばどのページにも常に表示させたいメニューなどは、レイアウトテンプレートで見た目を作成しておけば、わざわざ1つ1つビューファイルでメニューを作る必要がありません。とても効率的ですね。
つづく
- 投稿日:2020-08-08T10:15:24+09:00
【初心者が悩む】RubyとPHPとPythonどれが良いのか?
まずはじめに
プログラミングをやってみようとしてまず考える事が「どのプログラミング言語から初めよう?」というところではないでしょうか。
そしてググっていくとRubyというプログラミング言語が真っ先に情報として入ってくるのではないでしょうか?
Rubyが真っ先に初心者に引っかかる理由は何と言っても「プログラミングスクールの殆どがRubyを激推ししているから」に尽きます。
ちなみに更にググってみるとRubyと似た言語にPHPとPythonがあるのです。
一体どの言語を勉強すれば良いのでしょうか?
RubyとPHPとPythonのイメージ
まず、殆ど知識が無い状態の私が持っていたイメージ。
- Ruby - 初めて耳にする。
- PHP - 古臭い。
- Python - 初めて耳にする。
結果、なんとなくPHPは聞いたことがある...という程度です。私の場合は、ワードプレスでブログ運営していた時期が少しばかりあったのでPHPというプログラミング言語の存在は知っていました。
PHPは古臭いと書きましたが、ググってみると、
- Ruby - 1993年2月24日生まれ(1995年12月発表)
- PHP - 1994年生まれ(1995年6月8日発表)
- Python - 1990年生まれ(1991年発表)
PHPがこの3つのプログラミング言語の中で新しいことが分かりました。イメージだけで、古臭いと決め付けていたPHPに謝りたいです。
PHPだけ少し違う!?
比較されるには何か理由がある訳ですが、この3つのプログラミング言語は、サーバーサイドでとても使われている言語です。
そして、記述の方法がとてもよく似ています。
例えばシンプルにHello world!を3つの言語で使用してみましょう!
Rubyprint "Hello World!"PHP<?php echo "Hello World!"; ?>Pythonprint("Hello world!")......
....
..気づきましたか!?
RubyとPythonは書き方が似ていますが、PHPだけ少しゴチャっとしていますよね。先ほどは、記述方法がよく似ていると書きましたが、実はよくよく見てみるとPHPだけどこか違います。なぜ、PHPだけ少しゴチャっとしているのかはPHPのWikipediaに下記のような記載を見つけましたが、これが答えなのではないでしょうか?
元々PHPはプログラミング言語と言えるものではなく、単にテンプレート的な処理を行うだけであったが、度重なる機能追加やコードの書き直しにより、2017年現在リリースされているPHP 5やPHP 7は目的によらず汎用的に使うことの出来るスクリプト言語となっている。
要するに
PHPは元々、プログラミング言語とは違うものだった。
それが答えだと思います。RubyとPHPとPythonはなぜ比較されるのか?
ここでは大きく考えられる2つの要因について書きます。
フレームワークが凄い
フレームワークは、アプリケーションを作るときに開発工程を大幅に短縮することのできるソフトウェアのことで、このフレームワークが充実している=凄い機能のアプリを短期間で作成することのできる。使える人が使えば、魔法のアイテムのようなものですが、今回紹介したRubyとPHPとPythonには、
- Ruby - Ruby on Rails
- PHP - Laravel
- Python - Django
上記のような素晴らしいフレームワークが揃っています。
近年伸びているメジャーサイトが利用している
やっぱりここに尽きるのではないでしょうか?
- Ruby - Twitter, Hulu etc...
- PHP - Wikipedia, Facebook etc...
- Python - Googleの検索エンジン, YouTube etc...
どのプログラミング言語も甲乙付け難い一流企業が利用しています。
結局どの言語を学べばいいのか?
興味を持った言語を学べば良いと言ったらそれで済む話ですが、
趣味ではなく就職や転職の為に学んでいるのならば単純に求人数だけを見てみると、
PHP>=Ruby>Python
の傾向なので、PHPが一番なのかもしれません。
あくまで、求人数だけでの話ですが...。
- 投稿日:2020-08-08T07:57:25+09:00
AWS Copilotを使ってRailsアプリケーションのCI/CDパイプラインを爆速で構築する
記事の概要
AWS Copilotを使って作成したECS上のRailsアプリケーションにおいて、CI/CDパイプラインを構築します。
また、その際にハマったポイントを共有します。↓の記事の続きになります。
AWS Copilotを使ってRailsコンテナの本番環境を爆速で構築するAWS Copilot
AWSでコンテナ化されたアプリケーションの開発、リリースを容易に行うためのコマンドラインツールです。
コマンドを叩くとCloudFormationが動き、必要なリソースの作成やデプロイを行うことができる。CI/CDパイプラインもコマンド一つで作成できます。※Fargate起動タイプのみサポートしています
Pipeline
Githubへのpushをトリガにしてコンテナデプロイを実行するための仕組みです。
CopilotによってPipelineを作成すると、CloudFormationによってCodeBuildのリソースが作成されます。Pipeline作成方法
手順概要
- GitHubの個人アクセストークン準備
- master.keyのAmazon SSMへの登録
- Pipelineの定義
- Pipelineの作成
- ビルドプロジェクトのイメージ修正(Rubyのバージョン次第)
GitHubの個人アクセストークン準備
PipelineからGithubリポジトリを参照するために、GitHubの個人アクセストークンが必要なので事前に準備しておく必要があります。
アクセストークンは
repo
、admin:repo_hook
のスコープが必要です。
個人アクセストークンを使用するmaster.keyのAmazon SSMへの登録
Railsのmaster.keyは普通はGit管理から外すためGithub上にありませんが、PipelineはGithubリポジトリを参照してDockerイメージを作るためmaster.keyを何かしらの方法でECSに渡す必要があります。
セキュアに管理するためにAmazon SSMのパラメータストアを利用します。下記コマンドでmaster.keyの文字列をAmazon SSMのパラメータストアに登録します。
タグの値については適宜自身のものに変更してください。$ aws ssm put-parameter --name RAILS_MASTER_KEY --value master.keyの文字列 --type SecureString\ --tags Key=copilot-environment,Value=production Key=copilot-application,Value=copilot-demo続いて、Serviceのmanifest.ymlを変更します。
secretsを宣言することでECSからSSMのパラメータストアを参照できます。
「ECSで参照できる環境変数: SSMに登録したパラメータのキー」のように指定します。copilot/api/manifest.ymlvariables: RAILS_ENV: development secrets: RAILS_MASTER_KEY: RAILS_MASTER_KEY # ECSで参照できる環境変数: SSMに登録したパラメータのキーPipelineの定義
続いてPipelineを定義します。
EnvironmentやServiceを作成した時と同じように対話型で進めていきます。
このタイミングでPipelineが参照するGithubリポジトリや個人アクセストークンを指定します。$ copilot pipeline init Would you like to add an environment to your pipeline? [? for help] (y/N) > y Which environment would you like to add to your pipeline? [Use arrows to move, type to filter, ? for more help] > production Which GitHub repository would you like to use for your service? [Use arrows to move, type to filter, ? for more help] > https://github.com/ssshun/rails_copilot Please enter your GitHub Personal Access Token for your repository rails_copilot: [? for help] > XXXXXXXXXXXXXX完了すると以下の2ファイルが作成されます。基本はデフォルトのままで問題ないです。
- buildspec.yml
- pipeline.yml
Pipelineの作成
以下のコマンドでPipelineを作成
$ git add . && git commit -m "Adding Pipeline Buildspec" && git push $ copilot pipeline updateしばらく経ってからCodeBuildを確認すると、ビルドプロジェクトとパイプラインが作成されているのがわかります。
ビルドプロジェクトのイメージ修正
アプリケーションのRubyのバージョン次第ではこの手順は不要です。
2020/08/08時点では、アプリケーションがRuby2.7を利用する場合、この作業が必要でした。buildspec.ymlを修正し、ビルドプロジェクトのrubyランタイムのバージョンを2.7に変更します。
copilot/buildspec.ymlversion: 0.2 phases: install: runtime-versions: docker: 18 ruby: 2.7続いて、AWSコンソールにて、ビルドプロジェクト > ビルド詳細 > 環境 からイメージを修正します。
CopilotでPipelineを作成した場合、イメージがaws/codebuild/amazonlinux2-aarch64-standard:1.0
になるのですが、Ruby2.7のランタイムがaws/codebuild/amazonlinux2-aarch64-standard:1.0
に対応していないためです。Ruby2.7に対応している
aws/codebuild/amazonlinux2-x86_64-standard:3.0
に変更します。
buildspecを修正したので、Pipelineを更新します。
$ git add . && git commit -m "Modifying Pipeline Buildspec" && git push $ copilot pipeline updateハマったポイント
Pipeline名がCloudFormationの命名規則違反
プロジェクトディレクトリにアンダースコアを入れて、そのままPipelineを作成すると以下のようなエラーが発生します。
check if pipeline exists: describe stack pipeline-copilot-demo-ssshun-rails_copilot: ValidationError: 1 validation error detected: Value 'pipeline-copilot-demo-ssshun-rails_copilot' at 'stackName' failed to satisfy constraint: Member must satisfy regular expression pattern: [a-zA-Z][-a-zA-Z0-9]*|arn:[-a-zA-Z0-9:/._+]*原因ですが、プロジェクトのディレクトリ名にアンダースコアが含まれると、デフォルトのPipeline名にもアンダースコアが入ります。
そのため、このままだとCloudFormationのスタック名の命名規則に違反してしまいます。copilot/pipeline.yml# The name of the pipeline name: pipeline-copilot-demo-ssshun-rails_copilot # プロジェクトディレクトリがrails_copilotの場合のデフォルト以下のようにアンダースコアが含まれないように名前を修正すれば解消されます。
copilot/pipeline.yml# The name of the pipeline name: pipeline-copilot-demo-ssshun-rails-copilotビルドプロジェクトのランタイムとイメージの不整合
CodeBuildにてビルドが成功しないのでログを確認したところ以下のエラーが発生していました。
アプリケーションのランタイム(Ruby2.7)とビルドプロジェクトのランタイム(Ruby2.6)の不整合が原因と思われます。rbenv: version `ruby-2.7.1' is not installed (set by /codebuild/output/src020247698/src/.ruby-version)ビルドプロジェクトのランタイムをRuby2.7に変更したらいけるかと思い、buildspecを修正しましたが、
copilot/buildspec.ymlversion: 0.2 phases: install: runtime-versions: docker: 18 ruby: 2.7再度、別のエラーが発生しました。
Ruby2.7のランタイムがCodeBuildのビルドプロジェクトのイメージaws/codebuild/amazonlinux2-aarch64-standard:1.0
に対応していないためでした。Phase complete: DOWNLOAD_SOURCE State: FAILED Phase context status code: YAML_FILE_ERROR Message: Unknown runtime version named '2.7' of ruby. This build image has the following versions: 2.6上の手順で書いた通り、イメージをRuby2.7に対応している
aws/codebuild/amazonlinux2-x86_64-standard:3.0
に変更して解決しました。ECSからSSMのパラメータストアが参照不可
master.key参照のためにAmazon SSMのパラメータストアを登録する際に、タグは要らないだろうと思って以下のように登録していました。
$ aws ssm put-parameter --name RAILS_MASTER_KEY --value master.keyの文字列 --type SecureStringその状態でPipelineでデプロイしたところ、ECSタスクで以下のエラーが発生しました。
パラメータストアのRAILS_MASTER_KEYの参照権限がないとのことでした。Fetching secret data from SSM Parameter Store in ap-northeast-1:AccessDeniedException: User: arn:aws:sts::XXXXXXXXXXXX:assumed-role/copilot-demo-production-api-ExecutionRole-DYGK7EGS469J/0e93e07304b641d58e5fc147122d2f4c is not authorized to perform: ssm:GetParameters on resource: arn:aws:ssm:ap-northeast-1:XXXXXXXXXXXX:parameter/RAILS_MASTER_KEY status code: 400, request id: 8b6bac83-1d83-4abe-8d19-bbaa4a5e4a29調べていくと、
manifest.yml
でsecretsを設定するとECSのタスク実行ロールにSSM参照用のIAMポリシーが作成されることがわかりました。
ポリシーをよくよく見ると、パラメータストアのタグで条件指定して参照権限を付与していました。ここら辺のきめ細やかさはすごいですね。copilot-demo-production-apiSecretsPolicy{ "Version": "2012-10-17", "Statement": [ { "Condition": { "StringEquals": { "ssm:ResourceTag/copilot-environment": "production", "ssm:ResourceTag/copilot-application": "copilot-demo" } }, "Action": [ "ssm:GetParameters" ], "Resource": [ "arn:aws:ssm:ap-northeast-1:XXXXXXXXXXXX:parameter/*" ], "Effect": "Allow" }, { "Condition": { "StringEquals": { "secretsmanager:ResourceTag/copilot-application": "copilot-demo", "secretsmanager:ResourceTag/copilot-environment": "production" } }, "Action": [ "secretsmanager:GetSecretValue" ], "Resource": [ "arn:aws:secretsmanager:ap-northeast-1:XXXXXXXXXXXX:secret:*" ], "Effect": "Allow" }, { "Action": [ "kms:Decrypt" ], "Resource": [ "arn:aws:kms:ap-northeast-1:XXXXXXXXXXXX:key/*" ], "Effect": "Allow" } ] }パラメータストア登録時には以下のようにしっかりとタグ指定しましょう。
$ aws ssm put-parameter --name RAILS_MASTER_KEY --value master.keyの文字列 --type SecureString\ --tags Key=copilot-environment,Value=production Key=copilot-application,Value=copilot-demoまとめ
今回作成したコードは以下です。
https://github.com/ssshun/rails-copilotAWS Copilotを使って作成したECS上のRailsアプリケーションにおいて、CI/CDパイプラインを構築しました。
AWSコンソールでの操作は最小限で簡単にデプロイフローを作成できました。
- 投稿日:2020-08-08T02:00:35+09:00
『CircleCI』Rails appに、circleCIを組み込む
やりたいこと
- pushした際に、testを走らせsuccess or failをslackに通知。
- masterに、mergeされた際は1をやった後に、deploy jobを走らせsuccess or failをslackに通知
必要なこと
- circleCIに、登録
- circleCI監視下に置きたいRepositoryを設定
- credentials.ymlを使って環境変数を管理している場合circleCIにmaster.key用の環境変数を作る
- capistranoによる自動deploy flowを実現するために、circleCIに秘密鍵を登録する
master.keyの登録
see -> https://qiita.com/murata0705/items/9c99fc715d8b987a5b6e
SSH鍵の登録
see -> https://circleci.com/docs/ja/2.0/add-ssh-key/#%E6%89%8B%E9%A0%86参考
.circleci/config.ymlversion: 2.1 orbs: ruby: circleci/ruby@0.1.2 slack: circleci/slack@3.4.1 jobs: build: docker: - image: circleci/ruby:2.5.1-node-browsers environment: RAILS_ENV: test BUNDLER_VERSION: 2.1.4 - image: circleci/mysql:5.6.47-ram working_directory: ~/app steps: - checkout - run: name: Install bundler command: gem install bundler -v 2.1.4 - run: name: Which bundler? command: bundle -v - restore_cache: keys: - v1-dependencies-{{ checksum "Gemfile.lock" }} # fallback to using the latest cache if no exact match is found - v1-dependencies- - run: name: Bundle Install command: bundle install --jobs=4 --retry=3 --path vendor/bundle - save_cache: paths: - ./vendor/bundle key: v1-dependencies-{{ checksum "Gemfile.lock" }} - run: name: Wait for DB command: dockerize -wait tcp://127.0.0.1:3306 -timeout 120s # Database setup - run: bundle exec rake db:create - run: bundle exec rake db:schema:load # run tests! - run: name: run tests command: | mkdir /tmp/test-results TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)" bundle exec rspec --format progress \ --format RspecJunitFormatter \ --out /tmp/test-results/rspec.xml \ --format progress \ $TEST_FILES # collect reports - store_test_results: path: /tmp/test-results - store_artifacts: path: /tmp/test-results destination: test-results # run rubocop - run: name: run rubocop command: bundle exec rubocop - slack/status: success_message: ':successcircleci:$CIRCLE_BRANCH Build Success\n:github: User:$CIRCLE_USERNAME' failure_message: ':failcircleci2:$CIRCLE_BRANCH Build Fail\n:github: User:$CIRCLE_USERNAME' webhook: '${SLACK_WEBHOOK}' deploy: docker: - image: circleci/ruby:2.5.1-node-browsers environment: BUNDLER_VERSION: 2.1.4 working_directory: ~/app steps: - checkout - run: name: Install bundler command: gem update bundler - run: name: Which bundler? command: bundle -v - restore_cache: keys: - v1-dependencies-{{ checksum "Gemfile.lock" }} # fallback to using the latest cache if no exact match is found - v1-dependencies- - run: name: Bundle Install command: bundle install --jobs=4 --retry=3 --path vendor/bundle - save_cache: paths: - ./vendor/bundle key: v1-dependencies-{{ checksum "Gemfile.lock" }} - add_ssh_keys: fingerprints: - 0f:2a:6c:6a:85:f7:b4:5a:18:95:9f:71:f3:14:d0:a8 - run: name: caistrano deploy command: bundle exec cap production deploy - slack/status: success_message: ':successcircleci:$CIRCLE_BRANCH Deploy Success\n:github: User:$CIRCLE_USERNAME' failure_message: ':failcircleci2:$CIRCLE_BRANCH Deploy Fail\n:github: User:$CIRCLE_USERNAME' webhook: '${SLACK_WEBHOOK}' workflows: version: 2.1 build-deploy: jobs: - build - deploy: requires: - build filters: branches: only: master補足
全くCI/CDに対する知識ない状態でググりながら書いたので所々おかしいです。
試しにやってみようみたいな突発的なモチベーションからだったので、、、参考になるリンク
- 投稿日:2020-08-08T00:25:22+09:00
carrierwaveを用いて画像投稿機能を作成
自分用です!!
carrierwaveをインストール
Gemfilegem carrierwavebundle installしてください。
uploaderを生成
ターミナルrails g uploader board_imageこれによって、「この設定をこのモデルとこのモデルに適応する」といったことを柔軟に行えるような仕様となっているのです。
uploaderdef store_dir "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" endといった記述が施されています。
これは、carrierwaveを通じた画像のアップロード先をどこにするのかを指定しており、指定されたディレクトリに、アップロードされたファイルが保存されていくことになります。
DBに保存されるのは、ファイルそのものではなく、ファイルへの参照データになります.
モデルの関連付け
boardモデルと、boardカラムに保存される画像の関連付けを行います。
board.rbclass Board < ApplicationRecord belongs_to :user mount_uploader :board_image, BoardImageUploader validates :title, presence: true, length: { maximum: 255 } validates :body, presence: true, length: { maximum: 65_535 } enduploadファイルでの設定
uploardclass BoardImageUploader < CarrierWave::Uploader::Base storage :file def store_dir "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" end def default_url 'board_placeholder.png' end def extension_whitelist %w[jpg jpeg gif png] end endここで、
def default_url
'board_placeholder.png'
endは、デフォルトでの画像を指定しています。
プレビューでは最初にここで指定した画像が表示されます。def extension_whitelist
%w[jpg jpeg gif png]
endは、アップロードできる拡張子を制限します。
formを作成
formをパーシャルで作成します。
ここでは、画像用のformはをfile_fieldを用います。
_form.html.erb<%= form_with model: board, local: true, class: "form-group" do |f| %> <%= render "shared/error_messages", object: f.object %> <div class="form-group"> <%= f.label :title %> <%= f.text_field :title, class: "form-control", id: "board_title" %> </div> <div class="form-group"> <%= f.label :body %> <%= f.text_area :body, class: "form-control", id: "board_body", rows: "10" %> </div> <div class="form-group"> <%= f.label :board_image %> <%= f.file_field :board_image, class: "form-control", accept: 'image/*', onchange: 'previewFileWithId(preview)' %> <%= f.hidden_field :board_image_cache %> <div class='mt-3 mb-3'> <%= image_tag board.board_image.url, id: 'preview', size: '300x200' %> </div> </div> <%= f.submit (t 'defaults.create'), class: "btn btn-primary"%> <% end %>ここでの、accept: 'image/*は、画像ファイル全般を指定しています。
<%= image_tag board.board_image.url, id: 'preview', size: '300x200' %>プレビューを表示しています。boardモデルのboard_imageのurlを呼び出し、表示しています。
<%= f.hidden_field :board_image_cache %>hidden属性でimage_cacheは、画像を指定したけれども、バリデーションエラーなどにより保存が失敗した場合の画面再表示時などに、画像情報をキャッシュしておくための領域。
<%= f.file_field :board_image, class: "form-control", accept: 'image/*',onchange:'previewFileWithId(preview)' %>onchangeとは、イベントハンドラープロパティで、ユーザーの入力の応じて動的に表示内容を変えるときに発生するchangeイベントを処理します。
input,select,textarea要素において、ユーザーによる要素の変更が完了した際に行われます。
onchangeの書き方は、
onchange: '関数名()'で表します。
JSファイルを設定する
javascriptの記載は、application.jsには記載せず、別の専用ファイルを作成する。
ここでは、application.jsは個別のJavaScriptを読み込む専用のファイルのため、preview.jsファイルを作成し記載する。
preiew.jsfunction previewFileWithId(id) { const target = this.event.target; const file = target.files[0]; const reader = new FileReader(); reader.onloadend = function () { preview.src = reader.result; } if (file) { reader.readAsDataURL(file); } else { preview.src = ''; } }1行ずつ解説していくと、
const target = this.event.target;は、
traget・・・操作を差し込む対象のオブジェクト
event.target・・・最初にイベントが起こった要素です。今回だと、ファイルを選択した時のイベントを示します。const file = target.files[0];targetには「files」というプロパティが用意されています。
管理されているファイルは、「File」というオブジェクトの形をしています。
このFileオブジェクトには、ファイルに関する各種の情報や、ファイルアクセスのためのメソッドなどがまとめられているのです。files[0]で一つ目のFileオブジェクトを取り出しています。
const reader = new FileReader();FileReaderオブジェクトで、ファイルを取得します。
reader.onloadend = function () { preview.src = reader.result; }onloadend、FileReaderのイベントです。データの読み込みが成功か失敗に関わらず終了した時にloadendイベントが発生し、ここに設定したコールバック関数が呼び出されます。
そして、取得されたファイルの結果を、previewのsrc属性に指定しています。
if (file) { reader.readAsDataURL(file); } else { preview.src = ''; }readAsDataURL()は、FileReaderのメソッドです。ファイルを、Data URIとして読み込むメソッドです。例えば画像ファイルをこのメソッドで読み込んで、読み込んだデータをimg要素のsrc属性に指定すればブラウザに表示できます。
前文でscr属性を指定したので、ここで、画像を表示させます。
エラーメッセージを設定
最後にエラーメッセージを設定していきます。
carrierwave.ja.ymlを新たに生成し、記載していきます。
carrierwave.ja.ymlja: errors: messages: carrierwave_processing_error: 処理できませんでした carrierwave_integrity_error: は許可されていないファイルタイプです carrierwave_download_error: はダウンロードできません extension_whitelist_error: "は %{allowed_types}の形式でアップロードしてください" extension_blacklist_error: "%{extension}ファイルのアップロードは許可されていません。アップロードできないファイルタイプ: %{prohibited_types}" content_type_whitelist_error: "%{content_type}ファイルのアップロードは許可されていません。アップロードできるファイルタイプ: %{allowed_types}" content_type_blacklist_error: "%{content_type}ファイルのアップロードは許可されていません" rmagick_processing_error: "rmagickがファイルを処理できませんでした。画像を確認してください。エラーメッセージ: %{e}" mini_magick_processing_error: "MiniMagickがファイルを処理できませんでした。画像を確認してください。エラーメッセージ: %{e}" min_size_error: "を%{min_size}以上のサイズにしてください" max_size_error: "を%{max_size}以下のサイズにしてください"これで完成です!