20201130のRailsに関する記事は23件です。

Rails初心者の僕がCloud9を使用せずRailsチュートリアルを学習する理由3選

第6版Railsチュートリアルを学び始めて1週間が経ったしょう(@syo_aqn)です。
1章の開発環境構築で「Cloud9使って開発環境を整える作業」について疑問を覚えたのでこのような記事を書いてみました。

結論から先に述べると、Cloud9を使用しない理由は以下の3つです。
*Cloud9にリソースを割きたくない
*Cloud9は完全ではない
*ネットに繋がっていないと開発ができない

これらを具体的に解説しつつ、最後に僕がどのような開発環境でRailsチュートリアルに取り組んでいるかをちょこっとだけお話します

(この記事はRailsチュートリアルの学習が進むにつれて更新されていきます。投稿主は現在5章まで学習中ですφ(・・))

解説の前に

解説の前に1つだけ伝えておきたいことがあります。
僕はに何かを身に付けるとき「守・破・離」という考え方をとても大切にしています(守・破・離の解説はこちら)。
初心者なのにCloud9を使わないという行為は「守・破・離」から乖離してますが、Cloud9を使わない理由の方がデカかったのでこの記事を書いてみようと思ったわけです。

では、解説していきます。

CloudIDEにリソースを割きたくない

Railsチュートリアルに「様々なテキストエディタの使い方を知っておくことも重要」と書かれていますが、それはプログラミングにある程度慣れている経験者の話で、僕みたいな初心者にとっては別です。

この先も趣味としてRailsのコードを書くのなら話は別ですが、僕は転職を前提にRailsチュートリアルに取り組んでいます。

実務でCloudIDEを使用している企業というのはあまり聞いたことはありませんし、そもそも趣味でコードを書いていた経験があるのでテキストエディタには慣れていたので「わざわざ新しいことを覚えるくらいなら今はRailsチュートリアルにリソース割きたいな」って感じです。

CloudIDEは完全ではない

CloudIDEはブラウザ上で全てを完結できたり、ローカルのOSに依存しなかったりと便利な面があるのですが、実は結構めんどくさい輩です。

エンジニアのQ&Aサイトteratailで「Cloud9 Rails」と調べてみたら約950件の質問が投稿されていました。

Cloud9を利用することで予期せぬエラーや不具合を避けることができますが、Cloud9を利用することで発生してしまう不具合もあるので、それなら実務に近い環境で開発して、そこで発生したエラーを解決する方が今後の自分のためになると考えました。

ネットに繋がっていないと開発ができない

お恥ずかしい話、僕の実家ではWi-Fiが契約されていないので、実家に帰宅した際にはPCでの開発が不可能になってしまいます。
諸事情により、高頻度で実家に帰らなければならない僕にとっては致命的でした。

ローカルで開発していれば、わからないことはPCでググりつつ開発自体はPCで行うことができるので、使用できる状況が限られてしまうCloud9は避けました。

僕の現在の作業環境

PCスペック

スクリーンショット.png
MacBook Proで一番安かったですが、今のところはスペック面で不満を感じたことはありません。

テキストエディタ(VSCode)と導入しているプラグイン一覧

ここは、現在利用していないプラグインがたくさんインストールされていたので後日編集して公開します。

終わりに

まとめると
-転職を考えているから実務で利用頻度の少ないCloud9は避ける
-エラー解決でググるなら実務の役にたちそうな事象でググりたい
-両親がネットに疎すぎるあまり、実家に帰宅するとCloud9を使えない

って感じです。

以上「趣味ではじめたプログラミングで転職を目指している人」の持論でした。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ActionMailerのSMTP設定を動的に変更する

この記事について

Rails からメールを送る際、ActionMailerを使ってメールを送るケースが多いと思だろう。
しかし メールを送るサーバーを動的に設定したい場合はどうすればいいかについて解説している記事は少ないため、この記事で解説する。

一般的にRailsからActionMailerを使ってSMTP経由でメールを送る場合、下記の記事が参考になる。

この場合、SMTPサーバーの設定を config/environment.rbconfig/environments/production.rbconfig.action_mailer.smtp_settings = { ... }として設定することになる。

これは、1つのアプリケーションから1つのメールサービスしか使用しない場合は問題なく動作するが、ユーザーやグループによってアプリケーションが使用するメールサーバーを変えたい場合は意図したように機能しないだろう。

この記事ではユーザーやグループによってアプリケーションが使用するメールサーバーを変えたい場合、つまりは1つのアプリケーションから複数のメールサーバーを使用する場合について1つの解法を示していく。

定石

Railsでメールを送る場合、Railsガイド / Action Mailer の基礎 / Action Mailerを設定する に沿ってメールサーバーの設定を config/environment.rbconfig/environments/production.rb に対して config.action_mailer.smtp_settings = { ... }として設定することになる。

config/environment.rb
ActionMailer::Base.smtp_settings = {
  :user_name => 'your_sendgrid_username',
  :password => 'your_sendgrid_password',
  :domain => 'yourdomain.com',
  :address => 'smtp.sendgrid.net',
  :port => 587,
  :authentication => :plain,
  :enable_starttls_auto => true
}

この場合はActionMailer経由の全てのメールがこのSMTP設定を用いて配信されることになる。

カスタマイズ

しかし実際のところはユーザーやグループによっては特定のメールサーバーにSMTPで接続してメールの配信を行いたいといったケースが出てくる事が多い。

上記のように ActionMailer::Base.smtp_settings = {} で設定してしまう場合、適用した瞬間から次に上書きされるまでの間はそのSMTP接続を使用してメール送信を行なってしまうため、タイミング次第では意図しないSMTPサーバーの使用・・・古い言葉を使うと『混線』を起こすことになる。

これに対する1つの解法としては、ユーザーやグループといったメールサーバー毎にコンテナ化したアプリを配置することで解決する方法もあるが、今回は1つのRailsアプリ(コンテナ)で複数のメールサーバー話を使用するカスタマイズを行うやり方の1つを紹介する。

やり方

カスタマイズといってもそう大したことをするわけではなく、 ActionMailer::Base#mail の引数である delivery_method_options:を利用する。

delivery_method_options については Railsガイドで解説されているが、実際に認知されているケースは多くないように感じる。

Railsガイドではuser_namepasswordaddressを上書きしている例が書かれているが、実はこの delivery_method_options:は同様に他のsmtp_settingsの値についても設定する事ができる

実際にやってみる

はじめに、ActionMailer::Baseモジュールに設定されたデフォルトのsmtp_settingsを取得してみる

ActionMailer::Base.smtp_settings
 => {:address=>"localhost", :port=>25, :domain=>"localhost.localdomain", :user_name=>nil, :password=>nil, :authentication=>nil, :enable_starttls_auto=>true} 

何も設定されない場合は上記のような設定になっている。

ここでSaaS経由でのメール送信について実行してみる。

SendGridでAPIキーを使ったメール送信を行う場合、SMTP接続設定パラメータは下記のようになる。

ActionMailerの設定項目 設定値
user_name apikey
password APIキーの値 (仮に {APIキー} とする)
address smtp.sendgrid.net
domain メール送信元ドメイン (仮に {送信元ドメイン}とする)
authentication login
enable_starttls_auto true
port 587

これをActonMailerで動的に使用する場合、下記のようにdelivery_method_options:を使って、メール毎のSMTPサーバーの設定を上書きする。
(送信先アドレスは、仮に{YOUR_TEST@MAIL.ADDRESS}として設定)

ActionMailer::Base.mail(
  to:      '{YOUR_TEST@MAIL.ADDRESS}',
  from:    'from@{送信元ドメイン}',
  subject: 'テストメール',
  body:    'メール本文',
  delivery_method_options: {
    user_name: 'apikey',
    password:  '{APIキー}',
    address:   'smtp.sendgrid.net',
    domain:    '{送信元ドメイン}',
    authentication: 'login',
    enable_starttls_auto: true,
    port: 587,
  }
).deliver_later

上記の例では ActionMailer::Base に対して上書きを行っているが、app/mailers配下の各クラスに対しても同様の処理を行ってメール配信を行う事ができる。

ex)HogeNotifyが存在している場合
HogeNotify.mail(
  to:      '{YOUR_TEST@MAIL.ADDRESS}',
  from:    'from@{送信元ドメイン}',
  subject: 'テストメール',
  body:    'メール本文',
  delivery_method_options: {
    user_name: 'apikey',
    password:  '{APIキー}',
    address:   'smtp.sendgrid.net',
    domain:    '{送信元ドメイン}',
    authentication: 'login',
    enable_starttls_auto: true,
    port: 587,
  }
).deliver_later

また、rails consoleから確認する場合は deliver_later ではなく deliver を使う事で同期的にメールを送って確認する事ができる。

1. consoleを起動する

bundle exec rails c
Running via Spring preloader in process 2509
Loading development environment (Rails 6.0.3.4)

2. メールを送信する

ActionMailer::Base.mail(
  to:      '{YOUR_TEST@MAIL.ADDRESS}',
  from:    'from@{送信元ドメイン}',
  subject: 'テストメール',
  body:    'メール本文',
  delivery_method_options: {
    user_name: 'apikey',
    password:  '{APIキー}',
    address:   'smtp.sendgrid.net',
    domain:    '{送信元ドメイン}',
    authentication: 'login',
    enable_starttls_auto: true,
    port: 587,
  }
).deliver

まとめ

以上のように ActionMailerが利用するメールサーバーは、 config/environment.rbconfig/environments/production.rb に対して設定する以外に、ActionMailer::Base#mail の引数である delivery_method_options: を使って設定する事で、動的なSMTPサーバー設定を施す事ができる。

これはサービスを利用するユーザーやグループ単位でのメールサーバの切替等に活用できる仕組みであり、Railsの高い汎用性を表している一面であるとも言えるのではないだろうか。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

image_tag

railsチュートリアルを学習している時

問 image_tagで画像を表示してください

まずimege_tagってなんぞやということで検索。

image_tagとはHTMLのタグを生成するためのメゾット

らしい。

なるほど、、img以外にも画像を挿入する方法があるのか

書き方

image_tag "rails_icon.png", alt: "Rails icon", id: "pic1", class: "image"

app/assets/images配下に画像がある場合これで良いらしいが、

public配下の画像を表示する場合には、画像ファイルのパスを次のように / から記載する必要があるらしい。

image_tag "/rails_icon.png", alt: "Rails icon", id: "pic1", class: "image"

なるほど。。。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

コンパイルの流れをざっくり掴んでいく

概要

JSを触っていく上でどのように解釈してブラウザに表示されているのだろう?と思いました。この機会に裏で何をやっているのか理解をしておこうとおもったのでまとめていきます。

ブラウザが認識できる言語

まず、ブラウザで認識されるのはHTML, CSS, JavaScript, WebAssemblyという言語です。

たとえば、Railsでコードを書いていったとしても最終的に開発者ツールなど見たらHTMLなどに変換されています。

高級言語

高級言語とはプログラミング言語の分類のひとつで、人間がわかりやすいように設計されているものです。反対に、機械がわかりやすい言語のことを低級言語と呼びます。たとえば、開発するときに効率的にはやく書きたいときに扱うのが高級言語でSCSSなどの人間が便利だと思うもののことです。

コンパイル

コンピュータが分かる言葉にするには、コンパイルをして表示させています。プログラミング言語は機械に認識してもらわないと動きません。端的に言うと、機械に認識してもらう作業、要するに機械が理解できるようプログラミング言語を翻訳する作業のことをコンパイルといいます。

コンパイルの流れ

コンパイルはコンピュータがわかるように翻訳する作業のことで、翻訳作業を行ってくれているのはコンパイラというプログラムです。

一度整理すると

1.プログラミング言語をコンピュータに理解してもらうには翻訳をしなければならない。
2.翻訳作業のことをコンパイルと呼びコンパイラというプログラムで翻訳される。

ただコンパイラはなんでも翻訳してくれるわけではありません。そこで出てくるのがプリコンパイルというものです。

プリコンパイルとは

コンパイラが言語の翻訳ができるように、事前に準備することです。コンパイラに翻訳をお願いする前に、もっとコンピュータのわかりやすい言葉にしてあげることです。

アセットパイプライン

アセットパイプラインとは、JavaScriptやCSSなどのアセットを小さくしたり圧縮したりしてまとめてくれる機能のことです。複数のアセットファイルを一つにまとめてブラウザに表示するために必要な機能です。処理の流れを簡単にいうと、複数のアセットファイルをプリコンパイルして連結して、最小化または圧縮して最終的に軽量化されたものをブラウザに渡せるようにpublicディレクトリに配置します。

Sprockets

Railsでは、プリコンパイルするために、SprocketsというGemを用いてアセットパイプラインをしていました。しかし、JavaScriptの使用が多くなり、Railsのバージョン6系からモジュールバンドラによるプリコンパイルが主流になりました。

モジュールバンドラ

モジュールバンドラとはJavaScriptの依存関係を考慮しながら管理してくれるものです。依存関係を考慮しながらというのが大切で、複数あるJavaScriptファイルを1つにまとめることでブラウザで読み取ることができるようにしています。また、1つのファイルにすることで通信の高速化を可能にしています。

JavaScriptではwebpackというモジュールバンドラを利用しています。

webpackとWebpacker

webpackを使えば依存関係の管理ができるのですが、Railsではもっと簡単に管理できるものが用意されています。それはWebpackerというものです。専用の設定ファイルやヘルパーメソッドを用意してくれるGemでRailsのバージョン6系からはデフォルトでWebpackerというGemが用意されているので、導入のことを意識せずとも使えています。Webpackerによってプリコンパイルに加え、JavaScriptのパッケージを管理することを可能にしています。

npmとyarn

Webpackerにパッケージをインストールして入れていくにはパッケージ管理ツールを使います。パッケージ管理ツールにはnpmというものがありますが、Railsではyarnというものを使います。yarnはpackage.jsonとyarn.lockで使用するパッケージを管理します。RailsのGemfileとGemfile.lockのように管理されるようになります。簡単にいうと、package.jsonで使用するパッケージを管理して、yarn.lockで使用するパーケージのバージョンを管理しているということです。

まとめ

  • コンパイルとはコンピュータが理解できることばに翻訳すること。
  • コンパイラというプログラムが翻訳している。
  • ブラウザは一つのファイルしか読み取ることができない。
  • プリコンパイルとは、コンパイラが理解できるように事前に準備をすること。
  • アセットパイプラインとはプリコンパイル連結圧縮配置する機能のこと。
  • publicディレクトリに配置することでブラウザが読み込めるようにしている。
  • SprocketsというGemでのプリコンパイルからWebpackerというGemが使われるようになり、プリコンパイルに加えJavaScriptのパッケージ管理を行ってくれている。
  • 最近はwebpackerというモジュールバンドラで管理しており、依存関係を解決しながらモジュールを一つにまとめることでブラウザに表示されるような仕組みになっている。
  • webpackerにパッケージを入れるにはnpmを使うがRailsではyarnというものが使われていてパッケージを管理している。

参考文献

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Docker】docker-composeのRails開発環境でbinding.pryをする

サクッと説明していく!!!

docker-compose.yml
# 下記を追加
tty: true
stdin_open: true

web:
  build:
  context: .
  dockerfile: Dockerfile
  command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3001 -b '0.0.0.0'"
  # ここから
  tty: true
  stdin_open: true
  # ここまで追加
  depends_on:
    - db
  ports:
    - "3001:3001"
  volumes:
    - .:/app
  • docker-compose upを実行。
  • docker psで起動中のコンテナを確認(idを確認)
  • docker attach コンテナid

以降、binding.pryしたところで止まるようになる。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails パンくずリストの作成

はじめに

Railsアプリのヘッダー部分にパンくずリストを追加しました。忘れないように書き記します。

開発環境
ruby 2.6.5
Rails 6.0.3.4

目次

1.Gemの導入
2.パンくずの設定
3.CSSの設定

1.Gemの導入

gretelというGemを使用する。 下記Gemfileに追記後、ターミナルで忘れずにbundle installを実行する。

公式GitHub

Gemfile
gem "gretel"

2.パンくずの設定

パンくずの設定を書き込むbreadcrumbs.rbファイルを作成する。作成方法は下記のようにターミナルでコマンドを実行する。

ターミナル
rails g gretel:install

今回下記のような4層でパンくずリストを構成する。
トップページ > 掃除提案 > 登録一覧 > 掃除箇所の登録

config/breadcrumbs.rb
crumb :root do
  link "トップページ", root_path
end

crumb :clean_suggestions do #ページの名前
  link "掃除提案", clean_suggestions_path #リンク名、リンク先ページ
  parent :root
end

crumb :suggestions do
  link "登録一覧", suggestions_path
  parent :clean_suggestions
end

crumb :new_suggestion do
  link "掃除箇所の登録", new_suggestion_path
  parent :suggestions
end

各ヘッダーのビューにパンくずリストを追記する。なお「separator: " > "」はリスト間に「>」を挿入する。これによりブラウザ上に表示される。

トップページのヘッダー.html.erb
<%= link_to "トップページ", root_path, class: :logo %>
<% breadcrumb :root %>
掃除提案のヘッダー.html.erb
<% breadcrumb :clean_suggestions  %>
<%= breadcrumbs separator: " > " , class: :logo %>
登録一覧のヘッダー.html.erb
<% breadcrumb :suggestions  %>
<%= breadcrumbs separator: " > " , class: :logo %>
掃除箇所の登録のヘッダー
<% breadcrumb :new_suggestion  %>
<%= breadcrumbs separator: " > " , class: :logo %>

3.CSSの設定

logoクラスは「>」に適用される。現在のページを表す部分は自動的にcurrentクラスが割り当てられている。下記記述により、現在のページを太字とし、それ以外にカーソルを合わせると色が変わるようになる。

header.css
.logo {
  margin-left: 3vw;
}

.logo a {
  margin-right: 0.5vw;
}

.current {
  font-weight: bold;
  margin-right: 1vw;
}

.logo:hover,.logo a:hover {
  color: Chocolate;
}

4fe7bb811a01b4e77db7797b103d012f.gif

以上

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Docker】Dockerfileを書いて既存Railsの開発環境をDocker化してみた。

コンテナを作成するまでの流れ

Dockerfileからdocker imageを作り、docker imageを元に「コンテナ」が作られます。

そもそもDockerfileとは?

Dockerの上で動かす「コンテナ」の構成を記述するためのファイルのことです。つまり、DockerfileからDocker imageが作られ、それを元にコンテナが起動するという感じですね。

そもそもdocker imageとは

コンテナの元と捉えると良いかもしれません。Dockerfileを元にイメージを作ることができます。また、このdocker imageを共有することで、同じ実行環境でアプリケーションを動かすことが可能になります。

そもそもコンテナとは?

簡単にいうと、アプリケーションの実行環境のことです。ミドルウェアを含んだ実行環境の中でアプリケーションが動作します。また、Docker Engineがこのコンテナを管理します。(停止,再起動等)

実際にコマンドを追ってみる。

下記のコマンドでDockerfileからdocker imageを作成できます。【Dockerfile→docker image

docker build -t [image名]:[tag名] Dockerfileの場所

下記のコマンドでdocker imageからコンテナを作成することができます。【docker image→コンテナ】

docker create --name コンテナ名 image名

下記のコマンドでコンテナを起動させることができます。

docker start コンテナ名

ともかく実際にコンテナを作ってみる

Dockerfileを用意

Dockerfile内の基本コマンド

【FROM】

ベースイメージを指定します。ここに指定したimageを元にimageを作成することになります。基本的には公式のイメージを取得すればOK。

【RUN】

指定したコマンドを実行します。ミドルウェアをインストールする時に使われがち。何回も使用することができ、結果はデフォルトでキャッシュされる。

【CMD】

指定したコマンドを実行します。RUNとの違いは、コンテナの起動時にコマンドが実行されるということです。一つのDockerfileに一つだけ指定することができます。

【EXPOSE】

公開ポートを指定することができます。

【ENV】

Dockerfile内で使用する環境変数を指定することができます。

【ADD】

指定したホストのファイルやディレクトリ,リモートファイルをコンテナ内の指定したpathにコピーします。

【COPY】

指定したホストのファイルやディレクトリ,リモートファイルをコンテナ内の指定したpathにコピーします。

*ADDはリモートファイルはコピーできますがCOPYはできません。ADDは自然解凍されますが、COPYは自然解凍されません。

【ENTRYPOINT】

指定したコマンドをコンテナ起動時に実行します。
CMDがあれば省略可能です。

【VOLUME】

dockerが管理するデータ領域にマウントする機能。

【WORKDIR】

コマンド実行をする時のworking directoryをここで指定します。

では、基本的なコマンドはさらえたので実際に書いていきましょう!

Dockerfileを実際に書いていく

今回はRailsの環境構築のためのDockerfileを書いていきます。

# ベースとなるimageをFROMに指定
FROM ruby:2.6.3
# 基本的なソフトウェアをRUNコマンドでインストール
RUN apt-get update -qq && \
    apt-get install -y build-essential \ 
                       libpq-dev \        
                       nodejs           

# コンテナ内に/appディレクトリを作成
RUN mkdir /app
# working dirに/appを指定
WORKDIR /app
# ホストのGemfile,Gemfile.lockファイルをコンテナ内の/app内にコピー
COPY Gemfile /app/Gemfile
COPY Gemfile.lock /app/Gemfile.lock

# bundlerをインストール
RUN gem install bundler
# bundle installを実行
RUN bundle install
# ホストのカレントディレクトリをコンテナ内の/appにコピー
COPY . /app
# 公開ポートを指定。
EXPOSE 3001
# コンテナを起動するのと同時にrails server立ち上げる
CMD ["rails", "server", "-b", "0.0.0.0"]

 Dockerfileからimageを作成

タグ名とimage名は適当です。本来ならば、タグ名はバージョン管理に使われます。

docker build -t test:test .

では、docker imagesでimage一覧をみてみましょう

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
test                test                f41bb9a8148e        31 seconds ago      1.07GB

ちゃんと作成されていますね!

docker imageからコンテナを作る

コンテナを作るコマンドは下記でしたね。

docker create --name コンテナ名 image名

では、下記のコマンドを実行してください。

docker create --name hoge test

処理が完了したら下記のコマンドを実行して、作成されているか確認してください。

docker ps -a

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                   PORTS               NAMES
45ed30bea859        test:test           "rails server -b 0.0…"   14 seconds ago      Created                                      hoge

いい感じに作れていますね!

コンテナを起動してみる

docker start コンテナ名でコンテナを起動できるので、今回は

docker start hogeでコンテナが起動できるかと思います。

以上です。お疲れ様でした?‍♂️

PS:Railsのdocker-composeによる開発環境構築も書くかも

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

今更 Docker - Rails アプリケーションを作りたかった

大人気 Docker を使ってのアプリケーション開発が活発化している(根拠なし)今日このごろ、実務で使っていても 実のところ細かいことについては一切何もわかっていない という体たらくに終止符を打つべくして、 Rails の開発環境を定義してみよう、というのが本日の題である。

先ずはとりあえず実行したい

ということで正しい経路かどうかはわからんが、 Docker のドキュメント あたりを読み進めていく。重要そうなことが書いてある気がするのを全力で読み飛ばしつつ、まずは取り敢えず対話側での実行をしたい。

docker -it ruby:2.6.6 bin/bash

2.6.6-alpine 使いたかったけど Rails のインストール時にコンパイルエラー食らったから一旦諦める
オプションについては

  • -t: コンテナの中に擬似ターミナル(pseudo-tty)を割り当てる
  • -i: コンテナの標準出力(STDIN)を取得する

ということらしく、つまり この指定がないと対話型で使うことはできん ようだ。

Rails のアプリを発生させるぞ

コンテナに入ってさえしまえば、あとは単に rails new をするだけなので

gem install rails -v 6.0.3
rails new myapp

このままだと Node.js not installed. のエラーが出てたりとか、細かくは色々あるようだが、何にせよこれで開発に使えるアプリケーションソースが出来る… 訳がない のである。

ホスト側にファイルを置きたいんだけど

知っての通り(?)、コンテナ内のファイルはそのコンテナ内にあるものであって、そのままではホスト側から識別可能なものにならないため、開発に着手するには更に一手必要になる。
これの実現には Docker Volume の活用が必要で、コンテナの作成時に -v のオプションを与えると良いらしい。

# まぁ「今いるところ」なら pwd でいいかなというアレ
docker -it -v `${pwd}`:/webapp ruby:2.6.6 bin/bash

これにより、ホスト側のカレントディレクトリがコンテナ側の /webapp ディレクトリにマウントされる(= ファイルを突っ込んだ場合はホスト側に配置される)ようになる。ホスト側の任意のディレクトリをマウントしたい場合は 左側も絶対パス指定じゃないと駄目 らしい点には留意が要る。 相対パスでも構わん、と書いてあるのは多分これ別の文脈の説明だな?

さておき、この状況であれば /webapp にさえ配置してやれば rails new の生成物がホスト側でも確認できるので、

rails new webapp/myapp

とすることで、手元に直接的に Ruby の実行環境を持っていなくても Rails のアプリケーションが作れる。

ひとまずはここまで。実用的な開発環境の定義には Dockerfile や docker-compose の活用が前提だと思うので、遠からずそちらも書き散らしていくとしたい。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Float型にて、計算した際に、値に少々ズレが生じる件について

環境

Ruby 2.6
Rails 5.1.7

背景

機能実装中、数値を計算する処理が何か合わないなぁと思ったら表題の現象が起きてた。
これは初めて遭遇したので備忘録として。

現象

ruby
irb(main):005:0> 2.2 * 100
=> 220.00000000000003
irb(main):006:0> 2.3 * 100
=> 229.99999999999997
irb(main):007:0> 2.4 * 100
=> 240.0

Float型に100掛けると何故か100倍になっておらず少々の誤差があることに気づいた

対応

https://qiita.com/yusabana/items/fd4a0185c1f120403a74
こちらの記事を参考にBigDecimalを使用してあげると綺麗な数値が出る

ruby
irb(main):017:0> (BigDecimal(2.2.to_s) * 100).to_f
=> 220.0
irb(main):015:0> (BigDecimal(2.3.to_s) * 100).to_f
=> 230.0
irb(main):018:0> (BigDecimal(2.4.to_s) * 100).to_f
=> 240.0

以上

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsでflatpickrを使ってみる

はじめに

フォームから日付を入力する際、カレンダーから直感的に日付選択できるようにする"datetimepicker"等の日付ピッカー。
その一種であるflatpickrをRailsで使う方法がQiitaに見当たらなかったので記事にしてみました。
なお、当方初学者かつ初投稿なので、間違いなどございましたらご指摘いただけますと幸いです。

環境

  • ruby 2.6.6
  • Rails 5.2.4.4

flatpickrについて

flatpickrは非常に軽量で導入も簡単です。
flatpickr以外の日付ピッカーとしてbootstrap-datetimepickerが有名ですが、bootstrapやjQueryに依存していたり、bootstrapのバージョンの互換性などなにかと面倒です。
私のような初学者でもポートフォリオへの導入がしやすいかと思います。

関連ページ

flatpickrは色々細かく設定できるようなので、上記サイトを御覧ください。

  • flatpickr-rails (github)
    Railsで簡単に使えるようgemパッケージ化してくれています。
    今回はこちらを使って導入していきます。

flatpickrインストール

今回は先程のGemを使用するので、Gemfileに以下を記述し、インストールします。

gemfile
gem 'flatpickr'
tarminal
$ bundle install

app/assets/stylesheets/application.cssの拡張子cssをscssに変更
上部にflatpickrを読み込ませる記述を追加します。

application.scss
/* 
 ...
 ...
// 〜〜〜〜 以下を追加 〜〜〜〜
 *= require flatpickr
// 〜〜〜〜 以上を追加 〜〜〜〜
 */

app/assets/javascripts/application.jsも同様に記述します。
日本語化するのであれば、一緒にflatpickr/l10n/jaも導入しましょう。

application.js
//= require rails-ujs
//= require activestorage
// 〜〜〜〜 以下を追加 〜〜〜〜
//= require flatpickr
//= require flatpickr/l10n/ja
// 〜〜〜〜 以上を追加(require turbolinksより上に追加) 〜〜〜〜
//= require turbolinks
//= require_tree 

以上でflatpickrの準備は整いました。次は、viewでフォームから実際にflatpickrを表示してみましょう。

表示してみる

今回はnewページで、Taskモデルのdate型のaction_atというカラムにデータを入れる場合を想定しましょう。
モデルやカラム名は適宜読み替えて実装してください。

viewではRailsのいつもの感じでform_withを使ってフォームを作りましょう。

views/tasks/new.html.erb
<%= form_with(model: @task, local: true) do |f| %>
  <%= f.text_field :action_at, id: "flatpickr", type: "text", readonly: "" %>
<% end %>

text_fieldにわかりやすくid: "flatpickr"と記述しました。
idの名前は何でもいいですが、次のjsに書くflatpickrの第一因数と一致させるようにしてください。
また、readonly:""でユーザーにflatpickr以外から文字入力をさせないようにしましょう。

続いてJavaScriptの設定に移ります。
新しいjsファイルを作成する場合、ファイル名をflatpickr.jsにすると//= require flatpickrと被って動かなくなるので注意しましょう。
turbolinksを使用していない場合は最初の行は必要ありません。

datetime.js
document.addEventListener('turbolinks:load', () => {
  flatpickr('#flatpickr')
})

これでフォームをクリックするとflatpickrが表示されるはずです!
スクリーンショット 2020-11-30 14.42.31.png

カスタマイズ例

jsでのカスタマイズ例なんかは既にいろいろ記事が上がっていたり、公式サイトにも載っているのですが、少しだけ例を挙げておきます。

日本語化とスマホ対応

datetime.js
document.addEventListener('turbolinks:load', () => {
  // カレンダーの日本語化
  flatpickr.localize(flatpickr.l10ns.ja)
  // カレンダー表示
  flatpickr('#flatpickr', {
    // スマートフォンでもカレンダーに「flatpickr」を使用する設定
    disableMobile: true,
  });
})

//= require flatpickr/l10n/jaで日本語化を読み込んでいるので、これで曜日などが日本語になります。
スクリーンショット 2020-11-30 14.43.22.png

選択可能日を設定

datetime.js
document.addEventListener('turbolinks:load', () => {
  const TODAY = new Date(new Date().setHours(0, 0, 0, 0))

  flatpickr.localize(flatpickr.l10ns.ja)
  flatpickr('#flatpickr', {
    disableMobile: true,
  //今日までを選択可能にする
    maxDate: TODAY
  });
})

今日までを選択可能にしました。minDate:とかで一ヶ月前までを選択可能にしたりもできます。
スクリーンショット 2020-11-30 14.41.21.png
11月28日時点なら、29日、30日と来月以降の文字は選択不可になっています。

テーマ変更

application.scss
/* 
 ...
 ...
 *= require flatpickr
 *= require flatpickr/themes/dark.css
 */

flatpickrには色々なテーマが用意されており、scssに読み込ませるだけで変更できます。
公式サイト日本語約ページにサンプルがあります。
Themes
スクリーンショット 2020-11-30 14.45.09.png
上の例はdarkテーマを採用していますが、darkのところを他のテーマ名に変えるだけで適用できます。
スクリーンショット 2020-11-30 14.45.49.png
material_blue.css
スクリーンショット 2020-11-30 14.46.31.png
airbnb

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails]ページネーション機能

実装したいこと

完成形

投稿が多くなってくると一覧表示した時に見にくくなってしまうのでページを分けました。

目次

  • 1. kaminariのインストール
  • 2. ページネーションの表示
  • 3. デザイン
  • 4. ラベルの変更

1. kaminariのインストール

Gemfileの一番下に以下を記述し、ターミナルでbundle installを実行します。

Gemfile
gem 'kaminari'

2. ページネーションの表示

今回はbefore_actionを用いて投稿一覧を表示しています。
ページネーションを表示させたいデータに.page(params[:page])を追記します。
また、.per(10)を追記することで1ページに10件のデータを表示するという設定をします。
デフォルトでは25件が表示されるようになっています。

app/controllers/posts_controller.rb
def index_post
  @posts = Post.order(created_at: :desc).page(params[:page]).per(10)
end

ページネーションを表示させたいところに<%= paginate @posts %>を追記します。

app/views/posts/index.html.erb
~~
  <div class='item-contents'>
    <h2 class='title'>クチコミ一覧</h2>
    <%= render "shared/posts" %>
    <%= paginate @posts %>   # 追記
  </div>
</div>

3. デザイン

今回はbootstrapとFont Awesomeを用いて実装しました。
まずbootstrapとFont Awesomeを読み込みます。

app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>CosmeticReview</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    # 以下を追記 Font Awesome読み込み
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.9.0/css/all.css">
    # 以下を追記 bootstrap読み込み
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%# <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> %>
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <%= yield %>
  </body>
</html>

次に、kaminariにbootstrapを適用させます。
ターミナルで以下を実行します。

ターミナル
rails g kaminari:views bootstrap3

実行後、app/views/kaminariフォルダが自動生成され、ページネーションにbootstrapが適用されます。

CSSでさらに自分の好みのデザインに変更します。

app/assets/stylesheets/index.css
/* ページネーション */
.pagination {
  display: flex;
  justify-content: center;
}
.pagination > li > a {
  border: none;
  color: #999;
}
.pagination > li > a:hover {
  color: turquoise;
  background-color: white;
}
.pagination > .active > a {
  color: turquoise;
  background-color: white;
}
.pagination > .active > a:hover {
  background-color: white;
  color: turquoise;
}
/* --ページネーション */

4. ラベルの変更

今回はラベルにアイコンを用いて実装しました。

config/locales/ja.yml
ja:
 views:
     pagination:
       first: <i class="fas fa-angle-double-left"></i>
       last: <i class="fas fa-angle-double-right"></i>
       previous: <i class="fas fa-angle-left"></i>
       next: <i class="fas fa-angle-right"></i>
       truncate: "..."

3 参考リンク

https://github.com/kaminari/kaminari
https://qiita.com/rio_threehouse/items/313824b90a31268b0074

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails findとfind_by

findメソッド

findメソッドを使用すると、与えられたどのオプションにもマッチする
主キー(primary key)に対応するオブジェクトを取り出すことができる
主キーを複数指定することも可能

該当するものがない場合

該当するものがないと「エラー」
ActiveRecord::RecordNotFound例外が発生する

find_byメソッド

与えられた条件にマッチするレコードのうち最初のレコードの1件だけを返す
検索条件は、主キーだけでなく他のカラム等でも検索することができる
検索条件は、複数指定することも可能

該当するものがない場合

該当するものがないと「nil」を返す

参考記事

https://railsguides.jp/active_record_querying.html
https://qiita.com/nakayuu07/items/3d5e2f8784b6f18186f2
https://pikawaka.com/rails/find_by

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

1-nの関連モデルでnのデータを取得する場合は1のモデルから取ろうという話

前提

※Railsでの話ですが、他のライブラリにも同じことが言えると思います

以下のモデルがあります
User
UserPost
※1-nの関係

以下のURLがあります

/posts # 自分の投稿一覧を取得
/users/:user_id/posts # user_idの投稿一覧を取得

Controllerの処理

/postsの例

UserPost.where(user_id: @current_user.id)....

こんな感じでやったりする人がいますが、これはだめです。
こうしましょう

@current_user.user_posts...

UserPostからとるようにすると、なんかの手違いでwhere条件を消してしまったりして、userの条件が外れる可能性があります。
userからとるようにしておけば、必ずそのユーザーで絞り込まれるので、その事故を防ぐことができます

/users/:user_id/postsの例も理由は同じです

結論

必ず親側のモデルからデータをとるようにするクセをつけるといいと思います

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

opentelemetry-ruby で Rails アプリケーションをトレーシングしてみる

はじめに

まだ beta 版のようですが、気になってた opentelemetry-ruby を使って Rails アプリケーションへのリクエストをトレースし、Jaeger で可視化するところまでやってみようと思います。

Opentelemetry とは

OpenCensusOpenTracing の2つのプロジェクトが統合されたもので、Tracing だけでなく Metrics、Logs といった Observavility 全体を実現するための標準化された API およびライブラリが提供されています。今回は、Opentelemetry のなかの Tracing を使ってみようと思います。

公式ページの絵がかわいくてほっこりしますよね。

なお、Opentelemetry のアーキテクチャについては、New Relic 社の『OpenTelemetry: 計装器を長く使い続けるために』が図示されていてわかりやすかったです。

環境

Docker for Mac
Ruby on Rails 6.0.3.4
MySQL 5.7
Jaeger 1.20

Jaeger を起動する

JaegerGetting Started の All in One を使用します。

それぞれのポート役割については こちら に記載されています。

docker run --rm --name jaeger \
  -p 5775:5775/udp \
  -p 6831:6831/udp \
  -p 6832:6832/udp \
  -p 5778:5778 \
  -p 16686:16686 \
  -p 14268:14268 \
  -p 14250:14250 \
  -p 9411:9411 \
  jaegertracing/all-in-one:1.20

これで Jaeger の GUI に下記の URL からアクセスできるようになりました。

http://localhost:16686/search

Rails アプリ

Rails アプリケーションは、 Rails チュートリアルToy アプリケーションで作ったものを使用します。

今回は簡単にユーザの一覧と詳細ページにアクセスし、トレースできるか確認してみようと思います。

スクリーンショット 2020-11-26 1 40 00

opentelemetry-ruby の使い方

opentelemetry-ruby に関連する Gem は全てこのリポジトリにあるようです。

https://github.com/open-telemetry/opentelemetry-ruby

そして、Jaeger にトレースデータを Export するには、opentelemetry-ruby リポジトリ内にある opentelemetry-exporter-jaeger を Gem インストールすれば良さそうです。

また opentelemetry-ruby リポジトリ内に instrumentation ディレクトリがあり、Rails や mysql2、faraday など様々な Instrumentation 機能が用意されてるようです。

今回は、Rails と mysql2 の Instrumentation 機能を使ってみようと思います。

これを使うことで、Controller・Action の処理時間や実行されたクエリなどがトレースできそうです。

Rails の Instrumentation は opentelemetry-instrumentation-rails、mysql2 の Instrumentation は opentelemetry-instrumentation-mysql2 を Gem インストールすれば良さそうですが、opentelemetry-instrumentation-rails はまだ rubygems.org に公開されていないようでした。

なので、opentelemetry-instrumentation-rails は opentelemetry-ruby を git clone して、Gemfile で path 指定をして使ってみようと思います。

(執筆時点(11/27)では公開されていませんでしたが、現在は公開されているようです。)

実装

opentelemetry-ruby を git clone してきます。

$ git clone git@github.com:open-telemetry/opentelemetry-ruby.git

次に、Rails アプリ の Gemfile に下記を追加します。

Gemfile
gem 'opentelemetry-sdk'
gem 'opentelemetry-exporter-jaeger'
gem 'opentelemetry-instrumentation-mysql2'
gem 'opentelemetry-instrumentation-rails', path: '/path/to/opentelemetry-ruby/instrumentation'

opentelemetry-instrumentation-rails だけ clone してきた path を指定します。

また Docker を使う場合は、clone してきた opentelemetry-ruby を Volume マウントした先の path を指定します。

ここで、path を/path/to/opentelemetry-ruby/instrumentation/railsではなく、/path/to/opentelemetry-ruby/instrumentationとすることで、依存関係にある opentelemetry-instrumentation-rack も clone してきた opentelemetry-ruby のinstrumentation/rackから取得してきてくれます。

次に、config/appliction.rb に下記を追加します。

config/appliction.rb
require 'opentelemetry/sdk'
require 'opentelemetry/exporter/jaeger'

OpenTelemetry::SDK.configure do |c|
  c.use 'OpenTelemetry::Instrumentation::Rails'
  c.use 'OpenTelemetry::Instrumentation::Mysql2'
  c.add_span_processor(
    OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(
      exporter: OpenTelemetry::Exporter::Jaeger::AgentExporter.new(host: 'host.docker.internal', port: 6831)
    )
  )
  c.service_name = 'toy-app'
  c.service_version = '0.1.0'
end

この use の部分ですが、

c.use 'OpenTelemetry::Instrumentation::Rails'
c.use 'OpenTelemetry::Instrumentation::Mysql2'

use_all とも書けるようです。

c.use_all

use_all すると利用可能な Instrumentation を全て use してくれるようです。

そして、Jaeger にトレースデータを Export する方法は、UDP を介した ThriftCompact 形式 で Jaeger Agent に Export する方法と、HTTP を介した ThriftBinary 形式で Jaeger Collector に Export する方法の2種類用意されているようです。

今回は、Jaeger のアーキテクチャ的に自然な UDP で Jaeger Agent に Export する方法でやってみます。

host は、Docker for Mac で検証しているためhost.docker.internalを指定します。

port は、Jaeger の UDP の ThriftCompact 形式の公開ポートである 6831 を指定します。

OpenTelemetry::Exporter::Jaeger::AgentExporter.new(host: 'host.docker.internal', port: 6831)

service_name は、アプリケーションの名前を指定します。

service_version は、アプリケーションのバージョンを指定します。今回は適当に 0.1.0 を指定しました。

実装はこれで完了です。

動作確認

それでは bundle install 後、Rails アプリケーションを再起動して、Toy アプリケーション の ユーザ一覧とユーザの詳細ページにアクセスしてみます。

スクリーンショット 2020-11-26 1 40 00

アクセスすると、Jaeger の Service のところに service_name で設定した toy-app が出現するので選択して、Find Traces をクリックします。

スクリーンショット 2020-11-26 9 46 55

ちゃんとトレースできてそうですね。

スクリーンショット 2020-11-26 10 00 48

SQL も確認できました。

<ユーザ一覧>

スクリーンショット 2020-11-26 10 02 09

<ユーザ詳細>

スクリーンショット 2020-11-26 10 27 23

うまくできました!

さいごに

とても簡単に opentelemetry-ruby を使って Rails アプリケーションのトレースデータを Jaeger で確認することができました!

公式リリースが待ち遠しいですね!

明日は、@tsukasa_oishi さんの「どれだけリクエストをさばけるのかを待ち行列理論で考えてみた」です。お楽しみに!!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Cloud9 "VFS connection does not exist"と表示されるときの対処法

Railsチュートリアルの1.3.2 rails serverを進めていたとき、サーバーを立ち上がっても
”Oops VFS connection does not exist"と表示されてしまうエラーについてです。

https://blog.proglus.jp/3893/#VFS_connection_does_not_exist
↑参考資料

チュートリアル通り進めていても、エラーが出たので焦ってしまう人も多いと思います。

解決方法として

①Webサーバーの再起動

②使用ブラウザの確認

③EC2インスタンスの再起動

④OSのバージョンの更新

⑤Cookie設定

⑥広告ブロッカーやセキュリティソフト使用の有無

があるようです。私の場合、④と⑤を改善することで、サーバーを立ち上げることができました。ご参考までに。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Cloud9 × Raisl × Docker × MySQL で環境構築

はじめに

cloud9を使ったDockerの環境構築の記事が少なく戸惑ったこと、自身のアウトプットのために執筆します。

別の記事でも記載していますが、現在転職活動中の身ですのでプロではありません。
間違いなどありましたらご指摘いただければ、自身でも調べ速やかに修正いたします。

参考記事:
丁寧すぎるDocker-composeによるrails5 + MySQL on Dockerの環境構築(Docker for Mac)

ファイル内容は上記サイトから頂きましたが、port8080に対応するため一部編集を加えています。

目標

タイトルの構成で環境構築をし、「Yay! You’re on Rails!」を表示させる。

環境

Amazon linux
Ruby 2.6.3
Rails 5.2.4.4
MySQL 5.5.62
Docker 19.03.6
Docker-compose 1.27.4

やってきましょう

インスタンスのボリュームを増やす

cloud9を立ち上げてできるインスタンスはサイズが10GBとなっているので、容量が不足する可能性があります。
その都度不要ファイルを削除できればいいのですが、手っ取り早くコンソールから容量を増やしました。
(極少額の課金が発生するかもしれません、料金はご自身で調べてみてください)

まずはcloud9を立ち上げます。
その後EC2の画面に行くと、cloud9と同時に立ち上がったインスタンスがあります。

EC2のサイドメニューから下記の順番で選択します。
1.ボリューム
2.先ほど立ち上がったインスタンスのチェックボックス
3.アクション
4.ボリュームの変更

スクリーンショット 2020-11-29 190704.png

開いたウィンドウのサイズを16GBに変更
スクリーンショット 2020-11-29 190843.png

こうなればOK
スクリーンショット 2020-11-29 190917.png

インスタンスの状態がoptimizing(黄色のマーク)なので、10分程度放置し終わるのを待ちます。
スクリーンショット 2020-11-29 191119.png

状態が緑のマークになると、サイズも16GBとなり反映が確認できます。
スクリーンショット 2020-11-29 193501.png

cloud9のターミナルに移動します。
以下のコマンドで内部からもサイズ変更が反映されているかを確認します。

$ df -h
Filesystem      Size  Used Avail Use% Mounted on
devtmpfs        483M   60K  483M   1% /dev
tmpfs           493M     0  493M   0% /dev/shm
/dev/xvda1       16G  8.6G  7.0G  55% /

もしリロードしても反映されていないようなら次のコマンドを試してみてください。

$ sudo growpart /dev/xvda 1
$ sudo resize2fs /dev/xvda1

Docker-Composeのインストール

インストールの前に このページ で最新のバージョンを確認しておいてください。

下の1.27.4の箇所を確認した最新のバージョンに書き換えてインストールします。
私は"/home/ec2-user/environment"ディレクトリで実行しています。

$ sudo curl -L https://github.com/docker/compose/releases/download/1.27.4/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose 

$ docker-compose コマンドを実行できるように権限を与えます。

$ sudo chmod +x /usr/local/bin/docker-compose

バージョンの確認をして、表示されればインストールは完了です。

$ docker-compose --version
docker-compose version 1.27.4, build 40524192

ファイルの準備

プロジェクトディレクトリを作成して、その中に移動します。

$ mkdir myApp
$ cd myApp

そうしたら必要なファイルをtouchコマンドで作成していきます。
ここでファイルは4つ用意します。

$ touch Dockerfile
$ touch Gemfile
$ touch Gemfile.lock
$ touch docker-compose.yml

通常はviコマンドなどでファイルを書いていきますが、cloud9はせっかくエディタが付いているのでそちらで作業しましょう。

なおGemfile.lockは記載せずに空のままで大丈夫です。

各ファイルの項目は Docker × Ruby on Rails × MySQLの環境構築 この記事を参考にしてください。

Dockerfile
FROM ruby:2.6.3
RUN apt-get update -qq && \
    apt-get install -y build-essential \ 
                       libpq-dev \        
                       nodejs           
RUN mkdir /app_name 
ENV APP_ROOT /app_name 
WORKDIR $APP_ROOT
ADD ./Gemfile $APP_ROOT/Gemfile
ADD ./Gemfile.lock $APP_ROOT/Gemfile.lock
RUN bundle install
ADD . $APP_ROOT

FROM ruby:2.6.3

cloud9にはあらかじめrubyがインストールされています。
以前同様の環境構築をした際、インストール済みのバージョンとここで指定したバージョンが異なりエラーになりました。(原因は他にあるのかもしれませんが、2つのバージョンが競合したのか?)

その為ここのrubyのバージョンは$ ruby -vで確認したインストール済みのバージョンと同様にしてあります。

Gemfile
source 'https://rubygems.org'
gem 'rails', '5.2.4.4'

rails5系で現在最新のバージョンを指定。Ruby on Rails最新情報

docker-compose.yml
version: '3'
services:
  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: パスワード
      MYSQL_DATABASE: データベース名
    ports:
      - "3306:3306"

  web:
    build: .
    command: rails s -p 8080 -b '0.0.0.0'
    volumes:
      - .:/app_name
    ports:
      - "8080:8080"
    links:
      - db

command: rails s -p 8080 -b '0.0.0.0'

ports:
- "8080:8080"

cloud9ではport8080でサーバーに接続します。
その為、ホスト:コンテナ の両方を8080番で指定しています。

パスワードとデータベース名は任意の値を記載します。

これで設定を記載した3つのファイルと、空のGemfile.lockができました。

Railsプロジェクト作成

カレントディレクトリがプロジェクトディレクトリ(今回は/home/ec2-user/environment/myApp)であることを確認します。

そうしたらrails newを実行してアプリケーションの型を作ります。

$ docker-compose run web rails new . --force --database=mysql --skip-bundle

問題がなければプロジェクトディレクトリ配下にRailsのひな形が出来上がります。

$ ls
app  bin  config  config.ru  db  docker-compose.yml  Dockerfile  Gemfile  Gemfile.lock  lib  log  package.json  public  Rakefile  README.md  storage  test  tmp  vendor

データベース周りの設定のため/myApp/config/database.ymlを修正します。

database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: パスワード
  host: db

パスワードの箇所には先ほど"docker-compose.yml"で設定したのと同様の値を記載します。
ここで保存しようとすると、恐らくcloud9の上部に警告文が表示されます。

EACCES: permission denied

これはdatabase.ymlに対する書き込み権限が無いので保存できない旨の内容なので、権限を変更指定保存できるようにします。

/myApp/configに入り、ファイルの権限を確認します。

$ cd config
$ ls -l
-rw-r--r-- 1 root root 1657 Nov 29 19:06 database.yml

書き込み権限を変更し、反映されればdatabase.ymlを保存できるようになります。

$ sudo chmod 666 database.yml
$ ls -l
-rw-rw-rw- 1 root root 1657 Nov 29 19:06 database.yml

Dockerコンテナのビルド

プロジェクトディレクトリに戻り、コンテナを立ち上げます。

$ docker-compose build

PermissionError: [Errno 13] Permission denied: '/home/ec2-user/environment/myApp/config/master.key

このエラーが出るのは先ほど同様myApp/config/master.keyに対するパーミッションエラーなので、権限を変更します。

ディレクトリを移動して権限を確認。

$ cd config
$ls -l
-rw------- 1 root root   32 Nov 29 19:06 master.key

権限を変更して反映を確認します。

$ sudo chmod 666 master.key
$ ls -l
-rw-rw-rw- 1 root root   32 Nov 29 19:06 master.key

再トライ

$ docker-compose build
$ docker-compose up

これで私はうまくいきました。

データベースの作成

コンテナが起動したらショートカットキーAlt + Tでcloud9にターミナルをもう一つ立ち上げます。

開いたターミナルからプロジェクトファイルに移動して、データベースを立ち上げます。

$ cd myApp
$ docker-compose run web rails db:create

成功していれば Preview → Preview Running Application で「Yay! You’re on Rails!」が表示されます。
この時

**********.vfs.cloud9.ap-northeast-1.amazonaws.com で接続が拒否されました。

と表示されたら、右上の矢印ボタンを押して別タブで開けば表示されます。

サーバーを停止させる場合はCtrl + Cではなく、新しく開いた方のターミナルで下記を入力します。

$ docker-compose down

スクリーンショット 2020-11-26 184833.png

その他のエラー

Can't connect to MySQL server on 'db' (115)

コンテナが立ち上がり切っていない時に表示されます。
数秒待ってからリロードすれば表示内容が変わります。

Unknown database 'app_name_development'

データベースを作成していないとこの表示がされます。
新しいターミナルを開いてデータベースを作成すれば解消されます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RailsにおけるRESTfulな設計とはなにか?

RESTfulとは

RESTful APIは、基本的に「RESTの原則」に従って実装されているWebシステムのHTTPでの呼び出しインターフェースのことを指します。

https://blog.api.rakuten.net/ja/jp-restful-api/#:~:text=REpresentational%20State%20Transfer%E3%81%AE%E7%95%A5,%E3%81%AE%E3%81%93%E3%81%A8%E3%82%92%E6%8C%87%E3%81%97%E3%81%BE%E3%81%99%E3%80%82

なるほど..わからん。

Railsの根本的なところやん?こんなに理解がぼんやりしていてええの?
ってことでこの曇った視界をはっきりさせていく。

RESTful

アプリケーションを構成するリソースをHTTPリクエスト(GET/POST/PUT/DELETE)で作成、読み出し、更新、削除できる仕組み

要するにURLに対してどのHTTPリクエストを送るかでそのあとの動作をより分けているイメージか。


アプリケーションでユーザー関連のもろもろを取り扱うUserリソースを例にしてみる

アプリケーションの下記のような動作があったとする。

  • ユーザーを新しく登録するページを表示(new)
  • ユーザーを新しく作る(create)
  • 一人のユーザーを閲覧する(show)
  • 登録ユーザーの一覧をみる(index)
  • ユーザー情報を更新するページを表示(edit)
  • ユーザー情報を更新する(update)
  • ユーザーを消す(destroy)

これを冒頭でも述べた動作で振り分ける
ユーザーを新しく作るなら
HTTPリクエストは POST 
URLは/users
こうするとcreateアクションを呼び出すことができる。
※Railsではindex, show, new, edit, create, update ,destroyが暗黙のリクエスト

RESTfulな設計を使うには

HTTPリクエスト、URL、アクションの設定はroutes.rbでできる。

post '/users', to: 'users#create'

ただUsersリソースのように想定している動作がindex, show, new, edit, create, update ,destroyの7種類全てを使う場合はroutes.rbで

resources :users

の1行を追加するだけで全てのアクションが使える。

RESTfulな設計とは

・URLに対して、どのリクエスト(GET、POST、PUT、DELETE)かで結果が変わる仕組み

・routes.rbでその設定ができる。
・すべての挙動を想定している場合はresources :usersの一行でルーティング設定が終了する

参考

https://wa3.i-3-i.info/word11405.html
https://qiita.com/kidach1/items/43e53811c12351915278
https://qiita.com/katsutakashima/items/47977b9e7d18cf816734
railsチュートリアル
Ruby on Rails 入門

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby オブジェクトってなんなの??に答える

adventカレンダー初日の担当をさせていただきます !
DMM WEBCAMPでメンターをしているtanidaです !

Rubyのオブジェクトとは何か? オブジェクト指向とは何か?
そんな疑問に答えていければと思います。

ではでは、オブジェクトの世界を覗いてみましょう!

そもそもRubyにおいてオブジェクトとは

オブジェクト(インスタンス)とは、あるクラスから生成されたデータのこと!

*オブジェクトとインスタンスは同じモノだと、とりあえず覚えてください。

オブジェクト指向って何なんですか?

プログラムはオブジェクト間のメッセージのやりとり という考え方です。
この考え方を理解するためにも、オブジェクトについて理解を深めていきましょう。

1章 実際にオブジェクトを作ってみる?

PCにRubyのインストールされてない方はこのサイトのEditorにソースコードを書いて試せます。
https://try.ruby-lang.org/

Personクラス - 人クラス

object.rbというファイルを作成して以下のソースコードを実行してみます。

object.rb
class Person
  # initializeはオブジェクトの初期化のための特別なメソッド
  # クラス名.new()した時の引数が渡されます
  def initialize(name)
    @name = name
  end

  def greeting
    "Hi! I'm #{@name}!"
  end
end

# Personインスタンスを生成した後、initializeメソッドが呼び出されます。
# これがオブジェクト(インスタンス)です。
person = Person.new('menter taro')
p person

#<Person:0x00007fbd8686d490 @name="menter taro"> がターミナル上で確認できました。

  • 検証デモ object.gif

2章 もう少しオブジェクト(インスタンス)について調べてみる?

1. 所属するクラス

インスタンスはクラスに所属しているのでclassメソッドを利用すると、オブジェクトが所属するクラスはどこか教えてくれます。

puts person.class

2. インスタンス変数

インスタンス変数とはインスタンスが保持している変数の事です。
先ほどのコードでいうと、@name です。インスタンス変数は@マークがイニシャルでなければいけません。
インスタンス変数は同じインスタンス内であればその値を参照、変更ができます。

instance_variablesメソッドを利用するとインスタンス変数を教えてくれます。

puts person.instance_variables

3. インスタンスメソッド

インスタンスメソッドとは、クラス内に定義された、
クラスから生成されたオブジェクト(インスタンス)からしか呼び出せないメソッドのこと。

puts person.class.instance_methods(false)

instance_methodsの引数にfalseを付け加えると、
継承先のメソッドは表示しないようにしてくれます。(継承については説明を省きます)
今回はPersonクラスに定義されたインスタンスメソッドのみを聞きたいのでそうしています。

Personクラスから生成されたオブジェクト(インスタンス)からならgreetingを呼べます。

puts person.greeting

この呼び方はできない

puts greeting
  • イメージ図
    hito.png

  • 検証デモ
    object.gif

3章 アクセスメソッドの利用?

attr_accessor (いわゆるgetter/setter)

attr_reader(getter) と attr_writer (setter) が融合したもの

オブジェクトの外部からインスタンス変数を直接参照したり、インスタンス変数の値を更新することはできません。
でも、オブジェクトの外部から、簡単にインスタンス変数の値にアクセスしたいし、更新もしたい。。。
しかし、アクセスメソッドなら実現できます。

attr_accessor を追加するとオブジェクトから直接インスタンス変数の値を「参照」したり、「設定」したりできます。

object.rb
class Person
  attr_accessor :name # インスタンス変数@nameの値の参照、設定が可能になる。

  def initialize(name)
    @name = name
  end

  def greeting
    "Hi! I'm #{@name}"
  end
end

person = Person.new('menter taro')

puts person.name # 参照
person.name = 'menter jiro' # 設定
puts person.name # 参照
  • 検証デモ object.gif

*ちなみに他のオブジェクト指向言語でも、getterとsetterというワード、概念はあります。

4章 重要な概念レシーバーとは?

メソッドの戻り値を受け取る対象のことです。

Personクラスにあるインスタンスメソッドgreetingを呼び出した時に
"Hi! I'm menter taro" といった文字列が戻り値となっていました。

その戻り値を受け取る対象をレシーバーと言います.
先ほどのソースコードでの person がレシーバーとなります。

puts person.greeting # "Hi! I'm menter taro" というメッセージをpersonが受け取る。

つまり、レシーバーとはインスタンスメソッドを呼び出しているインスタンス自身のこと !

もう少しレシーバーについて詳しくみてきましょう。

呼び出されたメソッドのレシーバー自身を参照する - self

インスタンスメソッド内でselfと記述すると、そのメソッドを呼び出したレシーバを取得できます。

object.rb
class Person
  attr_accessor :name

  def initialize(name)
    @name = name
  end

  def greeting
    "Hi! I'm #{@name}"
  end

  def check_receiver
    # selfでレシーバーを取得
    # 言い換えれば、インスタンスメソッドの呼び出し元のオブジェクトを取得する
    puts self
    # レシーバーのnameも取得
    puts self.name
  end
end

person = Person.new('menter taro')
person.check_receiver
  • 検証デモ object.gif

オブジェクト指向の世界では
「オブジェクトにセッメージを送り」 そして 「オブジェクトがメッセージを受け取る」
このように捉えられるのでレシーバーと呼ぶらしいです。

オブジェクト指向プログラミングは
プログラムはオブジェクト間のメッセージのやりとり
`「オブジェクトのメッセージングによるプログラミングの手法」
と言われる理由が少しイメージできたのではないでしょうか?

5章 クラスメソッドとは?

レシーバがインスタンスではなくクラスそのものであるメソッドの事です。
書き方は色々とあるのですがこの記事ではself.メソッド名で定義します。
*先ほどのselfとは異なりインスタンスメソッド内ではなくクラス内に定義することになります。

object.rb
class Person
  attr_accessor :name

  def initialize(name)
    @name = name
  end

  def greeting
    "Hi! I'm #{@name}"
  end

  # クラスメソッド
  def self.person_class_method
    "クラスメソッドの戻り値ですよ〜"
  end
end

person = Person.new('menter taro')
puts Person.person_class_method

# インスタンスからはクラスメソッドは呼び出せない
puts person.person_class_method
  • 検証デモ object.gif

じゃあ、クラスメソッドをどういう時に利用するの?

と言われると(まぁ好きなように使えるのですが)
インスタンスからメソッドを呼び出すと意味がちょっと違和感がある場合や、
あるクラスのオブジェクトを参照中に他のクラスに関する処理を行いたい時 とかはクラスメソッドにすると良いかと思います。そのほうがソースコードの管理が楽になるはずです。

例えば、5人分のPersonインスタンスを一括で生成したい時...

Personのインスタンスから直接呼ぶとチョット違和感ありませんか!...?
- いきなり真面目な顔で 「人間五人作れ」 という人がいたら太郎さんは困ります。
hito.png

  • Monsterクラスのインスタンスを参照中、そのインスタンスに他のクラスに関する処理をまとめてしてくれ!と言うのもチョット違和感ありませんか...?
    monster.png

  • Personクラスに直接頼みましょう。その方がソースコードの管理がしやすいでしょう。
    hito.png

では実際にbulk_createというクラスメソッドで5人分のPersonインスタンスを生成してみます。

object.rb
class Person
  attr_accessor :name, :age

  def initialize(name, age)
    @name = name
    @age = age
  end

  def self.bulk_create(data)
    # mapでは各要素に処理を加えてその値を含んだ新しい配列を作ってくれています。
    data.map { |d| Person.new(d[:name], d[:age]) }
  end
end

# Hashの配列を定義
data = [
  {name: 'menter 一郎', age: 10},
  {name: 'menter 二郎', age: 20},
  {name: 'menter 三郎', age: 30},
  {name: 'menter 四郎', age: 40},
  {name: 'menter 五郎', age: 50}
]

puts Person.bulk_create(data)
puts
p Person.bulk_create(data)

Person.bulk_create(data) でクラスメソッドを呼び出すと、
五人のPersonオブジェクト(インスタンス)が格納された配列が戻り値となっています。
その配列を受け取っているレシーバーはPersonクラスということです。

  • 検証デモ object.gif

という事でクラスオブジェクトがレシーバーになるメソッドがクラスメソッドと言うことになります。

なるほどぉ〜?? ん? チョット待って...クラス「オブジェクト」...?
オブジェクトってあるクラスから生成されたデータインスタンスの事って言ってましたよね...?
クラスオブジェクトは別物なんでちゃんと「クラス」って言った方がいいんじゃないんですか??

うん、うん、そうそう... うん、オブジェクトはクラスに所属してるんだけどね...
まぁそうなんだけどね... 実はRubyでは「クラスもオブジェクト」なんです... ( 'ω' )

6章 クラスオブジェクト - Rubyにおいてクラスはオブジェクトだった?!?

クラスのクラス - その名は Classクラス ! (頭痛くなりますねわかります)

ここまでは、オブジェクト(インスタンス)クラスから生成されるデータと説明してきましが、なんとクラスもなんです。
実は、先ほどまで利用していたPersonクラスは実はオブジェクト(インスタンス)なのです !

オブジェクトの後にclassメソッドをつけると所属先のクラスを知ることができましたよね。
プログラムを実行して確認しましょう。

puts Person.class
# Class

「PersonクラスはClassクラスに所属しているオブジェクト」ということが分かりました。

  • Classクラス自体もクラスに属しているのですがこれについては説明を省きます。

PersonクラスはClassクラスのインスタンスということなので、Personクラスの実態は以下になります。

Class.new

クラスは実は定数

PersonクラスClass.newと分かりました。
では、Personという名前はどこからくるのでしょう...? 答えは定数です。
定数は覚えてますでしょうか?アルファベット大文字 ([A-Z]) で始まる識別子ですね。
以下のようにClass.new定数Personに割り当てます。

Person = Class.new 

今まで見てきた以下のコードは

class Person
end

実は

Person = Class.new

だったということになります。!(◎_◎;)

「Rubyではクラスは定数なんだよ!」の意味がわからん...?
と思っていた方はその事実に(つд⊂)ゴシゴシゴシ(;゚Д゚)…ハッ !?となったのではないでしょうか?

今まで見てきたclassの実態「Classクラスのオブジェクト(インスタンス)を定数に割り当てること」に等しかったってことか...?

  • 検証デモ (Personクラスをclassを使わず、定数で定義してみた) object.gif

前章のコードと同じように動作しました。
これでクラスはオブジェクトと言うことが分かりました。
*なのでインスタンスの特徴であるインスタンス変数の保持や、インスタンスメソッドを呼び出すことも可能です。

7章 Railsで利用してる身近なオブジェクト(一部を抜粋)?

1. モデル

わかりやすいところでいうとモデルですね。
Railsのmodelってclassって書いてありますよね。
model名.new とかはクラスからインスタンスを生成しているってことです。
model内にインスタンスメソッドを定義してるなら、インスタンスからそのメソッドを呼び出せるわけです。

2. コントローラー

controllerも見てみるとclassって書いてありますよね。
例えば、HogeControllerのindexアクションを実行するって事は、
HogeControllerクラスから生成されたインスタンスからインスタンスメソッドindexを実行している訳です。

先ほどRubyのクラスは定数ということが分かりました。
Railsのエラー文でも定数(constant)というワードが出てきます。
uninitialized conostant コントローラー名 っていうエラーは見たことあるでしょうか?
マッチしたUrlのパスの行き先のコントローラーが探索できなかった時に出るエラーですね。
Routingの get '/users', to: 'users#index' がマッチした時に UsersController が探索できないような時です。(よく誤字とかで)

コントローラーをちゃんと定義できてないという趣旨のエラー文が何故
初期化されてない定数 コントローラー名 ってエラー文になるねん?という疑問は
先ほどのRubyのクラスは定数だということを知って納得できたのではないでしょうか?

とりあえず、Railsを利用している時もあちこちでオブジェクトが利用されているんだな! ということだけ知っていればひとまずOKです!

まとめ

Rubyのオブジェクトをこれまで紹介してきました。

ざっくりまとめると
Rubyはオブジェクトの世界で成り立っているんだなぁ〜。
「オブジェクトのメッセージングによるプログラミング手法」 がオブジェクト指向なんだなぁ〜。
ということです。

Rubyを通してまだまだ知れることがあります。
今回の話題に関するものとして、特に継承moduleについて調べてみると良いでしょう。
実際に手を動かして、実験して理解を深めましょう !!! ☕️( ˙౪˙)? (疲れたので一服)

参考

書籍 たのしいRuby
https://www.ruby-lang.org/ja/
https://docs.ruby-lang.org/ja/2.7.0/doc/index.html
https://railsguides.jp/
...etc

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails エラーメッセージを日本語化したいとき

私自身の備忘録のためにも記事を投稿してみたいと思います。

Railsでエラーメッセージを日本語化したい場合

言語設定の変更

まずはconfigのapplication.rbファイルを下記のように編集します。

config/application.rb
# 中略
module Pictweet
 class Application < Rails::Application
   # Initialize configuration defaults for originally generated Rails version.
   config.load_defaults 6.0

   # 日本語の言語設定
   config.i18n.default_locale = :ja
  # 省略
 end
end

Gemの導入

日本語に対応する'rails-i18n'というGemを導入します。

gemfile
gem 'rails-i18n'

上記を記述したらターミナルでbundle installを実行。

これで「〜を記入してください」などの日本語化はできていると思います。
ですが、カラム名などは日本語化できていなので、次はその設定をしていきます。

Localeファイルの作成

deviseを導入している場合

localeファイルに対応する日本語を記述していくことで日本語化しています。
deviseを使ってユーザー登録等を導入されている方は下記の方法が便利かもしれないです。

config/localesディレクトリに、devise.ja.ymlというファイルを作成します。

https://github.com/tigrish/devise-i18n/blob/master/rails/locales/ja.yml

上記URLに記載されている記述を全て作成したymlファイルにコピペしましょう。
これでユーザー登録関係の一部のカラム名の日本語化はできているはずです。

自分で設定したカラム名の日本語化

config/localesディレクトリに、ja.ymlというファイルを作成します。
作成したら例のように編集していきましょう。

config/locales/ja.yml
ja:
 activerecord:
   attributes:
     user:
       nickname: ニックネーム
     tweet:
       text: テキスト
       image: 画像

この例であれば、nicknameとtext,imageが日本語化されます。

これでエラーメッセージの日本語化はできると思います!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【アウトプット】 Guardの導入

Guardを使うと、ファイルが保存されたと同時にそのファイルのテストが行われるので、いちいちコマンドを打たなくてもよくなる。

導入

GemfileにGemfileの :test グループと :development グループguard-rspec を追加。

Gemfile
group :development, :test do
  gem 'guard-rspec', require: false
end

そして、bundle install。

それから、Guardfileを追加。

$ bundle exec guard init rspec

実行するには、次のコマンドを実行。

$ bundle exec guard

すると、guardが起動し、ファイルの監視が始まる。これを維持しておくと、ソースコードやテストコードを編集した時、RSpecが自動で実行される。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Nature Remo Local APIを用いて、LAN内のRailsアプリからNature Remoを操作する

概要

LAN内だけでNature Remoを操作できるRailsアプリケーションを作成しました。Nature Remo Local APIを利用しています。

あらかじめ家電のリモコンの赤外線信号をDBに保存しておくことで、Nature Remoのサーバとの通信がうまくできない場合でもNature Remoから赤外線信号を送信できます。ラズパイ等で起動しておけば非常時に活躍すると思います。

リポジトリ:chappy30313331/nature_remo_local

デモ

demo

環境

下記の環境で動作確認しています。

  • Nature Remo ファームウェア
    • Remo/1.0.79-gbbcb0e8
  • OS
    • Raspberry Pi 4:Raspbian 10.6
    • macOS:Mojave 10.14.6
  • PostgreSQL
    • Raspberry Pi 4:psql (PostgreSQL) 11.9 (Raspbian 11.9-0+deb10u1)
    • macOS:psql (PostgreSQL) 13.1
  • Ruby 2.6.6
  • Rails 6.0.3.4

※ Raspberry Pi 4でRuby 2.7系を利用してRails(5系or6系)を起動するとSegmentation Faultが発生したので2.6系を利用しています。

セットアップ

リファレンスに従ってNature Remoのホスト名もしくはIPアドレスを調べ、環境変数に設定しておきます。

$ export NATURE_REMO_HOST=192.168.XX.XX
# OR
$ export NATURE_REMO_HOST=Remo-XXXXXX.local
$ bundle install
$ bin/rails db:setup
$ bin/rails server

使い方

  • サーバを起動し、トップページにアクセス
  • 家電を追加
  • 家電にボタンを追加
    • リモコンをNature Remoに近づけて、追加したいボタンを押下し青く光ればOK
    • 「読込」ボタンをクリックすると、読み取った信号が「信号」欄に表示されるので、名前をつけて保存
  • 追加したボタンを家電の画面でクリックすると、Nature Remoから赤外線信号が送信されます

現状、Nature Remoのサーバ側に保存されている信号をエクスポートする機能はCloud APIにないようなので、一つ一つ追加していくことしかできないです。

実装

Nature Remoにリクエストして返ってきた信号を保存しておいて、ボタンを押したときにそのまま送信するだけです。簡易的な画面を作ってCRUDと送受信機能を実装してあります。

read_signal.rb
class ReadSignal
  include Service

  def call
    uri = URI::HTTP.build(host: ENV['NATURE_REMO_HOST'], path: '/messages')
    HTTP.timeout(10)
        .headers('X-Requested-With' => 'local')
        .get(uri)
  end
end
send_signal.rb
class SendSignal
  include Service

  def initialize(signal)
    @signal = signal
  end

  def call
    uri = URI::HTTP.build(host: ENV['NATURE_REMO_HOST'], path: '/messages')
    HTTP.timeout(10)
        .headers('X-Requested-With' => 'local')
        .post(uri, body: @signal)
  end
end

参考リンク

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsで起きた最初のエラー

こんばんは、ピチピチの社会人です。

本日はRailsで起きたエラーについてです。

問題

RailsでCRUD処理について学んでいる時、ルート、コントロール、ビューの順にコードを書き、rails sをした時に以下のエラー文が出ました。

スクリーンショット 2020-11-29 23.43.10.png
エラー表示怖すぎ、、とりあえずエラー文を読んでみる。
色々調べてみるとどうやらビューファイルに問題があるらしい。

routes.rb
Rails.application.routes.draw do

  get '/users/new', to: 'users#new'
  post '/users', to: 'users#create'
end

users_controller.rb
class UsersController < ApplicationController

  def new
    @user = User.new
  end

  def create
    User.create(user_params)
  end

  private
  def user_params
    params.require(:user).permit(:name, :age)
  end
end

new.html.erb
<p>新規投稿</p>
<%= form_with model: @user, url: "/users", method: :post, local: true do |f| %>
  <p>お名前:<%= f.text_field :name %></p>
  <p>年齢:<%= f.text_field :age %></p>
  <%= f.submit "送信" %>
<% end %>

どこも間違えてる気がしないんですけど、、

原因

いくら考えてもコードの間違いが見つからず、いくら調べてもわからない。
結局一から作成し直すと、先ほど作ったnew.html.erbがusersではなくlayoutsディレクトリに格納されていたことが判明。そりゃエラー出るわ。

対策

分からなかったら素直に人に聞くこと。今回も自分で解決しようとして一時間ほど時間を無駄にしてしまったからある程度自分で考えて、分からなければ恥を忍んで聞くこと。

以上、最近プログラミング学習を始めたピチピチの社会人でした。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

初心者がRailsサーバー立ち上げるための環境構築で苦戦した話

概要

progateの手順通りにすすめていくと、見事にハマって全然手順どおりに行かず。。。
ようやく「Yay! You're on Rails!」の画面を拝むことができたので、
環境構築で躓いた部分を備忘録として書き残します。初心者が環境構築で挫折してしまう気持ちがわかりました。。。

環境

・macOS Catalina ver10.15.7
・ruby ver2.7.2p137 (2020-10-01 revision 5445e04352) [x86_64-darwin19]
・rbenv ver1.1.2
・Rails ver6.0.3.4
・homebrew ver2.5.12
・yarn ver1.22.10
・nodebrew v8.9.4
・node.js v15.3.0

ハマったことろ

1.Homebrewインストール
2.rbenv / ruby-buildインストール
3.webpackerインストール
4.nodebrew / node / yarnインストール

1.HomeBrewインストール

以下のエラーでインストール失敗。

Error: RPC failed; curl 56 OpenSSL ssl_read: SSL_ERROR_SYSCALL

上記の文をコピペして検索すると、色々対策案が出てきます。(ネットの通信速度が原因?)
バッファを増やすことで改善するようですが、自分の場合は時間開けて、
再インストールしたらできました。

2.rbenv ruby-buildインストール

インストール自体は問題なしでしたが、「PATHを通す」作業で少しハマりました。
自分が使っているシェルによって少し手順が変わります。
ざっと調べた感じ、「bash」「zsh」の2択でしょうか。
ちなみに、macOSを 「Catalina」 にアップデートすると、
デフォルトシェルが bash から zsh になっているようです。
[ パスを通すとは? : https://qiita.com/soarflat/items/d5015bec37f8a8254380 ]

まず使っているシェルの確認のために以下のコマンドをターミナルに打ちこみます。

$ echo $SHELL

出力結果が/bin/zshの場合
以下のコマンド入力をして、PATHを通します。

$ echo 'eval "$(rbenv init -)"' >>  ~/.zshrc
$ source ~/.zshrc

何をしてるか簡単に説明すると、.zshrcというファイルに、
eval "$(rbenv init -)"という文言を追記しています。
source ~/.zshrcでファイルの更新をしているようなイメージです。

出力結果が/bin/bashの場合
以下のコマンド入力をして、PATHを通します。

$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
$ source ~/.bash_profile

つまりは、シェルによって、編集するファイルが異なるということですね。
ちなみに.zshrc(.bash_profile)っていうのは、
設定ファイルと言われているもので、.zshrc(bash_profile)だと、
ターミナル起動時に読み込まれるファイルになっています。このファイルに環境変数、
今回の場合だとPATHを登録しておくことで、登録したディレクトリ直下のスクリプトが、
絶対パスを指定しなくても実行できるようになります。
[ 参考先:https://web-nari.net/2019/01/12/bash-profile/ ]

残るはRubyとRuby on railsのインストールを実施。
Railsコマンドでアプリケーションの作成まではすんなりと行きましたが、
最後のRailsサーバー立ち上げで、webpackerが見つかりませんと言われて
インストール失敗。。。
どうもRails6でwebpackerが標準となり、
webpackerがインストールされてないとエラーが出るようです。
webpackerってなんだよ。。。

3.webpackerインストール

webpackerとはなんぞやというのは、こちらのページを参考にしました。

インストールは以下のコマンドで実行できます。

$ rails webpacker:install


、、、うまくいかずまたエラーです。第4項に続きます。

4.nodebrew / node / yarnインストール

今度はyarnnodeと言われるものをインストールしろといわれました。
node.js関連のものみたいです。こいつらのインストール方法を調査。
こちらに行き着いたんですが、自分はXcodeが入っていなかったので、
nodeのインストールはnodebrewでやることにしました。
ちなみにnodebrewは、node.jpのver管理ツールです。
nodebrewはhomebrewでインストールできるみたいです。(ややこしい、、、)
手順はこちらを参考にさせていただきました。

$ brew install nodebrew

次にセットアップして、PATHを通します。

$ nodebrew setup
$ echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.zshrc
$ source ~/.zshrc

※~/.zshrcの部分は環境に応じて変更してください。
いよいよnodeのインストールです。
インストールできるVerを確認して、Ver指定をしてインストールします。
自分はとりあえず最新Verをインストールしました。

$ nodebrew ls-remote
↑Ver確認
$ nodebrew install-binary v15.3.0
↑この場合はv15.3.0をインストール
$ nodebrew use v15.3.0
↑最後に使用するVerを指定するしておく必要があるらしい

お次はYarnです。
公式ではnode.jsベースのパッケージマネージャーからのインストールは非推奨みたいです。nodebrewもnode.jsベースと言うことになると思うので、
YarnはHomeBrewでインストールします。
[ Yarn公式:https://classic.yarnpkg.com/ja/docs/install#alternatives-stable ]

$ brew install yarn --ignore-dependencies

--ignore-dependenciesをつけると、yarnだけをインストールすることができます。
通常のインストールすると以下のパッケージがインストールされます。
・icu4c
・node
・yarn
nodebrewでnodeはインストールしているので、homebrewでもインストールしてしまうと、
依存関係のエラーになってしまうようです。

しかしこのままだとicu4cもインストールされていないので、インストールします。

$ brew install icu4c

ここまでくればwabpackerも問題なくインストールできると思い、
再度挑戦するも次はこんなエラーが発生。

Error: An exception occurred within a child process:
  RuntimeError: /usr/local/opt/node not present or broken
Please reinstall node. Sorry :(

入れたはずのnodeが見つからないと言っています。
/usr/local/opt/nodeのディレクトリにないと言っているので、
このディレクトリに、先ほど入れたnodeが存在するようにする必要があります。
手順は、
1.ディレクトリの作成
2.シンボリックリンクの設定
になります。
[ 手順はこちらを参考させていただきました。 ]

1.ディレクトリの作成

$ mkdir /usr/local/opt/node

2.シンボリックリンクの設定
/usr/local/opt/nodeにアクセスすると、
nodebrewで入れたnodeが存在するディレクトリへリンクするように設定します。

$ ln -s ~/.nodebrew/current/ /usr/local/opt/node/

そして再度、

$ rails webpacker:install


以下の表示がでて成功です。

Webpacker successfully installed ? ?

この状態で再度rails sを実行すると、、、

スクリーンショット 2020-11-29 23.38.34.png

無事成功です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む