- 投稿日:2020-02-23T22:54:37+09:00
deviseインストール後rails s でローカルサーバー起動しない
自分用忘備録
環境
ruby 2.6.3
rails 5.2.4undefined method `config' for Devise:Module (NoMethodError)
config/initializers/devise.rb
Devise.setup do |config|
~~
Devise.config.sign_out_via = :get
Deviseを入れていて、二重にしてしまったのが、原因。
config.sign_out_via = :get
に修正。
無事開通。
- 投稿日:2020-02-23T21:51:07+09:00
RSpecでHTTPメソッドDELETEのテストをする時の注意点
概要
"expected #count to have changed by -1, but was changed by 0"
のエラー文の解消話です。前提
- 具体的なコードはほとんど書いていないです。
テストが落ちたコード
describe OrdersController do describe 'delete #destroy' do it "deletes the article" do order = create(:order) expect{ delete :destroy, id: order }.to change(Order,:count).by(-1) end end endブルーな気持ち
DELETEについてのテストを書いていたのですが、
"expected #count to have changed by -1, but was changed by 0"
のエラー文が登場して原因がわからず頭を抱えていました。解決方法
DELETEの処理がレコードの物理削除ではなく論理削除を行なっていたことが原因でした
そのため、レコードの総数ではなく論理削除処理が行われていることをテストするようにテスト方法を見直して解決できました。
まとめや自己反省
"expected #count to have changed by -1, but was changed by 0"
のエラーが発生したら
物理削除
ではなく論理削除
ではないか?と疑ってみてください。destroyメソッドの中身を読み直すと物理削除ではなく論理削除を行なっていることが気づけただろうから、テスト対象のメソッドを見直してからテストを書くようにしよう。
- 投稿日:2020-02-23T20:43:15+09:00
Rails6 DBのupdate_atなどに格納された日にちをYYYY-MM-DDの形で取り出す
目的
- DBのcreated_atやupdate_atなどのカラムに格納された日にちの値を
YYYY-MM-DD HH:MM:SS
の形で取り出す方法をまとめる困りごと
特定のidのupdate_atをそのまま使用しようとすると下記の様に出力されてしまう。
Tue, 04 Feb 2020 09:01:35 UTC +00:00
YYYY-MM-DD HH:MM:SS
の形で出力したい。2020-02-04 09:01:35結論
- 取得したupdate_atの値を
.to_s
で文字列に変換することでYYYY-MM-DD HH:MM:SS
で得ることができる。書き方の例
- Postモデルのpostsテーブルのidが1のレコードのupdate_atカラムに格納されている日にちデータを
YYYY-MM-DD HH:MM:SS
の形で変数に格納する方法を記載する。postsデーブルのidが1のレコードに格納されているデータはすでにDBに格納されているものとする。
#DBのpostsテーブルのidが1のレコード情報を変数@postに格納 @post = Post.find_by(id: 1) #変数last_update_dateに先に取得したidが1のレコードのupdated_atをto_sメソッドにて文字列にしたものを格納する。 last_update_date = @post.updated_at.to_s puts last_update_date
- 投稿日:2020-02-23T19:44:02+09:00
【Ruby on Rails】 Railsのgem"ancestry"によるタグ機能実装(多階層構造)
今回はタグ機能を実装するために、 Railsのgem"ancestry"を利用していきます。
これに関しては今回初めてなので、学習しながらメモしていきたいと思います仕組みを理解する。
タグの階層とどうやって紐づけるか理解していきましょう!!
gem無しの場合親コテゴリー - 中間カテゴリ-(親_子) - 子カテゴリー - 中間カテゴリー(子_孫) - 孫カテゴリー - 中間テービル(孫_商品) - 商品gemがないと上記のような仕組みのため、非常にめんどくさいです。
gem'ancestry'の場合商品 - 中間テーブル - カテゴリー上記だけで完結します。だから非常に楽ですね
ではどうして、カテゴリーテーブル一つで3階層可能なのか?疑問になりますよね
一緒に学習しましょう!タグの3階層の仕組み
3階層までタグが作成可能で、
一番上の親カテゴリは祖先がないので、
ancestryカラム: NULL
ID:14番目のレコードですが、ancestry: 1になってます。
祖先はID:1のレコードという意味ですね。つまりレディースが親カテゴリということです。
では、さらにトップスよりも下の階層(3階層目)はどうなのか?
つまり、祖先はID:1番目の レディースになるということです。ancestry: 1/14となっています。
つまり、ID:1の子である,ID:14番目の子という表示カテゴリータグの仕組み1階層目: null 2階層目: 1階層目のID 3階層目: 1階層目のID/2階層目のID3階層目のancestryカラムを取得すれば、2階層目、1階層目と辿れる仕組みです。3階層目までしか構造上できないようです(もしもできる場合は、コメントで教えていただければ幸いです。)4階層目を実装するには、別のテーブルが必要となります。
どうやって商品と紐づけるのか?
タグIDと商品IDを紐づける中間テーブルをおきます。
product_categoriesテーブル
Column Type Options product_id references null: false category_id references null: false 実際にDBを見て理解していきましょう!!
この例だと
productのID:1番目とcategory_id:7番目が紐づいてます。
categoryの7番目は、コスメ・香水・美容ですから、
商品は「コスメ・香水・美容」カテゴリに紐づいているとわかります。このように、中間テーブルを利用して商品とカテゴリーを紐づけていきます。
モデル商品 - 中間テーブル - カテゴリーまとめ
カテゴリータグの仕組み1階層目: null 2階層目: 1階層目のID 3階層目: 1階層目のID/2階層目のIDモデル商品 - 中間テーブル - カテゴリー表示する仕組み1. htmlより、親カテゴリを並べる 2. 親カテゴリを選択されたら、コントローラーで子カテゴリを取得、JS(ajax)で追加表示 3. 子カテゴリが選択されたら、コントローラーで孫kてゴリを取得、JS(ajax)で追加表示 親 > 子 > 孫 親 > 子: 親.children > 孫: 子.children #ここは後述します。実装をしていく。
それでは実装していきましょう!!
インストール
Gemfilegem 'ancestry'を追加して
ターミナル$ bundle instalインストールをしたら、再起動させたいので、
ターミナル$ rails sモデルの作成
商品モデルはすでに作成してる前提で、作成方法を記述しません。
カテゴリーモデルを作成します。
ターミナル$ rails g model categoryモデルを作成したら、migrateファイルを記述していきましょう!!
categoriesテーブル
Column Type Options name string null: false, index: true ancestry string index: true Association
- has_many :products
- has_ancestry
migateファイルclass CreateCategories < ActiveRecord::Migration[5.2] def change create_table :categories do |t| t.string :name, index: true, null: false t.string :ancestry, index: true t.timestamps end end endターミナル$ rake db:migrate中間テーブル(product_categories)を作成
ターミナル$ rails g model product_categoryproduct_categoriesテーブル
Column Type Options product_id references null: false category_id references null: false アソシエーション
- belongs_to :product
- belongs_to :category
上記のテーブルになるようにmigrateファイルを記述していきます。
migrateファイルclass CreateProductCategories < ActiveRecord::Migration[5.2] def change create_table :product_categories do |t| t.references :product, null:false t.references :category, null:false t.timestamps end end endターミナルrake db:migrateアソシエーション
カテゴリーモデルは下記になります
category.rbclass Category < ApplicationRecord has_ancestry has_many :product_categories, dependent: :destroy has_many :products, through: :product_categories end中間テーブルは下記になります。
product.category.rbclass ProductCategory < ApplicationRecord belongs_to :product belongs_to :category end商品モデルは下記になります
product.rbclass Product < ApplicationRecord has_many :product_categories, dependent: :destroy has_many :categories, through: :product_categories endはい!これでモデルは完了ですね。
では次に進みましょう!!!DB → モデル → コントローラー
seeds.rbでカテゴリを生成
今回はモデル別にseedファイルを作成するやり方をします
[通常方法](https://www.sejuku.net/blog/28395)seeds.rbrequire './db/seeds/category.rb'カテゴリー用のseedファイルを作成しましょう
db > seedsのフォルダを作成 > category.rbを作成seeds/category.rb#親カテゴリ lady = Category.create(name: "レディース") #子カテゴリー lady_1 = lady.children.create(name: "トップス") #孫カテゴリー lady_1.children.create([{name: "Tシャツ/カットソー(半袖/袖なし)"},{name: "Tシャツ/カットソー(七分/長袖)"},{name: "シャツ/ブラウス(半袖/袖なし)"},{name: "シャツ/ブラウス(七分/長袖)"},{name: "ポロシャツ"},{name: "キャミソール"},{name: "タンクトップ"},{name: "ホルターネック"},{name: "ニット/セーター"},{name: "チュニック"},{name: "カーディガン/ボレロ"},{name: "アンサンブル"},{name: "ベスト/ジレ"},{name: "パーカー"},{name: "トレーナー/スウェット"},{name: "ベアトップ/チューブトップ"},{name: "ジャージ"},{name: "その他"}])では生成しましょう
ターミナル$ rails db:seedコントローラーの作成
DB → モデル → コントローラーの処理で進むので、コントローラーを作成します。
仕組み1. htmlより、親カテゴリを並べる 2. 親カテゴリを選択されたら、コントローラーで子カテゴリを取得、JSで追加表示 3. 子カテゴリが選択されたら、コントローラーで孫kてゴリを取得、JSで追加表示 親 > 子 > 孫この仕組みを動かすための独自メソッドを作成します。
products_controller.rbclass ProductsController < ApplicationController def get_category_children @children = Category.find(params[:parent_id]).children end def get_category_grandchildren @grandchildren = Category.find("#{params[:child_id]}").children end endと上記のアクションを作成します。
@children = Category.find(params[:parent_id]).children上記の.childenって何?ってなると思いますが、
親カテゴリから子カテゴリを取得するためのメソッドです。先ほど親>子>孫の順番で取得すると説明しましたが、.childrenを使うので下記のようになります。
親 > 子:親カテゴリ.chidren > 孫: 子カテゴリ.children他にもいろんなメソッドが用意されているので、一度Githubを見ていただければと思います。
Github:ancestroyAjaxを導入する(JQuery)
route.rb
Ajaxに対応したルーティングにします。
route.rbresources :products do collection do # 新規用(new) usr:products/newのため get 'get_category_children', defaults: { format: 'json' } get 'get_category_grandchildren', defaults: { format: 'json' } end member do # 編集(edit用) usl: products/id/editのため get 'get_category_children', defaults: { format: 'json' } get 'get_category_grandchildren', defaults: { format: 'json' } end endAjax対応のコントローラーにする。
先ほどコントローラーを作成していましたが、改良します
products_conroller.rbdef get_category_children respond_to do |format| format.html format.json do @children = Category.find(params[:parent_id]).children end end end def get_category_grandchildren respond_to do |format| format.html format.json do @grandchildren = Category.find("#{params[:child_id]}").children end end endこれでAjax対応のコントローラーになりました。
jbuilder作成
コントローラーとAjax用jsとで情報の架け橋となるjbuilderを作成
子カテゴリを追加するために、idと名前をjsに持っていきたい。children.jbuilderjson.array! @grandchildren do |child| json.id child.id json.name child.name endgrandchildren.jbuilderjson.array! @grandchildren do |grandchild| json.id grandchild.id json.name grandchild.name endAjax用のjs
Ajaxで要素を追加するjsを記述します。
category-ajax.js$(document).on('turbolinks:load', function(){ // カテゴリーの選択肢が入ったdiv var categoryBox = $('.form-details__form-box__category') // 親カテゴリー function appendOption(category) { var html = `<option value="${category.id}" data-category="${category.id}">${category.name}</option>` } // 子カテゴリー function appendChildBox(insertHTML) { var childSelectHtml = ''; childSelectHtml = `<div class='form-select' id="child-category"> <select class= 'select-default' name="product[category_ids][]"> <option value>---</option> ${insertHTML} </select> <i class='fa fa-angle-down icon-angle-down'></i> </div>` categoryBox.append(childSelectHtml); } // カテゴリーボックスで親カテゴリが変わった場合 categoryBox.on("change", "#parent-category", function(){ var parentCategory = $("parent-category").value; if(parentCategory !== "") { $.ajax ({ url: '/products/get_category_children', type: "GET", data: { parent_id: parentCategory }, dataType: 'json' }) .done(function(children){ $('#child-category').remove(); $('#grandchild-category').remove(); var insertHTML = ''; children.forEach(function(grandchild){ insertHTML += appendOption(grandchild); }); appendGrandchildrenBox(insertHTML); }) .fail(function(){ alert('カテゴリー取得に失敗しました'); }) } else { //親カテゴリーが初期値(---)の場合、子カテゴリー以下は非表示にする //親カテゴリが未選択の場合、子、孫カテゴリの選択欄は非表示にしたいので、そのように変更 $('#child-category').remove(); $('#grandchild-category').remove(); $('#size').remove(); } }) })学習して作成中
参考になるサイト
Github:ancestroy
Railsでタグ機能をgemを使わずに実装した際のメモ
Railsのgem"ancestry"による多階層構造の実現
- 投稿日:2020-02-23T19:26:55+09:00
RailsをAWSでデプロイする
はじめに
手軽にRailsをAWSにデプロイする手順をまとめました。
極力シンプルになるように、EC2インスタンスを一つ作成し、その中に自分のRailsアプリを含め、必要なものを全てインストールしてデプロイします。
データベースはMySQL、WebサーバーはNginXでの環境構築です。
AWSのサーバーでのファイルの書き込みはviというコマンドで行います。(vi ファイル名でそのファイルを編集、そのファイルがない場合は新たにファイルを作って書き込みできます。詳しい使い方は要検索!)
注意点
コードの中で、/var/www/rails/{アプリ名}などと書いている時がありますが、自分の環境に合わせて、
/var/www/rails/sample_appとしてください
/var/www/rails/{sample_app}ではないのでご注意。
第一章 サーバーの準備
1.VPCを作成
- 名前は適当につける
- IPv4CIDERブロックは10.0.0.0/16に設定
- あとはデフォルトで
2.サブネットを作成
- 名前は適当につける
- VPCは先程作ったVPCを選択
- IPv4CIDERブロックは10.0.0.0/24に設定
3.インターネットゲートウェイを作成
- 名前は適当につける
- 作成後は先程作ったVPCをアタッチ
4.ルートテーブルを作成
- 名前は適当につける
- 作成後はルートの設定で0.0.0.0/0を追加し保存
- サブネットの関連付けで先程作ったサブネットを選択
- あとはデフォルトで
5.セキュリティグループを作成
- 名前は適当につける
- 作成後は
タイプ:HTTP ソース:任意の場所(他の設定はデフォルト)
と、
タイプ:SSH ソース:任意の場所(他の設定はデフォルト)
を追加し保存- あとはデフォルトで
6.EC2を作成
EC2インスタンスの作成
- 無料枠からAmazonLinuxを選ぶ(AmazonLinux2を選ばないように注意、この後の環境構築で差が出てきてしまうので)
- ネットワーク:先程作ったVPCを選択
- サブネット:先程作ったサブネットを選択
- 自動割り当てパブリックIP:有効化を選択
- セキュリティーグループ:先程作ったセキュリティグループを選択
キーペアの登録とElasticIPの割当て
- キーペアファイル(~.pem)はローカル(自分のパソコンのこと)の.ssh配下に移動
- ElasticIPを作り先ほど作ったEC2インスタンスに割り当てる
第二章 サーバーにログインし環境構築
1.EC2にログイン
キーペアファイルのあるディレクトリに移動
cd .sshキーペアファイルに権限を付与
chmod 600 {自分のキーペアの名前}.pemサーバー(EC2インスタンス)にログイン
ssh -i {自分のキーペアのpemファイル} ec2-user@{自分のElasticIPアドレス}ユーザーを作成
sudo adduser {新規ユーザー名} (#新規ユーザー名の登録) sudo passwd {パスワード} (#新規ユーザー名のパスワード登録) sudo visudoユーザーの権限の変更
1.rootに関する権限の記述箇所 root ALL=(ALL) ALL を探す。 2.その下に、作成したユーザーに権限を追加する記述 {ユーザー名} ALL=(ALL) ALL を追加するユーザーの切替
sudo su - {ユーザー名}2.諸々必要なものをインストール
sudo yum install git make gcc-c++ patch openssl-devel libyaml-devel libffi-devel libicu-devel libxml2 libxslt libxml2-devel libxslt-devel zlib-devel readline-devel mysql mysql-server mysql-devel ImageMagick ImageMagick-devel epel-release3.Rubyをインストール
以下Rubyをインストールするための下準備
git clone https://github.com/sstephenson/rbenv.git ~/.rbenvecho 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profileecho 'eval "$(rbenv init -)"' >> ~/.bash_profilesource .bash_profilegit clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-buildrbenv rehash以下Rubyのインストールです、インストールするRubyのバージョンは自分の環境に合わせてください
rbenv install -v 2.6.5rbenv global 2.6.5rbenv rehashインストールできたか確認
ruby -v4.node.jsをインストール
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash. ~/.nvm/nvm.shnvm install node5.Yarnをインストール
curl -o- -L https://yarnpkg.com/install.sh | bashexport PATH="$HOME/.yarn/bin:$HOME/.config/yarn/global/node_modules/.bin:$PATH"第三章 Rails、DB、Webサーバーの設定
1.Railsの設定
/var/www/rails/ の配下にRailsアプリを持ってくる、以下を一行一行実行していく
cd / (/ディレクトリに移動) sudo chown {ユーザー名} var (varフォルダの所有者を{ユーザー名}にする) cd var (varディレクトリに移動) sudo mkdir www (wwwディレクトリの作成) sudo chown {ユーザー名} www (wwwフォルダの所有者を{ユーザー名}にする) cd www (wwwディレクトリに移動) sudo mkdir rails (wwwディレクトリの作成) sudo chown {ユーザー名} rails (railsフォルダの所有者を{ユーザー名}にする) cd rails (railsディレクトリに移動)GitHubからクローン
git clone {自分のRailsのアプリのリポジトリのclone用URL}DBとの接続用の設定、以下をRailsアプリ内のconfig/database.ymlに追加
production: <<: *default database: {アプリ名} username: root #ここをrootに変更する password: #ここを空欄にする※ローカルのconfig/master.keyの一行を全てコピーし、
cloneしてきたアプリのconfig/master.keyに記載をする
(master.keyはgitignoreされておりローカルのmaster.keyの内容は
githubには反映されないため自分でコピペしてくる)2.MySQLの設定
起動
sudo service mysqld startln -s /var/lib/mysql/mysql.sock /tmp/mysql.sockDBの作成
rails db:create RAILS_ENV=productionマイグレーション
rails db:migrate RAILS_ENV=production3.Unicornの設定
Gemfileに以下を追記
group :production, :staging do gem 'unicorn' endbundlerをインストール
gem install bundlerbundlerでunicornのgemをインストール
bundle install設定ファイルの追加
vi ~/var/www/rails/{アプリ名}/config/unicorn.conf.rb以下を設定ファイルに記載
# set lets $worker = 2 $timeout = 30 $app_dir = "/var/www/rails/{アプリ名}" #自分のアプリケーション名 $listen = File.expand_path 'tmp/sockets/.unicorn.sock', $app_dir $pid = File.expand_path 'tmp/pids/unicorn.pid', $app_dir $std_log = File.expand_path 'log/unicorn.log', $app_dir # set config worker_processes $worker working_directory $app_dir stderr_path $std_log stdout_path $std_log timeout $timeout listen $listen pid $pid # loading booster preload_app true # before starting processes before_fork do |server, worker| defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect! old_pid = "#{server.config[:pid]}.oldbin" if old_pid != server.pid begin Process.kill "QUIT", File.read(old_pid).to_i rescue Errno::ENOENT, Errno::ESRCH end end end # after finishing processes after_fork do |server, worker| defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection end4.NginXの設定
インストール
sudo yum install nginxNginxの設定
ディレクトリを移動
cd /etc/nginx/conf.d/etc/nginx/conf.d下に設定ファイルの作成
vi {アプリ名}.conf以下を記載
# log directory error_log /var/www/rails/{アプリ名}/log/nginx.error.log; #自分のアプリケーション名に変更 access_log /var/www/rails/{アプリ名}/log/nginx.access.log; #自分のアプリケーション名に変更 # max body size client_max_body_size 2G; upstream app_server { # for UNIX domain socket setups server unix:/var/www/rails/{アプリ名}/tmp/sockets/.unicorn.sock fail_timeout=0; #自分のアプリケーション名に変更 } server { listen 80; server_name ~~~.~~~.~~~.~~~; #自分のElasticIP # nginx so increasing this is generally safe... keepalive_timeout 5; # path for static files root /var/www/rails/{アプリ名}/public; #自分のアプリケーション名に変更 # page cache loading try_files $uri/index.html $uri.html $uri @app; location @app { # HTTP headers 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; } # Rails error pages error_page 500 502 503 504 /500.html; location = /500.html { root /var/www/rails/{アプリ名}/public; #自分のアプリケーション名に変更 } }第四章 世界に公開
1.Railsのプリコンパイル
rails assets:precompile RAILS_ENV=production2.NginXを起動
sudo service nginx start3.Unicornを起動
bundle exec unicorn_rails -c /var/www/rails/{アプリ名}/config/unicorn.conf.rb -D -E production4.お疲れ様です
これでブラウザに自分のElasticIPを打ち込むと世界中のパソコンやスマホから自分のアプリにアクセスできます!
5.その他コマンド
unicornの起動確認
ps -ef | grep unicorn | grep -v grepunicornの終了
kill {masterのPID}以下のようなYarnのエラーが出ることがあります(Railsコマンドを実行した際にこのようなエラーが出る時があります)
======================================== Your Yarn packages are out of date! Please run `yarn install --check-files` to update. ========================================エラー文に従い以下を実行しましょう
yarn install --check-files
- 投稿日:2020-02-23T18:04:01+09:00
本番環境にrake db:seedを叩き込む方法
開発環境、テスト環境、本番環境にseedデータを叩き込む
seedデータとは
seedデータとは、データベースに投入する初期データのこと
この初期データの投入は、db/seeds.rb に記載します。
db/seeds.rb# 親階層 lady = Category.create(name: "レディース") men = Category.create(name: "メンズ") baby_kids = Category.create(name: "ベビー・キッズ") interior_residence_accessory = Category.create(name: "インテリア・住まい・小物") book_music_game = Category.create(name: "本・音楽・ゲーム") toy_hobby_goods = Category.create(name: "おもちゃ・ホビー・グッズ") cosme_perfume_beauty = Category.create(name: "コスメ・香水・美容") appliance_smartphone_camera = Category.create(name: "家電・スマホ・カメラ") sport_leisure = Category.create(name: "スポーツ・レジャー") handmade = Category.create(name: "ハンドメイド") ticket = Category.create(name: "チケット") car_motorcycle = Category.create(name: "自動車・オートバイ") others = Category.create(name: "その他") # 子階層_レディース lady_1 = lady.children.create(name: "トップス") lady_2 = lady.children.create(name: "ジャケット/アウター") lady_3 = lady.children.create(name: "パンツ") lady_4 = lady.children.create(name: "スカート") lady_5 = lady.children.create(name: "ワンピース") lady_6 = lady.children.create(name: "靴") lady_7 = lady.children.create(name: "ルームウェア/パジャマ") lady_8 = lady.children.create(name: "レッグウェア") lady_9 = lady.children.create(name: "帽子") lady_10 = lady.children.create(name: "バッグ") lady_11 = lady.children.create(name: "アクセサリー") lady_12 = lady.children.create(name: "ヘアアクセサリー") lady_13 = lady.children.create(name: "小物") lady_14 = lady.children.create(name: "時計") lady_15 = lady.children.create(name: "ウィッグ/エクステ") lady_16 = lady.children.create(name: "浴衣/水着") lady_17 = lady.children.create(name: "スーツ/フォーマル/ドレス") lady_18 = lady.children.create(name: "マタニティ") lady_19 = lady.children.create(name: "その他") # 孫階層_レディース lady_1.children.create([{name: "Tシャツ/カットソー(半袖/袖なし)"},{name: "Tシャツ/カットソー(七分/長袖)"},{name: "シャツ/ブラウス(半袖/袖なし)"},{name: "シャツ/ブラウス(七分/長袖)"},{name: "ポロシャツ"},{name: "キャミソール"},{name: "タンクトップ"},{name: "ホルターネック"},{name: "ニット/セーター"},{name: "チュニック"},{name: "カーディガン/ボレロ"},{name: "アンサンブル"},{name: "ベスト/ジレ"},{name: "パーカー"},{name: "トレーナー/スウェット"},{name: "ベアトップ/チューブトップ"},{name: "ジャージ"},{name: "その他"}]) lady_2.children.create([{name: "テーラードジャケット"},{name: "ノーカラージャケット"},{name: "Gジャン/デニムジャケット"},{name: "レザージャケット"},{name: "ダウンジャケット"},{name: "ライダースジャケット"},{name: "ミリタリージャケット"},{name: "ダウンベスト"},{name: "ジャンパー/ブルゾン"},{name: "ポンチョ"},{name: "ロングコート"},{name: "トレンチコート"},{name: "ダッフルコート"},{name: "ピーコート"},{name: "チェスターコート"},{name: "モッズコート"},{name: "スタジャン"},{name: "毛皮/ファーコート"},{name: "スプリングコート"},{name: "スカジャン"},{name: "その他"}]) lady_3.children.create([{name: "デニム/ジーンズ"},{name: "ショートパンツ"},{name: "カジュアルパンツ"},{name: "ハーフパンツ"},{name: "チノパン"},{name: "ワークパンツ/カーゴパンツ"},{name: "クロップドパンツ"},{name: "サロペット/オーバーオール"},{name: "オールインワン"},{name: "サルエルパンツ"},{name: "ガウチョパンツ"},{name: "その他"}]) lady_4.children.create([{name: "ミニスカート"},{name: "ひざ丈スカート"},{name: "ロングスカート"},{name: "キュロット"},{name: "その他"}]) lady_5.children.create([{name: "ミニワンピース"},{name: "ひざ丈ワンピース"},{name: "ロングワンピース"},{name: "その他"}]) lady_6.children.create([{name: "ハイヒール/パンプス"},{name: "ブーツ"},{name: "サンダル"},{name: "スニーカー"},{name: "ミュール"},{name: "モカシン"},{name: "ローファー/革靴"},{name: "フラットシューズ/バレエシューズ"},{name: "長靴/レインシューズ"},{name: "その他"}]) lady_7.children.create([{name: "パジャマ"},{name: "ルームウェア"}]) lady_8.children.create([{name: "ソックス"},{name: "スパッツ/レギンス"},{name: "ストッキング/タイツ"},{name: "レッグウォーマー"},{name: "その他"}]) lady_9.children.create([{name: "ニットキャップ/ビーニー"},{name: "ハット"},{name: "ハンチング/ベレー帽"},{name: "キャップ"},{name: "キャスケット"},{name: "麦わら帽子"},{name: "その他"}]) lady_10.children.create([{name: "ハンドバッグ"},{name: "トートバッグ"},{name: "エコバッグ"},{name: "リュック/バックパック"},{name: "ボストンバッグ"},{name: "スポーツバッグ"},{name: "ショルダーバッグ"},{name: "クラッチバッグ"},{name: "ポーチ/バニティ"},{name: "ボディバッグ/ウェストバッグ"},{name: "マザーズバッグ"},{name: "メッセンジャーバッグ"},{name: "ビジネスバッグ"},{name: "旅行用バッグ/キャリーバッグ"},{name: "ショップ袋"},{name: "和装用バッグ"},{name: "かごバッグ"},{name: "その他"}]) lady_11.children.create([{name: "ネックレス"},{name: "ブレスレット"},{name: "バングル/リストバンド"},{name: "リング"},{name: "ピアス(片耳用)"},{name: "ピアス(両耳用)"},{name: "イヤリング"},{name: "アンクレット"},{name: "ブローチ/コサージュ"},{name: "チャーム"},{name: "その他"}]) lady_12.children.create([{name: "ヘアゴム/シュシュ"},{name: "ヘアバンド/カチューシャ"},{name: "ヘアピン"},{name: "その他"}]) lady_13.children.create([{name: "長財布"},{name: "折り財布"},{name: "コインケース/小銭入れ"},{name: "名刺入れ/定期入れ"},{name: "キーケース"},{name: "キーホルダー"},{name: "手袋/アームカバー"},{name: "ハンカチ"},{name: "ベルト"},{name: "マフラー/ショール"},{name: "ストール/スヌード"},{name: "バンダナ/スカーフ"},{name: "ネックウォーマー"},{name: "サスペンダー"},{name: "サングラス/メガネ"},{name: "モバイルケース/カバー"},{name: "手帳"},{name: "イヤマフラー"},{name: "傘"},{name: "レインコート/ポンチョ"},{name: "ミラー"},{name: "タバコグッズ"},{name: "その他"}]) lady_14.children.create([{name: "腕時計(アナログ)"},{name: "腕時計(デジタル)"},{name: "ラバーベルト"},{name: "レザーベルト"},{name: "金属ベルト"},{name: "その他"}]) lady_15.children.create([{name: "前髪ウィッグ"},{name: "ロングストレート"},{name: "ロングカール"},{name: "ショートストレート"},{name: "ショートカール"},{name: "その他"}]) lady_16.children.create([{name: "浴衣"},{name: "着物"},{name: "振袖"},{name: "長襦袢/半襦袢"},{name: "水着セパレート"},{name: "水着ワンピース"},{name: "水着スポーツ用"},{name: "その他"}]) lady_17.children.create([{name: "スカートスーツ上下"},{name: "パンツスーツ上下"},{name: "ドレス"},{name: "パーティーバッグ"},{name: "シューズ"},{name: "ウェディング"},{name: "その他"}]) lady_18.children.create([{name: "トップス"},{name: "アウター"},{name: "インナー"},{name: "ワンピース"},{name: "パンツ/スパッツ"},{name: "スカート"},{name: "パジャマ"},{name: "授乳服"},{name: "その他"}]) lady_19.children.create([{name: "コスプレ"},{name: "下着"},{name: "その他"}])このseedデータをデータベースに投入するには
$ rake db:seedで開発環境には投入出来ます。
テスト環境では
$ rake db:seed RAILS_ENV=testでおけ
問題は本番環境でのseedデータの投入でござんす
上記のイメージだと
$ rake db:seed RAILS_ENV=productionこれで入りそうですが 本番環境のデータベースはそんな単純ではない
おおん? 何やっても入らんぞ?
と悩んだあげく
/var/www/アプリ名/current まで移動して実行すればデータ投入ができました。
/var/www/アプリ名 に設定して
cd currentこの状態で
rake db:seed RAILS_ENV=productionこれで 本番環境にseedデータを叩き込むことが出来ました。
なぜcurrentだと入るのか? ここは謎のまんまです。さて なぜ seedデータなのか
多階層カテゴリを扱いたかったからです
結局はancestryというgemを使いたくて そのためにはseedでデータ投入するのが一番効率的だというお話です。
gem ancestryについてはこちら
https://qiita.com/Sotq_17/items/120256209993fb05ebac
- 投稿日:2020-02-23T17:59:34+09:00
Nginxで403 Forbiddenエラーの解決策(Rails+AWS+Nginx+Unicorn環境)
ハマったこと
Railsで作ったアプリをAWSにデプロイして、いざアクセスしようとしたら403 Forbiddenエラーになりました。(下図)
前提条件
Ruby: 2.6.3
Rails: 6.0.2
Nginx: 1.12.2
サーバーのOS: Amazon Linux 2解決策(先に結論だけ)
chmod 701 /home/ec2-user
で解決しました(ec2-userディレクトリのパーミッションを700→701に変更しました)※
/home/ec2-user/
直下にRailsアプリを配置していますエラーに遭遇するまでの経緯
下記のページを参考にしながら、RailsアプリをAWSにデプロイする作業を進めていました。
https://qiita.com/Yuki_Nagaoka/items/975b7598806d6ae0c0b2上記のページでは、Railsアプリの設置場所を
/var/www/rails/
配下にしているのですが、「アプリの設置場所は好きなところでいいだろう」と思って、自分の場合は~/
(/home/ec2-user/
と同義)に配置しました。結果的に、この設置場所の違いが今回のエラーを発生させることになりました。
エラーに遭遇してから、解決するまでの経緯
そもそも、403 Forbiddenとは?
ページが存在するものの、ページを表示する権限がなくてアクセスが拒否されたことを示すHTTPステータスコードです。
(今回の場合は、NginxがRailsアプリがあるディレクトリへのアクセス権限を持っていなかったのが原因で403エラーが発生しました)参考:https://ja.wikipedia.org/wiki/HTTP_403
ログを確認し、エラーの原因を調べる
Nginxのログファイルの場所は、Nginxの設定ファイルに記述されています。
Nginxの設定ファイルは、OSによっても異なりますが、Amazon Linuxの場合は/etc/nginx/nginx.conf
,/etc/nginx/nginx.conf.default
,/etc/nginx/conf.d/***.conf
にあります。
/etc/nginx/conf.d/***.conf
の中身を見てみると、ログの場所が記述されているはずです。/etc/nginx/conf.d/***.conferror_log /home/ec2-user/***/log/nginx.error.log; access_log /home/ec2-user/***/log/nginx.access.log; . . .エラーログ(/home/ec2-user/***/log/nginx.error.log)の中身を見てみると、以下のように
Permission denied
のエラーが発生していることが分かりました。/home/ec2-user/***/log/nginx.error.log2020/02/23 05:01:35 [crit] 26964#0: *47 stat() "/home/ec2-user/***/public/" failed (13: Permission denied), client: ***, server: ***, request: "GET / HTTP/1.1", host: "***" 2020/02/23 05:01:35 [crit] 26964#0: *47 connect() to unix:/home/ec2-user/***/tmp/sockets/.unicorn.sock failed (13: Permission denied) while connecting to upstream, client: ***, server: ***, request: "GET / HTTP/1.1", upstream: "http://unix:/home/ec2-user/***/tmp/sockets/.unicorn.sock:/", host: "***" 2020/02/23 05:01:35 [error] 26964#0: *47 open() "/home/ec2-user/***/public/500.html" failed (13: Permission denied), client: ***, server: ***, request: "GET / HTTP/1.1", upstream: "http://unix:/home/ec2-user/***/tmp/sockets/.unicorn.sock/", host: "***"念の為、Unicornのログファイルも見ておいた方が良いです。サーバー上のページにブラウザからアクセスして、Nginxのログは出てくるがUnicornのログに何も表示されないのであれば、Nginxでエラーが起きていることが分かるからです。
もしUnicornのログに何か表示されれば、Railsアプリ内でエラーが起きているということになります。
パーミッションとは?
以下サイトを参考にしてください。
https://eng-entrance.com/linux-permission-basicなぜパーミッションがdenyされるのか?
ユーザーのディレクトリ(/home/ec2-user/)のパーミッションは700なので、その他のユーザーが/home/ec2-user/配下のディレクトリにアクセスできないことが原因です。
ブラウザからサーバー上のページにアクセスしたときに、nginxの実行ファイルは
nginx
というユーザー名で、Railsアプリがあるディレクトリにアクセスしていくつかのファイル(例えば、tmp/sockets/.unicorn.sockやpublic/など)を読み込みます。つまり、
nginx
という名前のユーザーが、それらのファイルへのアクセス権限を持っている必要があります。また、ファイルにアクセスするためには、ルートディレクトリからそのファイルがあるディレクトリまでのすべてのディレクトリでアクセス権限を持っていなければいけません。ちなみに、アクセス権限はパーミッションでいうところの実行権限(x)です。
解決策
したがって、nginxユーザーがec2-userディレクトリ配下にあるRailsアプリにアクセスできるようにするために、ec2-userディレクトリの「その他のユーザー」に実行権限を付与する必要があります。
(つまり、下記を実行することで解決)
chmod 701 /home/ec2-user
参考にしたサイト
- 投稿日:2020-02-23T17:30:09+09:00
フォームの遷移先の指定方法
Railsでフォームの遷移先が思ったようにいかなく、つまずいたため備忘録も兼ねて書かせていただきます。
問題点
編集データを
carts#update
に届けく、以下のようにしてみたがcarts/edit.html.erb<%= form_with(model: @cart, local: true ) do |f| %> <div> <%= f.label :quantity, "購入数" %> <%= f.number_field :quantity %> </div> <%= f.submit "更新", class: "btn" %> <% end %>この遷移先が、なぜか
cart_product_path
になってしまう。
また、Did you mean? で言われているedit_product_path
も希望する遷移先とは違う。改善方法
form_with
のオプションで、url: cart_path
と指定するとうまく遷移するようになりました。carts_add POST /carts/add(.:format) carts#add carts GET /carts(.:format) carts#index edit_cart GET /carts/:id/edit(.:format) carts#edit cart PATCH /carts/:id(.:format) carts#update (#遷移先にしたい) PUT /carts/:id(.:format) carts#update DELETE /carts/:id(.:format) carts#destroycarts/edit.html.erb<%= form_with(model: @cart, url: cart_path, local: true ) do |f| %> <div> <%= f.label :quantity, "購入数" %> <%= f.number_field :quantity %> </div> <%= f.submit "更新", class: "btn" %> <% end %>
- 投稿日:2020-02-23T17:13:26+09:00
(メモ)【Rails勉強会 第9回】アソシエーンション Part3(2020/2/23)
※こちらの記事は,「人生逆転サロン共同開発参加者限定の勉強会」で使用したコードのメモ書きです。
人生逆転サロンの共同開発について知りたい方はこちらをご覧下さい。
http://yanbaru-spike.com/l/c/yE5eqgMh/NuSs3Jlb【開催日】 2/23(日) 19:30〜20:30
前回,Deviseでユーザーのログイン機能を実装し,メッセージの一覧表示,投稿機能までを実装しました。
今回は,メッセージの削除・編集機能を付け,さらに「いいね!」機能を実装するところまで解説したいと思います。
2.4 メッセージの削除機能
app/views/messages/index.html.erb<% @messages.each do |message| %> <div> <p>【メールアドレス】 <%= message.user.email %></p> <p>【内容】 <%= message.content %></p> <!-- ***** 以下を追加 ***** --> <p> <%= link_to "削除", message_path(message), method: :delete, data: { confirm: "削除しますか?" } %> </p> <!-- ***** 以上を追加 ***** --> </div> <hr> <% end %>
- 悪い例
app/controllers/messages_controller.rbclass MessagesController < ApplicationController # ***** 以下を編集 ***** def destroy @message = Message.find(params[:id]) @message.destroy! redirect_to root_path end # ***** 以上を編集 ***** end【問題】 なぜこの書き方ではいけないのか?
- 修正後
app/controllers/messages_controller.rbclass MessagesController < ApplicationController # ログイン必須とする before_action :authenticate_user! # ***** 以下を追加 ***** # 自分のメッセージであるかどうかをチェックする before_action :correct_user, only: %i[edit update destroy] # ***** 以上を追加 ***** def index @messages = Message.includes(:user) end def new @message = Message.new end def create current_user.messages.create!(message_params) redirect_to root_path end def edit end def update end # ***** 以下を編集 ***** def destroy @message.destroy! redirect_to root_path end # ***** 以上を編集 ***** private def message_params params.require(:message).permit(:content) end # ***** 以下を追加 ***** def correct_user @message = current_user.messages.find_by(id: params[:id]) redirect_to root_path if @message.nil? end # ***** 以上を追加 ***** end2.5 メッセージの編集機能
app/views/messages/index.html.erb<% @messages.each do |message| %> <div> <p>【メールアドレス】 <%= message.user.email %></p> <p>【内容】 <%= message.content %></p> <p> <%= link_to "削除", message_path(message), method: :delete, data: { confirm: "削除しますか?" } %> <!-- ***** 以下を追加 ***** --> <%= link_to "編集", edit_message_path(message) %> <!-- ***** 以上を追加 ***** --> </p> </div> <hr> <% end %>app/controllers/messages_controller.rbclass MessagesController < ApplicationController # ログイン必須とする before_action :authenticate_user! before_action :correct_user, only: %i[edit update destroy] def index @messages = Message.includes(:user) end def new @message = Message.new end def create current_user.messages.create!(message_params) redirect_to root_path end def edit end # ***** 以下を編集 ***** def update @message.update!(message_params) redirect_to root_path end # ***** 以上を編集 ***** def destroy @message.destroy! redirect_to root_path end private def message_params params.require(:message).permit(:content) end def correct_user @message = current_user.messages.find_by(id: params[:id]) redirect_to root_path if @message.nil? end endapp/views/messages/edit.html.erb<%= form_with model: @message, local: true do |form| %> <%= form.text_field :content, required: true %> <%= form.submit "送信" %> <% end %>3. いいね機能の実装(多対多)
この章では,Twitterなどでおなじみの「いいね!」機能(の簡易版)を実装してみましょう。
2章のusersテーブルとmessagesテーブルのように関連付けを行えば……と思いきや,実は面倒な事態が起きています。
例えば次のような場合を考えてみましょう。
- usersテーブル
id 1 test@example.com 2 hoge@example.com 3 fuga@example.com
- messagesテーブル
- 「いいね!」と直接関係のない
user_id
のカラムは省略
id content 「いいね!」した人 補足:「いいね!」したuser_id 1 おはよう hogeさん, fugaさん [2, 3] 2 こんにちは testさん, fugaさん [1, 3] 3 こんばんは fugaさん 3 4 おやすみ hogeさん 2
1つのメッセージを「いいね!」しているユーザーは複数
1人のユーザーが「いいね!」しているメッセージも複数
「いいね!」については,usersテーブルとmessagesテーブルの関係は「1対多」ではなく「多対多」になっている!
配列を入れたり,ほとんど同じレコードを作成するのは避けたい。どうすればよいか?
3.1 多対多のアソシエーション
「多対多」の場合は中間テーブルを作成し,2つの「1対多」に切り分ける
- usersテーブル
id 1 test@example.com 2 hoge@example.com 3 fuga@example.com
- messagesテーブル
id content 補足:「いいね!」した人 補足:「いいね!」したuser_id 1 おはよう hogeさん, fugaさん [2, 3] 2 こんにちは testさん, fugaさん [1, 3] 3 こんばんは fugaさん 3 4 おやすみ hogeさん 2
- likesテーブル(中間テーブル)
id user_id message_id 補足 1 2 1 hogeさんが「おはよう」に「いいね!」 2 3 1 fugaさんが「おはよう」に「いいね!」 3 1 2 testさんが「こんにちは」に「いいね!」 4 3 2 fugaさんが「こんにちは」に「いいね!」 5 3 3 fugaさんが「こんばんは」に「いいね!」 6 2 4 hogeさんが「おやすみ」に「いいね!」
usersテーブルとlikesテーブルとの関係は「1対多」
messagesテーブルとlikesテーブルとの関係も「1対多」
3.2 中間テーブルの実装とアソシエーション
ターミナルrails g model Like user_id:integer message_id:integer「いいね!」が重複しないように,つまり,
[user_id, message_id]
の組が同じであるものが複数作成できないようにバリデーションを入れてからマイグレーションを行う。db/migrate/日時_create_likes.rbclass CreateLikes < ActiveRecord::Migration[6.0] def change create_table :likes do |t| # ***** 以下を修正 ***** t.integer :user_id, null: false, index: true t.integer :message_id, null: false, index: true # ***** 以上を修正 ***** t.timestamps end # ***** 以下を追加 ***** add_index :likes, [:user_id, :message_id], unique: true # ***** 以上を追加 ***** end endターミナルrails db:migrate
- モデルにバリデーションと関連付けを入れておく
- UserモデルとLikeモデルは「1対多」
- MessageモデルとLikeモデルは「1対多」
app/models/like.rbclass Like < ApplicationRecord belongs_to :user belongs_to :message validates :user_id, presence: true, uniqueness: { scope: :message_id } validates :message_id, presence: true endapp/models/user.rbclass User < ApplicationRecord has_many :messages, dependent: :destroy # ***** 以下を追加 ***** has_many :likes, dependent: :destroy # ***** 以上を追加 ***** # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable endapp/models/message.rbclass Message < ApplicationRecord belongs_to :user # ***** 以下を追加 ***** has_many :likes, dependent: :destroy # ***** 以上を追加 ***** validates :content, presence: true, length: { maximum: 140 } end
- 先ほどの表のような初期データを投入
db/seeds.rb# 中身は全て入れ替えて下さい user_list = [ { email: "test@example.com", password: "password" }, { email: "hoge@example.com", password: "password" }, { email: "fuga@example.com", password: "password" } ] message_list = [ { user_id: 1, content: "おはよう" }, { user_id: 2, content: "こんにちは" }, { user_id: 1, content: "こんばんは" }, { user_id: 1, content: "おやすみ" } ] like_list = [ { user_id: 2, message_id: 1 }, { user_id: 3, message_id: 1 }, { user_id: 1, message_id: 2 }, { user_id: 3, message_id: 2 }, { user_id: 3, message_id: 3 }, { user_id: 2, message_id: 4 } ] User.create!(user_list) Message.create!(message_list) Like.create!(like_list) puts '初期データの投入に成功しました!'ターミナルrails db:migrate:reset db:seed
rails c
で確認次のようにすれば,「いいね!」の総数を表示できる
app/views/shared/_header.html.erb<header> <% if user_signed_in? %> <%= link_to "投稿一覧", root_path %> <%= link_to "新規投稿", new_message_path %> <%= link_to 'アカウント編集', edit_user_registration_path %> <%= link_to "ログアウト", destroy_user_session_path, method: :delete %> <%= "【ログイン中のアドレス】#{current_user.email}" %> <!-- ***** 以下を追加 ***** --> <%= "【いいね数】 #{current_user.likes.count}" %> <!-- ***** 以上を追加 ***** --> <% else %> <%= link_to "新規登録", new_user_registration_path %> <%= link_to "ログイン", new_user_session_path %> <% end %> </header> <hr>【問題】メッセージを「いいね!」しているユーザーを取得するには?
app/models/message.rbclass Message < ApplicationRecord belongs_to :user has_many :likes, dependent: :destroy # ***** 以下を追加 ***** # message.liked_users で message を「いいね!」しているユーザー一覧が取得できるようになる has_many :liked_users, through: :likes, source: :user # ***** 以上を追加 ***** validates :content, presence: true, length: { maximum: 140 } end【問題】自分が「いいね!」しているメッセージを取得するには?
app/models/user.rbclass User < ApplicationRecord has_many :messages, dependent: :destroy has_many :likes, dependent: :destroy # ***** 以下を追加 ***** # user.liked_messages で user が「いいね!」しているメッセージ一覧が取得できるようになる has_many :liked_messages, through: :likes, source: :message # ***** 以上を追加 ***** # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable end3.2 「いいね!」ボタンの実装
app/views/messages/index.html.erb<% @messages.each do |message| %> <div> <p>【メールアドレス】 <%= message.user.email %></p> <p>【内容】 <%= message.content %></p> <p> <%= link_to "削除", message_path(message), method: :delete, data: { confirm: "削除しますか?" } %> <%= link_to "編集", edit_message_path(message) %> <!-- ***** 以下を追加 ***** --> <% if message.likes.exists?(user_id: current_user.id) %> <!-- いいね!済み --> ★ <% else %> <!-- いいね!していない --> ☆ <% end %> <!-- ***** 以上を追加 ***** --> </p> </div> <hr> <% end %>N+1問題を解消したい場合は,例えば次のように修正する。
app/controllers/messages_controller.rbdef index @messages = Message.includes(:user) # ***** 以下を追加 ***** # ユーザーが「いいね!」した全てのメッセージidの配列 @liked_message_ids = current_user.likes.pluck(:message_id) # ***** 以上を追加 ***** endapp/views/messages/index.html.erb<% @messages.each do |message| %> <div> <p>【メールアドレス】 <%= message.user.email %></p> <p>【内容】 <%= message.content %></p> <p> <%= link_to "削除", message_path(message), method: :delete, data: { confirm: "削除しますか?" } %> <%= link_to "編集", edit_message_path(message) %> <!-- ***** 以下を修正 ***** --> <% if @liked_message_ids.include?(message.id) %> <!-- ***** 以上を修正 ***** --> <!-- いいね!済み --> ★ <% else %> <!-- いいね!していない --> ☆ <% end %> </p> </div> <hr> <% end %>次に,「☆」を押したら「いいね!」の状態(「★」に変更)できるようにしましょう。
config/routes.rbRails.application.routes.draw do devise_for :users # ***** 以下を追加 ***** resources :messages do resource :likes, only: [:create, :destroy] end # ***** 以上を追加 ***** root to: "messages#index" end
rails routes | grep message
で作成されたルーティングを確認ターミナルtouch app/controllers/likes_controller.rb
app/controllers/likes_controller.rbclass LikesController < ApplicationController def create current_user.likes.create!(message_id: params[:message_id]) redirect_to root_path end def destroy current_user.likes.find_by(message_id: params[:message_id]).destroy! redirect_to root_path end endapp/views/messages/index.html.erb<% @messages.each do |message| %> <div> <p>【メールアドレス】 <%= message.user.email %></p> <p>【内容】 <%= message.content %></p> <p> <%= link_to "削除", message_path(message), method: :delete, data: { confirm: "削除しますか?" } %> <%= link_to "編集", edit_message_path(message) %> <% if @liked_message_ids.include?(message.id) %> <!-- いいね!済み --> <!-- ***** 以下を修正 ***** --> <%= link_to '★', message_likes_path(message), method: :delete %> <!-- ***** 以上を修正 ***** --> <% else %> <!-- いいね!していない --> <!-- ***** 以下を修正 ***** --> <%= link_to '☆', message_likes_path(message), method: :post %> <!-- ***** 以上を修正 ***** --> <% end %> </p> </div> <hr> <% end %>自分のメッセージに「いいね!」を表示させたくない場合は,次のように修正
app/controllers/likes_controller.rbclass LikesController < ApplicationController # ***** 以下を追加 ***** # 他人のメッセージであるかどうかをチェックし,自分のメッセージであれば「いいね!」ができないようにする before_action :check_others_message # ***** 以上を追加 ***** def create current_user.likes.create!(message_id: params[:message_id]) redirect_to root_path end def destroy Like.find_by(user_id: current_user.id, message_id: params[:message_id]).destroy! redirect_to root_path end # ***** 以下を追加 ***** private def check_others_message if Message.find(params[:message_id]).user_id == current_user.id redirect_to root_path end end # ***** 以上を追加 ***** endapp/views/messages/index.html.erb<% @messages.each do |message| %> <div> <p>【メールアドレス】 <%= message.user.email %></p> <p>【内容】 <%= message.content %></p> <p> <%= link_to "削除", message_path(message), method: :delete, data: { confirm: "削除しますか?" } %> <%= link_to "編集", edit_message_path(message) %> <!-- ***** 以下を修正 ***** --> <%= render 'like', message: message %> <!-- ***** 以上を追加 ***** --> </p> </div> <hr> <% end %>ターミナルtouch app/views/messages/_like.html.erb
app/views/messages/_like.html.erb<% if message.user != current_user %> <% if @liked_message_ids.include?(message.id) %> <!-- いいね!済み --> <%= link_to '★', message_likes_path(message), method: :delete %> <% else %> <!-- いいね!していない --> <%= link_to '☆', message_likes_path(message), method: :post %> <% end %> <% end %>
- 投稿日:2020-02-23T16:57:36+09:00
Redmineでもletter_openerを使って調整したメールを確認してみよう。
これはなに?
- Redmineでは、メール本文のヘッダやフッタのカスタマイズができます
- このカスタマイズが問題ないかどうか、letter_openerというgemを使って確認する方法をご紹介します
どういう人向けの記事?
このgemは、Railsでは非常に利用されているgemです。
どちらかというとRubyやRails専門ではないけれど、Redmineを運用したり、必要に応じてカスタマイズしたい人向けになります。
- developmentモード で利用が前提のgemのため、開発環境で検証する方法を理解している方向けになります
- カスタマイズの際に、まずdevelopmentモードで機能を追加調整する方針をとっている方
- その上で本番に適用する、という流れを実施できる方
どういうシーンに使うと便利?
- Redmineでメール部分のカスタマイズをしている方向け
- 管理画面からのヘッダ / フッタ調整だけでなく、内部のメール用のテンプレートをカスタマイズしたい場合
- プラグインでメールをカスタマイズしたり通知を追加したりする場合
想定通りの文言が当てはまってメールが生成されているかを確認しやすくなります。
やらないこと
- Qiita上にもletter_openerの記事はたくさんありますので、詳細には触れません
letter_openerの設定
公式のREADMEに記載がある通り進めればOKです。
RedmineもRailsアプリケーションなので、Gemfileとdevelopment.rbの設定のみで利用できるようになります。まずはgemの追加
- Redmineのソースをダウンロード(clone) します
- Redmine直下のGemfileに、以下を追記します
Gemfilegem "letter_opener", :group => :development追加したら、この追加gemを取得するため、
bundle install
を実行します。すでにRedmineに必要なgemが入っており、あとからその環境に追加する場合でも、同じくbundle install (bundle) であれば、追加で入ります。# オプション無しだとdevelopmentモードのgemを取得します bundle install設定ファイルの調整
Redmine公式のメール設定を確認
Redmineの公式サイトでの、メール送信設定は以下に記載があります。
- https://redmine.org/projects/redmine/wiki/EmailConfiguration (Email Configuration)
基本は、
config/configuration.yml.example
を元にconfig/configuration.yml
ファイルを作成し、設定をしていきます。developmentモードでも実際にsmtpを使ってメール送信を試すことができますが、デフォルトでは送信はされず、ログに送信メッセージが出力されます。
letter_openerの設定を追加する
letter_openerのREADMEに沿って設定する場合
developmentモードではメール送信をせず、letter_openerで確認する場合は、
config/environments/development.rb
に追記します。config/environments/development.rbconfig.action_mailer.delivery_method = :letter_opener config.action_mailer.perform_deliveries = trueRedmineにも
config/environments/development.rb
があるので、上記の通りの追記で利用が可能です。Redmineのconfig/configuration.ymlを使う場合
Redmine公式のメール設定にも記載がある通り、こちらでも送信設定を調整することができます。
delivery_methodをletter_openerに設定となります。config/configuration.ymldevelopment: email_delivery: delivery_method: :letter_opener perform_deliveries: trueメールを送って確認してみる
developmentモードでチケットを作成、終了してみた例です。
- メール送信対象のものは、tmp/letter_opener/ 以下に書き出されます
- 実際の送信内容と同じく、メールのテンプレートに変数が展開された形で書き出しになります
カスタマイズしたメールの確認
Redmineに慣れていない場合は、ユーザの方が直にメールに返信してしまう、ということもありがちです。
運用の初めのころは、そういったことも配慮して「このメールには返信しないでくださいね!」的なメッセージを追加していました。
Redmineの管理画面では、メール本文の上部と下部(ヘッダ / フッタ)に簡単にメッセージを追加できますので、試しに設定して、想定通りになっているか確認してみます。
Redmineの管理画面
結果はこのような感じ。
簡単ですが、十分に確認ができますね!
letter_opener_webも使う場合
letter_openerは、送信メールをファイルに書き出してくれるgemです。
さて、letter_openerはファイルシステムに書き出すため、ローカル開発環境やターミナルでの確認はできますが、開発環境がサーバにある場合は、ちょっと確認がしづらいですね。
こちらもRails開発ではポピュラーですが、letter_opener_webというgemを追加すると、Railsアプリケーションに同居する形で、ブラウザを通してletter_openerで書き出したメールを確認することができます。
追加するものは?
Gemfileに以下を追加します。
# developmentモードでのみ利用します group :development do gem 'letter_opener_web', '~> 1.0' end
- gem "letter_opener" 単体を先に追加していれば、置き換えをします
- bundle installの際に、依存関係でletter_openerも入ります
- 上記の通り、letter_openerの設定が必要です
delivery_method = :letter_opener
ルーティングを追加
letter_opener_webのREADMEに記載のあるとおり、ルーティングを追加します。
- https://github.com/fgrehm/letter_opener_web#usage
- こうすることで、http://localhost:3000/letter_opener にアクセスすると、tmp/letter_opener のディレクトリが参照できます
- Redmineへは、
config/routes.rb
の末尾(最後のendの手前)に追加で大丈夫ですconfig/routes.rb# 設定例 redmine $ svn diff config/routes.rb Index: config/routes.rb =================================================================== --- config/routes.rb (revision 19511) +++ config/routes.rb (working copy) @@ -374,4 +374,6 @@ end end end + + mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.development? end
mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.development?
を追加して再起動しますブラウザから確認してみる
ふたたびメール送信対象の操作をしてみます。
こちらはチケット変更の例。ブラウザでアクセスすると、新しいメールから降順に一覧が表示されます。
また、右側には最新のメールが表示されます。キャプチャの左隅の、tmp/letter_opener/ 側の件数と一致します。
letter_opener_webの画面から、不要になったメールを削除することも可能です。まとめ
以上、簡単な例でした。
一度通知が出てしまうと、相手のもとに届いてしまったメールは取り消せません。必要以上の情報が盛り込まれていないか?宛先は適切か?など、心配なことがありますね。
Redmineに限らず、慎重さが必要なメールに関しては、こういったツールでチェックができるというのは、とても助かりますね。実運用の際の、なにかにお役に立てば幸いです。
- 投稿日:2020-02-23T16:41:20+09:00
【Rails】deviseでパスワードなしでユーザ編集を完了させる
deviseでつくった編集画面で、パスワードを入力せずに編集を完了させようとすると、
Current password can't be blankというエラーメッセージが発生して、更新できないと思います。今回は、これをパスワードを入れずにユーザー情報を編集できるようにします。
この記事などを参考にして、
1. deviseのregistration_controllerを継承したコントローラを作成
2. ルーティングの変更
を行ったあとに、update_resourceメソッドをオーバーライドします。registrations_controller.rbclass RegistrationsController < Devise::RegistrationsController protected def update_resource(resource, params) resource.update_without_password(params) end endomniauthのログインを使う方は、パスワードはもとから設定しない(もしくは、乱数で設定する)場合も多いかと思いますので、そういった場合は以下のようにすればよいのではないでしょうか。
registrations_controller.rbclass RegistrationsController < Devise::RegistrationsController protected def update_resource(resource, params) if current_user.uid.present? || current_user.provider.present? resource.update_without_password(params) else super end end end
- 投稿日:2020-02-23T15:48:18+09:00
sidekiqざっくりまとめ
Railsで非同期処理を実現するsidekiqについて調べてわかったことをまとめます。
sidekiq自体はRails以外でも使えるものらしいです。何ができるか
非同期処理を実現する。
例えば画像アップロードの処理を非同期にすることで、ユーザーは画像アップロードが終わるまで待つことなく他のページに遷移できて、快適。必要なもの
- redisサーバー
- gem:
sidekiq
使い方
app/workers/◯◯_worker.rb
にクラスとメソッドを作成するworkerclass HogeWorker include Sidekiq::Worker def perform(id) @event = Event.find(id) @event.calculate_rank! end endcontroller内で
<クラス名>.<メソッド名>_async
でキューに入れるcontrollerdef ranking HogeWorker.perform_async @event.id endトリガーを発火して実行する
コマンドラインでコマンドを実行したり、あらかじめ定義した条件に合致した時、キューに入った処理が実行されます。
参考
- 投稿日:2020-02-23T15:37:39+09:00
ずぶの素人がAWSでRailsアプリを作るメモ
仕事でRailsを使うので、この機会に自分でも何かしようと思い行動に移すことにしました。
やりたいことリスト:
- Railsでサンプルアプリケーションをつくる
- 自分流にアレンジする
- 仕事で使わないような技術に触れるひとまずやってみようの精神で、失敗しながら学びます。
というわけでまずは環境から。
いろいろとローカルに用意するのは挫折しそうだったので、手っ取り早くAWSのCloud9を使用します。
ありがたいことに必要なものはそろっている(素人目線)ので、
新しく環境を作ったら、さくっと始めていきます。
新規作成した環境には初めは何もないので、Railsアプリをつくるときは
rails new sample -d mysql
でディレクトリから作成します。
(個人的にMySQLのほうが好きなのでDBを軽率に変更しています、「-d ~」はなくてもOKです)用意ができたのでさっそくRailsサーバーを立ち上げて(
rails s
)、まっさらなアプリを起動しよう…
としたのですが、エラーメッセージが。
仕事でも見たことないメッセージだったのでここでしばらくワタワタしました(素人感)。
まだしっかり理解してないですが、MySQLが起動してないのでDBに接続できないと怒られているようです。
ネットで調べると以下のような記事が。
MySqlのソケットエラーを解決するありがたく以下のコマンドを拝借して、実行します。
sudo /etc/init.d/mysqld restart
そうするとエラーの種類が変わりまして、”sample_development”なんてDBはねえよ、と言われました。
これは仕事場でも見たことがあったので、おとなしく
rake db:create
します。(rails db:createでもいいはず?)今度こそうまく動いて、Railsの初期アプリの画面が表示されました。
DBをSQLiteからMySQLに変更するだけでこんなにわたつく滑り出しで、今後どういった艱難辛苦があるか想像できませんが、ひとまず進めるだけは進めたいと思います。
ネタがあったり、詰まっていた部分が解決したらまたメモします。
- 投稿日:2020-02-23T14:53:56+09:00
【Rails】SQL文を直接実行する
ActiveRecordを使わずに、自分で作成したSQL文を使ってDBに問い合わせをする方法です。
name = 'サンプル太郎' email = 'tarou@example.com' now = Time.zone.now args = ['INSERT INTO users (name, email, created_at, updated_at) VALUES (?, ?, ?, ?)', name, email, now, now] #下準備 sql = ActiveRecord::Base.send(:sanitize_sql_array, args) #sql文を作成 ActiveRecord::Base.connection.execute(sql) #sql文を実行注意点
- 謎の戻り値が返ってくるので、
SELECT
はできません。- 実行速度やサーバーへの負荷をかなり抑えることができますが、バリデーションや外部キー制約が効かなくなるなど懸念点も多いので注意が必要です。
- いわゆる「Railsのレール」からは外れた実装だと思うので、ActiveRecordではどうにもならない時にだけ使う感じです。
- 投稿日:2020-02-23T14:26:19+09:00
attr_accessorで挫折した君へ
はじめに
僕は恥ずかしながら
attr_accessor
をRuby歴7ヶ月にして理解しました。学びたての頃は、『classの下についてる変なやつ』としか思っておらず、何のために置かれてるのかわからないまま、とりあえず置いとけ、エイっ!!という感じで使っていました(ひどい)ということで、attr_accessorで挫折した僕が、attr_accessorで挫折した人にattr_accessorを挫折しないように分かりやすく説明したいと思います。
ゴール
本記事では、以下のコードを完全に理解することをゴールとして説明します。
すでに理解できてるよという方はそっとブラウザバックしてください。user.rbclass User attr_accessor :name, :age def initialize(name, age) @name = name @age = age end end大前提
はじめに、大前提を説明して目線を合わせます。
『基本的に、オブジェクトの値をクラス外から参照・書き込みすることはできない』
どういうこと?と思った方は試しに以下のコードを実行してみてください。
user.rbclass User def initialize(name, age) @name = name @age = age end end user = User.new("山田",18) user.name user.ageおそらく、
undefined method `name' for #<User:0x00007faf4c182dd0 @name="山田", @age=18> (NoMethodError)
と怒られたはずです。
ちなみに、userの名前を書き換えるとどうなるでしょうか?
user.name = "佐藤" => undefined method `name=' for #<User:0x00007fee848daac0 @name="山田", @age=18> (NoMethodError)やはり怒られました...
そうなんです。何も設定をしなければ、いつも当たり前にやっていた参照、書き換えは実行できないんです。
『え??いつもRailsでやったときは出来てたのに何で今回は出来ないの??』
と思ったかもしれません。分かります。僕も全く同じように考えていました。
その答えは本記事の中でじっくり説明しますので、もう少し読み進めて行きましょう。力技で解決してみる
何も設定しなけば、オブジェクトの値の読み書きができないことが分かりました。
それなら、力技で解決するためにこんなコードを書いてみました。user.rbclass User def initialize(name, age) @name = name @age = age end def name @name end def name=(name) @name = name end end1つ目が、nameの値を読むためのメソッド、
2つ目が、nameの値を書き込むためのメソッドです。※ name=(name)という変な書き方にアレルギー反応が出た人がいるかもしれませんが、「値を更新するときはこう書くんだ」ぐらいで覚えてもらえれば大丈夫です。
これを書けば、
user.name
としたとき、nameメソッドが呼び出され、その中で@name
を参照しているため、正常に値を取り出すことができます。書き込みについても同様です。それでは、以下を実行してみましょう。
user.rbclass User 省略 end user = User.new("山田",18) p user.name p user.name = "佐藤"結果
"山田" "佐藤"今度はうまく行きました。
これで解決ですね、めでたしめでたし。。。。、となってしまったら大変です。なぜなら、このやり方だと属性(name、age)が増えるたびに読み書き用のメソッドを作らなければいけません。
今回でいうならこんな感じ。
user.rbclass User def initialize(name, age) @name = name @age = age end def name @name end def name=(name) @name = name end def age @age end def age=(age) @age = age end endこれは流石に面倒の極みです。
ということで、Rubyはこれを解決するためにアクセスメソッドというものを準備してくれています。ありがたや。すごく便利なアクセスメソッド
では、先ほどの面倒なコードをアクセスメソッドを使ってシンプルにしていきましょう。
attr_readerメソッド
attr_readerメソッドは以下の2つのメソッドの代わりになります。
# attr_reader :name, :age は以下の2つと同じ意味 def name @name end def age @age endつまり、先ほどの長ったらしいコードは以下のようにシンプルになります。
user.rbclass User attr_reader :name, :age def initialize(name, age) @name = name @age = age end def name=(name) @name = name end def age=(age) @age = age end endメソッドを2つ省略できたので、かなりシンプルになりました。もう少しスッキリさせましょう。
attr_writerメソッド
情報を書き込みするメソッドを省略するために、attr_writerメソッドがあります。
これを使うと以下のメソッドを省くことができます。# attr_writer :name, :age は以下の2つと同じ意味 def name=(name) @name = name end def age=(age) @age = age endこれを使うと、かなりスッキリ。
user.rbclass User attr_reader :name, :age attr_writer :name, :age def initialize(name, age) @name = name @age = age end end最初のコードと比べたら、別人のようですね!
でも、まだ甘いです。実はもっとシンプルにできます。
attr_accessorメソッド
もう十分でしょ、と思うかもしれませんがRubyにはattr_readerメソッドとattr_writerメソッドを兼ね備えた万能のメソッドが存在します。
それが、attr_accessorメソッドです!
これを使えば、
attr_reader :name, :age attr_writer :name, :ageが、
attr_accessor :name, :ageになります。最終形態は以下の通り。
user.rbclass User attr_accessor :name, :age def initialize(name, age) @name = name @age = age end end最終的にたったの8行におさまりました。アクセスメソッドの威力はハンパないですね!
つまり、これまで何となくクラスの頭に置いていたattr_accessorメソッドは、オブジェクトの値の読み書きを可能にしてくれる万能なメソッドだったというわけです。
じゃあ何でRailsでは何もしてないのにオブジェクトの値の読み書きができるのさ
普段、Railsで開発しているとき、特に何も意識しなくても、以下のようにオブジェクトの値を読み書きできますよね?
user.name => "佐藤" user.name = "山田" user.name => "山田"これはなぜでしょうか?
答え
Railsにおいて、テーブルに紐づく全てのModelはActiveRecordを継承しているから
解説
rails generate
で作成されたModelは、自動的にActiveRecordというクラスを継承するようにRailsが設定しています。class User < ApplicationRecord endsuperclassで先祖を辿っていくと、
irb> User.superclass => ApplicationRecord irb > ApplicationRecord.superclass => ActiveRecord::Base確かにActiveRecordというクラスがありました。
このActiveRecordにおいて、usersテーブルの各カラムをアクセスメソッド(attr_accessor)として登録しているため、
僕たちが意識しなくても、オブジェクトの値の読み書きが行えているわけですね。ActiveRecord様には足を向けて寝れません。笑
まとめ
以上を簡単にまとめるとこうなります。
- 基本的にクラス外からオブジェクトの値を読み書きすることができない
- 1つの属性ごとに読み書き専用のメソッドを作ればいつも通り読み書きできるようになる
- しかし、毎回メソッドを書くのはめんどくさい
- そこで、アクセスメソッドの出番!
- attr_readerメソッドを使うと、「読み」用のメソッドを省略できる
- attr_writerメソッドを使うと「書き込み」用のメソッドを省略できる
- attr_accessorメソッドを使えば「読み」「書き」どちらも省略できる
- Railsでオブジェクトの値を自由に読み書きできるのはActiveRecordを継承しているから
この記事でattr_accessorという不気味なメソッドへの理解が少しでも深まれば幸いです。
最後までお読みいただきありがとうございました!
- 投稿日:2020-02-23T13:59:26+09:00
docker-composeでRails6開発環境
docker-composeでRails5.2開発環境に続いて、Rails6の環境も作ってみます。5.2から移行してくるとyarnとwebpackerがなかなか最初はややこしく感じます…。最下部に理由を書いていますが、alpine版のイメージをベースにしています。
必要なファイルは2つです。
docker-compose.ymlversion: '3' services: db: image: postgres volumes: - ./postgresql/data:/var/lib/postgresql/data web: build: . command: "rails s -p 3000 -b '0.0.0.0'" volumes: - ./railsapp:/railsapp ports: - "3000:3000" depends_on: - dbFROM ruby:2.6-alpine RUN apk update && apk add libxml2-dev curl-dev make gcc libc-dev g++ nodejs \ postgresql-client postgresql-dev tzdata yarn \ && gem install rails -v "~> 6" -N RUN mkdir /railsapp WORKDIR /railsapp # 後で有効化します # COPY ./railsapp /railsapp # RUN bundle install && yarn installまずは以下の手順で新しいプロジェクトを生成します。railsappフォルダ下にファイルが作られます。
docker-compose build docker-compose run web rails new . --database=postgresql --skip-gitその後、上記Dockerfile内の最後の2行を有効化します。
COPY ./railsapp /railsapp RUN bundle install && yarn installデータベースの接続設定も修正が必要です。
railsapp/config/database.ymlhost: db username: postgres以下のコマンドを実行します。
docker-compose build docker-compose upあとは、いつもの要領でrailsの開発が開始できます!
docker-compose exec web rails db:create
docker-compose exec web rails g scaffold post title:string body:text published:boolean docker-compose exec web rails db:migrateハマりどころ
ruby:2.6
やruby:2.7
のイメージを使ってみたところ、yarnのバージョンが適合せず動作しなかったため(下記エラー)、
ruby:2.6-alpine
イメージを使用しています。軽量さが特徴のようですが、逆に言うと、
何か追加のgemを入れるたびにOS側のパッケージ追加が必要になるのが大変そうです…。ArgumentError: Malformed version number string 0.32+git初回の
bundle install
がかなり重たいのに、この手順だと2回それが走ることになり、待ち時間が長いです。
もし最初から使えるGemfile
が手元にあれば、それをrailsappに置いた状態でスタートすると速いです(公式の手順などで案内している方法)。参考URL
https://opiyotan.hatenablog.com/entry/rails-tips-docker-development
- 投稿日:2020-02-23T13:57:39+09:00
docker-composeでRails6開発環境
docker-composeでRails5.2開発環境に続いて、Rails6の環境も作ってみます。5.2から移行してくるとyarnとwebpackerがなかなか最初はややこしく感じます…。最下部に理由を書いていますが、alpine版のイメージをベースにしています。
必要なファイルは2つです。
docker-compose.ymlversion: '3' services: db: image: postgres volumes: - ./postgresql/data:/var/lib/postgresql/data web: build: . command: "rails s -p 3000 -b '0.0.0.0'" volumes: - ./railsapp:/railsapp ports: - "3000:3000" depends_on: - dbFROM ruby:2.6-alpine RUN apk update && apk add libxml2-dev curl-dev make gcc libc-dev g++ nodejs \ postgresql-client postgresql-dev tzdata yarn \ && gem install rails -v "~> 6" -N RUN mkdir /railsapp WORKDIR /railsapp # 後で有効化します # COPY ./railsapp /railsapp # RUN bundle install && yarn installまずは以下の手順で新しいプロジェクトを生成します。railsappフォルダ下にファイルが作られます。
docker-compose build docker-compose run web rails new . --database=postgresql --skip-gitその後、上記Dockerfile内の最後の2行を有効化します。
COPY ./railsapp /railsapp RUN bundle install && yarn installデータベースの接続設定も修正が必要です。
railsapp/config/database.ymlhost: db username: postgres以下のコマンドを実行します。
docker-compose build docker-compose upあとは、いつもの要領でrailsの開発が開始できます!
docker-compose exec web rails db:create
docker-compose exec web rails g scaffold post title:string body:text published:boolean docker-compose exec web rails db:migrateハマりどころ
ruby:2.6
やruby:2.7
のイメージを使ってみたところ、yarnのバージョンが適合せず動作しなかったため(下記エラー)、
ruby:2.6-alpine
イメージを使用しています。軽量さが特徴のようですが、逆に言うと、
何か追加のgemを入れるたびにOS側のパッケージ追加が必要になるのが大変そうです…。ArgumentError: Malformed version number string 0.32+git初回の
bundle install
がかなり重たいのに、この手順だと2回それが走ることになり、待ち時間が長いです。
もし最初から使えるGemfile
が手元にあれば、それをrailsappに置いた状態でスタートすると速いです(公式の手順などで案内している方法)。参考URL
https://opiyotan.hatenablog.com/entry/rails-tips-docker-development
- 投稿日:2020-02-23T13:35:13+09:00
Railsで間違えて作成したcontrollerやmodelを削除する方法
railsでプログラミングをするにあたって、間違えてcontrollerを作成してしまうことが僕はたまにあります。一文字間違えとか、あるあるです。
僕の場合はコントローラーの作成にこういったミスをするとどうしたらいいかわからなくなって、一からアプリケーションを作り直すということをプログラミングを学び始めの時などはやっていたりしました。
この方法を知って「なんて便利なんだ」と感動した覚えがあるので、備忘録もかねて残しておこうと思います。
controllerやmodelを間違えて作成した時の対処法
方法はシンプルかつ簡単です。例えばusers controllerを削除したいときは、。
rails destroy controller usersUser modelを削除したいときも同じように
rails destroy model userとすることで間違って作成したものを削除することができます。参考になれば幸いです。
- 投稿日:2020-02-23T13:17:07+09:00
【Rails】APIモードで使えるHTTPステータスコードのシンボルまとめ
はじめに
Railsで使えるHTTPステータスコードのシンボルの一覧です。
Rails APIモードで使えるのではないかと思います。環境
OS: macOS Catalina 10.15.3 Ruby: 2.6.5 Rails: 6.0.2.1きっかけ
JSONを返すAPIのコントローラーでは、以下のような一文をよく見かけます。
users_controller.rbrender json: user, status: :ok # この:okのことこれは、下記のようにも書けます。
users_controller.rbrender json: user, status: 200この方が簡潔に書けるし、「はいはい、
200
はOK
だよね!」と分かるかと思います。でも、これならどうでしょうか?
sample.rbstatus: 429シンボルで書くと、こうなります。
sample.rbstatus: :too_many_requests
「リクエスト多すぎ!」ってことですね。
1時間あたりに〇〇回しかリクエスト投げられないAPIを使っていて、リクエストを投げすぎたときに返ってきます。結論:
200
or:ok
どちらを使うべきか
- チーム開発を経た経験から、開発者のスキルが全員同じは絶対にない
- HTTPステータスコードより英語の方がわかりやすい
という点から、
:ok
の方が全体に対するメリットが多いのではないかと思います。とはいえ、「覚えられないのでリファレンス欲しいと思いましたので今回まとめました!
HTTPステータスコードのシンボル一覧
シンボル一覧.rb100 :continue 101 :switching_protocols 102 :processing 103 :early_hints 200 :ok 201 :created 202 :accepted 203 :non_authoritative_information 204 :no_content 205 :reset_content 206 :partial_content 207 :multi_status 208 :already_reported 226 :im_used 300 :multiple_choices 301 :moved_permanently 302 :found 303 :see_other 304 :not_modified 305 :use_proxy 306 :unused 307 :temporary_redirect 308 :permanent_redirect 400 :bad_request 401 :unauthorized 402 :payment_required 403 :forbidden 404 :not_found 405 :method_not_allowed 406 :not_acceptable 407 :proxy_authentication_required 408 :request_timeout 409 :conflict 410 :gone 411 :length_required 412 :precondition_failed 413 :payload_too_large 414 :uri_too_long 415 :unsupported_media_type 416 :range_not_satisfiable 417 :expectation_failed 421 :misdirected_request 422 :unprocessable_entity 423 :locked 424 :failed_dependency 425 :too_early 426 :upgrade_required 428 :precondition_required 429 :too_many_requests 431 :request_header_fields_too_large 451 :unavailablefor_legal_reasons 500 :internal_server_error 501 :not_implemented 502 :bad_gateway 503 :service_unavailable 504 :gateway_timeout 505 :http_version_not_supported 506 :variant_also_negotiates 507 :insufficient_storage 508 :loop_detected 509 :bandwidth_limit_exceeded 510 :not_extended 511 :network_authentication_required対応するヘルパーメソッド
ヘルパー一覧.rbdef invalid?; status < 100 || status >= 600; end def informational?; status >= 100 && status < 200; end def successful?; status >= 200 && status < 300; end def redirection?; status >= 300 && status < 400; end def client_error?; status >= 400 && status < 500; end def server_error?; status >= 500 && status < 600; end def ok?; status == 200; end def created?; status == 201; end def accepted?; status == 202; end def no_content?; status == 204; end def moved_permanently?; status == 301; end def bad_request?; status == 400; end def unauthorized?; status == 401; end def forbidden?; status == 403; end def not_found?; status == 404; end def method_not_allowed?; status == 405; end def precondition_failed?; status == 412; end def unprocessable?; status == 422; end def redirect?; [301, 302, 303, 307, 308].include? status; endおわりに
最後まで読んで頂きありがとうございました
どなたかの参考になれば幸いです
参考にさせて頂いたサイト(いつもありがとうございます)
- 投稿日:2020-02-23T12:14:40+09:00
Rails プロジェクト作成手順
今までCloud9を使ってRails開発をちょこちょこしていました。
今回は、イチからやってみようということでCloud9を使わずにプロジェクト作成をすることにしました。①Homebrewのインストール
Macユーザー限定ですが、まずは
Homebrew
のインストールを行います。
公式に書いてある通りにスクリプトを実行すれば、問題ないはずです。バージョンが表示されれば、うまくインストールされています。
$ brew -v Homebrew 2.2.6②rbenvのインストール
Rubyのバージョン管理ができるように
rbenv
のインストールを行います。$ brew install rbenv ruby-build次にパスを通します。
なぜかというと、MacデフォルトのRubyを使わずにrbenvでインストールしたRubyを使用するためです。MacデフォルトのRubyは、/usr/binというところに入っているのですが、rbenvでインストールしたRubyは、/Users/ユーザー名/.rbenv/shims/に入ります。
そのため、ターミナルからRubyを実行するときに、rbenvの中のRubyでRubyを実行するように切り替えをする必要があります。
$ echo 'export PATH="~/.rbenv/shims:/usr/local/bin:$PATH"' >> ~/.bash_profile $ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile $ source ~/.bash_profile //.bash_profileを読み込む
eval “$(rbenv init -)”
を.bash_profile
ファイルに書いて読み込みすることによって、Macにログインしたら、Rubyコマンドを実行するときはrbenv内のRubyを実行するように設定しておくができます。➂Rubyのインストール
ここでようやくRubyのインストールを行います。
まずは、インストール可能なバージョンを確認します。$ rbenv install --list今回は、
2.7.0
をインストールします。$ rbenv install 2.7.0 // 環境全体の有効なバージョンを2.7.0にする $ rbenv global 2.7.0 $ rbenv rehash $ ruby -v④Bundlerのインストール
次に、
Bundler
のインストールをします。
Bundler
とは、gemの依存関係とバージョンを管理するためのツールです。
Bundler
を使うと、依存関係のあるgemを一括でインストールしてくれます。
一括でインストールしたgemはすべて、依存関係が解決された状態で、インストールされます。$ gem install bundler $ bundle -v⑤Railsプロジェクトの作成
ここで、プロジェクトを作成します。
作成したプロジェクトの中で、bundle init
を行います。$ mkdir ~/testApp $ cd ~/testApp $ bundle init成功すれば、Gemfileが作られているはずです。
Gemfileとは、インストールしたいgemを列挙するものです。
ただ、このままだと使えないので、Gemfileを編集する必要があります。GemFile# frozen_string_literal: true source "https://rubygems.org" git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } gem "rails" ←コメントアウトを外すシステムのgemはできるだけクリーンに保ち、gemは
vendor/bundle
に入れてbundle exec
で呼び出すのがいいそうなのでそうします。$ bundle install --path=vendor/bundle $ bundle exec rails -v Rails 6.0.2.1
--path vendor/bundle
オプションを付けることで、プロジェクトのvendor/bundle
以下にgemが格納されます。
次回以降はオプションを付けなくてもvendor/bundle以下に格納されるはずです。プロジェクト別にgemをインストールすると、プロジェクトごとのgemのバージョンの違いを気にすることがなくなります。
最後に、Railsプロジェクトを作成します。
$ bundle exec rails new . -B --skip-test
.
を付けると現在のディレクトリに作成されます。少しだけオプションの説明をすると、
-B
はRailsプロジェクト作成時にbundle installを行わないようにします。
また、--skip-test
はデフォルトのminitestというテストを使わない時に付ける。他のテストフレームワークを利用したい時に使うといいです。
他のオプションはドキュメントを参考にするといいと思います。プロジェクトにいる状態で、下記コマンドを実行して、http://localhost:3000/ へアクセスします。(サーバー起動)
$ rails serverRailsの画面が表示されれば、成功です。
Cloud9はそこまで意識せずにプロジェクトが作れちゃうので、楽ですね!
ただ、環境構築で何が行われるのかを知るという意味ではやってみるのもいいかもしれません。
また、実際の開発現場でCloud9を使ってというのはあんまりないと思うので、できた方がいい気がします。補足
Rails6から
Webpacker
がデフォルトでインストールされます。
なので、Webpacker
やyarn
をインストールしないとサーバー起動時に失敗する場合があります。
その場合は、インストールしましょう。// yarnを先にインストールしないとwebpackerをインストールできない $ brew install yarn $ rails webpacker:install参照
- 投稿日:2020-02-23T11:32:24+09:00
[Rails] rbenvのコマンド、ググるのめんどくさい方へ(ターミナル上で完結する方法)
きっかけ
rbenvってそこまで使うものでもないので、
時間が経てばコマンドは忘れてしまいます。ただインターネットでいちいち調べるのが個人的には面倒で(おい)、
全部ターミナル上で完結させたいと感じていました。その方法を色々と調べましたので、同じような考えを持つ方のためにまとめておきます。
rbenvで使用できるコマンドを表示しよう
rbenv
と打ち込むと、コマンドが色々と出てきます。$ rbenv rbenv 1.1.2 Usage: rbenv <command> [<args>] Some useful rbenv commands are: commands List all available rbenv commands local Set or show the local application-specific Ruby version global Set or show the global Ruby version shell Set or show the shell-specific Ruby version install Install a Ruby version using ruby-build uninstall Uninstall a specific Ruby version rehash Rehash rbenv shims (run this after installing executables) version Show the current Ruby version and its origin versions List installed Ruby versions which Display the full path to an executable whence List all Ruby versions that contain the given executable
Some useful rbenv commands are:
以下がrbenvで用意されているコマンドです。各コマンドで使用できるオプションを表示しよう
今回は
rbenv install
に焦点をあてます。
コマンドの後ろに--help
を打ち込むか、helpコマンドを使用してください。$ rbenv install --helpまたは
$ rbenv help install前者を実行すると
$ rbenv install --help Usage: rbenv install [-f|-s] [-kpv] <version> rbenv install [-f|-s] [-kpv] <definition-file> rbenv install -l|--list rbenv install --version -l/--list List all available versions -f/--force Install even if the version appears to be installed already -s/--skip-existing Skip if the version appears to be installed already ruby-build options: -k/--keep Keep source tree in $RBENV_BUILD_ROOT after installation (defaults to $RBENV_ROOT/sources) -p/--patch Apply a patch from stdin before building -v/--verbose Verbose mode: print compilation status to stdout --version Show version of ruby-build For detailed information on installing Ruby versions with ruby-build, including a list of environment variables for adjusting compilation, see: https://github.com/rbenv/ruby-build#usageとでます。
この
Usage
の部分がrbenv install
で用意されているオプションです。
そしてその下に各コマンドの説明が書いてあります。こうすることでターミナル上でコマンドおよびオプションを確認することができました。
(ご参考) よく使うコマンド/オプション一覧
インストール可能なRubyのバージョンを確認
$ rbenv install -l (省略) 2.6.3 2.6.4 2.6.5 2.7.0-dev (省略)ファイルのパスを確認
$ rbenv which ファイル名
rbenv which
まで入力してtab
を押すと、候補が出てきます$ rbenv which --help bundler gem nokogiri racc2y rails rdoc ruby thor bundle erb irb racc rackup rake ri sprockets y2racc実行結果
$ rbenv which ruby => /Users/owner/.rbenv/versions/2.6.3/bin/ruby現在インストールされているRubyのバージョンを確認
$ rbenv versions system 2.5.3 2.6.0-dev * 2.6.3 (set by /Users/owner/.rbenv/version)現在使用しているRubyのバージョンを確認
$ rbenv version 2.6.3 (set by /Users/reiforu/.rbenv/version)ローカルのRubyのバージョンを変更・確認
$ rbenv local 2.6.3$ rbenv local 2.5.3$ rbenv local 2.6.3グローバルのRubyのバージョンを変更・確認
$ rbenv global 2.6.3$ rbenv global 2.5.3$ rbenv global 2.6.3
- 投稿日:2020-02-23T11:04:08+09:00
【Rails】portを使っていないのにAddress already in useエラーが出る場合の応急処置
はじめに
少し昔のrailsアプリ少しいじろうかと思ったのですが、見事にハマりました。
bundle update
だとかgem pristine
だとかをしたのですが、結局rails server
ができなかったので、奮闘記録と共にとりあえずのサーバー起動方法を書いておきます。動作環境
- Ruby 2.5.3
- Rails 5.2.4.1
- puma 3.12.2
- ローカル環境
Address already in useエラー
$ rails s => Booting Puma => Rails 6.0.2.1 application starting in development => Run `rails server --help` for more startup options [1234] Puma starting in cluster mode... [1234] * Version 4.3.1 (ruby 2.5.3-p105), codename: Mysterious Traveller [1234] * Min threads: 5, max threads: 5 [1234] * Environment: development [1234] * Process workers: 2 [1234] * Preloading application [1234] * Listening on tcp://127.0.0.1:3000 [1234] * Listening on tcp://[::1]:3000 Exiting Traceback (most recent call last): 37: from bin/rails:3:in `<main>' 36: from bin/rails:3:in `load' 35: from /Users/k_end/workspace/personal/kiite_app/bin/spring:15:in `<top (required)>' 34: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require' 33: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require' 32: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/spring-2.1.0/lib/spring/binstub.rb:11:in `<top (required)>' 31: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/spring-2.1.0/lib/spring/binstub.rb:11:in `load' 30: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/spring-2.1.0/bin/spring:49:in `<top (required)>' 29: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/spring-2.1.0/lib/spring/client.rb:30:in `run' 28: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/spring-2.1.0/lib/spring/client/command.rb:7:in `call' 27: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/spring-2.1.0/lib/spring/client/rails.rb:28:in `call' 26: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/spring-2.1.0/lib/spring/client/rails.rb:28:in `load' 25: from /Users/k_end/workspace/personal/kiite_app/bin/rails:9:in `<top (required)>' 24: from /Users/k_end/workspace/personal/kiite_app/bin/rails:9:in `require' 23: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/railties-6.0.2.1/lib/rails/commands.rb:18:in `<top (required)>' 22: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/railties-6.0.2.1/lib/rails/command.rb:46:in `invoke' 21: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/railties-6.0.2.1/lib/rails/command/base.rb:69:in `perform' 20: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/thor-1.0.1/lib/thor.rb:392:in `dispatch' 19: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/thor-1.0.1/lib/thor/invocation.rb:127:in `invoke_command' 18: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/thor-1.0.1/lib/thor/command.rb:27:in `run' 17: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/railties-6.0.2.1/lib/rails/commands/server/server_command.rb:138:in `perform' 16: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/railties-6.0.2.1/lib/rails/commands/server/server_command.rb:138:in `tap' 15: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/railties-6.0.2.1/lib/rails/commands/server/server_command.rb:147:in `block in perform' 14: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/railties-6.0.2.1/lib/rails/commands/server/server_command.rb:39:in `start' 13: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/rack-2.2.2/lib/rack/server.rb:327:in `start' 12: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/puma-4.3.1/lib/rack/handler/puma.rb:73:in `run' 11: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/puma-4.3.1/lib/puma/launcher.rb:172:in `run' 10: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/puma-4.3.1/lib/puma/cluster.rb:413:in `run' 9: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/puma-4.3.1/lib/puma/runner.rb:161:in `load_and_bind' 8: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/puma-4.3.1/lib/puma/binder.rb:90:in `parse' 7: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/puma-4.3.1/lib/puma/binder.rb:90:in `each' 6: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/puma-4.3.1/lib/puma/binder.rb:106:in `block in parse' 5: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/puma-4.3.1/lib/puma/binder.rb:222:in `add_tcp_listener' 4: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/puma-4.3.1/lib/puma/binder.rb:222:in `each' 3: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/puma-4.3.1/lib/puma/binder.rb:223:in `block in add_tcp_listener' 2: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/puma-4.3.1/lib/puma/binder.rb:229:in `add_tcp_listener' 1: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/puma-4.3.1/lib/puma/binder.rb:229:in `new' /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/puma-4.3.1/lib/puma/binder.rb:229:in `initialize': Address already in use - bind(2) for "127.0.0.1" port 3000 (Errno::EADDRINUSE)サーバーを起動させたままコンソールを閉じてしまうというよくあるパターンだと思い、いつも通りの手順を踏む。
$ ps ax | grep rails 834 s000 S+ 0:00.00 grep --color=auto rails
834
はps ax | grep rails
によるプロセスなので、他に動いているプロセスはない。$ ps aux | grep puma k_end 882 0.0 0.0 4276968 712 s000 R+ 7:50AM 0:00.00 grep --color=auto pumaこちらも同様。
$ lsof -wni tcp:3000もちろん意味なし。
この辺りで、いやまさかそんなはずが……と思い始める。ポートを使っているか確認してみた
teratailのRails sでポート3000番で立ち上がらないのコメントを参考にし、bashで確認したところ、
$ exec 3<>/dev/tcp/localhost/3000 bash: connect: Connection refused bash: /dev/tcp/localhost/3000: Connection refusedポート使っていないですね。
ということは、他のアプリなら起動できるのでは?と思い、やってみたところ……$ rails s => Booting Puma => Rails 5.2.3 application starting in development => Run `rails server -h` for more startup options Puma starting in single mode... * Version 4.3.1 (ruby 2.6.5-p114), codename: Mysterious Traveller * Min threads: 5, max threads: 5 * Environment: development * Listening on tcp://127.0.0.1:3000 * Listening on tcp://[::1]:3000 Use Ctrl-C to stop行けるんじゃん!!
やっぱり、ポートの問題ではなく、違うところでエラーがあるらしい。ということは、これはpumaの問題かなあ。というか、とりあえずでアップデートしたせいかrailsのバージョンも6台になってる。
奮闘の記録
pumaをシングルモードにしてみた
Puma starting in cluster mode...
とあったので、うまく動く方に合わせてsingle modeにしてみる。
参考:Pumaの使い方 まとめ$ rails s => Booting Puma => Rails 6.0.2.1 application starting in development => Run `rails server --help` for more startup options Puma starting in single mode... * Version 4.3.1 (ruby 2.5.3-p105), codename: Mysterious Traveller * Min threads: 5, max threads: 5 * Environment: development * Listening on tcp://127.0.0.1:3000 * Listening on tcp://[::1]:3000 Exiting Traceback (most recent call last): 37: from bin/rails:3:in `<main>' 36: from bin/rails:3:in `load' 35: from /Users/k_end/workspace/personal/kiite_app/bin/spring:15:in `<top (required)>' 34: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require' . . . 2: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/puma-4.3.1/lib/puma/binder.rb:229:in `add_tcp_listener' 1: from /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/puma-4.3.1/lib/puma/binder.rb:229:in `new' /Users/k_end/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/puma-4.3.1/lib/puma/binder.rb:229:in `initialize': Address already in use - bind(2) for "127.0.0.1" port 3000 (Errno::EADDRINUSE)single modeにはなったけど、やっぱりだめ。
Rails をダウングレードしてみた
gem 'rails', '~> 5.2.3'
を指定し、Gemfile.lockを削除してbundle install
結果、変わらず。
とりあえずの応急処置
pumaコマンドで起動
pumaコマンドでconfig/puma.rbを指定して起動する。
$ bundle exec puma -t 5:5 -p 3000 -e development -C config/puma.rb Puma starting in single mode... * Version 3.12.2 (ruby 2.5.3-p105), codename: Llamas in Pajamas * Min threads: 5, max threads: 5 * Environment: development * Listening on tcp://0.0.0.0:3000 Use Ctrl-C to stoppumaには問題はないのか?
WEBrickで起動
エラーが出ていたファイルが
~/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/puma-3.12.2/lib/puma/binder.rb
だったので、とりあえずpumaディレクトリごと削除。$ rails s => Rails 5.2.4.1 application starting in development on http://localhost:3000 => Run `rails server -h` for more startup options [2020-02-23 10:06:46] INFO WEBrick 1.4.2 [2020-02-23 10:06:46] INFO ruby 2.5.3 (2018-10-18) [x86_64-darwin17] [2020-02-23 10:06:46] INFO WEBrick::HTTPServer#start: pid=21009 port=3000WEBrickではちゃんとサーバーを起動できている。ということは、やっぱりpumaが原因だ。
ポート番号3000を指定して起動
$ rails s -p 3000 => Booting Puma => Rails 5.2.4.1 application starting in development => Run `rails server -h` for more startup options Puma starting in single mode... * Version 3.12.2 (ruby 2.5.3-p105), codename: Llamas in Pajamas * Min threads: 5, max threads: 5 * Environment: development * Listening on tcp://localhost:3000 Use Ctrl-C to stop問題なく起動できます。
以上の3通りの方法で起動することができました。一番普通と同じ動きをするのは、この方法かと思われます。
終わりに
この通り、とりあえずサーバーを起動する方法はありますが、いまだに
rails s
コマンドでは起動できていません。
rails s
とrails s -port 3000
ではポート番号を設定する部分が違うので、多分そこがぶっ壊れてるんだろうなと思っています。
解決策などございましたら、ぜひコメントをいただければ幸いです。
- 投稿日:2020-02-23T09:03:00+09:00
【rails】mysqlのデータベース、テーブル、全データを削除する方法(初心者向け)
データベースの中身を確認
$sudo service mysqld start $mysqld -u root mysql> show databases; mysql> USE データベース名; mysql> show tables; mysql> describe テーブル名; mysql> select * FROM データベース名.テーブル名;データベースの削除
※確認なしに即削除されます。使用注意。
mysql> show databases; mysql> DROP DATABASE データベース名;テーブルの削除
※確認なしに即削除されます。使用注意。
mysql> USE データベース名; mysql> show tables; mysql> DROP TABLE データベース名.テーブル名;全データ削除
mysql> USE データベース名; mysql> show tables; mysql> select * FROM データベース名.テーブル名; mysql> DELETE FROM データベース名.テーブル名;
- 投稿日:2020-02-23T08:08:41+09:00
【Rails】APIモードで使えるHTTPステータスコードの対応シンボル一覧
はじめに
Rails APIモードを使用するときに使えるHTTPレスポンスコードの対応シンボルをまとめました。
users_controller.rbrender json: user status: :ok # この:okのことこれは、
users_controller.rbrender json: user status: 200とも書けますし、「はいはい、
200
はOK
でしょ!」と分かるかと思います。
でも、users_controller.rbrender json: user status: 429だと「何だっけこれ?」となりませんか?笑
429
は:too many request
で外部APIを使ったときに1時間あたりのリクエスト回数の制限に達したときに返されます。チーム開発経験から、
:ok
や:too many request
としたほうが、
HTTPステータスコードを知らない人が読めるようにしたほうが開発者のレベルが揃っていないときに便利です。環境
OS: macOS Catalina 10.15.3 Ruby: 2.6.5 Rails: 6.0.2.1HTTPステータスコードの対応シンボル
※GitHubソースのコピペです
HTTP_STATUS_CODES = { 100 => 'Continue', 101 => 'Switching Protocols', 102 => 'Processing', 103 => 'Early Hints', 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content', 207 => 'Multi-Status', 208 => 'Already Reported', 226 => 'IM Used', 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 306 => '(Unused)', 307 => 'Temporary Redirect', 308 => 'Permanent Redirect', 400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Timeout', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Payload Too Large', 414 => 'URI Too Long', 415 => 'Unsupported Media Type', 416 => 'Range Not Satisfiable', 417 => 'Expectation Failed', 421 => 'Misdirected Request', 422 => 'Unprocessable Entity', 423 => 'Locked', 424 => 'Failed Dependency', 425 => 'Too Early', 426 => 'Upgrade Required', 428 => 'Precondition Required', 429 => 'Too Many Requests', 431 => 'Request Header Fields Too Large', 451 => 'Unavailable for Legal Reasons', 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Timeout', 505 => 'HTTP Version Not Supported', 506 => 'Variant Also Negotiates', 507 => 'Insufficient Storage', 508 => 'Loop Detected', 509 => 'Bandwidth Limit Exceeded', 510 => 'Not Extended', 511 => 'Network Authentication Required' }ヘルパーメソッドもあります
invalid?; status < 100 || status >= 600; informational?; status >= 100 && status < 200; successful?; status >= 200 && status < 300; redirection?; status >= 300 && status < 400; client_error?; status >= 400 && status < 500; server_error?; status >= 500 && status < 600; ok?; status == 200; created?; status == 201; accepted?; status == 202; no_content?; status == 204; moved_permanently?; status == 301; bad_request?; status == 400; unauthorized?; status == 401; forbidden?; status == 403; not_found?; status == 404; method_not_allowed?; status == 405; precondition_failed?; status == 412; unprocessable?; status == 422; redirect?; [301, 302, 303, 307, 308].include? status;おわりに
最後まで読んで頂きありがとうございました
どなたかの参考になれば幸いです
参考にさせて頂いたサイト(いつもありがとうございます)
- 投稿日:2020-02-23T02:23:30+09:00
【Rails】Railsでブランチを行き来して開発していてマイグレーションに変更がある場合の対応方法
はじめに
実務で開発をしているとブランチを行き来しなければならない場合はよくあると思います。
その場合、コミットしていないファイルについてはgit stash
などで対応できますが(参考:開発の流れの中で理解するGit + チートシート)、マイグレーションに変更がある場合はその対応も必要になるかと思います。
今回はそういった場合にどのように対応すれば良いか個人的な対応方法を書いていきます。前提
- masterブランチからトピックブランチにチェックアウトして開発を行っている
- トピックブランチでマイグレーションを変更し、
rails db:migrate
を実行した- その後、別のトピックブランチで作業する必要があり、マイグレーションを戻したい
現在のマイグレーションの状態を確認する
まずは以下のコマンドで現在のマイグレーションの状態を確認しましょう。
rails db:migrate:status database: hoge Status Migration ID Migration Name -------------------------------------------------- up 20200222000000 hoge up 20200222111111 hoge up 20200222222222 hoge up 20200222333333 hoge
Status
がup
であればマイグレーションが実行済み、down
であれば未実行です。
一番下のup 20200222333333 hoge
がトピックブランチで変更したマイグレーションだとします。
マイグレーションを戻すには、一番下のup 20200222333333 hoge
をdown 20200222333333 hoge
にする必要があります。マイグレーションを戻す
マイグレーションを戻すには以下のコマンドを実行します。
rails:db:rollbackマイグレーションの状態を確認すると、意図した結果が得られているはずです。
rails db:migrate:status database: hoge Status Migration ID Migration Name -------------------------------------------------- up 20200222000000 hoge up 20200222111111 hoge up 20200222222222 hoge down 20200222333333 hogeまた、
rails:db:rollback
を実行するとscheme.rb
が書き換わるので、その変更を破棄、またはgit stash
してから、別のトピックブランチに移動しましょう。ちなみに
STEP=n
でどこまでマイグレーションを戻すか指定できます。
以下の例では一番下から3つのマイグレーションがdownになります。(4つ前(n + 1前)までマイグレーションが実行された状態に戻せます。)rails:db:rollback STEP=3 rails db:migrate:status database: hoge Status Migration ID Migration Name -------------------------------------------------- up 20200222000000 hoge down 20200222111111 hoge down 20200222222222 hoge down 20200222333333 hogeおわりに
もう一度最初のトピックブランチに戻った時には
rails db:migrate
を実行して、マイグレーションを元に戻せばOKです。
- 投稿日:2020-02-23T00:20:24+09:00
Cloud9からGitHubのレポジトリへアップする手順(エラー解決方法含む)
- Git BashなどでGitを動かしたことがある。
- GitHubのレポジトリは作成済。
という方で、
- 「初めてAWS Cloud9上で開発を始めたため、作成したソースを、既にあるGitHubのレポジトリへアップしたい」
という方向けに作成しました。
私自身はgit bashでGit/GitHubを操作したことはありましたが、初めてCloud9でgitを扱う際、色々とエラーが出て困ったので、Cloud9用の記事が欲しかったなと思って作成しました。
なお、GitHubのレポジトリは「公開」にしている前提です。
(非公開だとまた手順が異なるよう)※Git/GitHub初学者の方は以下の動画がおすすめです。
https://www.udemy.com/share/101vBkAEMYcFxTTHgE/はじめに
まずはcloud9のターミナルを用意。
念のため、gitが入っているか確認します。(Cloud9だと当然入っていますが)$ git --version git version 2.14.5ローカルレポジトリ作成
ローカルレポジトリを作成したい任意のディレクトリに移動し
$ git initを実行すると、「.git」ディレクトリ(ローカルレポジトリ)が生成されます。
ステージングエリアにadd
まずは、ステージングエリアにadd
$ git add [file]※git addのオプションについては以下がわかりやすかったので参照下さい。
https://note.nkmk.me/git-add-u-a-period/ローカルレポジトリにcommit
そして、ステージングエリアにあるファイルをローカルレポジトリにcommit
$ git commit -m "[任意のメッセージ]"リモートレポジトリの登録とgit push
commitできたら、cloud9上で作成したgitのローカルレポジトリには登録完了です。
次に、GitHubのレポジトリ(リモートレポジトリ)にpush(アップロード)する必要があります。
まずはリモートレポジトリの登録から$ git remote add origin git@github.com:[自身のGitHubのレポジトリ].gitその後、
$ git push -u origin masterここで下記のようなエラーが出る方がいると思います。
Permission denied (publickey). fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists.上記のエラーは、それぞれの行ごとに、以下のような意味です。
パブリックキーで権限が拒否された。 リモートリポジトリが読み取れない。 アクセス権持っている?それともリポジトリ自体存在している?エラーを解決していきましょう。
先ほど、リモートレポジトリの登録は完了したかと思います。
そのため、先ほどのエラーメッセージの「リモートレポジトリ自体存在している?」は問題ないということになり、
「アクセス権持っている?」が問題になります。では、アクセス権を得ましょう。
GitHubへアクセスには、公開鍵が必要です。
開発環境で公開鍵を作成し、GitHubへ公開鍵を登録することでアクセスできるようになります。公開鍵の作成
まずは、cloud9内のディレクトリに、公開鍵を作成します。
$ ssh-keygen -t rsa -C "[リモートレポジトリを登録した自分のメールアドレス(・・・@gmail.comなど)]"(-Cより後のコメント部分はなくても実行可能ですが、GitHubに登録しているEmailアドレスを指定するのが一般的のようです)
「ssh-keygen」はSSH(Secure SHell)の公開鍵と秘密鍵を作成するコマンドです。
ちなみにオプションの意味は
- 「-t rsa」・・・作成する鍵の暗号化形式を「rsa」で指定
- 「-C "コメント"」・・・コメントを指定
もっと詳しく知りたい方は以下記事がよいと思います。
https://www.atmarkit.co.jp/ait/articles/1908/02/news015.html実行すると、以下のメッセージが出てきます。Enter~から始まる行が3回あり、各行にて入力を求められますが、すべて何も入力せずEnterを押して問題ありません。
Generating public/private rsa key pair. Enter file in which to save the key (/home/ec2-user/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again:上記でEnterを3回押すと、以下のメッセージが表示され、公開鍵が作成されます。(randomart imageの箇所は適当に書き換えています)
Your identification has been saved in /home/ec2-user/.ssh/id_rsa. Your public key has been saved in /home/ec2-user/.ssh/id_rsa.pub. The key fingerprint is: SHA256:・・・・・・・・・・・・・・・・・・・・・・・・・・ ……………@gmail.com The key's randomart image is: +---[RSA 2048]----+ |.................... | | .......... | | ......= ...... | | *..... ..... | | ...... BS+ | | =...........o.. | ho host github | ................. | | ......o*=.....+ | | .E..........*...... | +----[SHA256]-----+その後、.sshディレクトリを確認すると、公開鍵が作成されているのがわかります。
$ ls ~/.ssh/ authorized_keys id_rsa id_rsa.pub known_hostsid_rsa.pubファイルの内容をコピー
下記コマンドでid_rsa.pubのファイル内容を表示し、中身をコピーします。
(lessコマンドで中身を見るのではなく、ファイルの中身をすべてコピーしてもOK)$ less ~/.ssh/id_rsa.pubファイル内の以下のssh-rsaから始まる部分をコピーします。(メールアドレスまでコピーに含めても含めなくても特に変わりないのでどちらでも構いません)
ssh-rsa ・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・ ・・・・・・・・・・・・・・・・・・・・・・・・・・・ [メールアドレス]公開鍵をGitHubに登録
今コピーした部分を、GitHubに登録するのですが、まずGitHubにブラウザからアクセスし、右上の自分のプロフィール画像から「settings」をクリック
そして、左側のメニューから「SSH and GPG keys」を選択し、「New SSH key」をクリックします。
すると、登録画面が出てきます。
登録画面の「key」部分のテキストエリアに先ほどコピーした「ssh-rsa」から始まる文言を貼り付けます。
ちなみに、タイトルは何でも構いません。貼り付けができたら「Add SSH key」をクリック。
ここで、下記コマンドを打てば接続に成功できると書いている記事が多いですが、エラーが出て接続に失敗する場合もあります。
$ ssh -T git@github.comconfigファイルの作成
接続に失敗する場合は、.sshのディレクトリ内に「config」というファイルを作成します。
vimで、ファイルの作成と中身の記述を行います。$ vim ~/.ssh/configconfigファイルの中身に、下記の文言を貼り付けます。
なお、IdentityFileの後のパスは、自身の「id_rsa」ファイルを格納しているパスに変えてください。Host github github.com HostName github.com IdentityFile ~/.ssh/id_rsa User git新規作成ファイルの権限設定
作成できたら、権限設定をします。
新規でファイルを作成したので、適切な権限を設定し、適切に実行できるようにします。作成した当初は、configファイルに何も権限がない状態。
しかし今回は、「所有者に読み取り権限があり、その他のユーザには権限がない」という状態にする必要があります。
そのため、権限は600か400にします。
(書き込み権限はあってもなくてもよいため)所有者以外には権限を与えてはいけません。
600にするならば、以下を実行します。$ chmod 600 ~/.ssh/configssh実行
そして、下記を実行。
$ ssh -T git@github.com実行し、下記のような文字列が出力されたらOK!
Hi [username]! You've successfully authenticated, but GitHub does not provide shell access.これで、git pushが可能になります。
最後に、git pushを行う
git pushで、ローカルレポジトリのファイル類をリモートレポジトリにアップロードできます。
$ git push origin masterこれで完了です!
- 投稿日:2020-02-23T00:09:06+09:00
dockerでrailsの開発環境を構築する
概要
「Quickstart: Compose and Rails」
https://docs.docker.com/compose/rails/「もう環境構築で悩まない!Dockerを使ってRails環境構築!」
https://www.youtube.com/watch?v=BZS8AHF3TTo「DockerでのRuby on Rails環境構築を一つずつ詳解する」
https://qiita.com/daichi41/items/dfea6195cbb7b24f3419この記事をもとに
- ruby
- rails
- postgres
を設定していきます。途中記事内容だとerrorで
全体図
- dockerfileにてwebサーバーとdbをそれぞれコンテナビルド
- rails読み込む用のgemfile、gemfilerockを作成。これをもとに作業ディレクトリにrailsnewされる。
$ docker-compose run web rails new
docker-compose build
docker-compose up
で起動docker-compose run web rake db:create
でdb作成つまづきポイント
could not translate host name "db" to address: Name or service not
dbのpassがうまく渡せていなかった?
docker-compose.ymldb: image: postgres:9.5.18 environment: POSTGRES_PASSWORD: passwordにしてdatabase.ymlを下記に
config/database.ymldefault: &default adapter: postgresql encoding: unicode host: db username: postgres password: password pool: 5 development: <<: *default database: myapp_development test: <<: *default database: myapp_testrailsコマンドの打ち方
docker-compose run web rails ~でrailsコマンドを打てる。