20200125のRailsに関する記事は20件です。

【Rails】Qiita 週間いいね数ランキング【タグ別】

他のタグ

集計期間

01月18日 ~ 01月25日

いいね数ランキング

1位: WEBエンジニアへの転職を目指す外資系新卒が、8週間の学習過程を晒してみる

JavaScript Rails 転職 React 未経験エンジニア
12いいね
@Ryo__Mさん(01月20日 07時55分の投稿)

2位: Rails 6ではsend_data/send_fileメソッド呼び出し時にERB::Util.url_encodeは不要です

Ruby Rails
9いいね
@jnchitoさん(01月20日 23時32分の投稿)

3位: devise ユーザーのプロフィール画面作成と編集(デフォルトをカスタマイズ)

Ruby Rails devise Gem 初心者
5いいね
@akr03xxxさん(01月20日 14時01分の投稿)

4位: 【翻訳】URI.escapeは非推奨メソッドです。あなたのクエリ文字列をパーセントエンコードするには

Ruby Rails
3いいね
@jnchitoさん(01月25日 03時32分の投稿)

5位: Rails Javascript/Html: 投稿編集画面で写真の表示を確認したい!

JavaScript Rails HTML5
2いいね
@kokeshi1357さん(01月24日 11時45分の投稿)

6位: Railsで作成した1対1のメッセージ機能をコードリーディング

Rails アソシエーション
2いいね
@3rudenさん(01月22日 05時47分の投稿)

7位: 【Rails×Ajax】いいね機能の実装で上手く出来ないあなたへの2つの注意喚起 #学習者向け

Ruby JavaScript Rails エラー対処
2いいね
@shoji621さん(01月20日 03時03分の投稿)

8位: configure IIS with ruby on rails app on windows server

Ruby Rails Windows deploy Deployment
2いいね
@alokrawat050さん(01月19日 12時51分の投稿)

9位: ページ遷移先でリロードしないと非同期通信(ajax)できない

Ruby JavaScript Rails
2いいね
@avicii2314さん(01月19日 05時18分の投稿)

10位: https(SSL)通信の環境下でjavascriptが動かなくなる場合の原因と解決方法 ( 本番環境(AWS)でjavascriptを読み込む方法 )

Ruby JavaScript Rails
2いいね
@avicii2314さん(01月19日 04時17分の投稿)

11位: 【jQuery】RailsでValidation Pluginを使った動的なバリデーションチェックの実装 〜詳細実装/Bootstrap編〜

Ruby Rails jQuery Bootstrap Validation
1いいね
@tiphp452さん(01月25日 01時24分の投稿)

12位: Railsアプリ起動時に突然「Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)」になった時の対処法

Rails MySQL
1いいね
@President_Takaさん(01月25日 01時04分の投稿)

13位: Railsの思想

Rails
1いいね
@china55さん(01月24日 11時26分の投稿)

14位: メモ:ActionMailerのログにメールアドレスが出ないようにする

Rails ActionMailer
1いいね
@shouta-devさん(01月24日 04時50分の投稿)

15位: Rspecと Factoryの使い方

Ruby Rails RSpec FactoryGirl
1いいね
@gototakumaさん(01月23日 14時47分の投稿)

16位: 【Rails】 Heroku, Aws で詰まったときに見る記事まとめ

Rails Heroku AWS
1いいね
@wafuwafu13さん(01月23日 03時07分の投稿)

17位: rakeタスクに引数を渡したいとき

Ruby Rails rake
1いいね
@kaobabaさん(01月23日 02時10分の投稿)

18位: [Ruby on Rails]データベースの作成、カラムの追加

Ruby Rails
1いいね
@sansiroさん(01月22日 10時19分の投稿)

19位: 自動デプロイ(Capistrano)でエラー mkdir: ディレクトリ `/var/www' を作成できません: 許可がありません

Ruby Rails Capistrano AWS Rails5
1いいね
@nousiさん(01月21日 15時21分の投稿)

20位: CodeCommit + CodeDeploy + CodePipelineでEC2にデプロイ~CodeDeployの設定~

Rails AWS CodeDeploy CodeCommit CodePipeline
1いいね
@k_senbeiさん(01月21日 11時19分の投稿)

21位: create_or_find_by はユニーク制約が定義されたテーブルで効いてくる

Rails Rails6
1いいね
@ryosuke_satoさん(01月21日 10時00分の投稿)

22位: 【Rails】enumを使用したセレクトボックスの実装とDBへの保存

Ruby Rails
1いいね
@y-sunaさん(01月21日 08時11分の投稿)

23位: Rails 6+Grapeで作るAPIサーバーにDeviseトークン認証を付ける

Ruby Rails devise grape devise_token_auth
1いいね
@shimizu-nowhereさん(01月21日 07時50分の投稿)

24位: 【Rails】ActiveRecordで関連テーブルのカラムでwhereまたは、orderする【ActiveRecord】

Rails ActiveRecord
1いいね
@yutaroadachiさん(01月21日 06時12分の投稿)

25位: Cloud9でRails 6.0のSeleniumとGoogle Chromeを使える設定しましょう!

Rails Chrome Selenium cloud9 Rails6
1いいね
@pineappledreamsさん(01月21日 02時33分の投稿)

26位: Rails6 アプリからメールを送信する デプロイ環境編

Rails Mac 初心者 初心者向け Rails6
1いいね
@miriwoさん(01月20日 16時53分の投稿)

27位: 【Rails】Strong Parametersの書き方について

Rails
1いいね
@ktganaoさん(01月20日 13時48分の投稿)

28位: railsにおける get と post の違い

Rails
1いいね
@sakana_fishさん(01月20日 12時21分の投稿)

29位: エンジニアのポートフォリオを作ってみた

CSS JavaScript Rails HTML5 jQuery
1いいね
@ssstttさん(01月19日 13時06分の投稿)

30位: high_voltageで利用規約等の静的ページを作る

Ruby Rails 静的ページ 初学者向け high_voltage
1いいね
@royroyさん(01月19日 08時46分の投稿)

31位: RailsにおけるAjaxの実装(JavaScriptとjQueryのコード比較)

Ruby JavaScript Rails jQuery Ajax
1いいね
@t-yama-3さん(01月19日 08時19分の投稿)

32位: Hamlでのlink toの書き方【Rails】

Rails haml
1いいね
@Pirori3182さん(01月19日 06時26分の投稿)

33位: 【Rails】ActionMailer + AWS SES

Ruby Rails AWS ses ActionMailer
1いいね
@syukan3さん(01月19日 05時50分の投稿)

34位: Railsチュートリアル 第13章 ユーザーのマイクロポスト - 本番環境での画像アップロード

Rails Heroku AWS 初心者 Railsチュートリアル
1いいね
@rapidliner00さん(01月19日 05時49分の投稿)

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

【Rails】Qiita 週間いいね数ランキング【自動更新】

他のタグ

集計期間

01月19日 ~ 01月26日

いいね数ランキング

1位: 【翻訳】URI.escapeは非推奨メソッドです。あなたのクエリ文字列をパーセントエンコードするには

Ruby Rails
17いいね
@jnchitoさん(01月25日 12時32分の投稿)

2位: WEBエンジニアへの転職を目指す外資系新卒が、8週間の学習過程を晒してみる

JavaScript Rails 転職 React 未経験エンジニア
12いいね
@Ryo__Mさん(01月20日 16時55分の投稿)

3位: Rails 6ではsend_data/send_fileメソッド呼び出し時にERB::Util.url_encodeは不要です

Ruby Rails
9いいね
@jnchitoさん(01月21日 08時32分の投稿)

4位: devise ユーザーのプロフィール画面作成と編集(デフォルトをカスタマイズ)

Ruby Rails devise Gem 初心者
6いいね
@akr03xxxさん(01月20日 23時01分の投稿)

5位: 【jQuery】RailsでValidation Pluginを使った動的なバリデーションチェックの実装 〜詳細実装/Bootstrap編〜

Ruby Rails jQuery Bootstrap Validation
2いいね
@tiphp452さん(01月25日 10時24分の投稿)

6位: Rails Javascript/Html: 投稿編集画面で写真の表示を確認したい!

JavaScript Rails HTML5
2いいね
@kokeshi1357さん(01月24日 20時45分の投稿)

7位: Railsで作成した1対1のメッセージ機能をコードリーディング

Rails アソシエーション
2いいね
@3rudenさん(01月22日 14時47分の投稿)

8位: 【Rails×Ajax】いいね機能の実装で上手く出来ないあなたへの2つの注意喚起 #学習者向け

Ruby JavaScript Rails エラー対処
2いいね
@shoji621さん(01月20日 12時03分の投稿)

9位: 【Rails】Qiita 週間いいね数ランキング【自動更新】

Rails
1いいね
@kou_pg_0131さん(01月25日 23時17分の投稿)

10位: Railsアプリ起動時に突然「Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)」になった時の対処法

Rails MySQL
1いいね
@President_Takaさん(01月25日 10時04分の投稿)

11位: Railsの思想

Rails
1いいね
@china55さん(01月24日 20時26分の投稿)

12位: メモ:ActionMailerのログにメールアドレスが出ないようにする

Rails ActionMailer
1いいね
@shouta-devさん(01月24日 13時50分の投稿)

13位: Rspecと Factoryの使い方

Ruby Rails RSpec FactoryGirl
1いいね
@gototakumaさん(01月23日 23時47分の投稿)

14位: 【Ruby】mapメソッドのつかいかた(+別メソッドとの組み合わせの例など)

Ruby Rails
1いいね
@4EAE_Learnerさん(01月23日 20時11分の投稿)

15位: 【Rails】 Heroku, Aws で詰まったときに見る記事まとめ

Rails Heroku AWS
1いいね
@wafuwafu13さん(01月23日 12時07分の投稿)

16位: rakeタスクに引数を渡したいとき

Ruby Rails rake
1いいね
@kaobabaさん(01月23日 11時10分の投稿)

17位: [Ruby on Rails]データベースの作成、カラムの追加

Ruby Rails
1いいね
@sansiroさん(01月22日 19時19分の投稿)

18位: 自動デプロイ(Capistrano)でエラー mkdir: ディレクトリ `/var/www' を作成できません: 許可がありません

Ruby Rails Capistrano AWS Rails5
1いいね
@nousiさん(01月22日 00時21分の投稿)

19位: CodeCommit + CodeDeploy + CodePipelineでEC2にデプロイ~CodeDeployの設定~

Rails AWS CodeDeploy CodeCommit CodePipeline
1いいね
@k_senbeiさん(01月21日 20時19分の投稿)

20位: create_or_find_by はユニーク制約が定義されたテーブルで効いてくる

Rails Rails6
1いいね
@ryosuke_satoさん(01月21日 19時00分の投稿)

21位: 【Rails】enumを使用したセレクトボックスの実装とDBへの保存

Ruby Rails
1いいね
@y-sunaさん(01月21日 17時11分の投稿)

22位: Rails 6+Grapeで作るAPIサーバーにDeviseトークン認証を付ける

Ruby Rails devise grape devise_token_auth
1いいね
@shimizu-nowhereさん(01月21日 16時50分の投稿)

23位: 【Rails】ActiveRecordで関連テーブルのカラムでwhereまたは、orderする【ActiveRecord】

Rails ActiveRecord
1いいね
@yutaroadachiさん(01月21日 15時12分の投稿)

24位: Cloud9でRails 6.0のSeleniumとGoogle Chromeを使える設定しましょう!

Rails Chrome Selenium cloud9 Rails6
1いいね
@pineappledreamsさん(01月21日 11時33分の投稿)

25位: Rails6 アプリからメールを送信する デプロイ環境編

Rails Mac 初心者 初心者向け Rails6
1いいね
@miriwoさん(01月21日 01時53分の投稿)

26位: 【Rails】Strong Parametersの書き方について

Rails
1いいね
@ktganaoさん(01月20日 22時48分の投稿)

27位: railsにおける get と post の違い

Rails
1いいね
@sakana_fishさん(01月20日 21時21分の投稿)

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

【gon】jsでRails変数を取得する

Railsでjsライブラリを使うときに楽にRailsで定義した変数をJavaScriptに渡したい!楽したい!

プログラマ三大美徳

1.怠慢(Laziness)
2.短気(Impatience)
3.傲慢(Hubris)

まさにこれですね。

何を使うか?

RailsといえばGemですね。[gon]というgemです。
https://github.com/gazay/gon

インストール

Gemfileに記載

Gemfile
gem 'gon'

ターミナルからインストール

ターミナル
bundle install

読み込み設定

application.html.erb
<%= include_gon %>
<%= javascript_include_tag "application" %>

使ってみる

****.controller.rb
gon.user_name = 'my name is imaizumi'
****.js
console.log(gon.user_name)

スクリーンショット 2020-01-25 21.11.28.png

バッチリ変数を渡せました:yum:

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

Rails new とは

Rails new とは 

Railsを使用する際の型を作成するもの

rails new アプリケーション名 

で呼び出す。

rails new sample

rails new sample_app
など

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

Docker-composeでbundle installしてるのにgemの内容反映されないんですけど

注意事項

完全に個人用メモです。公式情報でもなんでもありません。ググってこの記事に来てしまった方はお気をつけください。違っていたら即直しますのでガンガンご指摘ください。(個人用メモなので追加もしていきます)

そもそもbundle installしたらサーバー再起動しろや

なので、gemfile編集してbundle installしたら以下のコマンド打てば良い(環境によるけど)

docker-compose restart・・・コンテナ再起動

そしたらGemの内容が反映されます。

docker勉強不足だって、はっきりわかんだね。

イメージをビルドしなおしたりコンテナ削除したりしなくて良い

dockerを理解してないと以下のようなコマンドを打ち始めます

docker-compose build・・・イメージビルド

docker-compose up -d・・・コンテナ作成&起動

結果、コンテナが増えまくるわけです。(えぇ。。。)

コンテナやたら多いと思ったら原因これかよw(錯乱)

まあこの方法でも解決できるんですけどね。。

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

ActiveRecord::StatementInvalid: Mysql2::Error: Duplicate column name '_id': ALTER TABLE `` ADD `_id` bigint

カラムの追加の後にrails db:migrate 

をした際にタイトルのエラーがMysqlにて出て苦戦したので、同じような方がいるかもなのでメモとして残します。

まず最初に結論からです。エラーの原因は、migrateした際

rails db:migrate:status
up 20200123145035 Create users
up 20200123150804 Create
up 20200124043414 Create
down 20200125060439 Create
down 20200125064510 Create

*downと書かれているファイルならupされてないので問題ないと作り直す為に、削除して作り直した事が原因で
起こりました。downのままですが、追加しようとしたカラムが一部だけ追加されていた事による重複です。

初心者さんで同じような事になる方もいると思いますので、その際しっかりとロールバックまたは、データベースを削除したかのご確認をしてみてください。

直し方

そして直した方法ですが・・・
rails db:drop
をしてデータベースを再作成する事でup済みのものに追加してしまいマイグレーションファイルが削除されなくなってしまったものをなかった事にしました。

rails db:create

raild db:migrate

これで、 rails g AddxxxRefToテーブル名 カラム名: で追加し直し。
正常に戻りました。今回は、作りたてだったので問題なかったですが、デプロイ済みの場合などはユーザーデータが消えたりして大変な事になりますので、お気をつけください。

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

Docker + rails + mysqlで開発環境を構築

はじめに

今回は、railsの開発環境をDocker+rails+mysqlで用意します。

構成

構成はローカルのMacにDockerを立て、webとdbコンテナをdocker-composeで管理します。

スクリーンショット 2020-01-25 10.06.34.png

開発環境

Docker 19.03.5
Ruby 2.6.5
Rails 5.2.4
MySQL 5.7.29

前提条件

Macを利用

Docker Desktopをインストール

まずは、ローカルのMacにDocker Desktopをインストールします。

https://www.docker.com/get-started

スクリーンショット 2020-01-22 0.09.31.png

「Download Desktop and Take a Tutorial」のボタンをクリックすると画面が遷移し、
アカウントがある人はログイン、ない人は「Sign Up」を押してアカウントを作成します。

スクリーンショット 2020-01-22 0.14.29.png

アカウント作成後、ログインし 「Get started with Docker Desktop」を押すと画面が遷移するので「Download Docker Desktop for Mac」を押しダウンロードします。

スクリーンショット 2020-01-22 0.16.16.png

ダウンロード完了後、インストールします。
install後、Macのターミナルにてdocker versionと打ち、バージョンが出れば無事インストールは完了です。

$ docker version
Client: Docker Engine - Community
 Version:           19.03.5
 API version:       1.40
 Go version:        go1.12.12
 Git commit:        633a0ea
 Built:             Wed Nov 13 07:22:34 2019
 OS/Arch:           darwin/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.5
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.12.12
  Git commit:       633a0ea
  Built:            Wed Nov 13 07:29:19 2019
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          v1.2.10
  GitCommit:        b34a5c8af56e510852c35414db4c1f4fa6172339
 runc:
  Version:          1.0.0-rc8+dev
  GitCommit:        3e425f80a8c931f88e6d94a8c831b9d5aa481657
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683

web(rails)コンテナの構築

開発を行うために任意の作業ディレクトリを作成します。

$ mkdir task_app/
$ cd task_app 

Gemfileの準備

オプションでディレクトリのマウントを指定していることで、Docker環境で作成されたGemfileがローカル環境に作成されます。

$ docker run --rm -v `pwd`:/task_app -w /task_app ruby:2.6 bundle init
Unable to find image 'ruby:2.6' locally
2.6: Pulling from library/ruby
8f0fdd3eaac0: Pull complete 
d918eaefd9de: Pull complete 
43bf3e3107f5: Pull complete 
27622921edb2: Pull complete 
dcfa0aa1ae2c: Pull complete 
0e1f1dc37f65: Pull complete 
c76a82442849: Pull complete 
5161fd3df3c4: Pull complete 
Digest: sha256:f38fce2b70ba23e90d6397995bea8419b86dd3f20b73846681adb52c63c0b002
Status: Downloaded newer image for ruby:2.6
Writing new Gemfile to /task_app/Gemfile      

Gemfileがローカルに作成されますので、railsのバージョンを指定します。
利用したいバージョンに合わせて適宜修正してください。

$ vi Gemfile

# gem "rails"
gem 'rails', '~> 5.2.3'

Dockerイメージの作成

rails環境のDockerイメージを作成します。

Dockerfileの作成 → ビルド → Dockerイメージ(task_app)

※Dockerfileはないので新規作成します。

$ vi Dockerfile

FROM ruby:2.6
WORKDIR /task_app
COPY Gemfile /task_app/Gemfile
RUN bundle install

$ docker build -t task_app .

Sending build context to Docker daemon  3.072kB
Step 1/4 : FROM ruby:2.6
 ---> a161c3e3dda8
Step 2/4 : WORKDIR /task_app
 ---> Running in a6b5dec7f0ed
Removing intermediate container a6b5dec7f0ed
 ---> 16367607e3e5
Step 3/4 : COPY Gemfile /task_app/Gemfile
 ---> 99de34366eef
Step 4/4 : RUN bundle install
 ---> Running in 8839dbf87256
Fetching gem metadata from https://rubygems.org/.............
Fetching gem metadata from https://rubygems.org/.
Resolving dependencies...
Fetching rake 13.0.1
Fetching rails 5.2.4.1
Installing rails 5.2.4.1
Bundle complete! 1 Gemfile dependency, 41 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
Post-install message from i18n:

HEADS UP! i18n 1.1 changed fallbacks to exclude default locale.
But that may break your application.

If you are upgrading your Rails application from an older version of Rails:
Please check your Rails app for 'config.i18n.fallbacks = true'.
If you're using I18n (>= 1.1.0) and Rails (< 5.2.2), this should be
'config.i18n.fallbacks = [I18n.default_locale]'.
If not, fallbacks will be broken in your app by I18n 1.1.x.
If you are starting a NEW Rails application, you can ignore this notice.

For more info see:
https://github.com/svenfuchs/i18n/releases/tag/v1.1.0

Removing intermediate container 8839dbf87256
 ---> 89e179509cba
Successfully built 89e179509cba
Successfully tagged task_app:latest

$ docker images

REPOSITORY          TAG                 IMAGE ID            CREATED              SIZE
task_app            latest              89e179509cba        About a minute ago   926MB

作成されてますね。

Railsアプリの作成

作成したDockerイメージ(task_app)を利用してrails newを実行し、Railsアプリを作成します。

$ docker run --rm -v `pwd`:/task_app task_app rails new . -B --database=mysql

       exist  
      create  README.md
      create  Rakefile
      create  .ruby-version
      create  config.ru
      create  .gitignore
    conflict  Gemfile
Overwrite /task_app/Gemfile? (enter "h" for help) [Ynaqdhm] 
       force  Gemfile
         run  git init from "."
Initialized empty Git repository in /task_app/.git/
      create  package.json
      create  app
      create  app/assets/config/manifest.js
      create  app/assets/javascripts/application.js
      create  app/assets/javascripts/cable.js
      create  app/assets/stylesheets/application.css
      create  app/channels/application_cable/channel.rb
      create  tmp/storage
      create  tmp/storage/.keep
      remove  config/initializers/cors.rb
      remove  config/initializers/new_framework_defaults_5_2.rb

Railsからデータベースへ接続するためのdatabase.ymlファイルが作成されますので修正します。

$ vi config/database.yml 

default: &default
  adapter: mysql2
  encoding: utf8
  pool: 
  username: root
  password: xxxxxxx #追加: MysqlのMYSQL_ROOT_PASSWORDと同じ値
  host: db  #追加: MySQLのコンテナ名と同じ値。この後構築します。

docker-compose.ymlにwebコンテナを追加します。

Railsが起動するDockerイメージを作成します。

$ vi Dockerfile 

FROM ruby:2.6
RUN apt-get update -qq && apt-get install -y nodejs #追加
WORKDIR /task_app
COPY Gemfile /task_app/Gemfile
RUN bundle install
CMD ["rails", "server", "-b", "0.0.0.0"] #追加

RailsアプリはDocker Composeを利用して起動させます。
docker-compose.ymlを作成し、webコンテナの起動設定をdocker-compose.ymlに記載します。

# vi docker-compose.yml

version: '3'
services:
  web:
    build: .
    ports:
      - '3000:3000'
    volumes:
      - .:/task_app

コンテナを停止するとmysqlのデータが消えてしまうため、データ永続化のため、volumesを入れています。

Dockerfileを編集したのでdocker-composeコマンドでDockerイメージをビルドします。

$ docker-compose build
Building web
Step 1/6 : FROM ruby:2.6
 ---> a161c3e3dda8
Step 2/6 : RUN apt-get update -qq && apt-get install -y nodejs
 ---> Running in c287be3cb98f
Reading package lists...
Building dependency tree...
Reading state information...
The following additional packages will be installed:
  libc-ares2 libnode64 libuv1 nodejs-doc
Suggested packages:
  npm
The following NEW packages will be installed:
  libc-ares2 libnode64 libuv1 nodejs nodejs-doc
0 upgraded, 5 newly installed, 0 to remove and 0 not upgraded.
Need to get 6753 kB of archives.
After this operation, 30.4 MB of additional disk space will be used.

* For more details, please refer to the Sass blog:
  https://sass-lang.com/blog/posts/7828841

Removing intermediate container 711351e6bba5
 ---> 5486636e708a
Step 6/6 : CMD ["rails", "server", "-b", "0.0.0.0"]
 ---> Running in 82d851651892
Removing intermediate container 82d851651892
 ---> a895f6cec871
Successfully built a895f6cec871
Successfully tagged task_app_web:latest

$ docker images

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

task_app_web        latest              a895f6cec871        8 minutes ago       1.02GB
task_app            latest              89e179509cba        About an hour ago   926MB

ここまででweb(rails)コンテナの構築が完了です。

db(mysql)コンテナの構築

depends_onにdbコンテナを追加します。
※depends_onはwebとDBコンテナの作成順序と依存関係を定義します。

# vi docker-compose.yml

version: '3'
services:
  web:
    build: .
    ports:
      - '3000:3000'
    volumes:
      - .:/task_app
    depends_on: #追加
      - db  #追加
  db:  #追加
    image: mysql:5.7  #追加
    volumes:  #追加
      - ./mysql:/var/lib/mysql  #追加
    environment:  #追加
      MYSQL_ROOT_PASSWORD: 'xxxxx'  #追加: Railsのpasswordと同じ値

一旦、Dockerコンテナを起動します。

$ docker-compose up

ただし、dbコンテナはありますがRuby on Railsで利用するデータベースがないので作成します。

$ docker-compose exec web rake db:create
Created database 'task_app_development'
Created database 'task_app_test'

$ docker-compose exec db mysql -uroot -pxxxxx

mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.

Your MySQL connection id is 7

Server version: 5.7.29 MySQL Community Server (GPL)
Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+----------------------+
| Database             |
+----------------------+
| information_schema   |
| mysql                |
| performance_schema   |
| sys                  |
| task_app_development | ← 作成
| task_app_test        |
+----------------------+
6 rows in set (0.00 sec)
mysql>

データベースも作成できましたので、db(mysql)コンテナの準備も完了です。

ブラウザでアクセス

http://localhost:3000/ でアクセスして確認します。

スクリーンショット 2020-01-19 23.09.22.png

見慣れた画面が出ましたね!

まとめ

Docker環境で簡単にrailsの開発環境が用意できました!

ちなみにDockerのキャラクターは、Moby(モビー)って言うらしいです。

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

メタプログラミング Ruby memo #1

概要

現在Rubyを勉強しており、「Rubyを勉強するならメタプログラミングRubyは必読!」という先輩からの教えがあり、読んでいるのでそれのまとめメモです。

筆者のRubyに関してのスキルは「プロになるためのRuby」を読んでRailsチュートリアルをさらっとくらいのレベルです。
お見知り置きいただければと。。。

今回はまずメタプログラミングに関してまとめようと思います。

個人的レベル感

「上級者向け過ぎてわからないことも多いだろうなあ」とびびっていたのですが案外わかりやすく、ひとつひとつコードを書きながら進めていくと理解が進むような造りになっていると感じました。

翻訳書なので、表現の仕方が基本的に海外よりなので、そこに関して苦手な人は読みづらいかもです...

何かあるごとに開く本というのが誰しもあると思うのですが、個人的にはこの本はそこにランクインするレベルだと思います。

そもそもメタプログラミングって何?(広い意味での)

  • ロジックを直接コーディングするのではなく、あるパターンをもったロジックを生成する高位ロジックによってプログラミングを行う方法、またその高位ロジックを定義する方法のこと( wikipedia)
  • 他のプログラム ( あるいは自身 ) を操作したり出力するプログラムを書くこと、または作業の一部をコンパイル時に行い、残りの作業を実行時に行うようなプログラムを書くことである。
  • コードジェネレータやコンパイラが行うコード生成のこと。

Rubyは「動的メタプログラミング」

  • Rubyに関して言えば、「コードを生成するためのコードを書くこと」が簡単にできてしまう。 (本書の言葉を借りれば「シームレスかつエレガントに」)
  • 「魔法」や「黒魔術」と呼ばれるくらい、簡潔にコードが書ける。
  • 大いなる力には、大いなる責任が伴うことを忘れてはいけない」 by Matz

言語要素を実行時に操作するコードを記述すること

コードジェネレータやコンパイラが行うコード生成のことも、「広い意味でのメタプログラミング」と言えるのだが、Rubyはこの定義には含まれない。
これを「静的メタプログラミング」と呼ぶならば、Rubyは「動的メタプログラミング」と呼べる

メタプログラミングに利用されている技術の例

実際に本書で使われている技術の一例を紹介しようと思います。
※ もっと沢山あります。

既存のクラスの振る舞いを変更する(モンキーパッチ)

mokey_patch.rb
"abc".reverse # => "cba"

class String
  def reverse
    "オーバーライド"
  end
end

"abc".reverse # => "オーバーライド"

1. 再定義したメソッドから以前のメソッドをエイリアスで呼び出す

around_arias.rb
# String#reverseに新たな機能を追加する
"abc".reverse # => "cba"

class String
  alias_method :old_reverse, :reverse

  def reverse
    "hoge#{old_reverse}hoge"
  end
end

"abc".reverse # => "hogecbahoge"

2. 該当するメソッドのないメッセージに応答する

method_missing.rb
class Hoge; end

hoge = Hoge.new
hoge.no_define_method
# => NoMethodError (undefined method `no_define_method' for #<Hoge:0x00007f9649836be8>)


# BasicObject#method_missingを書き換える(noMethodErrorを返しているメソッド)
class Hoge
  def method_missing(name, *args)
    name.to_s.reverse
  end
end

hogehoge = Hoge.new
hogehoge.no_define_method
# => "hogedohtem_enifed_onhoge"

動的メソッド

dynamic_method.rb
class C; end

C.class_eval do
  define_method :my_method do
    "動的メソッド"
  end
end

obj = C.new
obj.my_method
# => "動的メソッド"

ざっくりまとめると

  • 上記のようなRubyの技術を駆使してコードのリファクタなどを例を用いてわかりやすく説明してくれています。
  • ActiveRecordなどのRailsのコードもどのようなスキルを駆使して書かれているか説明してくれているので、難しいコードを読んだことない人にとってはとっつきやすいかもしれません。
  • 本書の最後のほうでも言っているのですが、メタプログラミングがどうとか考えずにただのプログラミングだと思えという言葉がなぜかしっくりきました。 (自分のバイアスがかかっていただけかも?)
  • Rubyの「特徴」を事細かに説明してくれている良書だと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】Railsとdeviseのデフォルトバリデーションを解除する方法

はじめに

知人がemailの正規表現を使ったバリデーションを自ら作成して設定しようとした際、うまく設定を反映させられませんでした
いろいろ調べたところRailsのバリデーションやらdeviseのバリデーションやらが絡んでいたためでした
今まで知らないで使ってたことなど勉強になったことが多かったので整理してまとめておきます

対象読者

  • form_withやform_forが何かをなんとなく理解している人
  • バリデーションが何かをなんとなく理解してる人

環境

  • Ruby: 2.5.1
  • Rails: 5.2.3

状況

  • 正規表現で~@~.~という形じゃないとアドレスとして登録できないようなカスタムバリデーションを作成した
  • そのバリデーションを有効にしたが、下記の画像のような謎のバリデーションにひっかかった

スクリーンショット 2020-01-25 12.30.17.png

自分で作ったカスタムバリデーションじゃないのがでてきた。。。ってなったんですが
結論、Railsのバリデーションとdeviseのバリデーションを解除してやれば、目的通り自作のカスタムバリデーションのみ反映させられました

以下に、やり方と解説を記載します

Railsのバリデーション設定

Railsでメールアドレスやパスワードをユーザーに入力させるとき、入力フォームを作成するためにform_forやform_withを使いますよね。こんな感じで

new.html.haml
= form_with(model: @user, local: true, class: 'hoge') do |form|
  = form.label :email, 'メールアドレス'
  = form.email_field :email

ここで記載したemail_fieldがさっきのバリデーションの正体です
このように記載することでRailsはこの入力フォームをemailだと認識して、簡単なバリデーションを自動でかけるようになっているみたいです

なので先ほどの記載を以下のように書き換えるとRails側でバリデーションをかけないようにできます

new.html.haml
#変更前
= form.email_field :email

#変更後
= form.text_field :email



結果がこちら
スクリーンショット 2020-01-25 13.03.13.png

先ほどのバリデーションは消えましたが、フラッシュメッセージにバリデーションが2つ出てきてしまいました

deviseのバリデーション設定

今のままだとバリデーションが2つ出てきてしまいます。先ほどの画像の左側がdeviseのバリデーション、右側が自分で設定したカスタムバリデーションです
今回は自分が設定したカスタムバリデーションだけ表示させたいので、deviseのバリデーション設定を解除します

通常、deviseをインストールした場合、モデル内に下記のような記述があると思います

models/user.rb
devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

この:validatableがdeviseのバリデーションなので、この記述を消します

models/user.rb
devise :database_authenticatable, :registerable,
         :recoverable, :rememberable

これでdeviseのデフォルトのバリデーションも解除できました


結果はこちら
スクリーンショット 2020-01-25 13.05.12.png

ちゃんと自分で設定したバリデーションだけが適用されていますね
*カスタムバリデーションの作成の仕方は最後の参考URLに載せておきます

まとめ

  • Railsのemail_fieldではメールアドレス用の簡単なバリデーションをかける仕様になっている
  • deviseではデフォルトで簡単なバリデーションをかけるようになっている
  • バリデーションの優先順位はemail_field > devise, カスタム(自作)
  • カスタムバリデーションのみ適用させる場合は、text_fieldを使い、deviseの:validatableを削除する

Railsもdeviseも知らないところで色々と機能してくれてますが、少しずつそういう部分を理解していくことで、色々応用できそうですね
特にdeviseは便利ですが、意味を理解していないで使っている部分が多いと思ったので今回のようなケースはかなり勉強になりました

余談ですが、password_fieldは入力した文字を"●"で秘匿化してくれてます

間違いなどがあれば指摘していただけると助かります
少しでも参考になった、勉強になったという方がいらっしゃれば幸いです

参考URL

自作のカスタムバリデーションを作成する方法
- https://guides.rubyonrails.org/active_record_validations.html
- https://qiita.com/kouheiszk/items/215afa01eeaadbd99340

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

devise 導入直後のエラー(docker)

概要

[Rails] deviseの使い方(rails4版)
このサイト↑に沿ってdevise導入し、そこでこのエラーが発生しました。
その対処法を記載をしています。

エラーの内容

スクリーンショット 2019-12-26 23.25.40.png

ルーティングエラー
Rails routes で調べても特に問題なさそう・・
Rails: deviseをインストールした後のエラー
これ↑を実装したが、エラー治らず・・・

対処法

問題は恐らくdockerなのでは?となり、とりあえず
docker再起動→ローカルを再起動

docker再起動方法
右上にあるクジラを押す→restart 完了!!
スクリーンショット 2020-01-25 14.21.04.png

それでもう一度localhostをリロードすると治りました。
お疲れさまでした!!

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

【rails】SystemSpec(capybara) on dockerでつまずいた時のメモ

Capyabaraの設定方法

https://qiita.com/ngron/items/f61b8635b4d67f666d75
上の記事をもとに設定

解決したかったこと

Selenium::WebDriver::Error::UnknownErrorを解決して、systemtestを行う

失敗例

Gemfile.
group :test do
  gem 'capybara', '>= 2.15'
  gem 'selenium-webdriver'
end

成功例

Gemfile.
group :test do
  gem 'capybara'
  gem 'selenium-webdriver'
end

行ったこと

1、gem(capybara、selenium-webdriver)のバージョン固定を外す。
gemのバージョンを固定しているといつまでたってもエラー(Selenium::WebDriver::Error::UnknownError)が解決できない。
2、docker-compose build

参考記事

Rails + Selenium + DockerでSystemSpecの環境構築
https://qiita.com/ngron/items/f61b8635b4d67f666d75

ありがとうございます!!

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

【翻訳】URI.escapeは非推奨メソッドです。あなたのクエリ文字列をパーセントエンコードするには

この記事は以下のブログ記事の日本語訳です。

URI.escape is obsolete. Percent-encoding your query string

【翻訳】URI.escapeは非推奨メソッドです。あなたのクエリ文字列をパーセントエンコードするには

みなさんはRuby 2.7.0を使っているプロジェクトで以下の警告に遭遇しましたか?

warning: URI.escape is obsolete
warning: URI.encode is obsolete

この警告の直し方を見ていきましょう!

歴史について少しだけ

Ruby 2.7.0ではURI.escapeまたはエイリアスメソッドのURI.encodeを呼びだしたときに警告が出ます。これはあたかも新しく追加された警告のように見えますが、実際はなんと・・・10年以上も非推奨とされ続けていたのです!どうしても今までこの警告を目にしなかったんだろう?と不思議に思っている方へ。答えはこうです。これまではverboseモードでスクリプトを実行したときだけ表示されていました。そして、この仕様が最近変わりました。これがその理由です。

じゃあなんでURI.escapeは非推奨メソッドなの?

「URIをエスケープする」という概念は実はやっかいです。なぜならURIは多数の要素(pathqueryなど)から成り立っており、その要素をすべて同じ方法でエスケープするわけではないからです。たとえば、#という文字について考えてみましょう。この文字はURIの最後に出てくるときは問題ありません(これは世間ではアンカーと呼ばれます。URI用語で言うところのfragment要素です)。しかし、ユーザー入力の一部に#が使われたとき(たとえば検索キーワードなど)は、入力値を正しく解釈するためにそれをエンコードしたいと思うはずです。同様に、クエリ文字列に=&といった予約文字が含まれていた場合、それらが間違って区切り文字として解釈されないようにエスケープしたくなるはずです(あたかも予約文字であるかのように)。

URI.escapeは単純にgsubメソッドを使って文字列全体を置換しているだけです。各要素が何であるかは区別しません。なので、上で述べたような複雑な問題は一切考慮されないのです。

どう修正するの?

URI文字列をまるごとを受け取って、各要素の違いをうまく解釈しつつ最適なエスケープ処理を加える、というような既存の解決策はまだ見つかっていません。ですので、私が考えるに、こういう場合は各要素を別々にエンコードするのが良いと思います。最も一般的な(そして最も問題が起きやすい)ユースケースは、おそらくクエリ文字列(query要素)のエンコーディングでしょう。そこで、今回はこのユースケースに焦点を当てます。RubyのURIモジュールには2種類の便利なメソッドが用意されているので、これを使えばうまくいきます!

クエリ文字列をパーセントエンコードする

URI.encode_www_form_component(string, enc=nil)

このメソッドは*, -, ., 0-9, A-Z, _, a-zだけをそのまま残し、それ以外のすべての予約文字をパーセントエンコードします。さらに、スペースも+に置換してくれます。以下の例を見てください。

query = "Tom & Jerry"
query = URI.encode_www_form_component(query)
query # => "Tom+%26+Jerry"
post = "So scared, but let's do this! #yolo"
post = URI.encode_www_form_component(post)
post # => "So+scared%2C+but+let%27s+do+this%21+%23yolo"

ご覧のとおり、適切なエスケープ処理を加えて安全なクエリ文字列を作ることができました。しかし、これだとちょっと手間がかかりすぎると感じた場合は、クエリ全体を適切に処理してくれる便利な方法があります。それがこちらです。

URI.encode_www_form(enum, enc=nil)

このメソッドは先ほどのメソッドとはインターフェースが若干異なり、Enumerable(通常はネストした配列かハッシュ)を受け取ります。それから、そのデータを使ってクエリ文字列を構築します。このメソッドは内部で.encode_www_form_componentを使うため、エンコーディング規則はどちらも同じです。異なるのは使い方だけです。以下の例を見てください。

URI.encode_www_form([["search", "Tom & Jerry"], ["page", "3"]])
# => "search=Tom+%26+Jerry&page=3"

URI.encode_www_form(["search", "2 + 2 = 5"])
# => "search=2+%2B+2+%3D+5"

URI.encode_www_form(search: "why is URI.escape obsolete", category: "meta")
#=> "search=why+is+URI.escape+obsolete&category=meta"

# Shameless plug
URI.encode_www_form(q: "how to speed up your CI?", tag: ["#devops", "#productivity"], lang: "en")
#=> "q=how+to+speed+up+your+CI%3F&tag=%23devops&tag=%23productivity&lang=en"

とても簡単ですね。

Railsの場合は?

Hash#to_query

Hash.to_paramというエイリアスメソッドもあります)

RailsはHashクラスを拡張して、この便利なメソッドを追加しています。このメソッドは正しい形式でクエリ文字列を返します。値は適切にエスケープされます。

query_data = { q: "how to speed up your CI?", tag: ["#devops", "#productivity"], lang: "en" }
query_data.to_query
#=> "lang=en&q=how+to+speed+up+your+CI%3F&tag%5B%5D=%23devops&tag%5B%5D=%23productivity"

(キーがアルファベット順にソートされる点にも注意してください)

このメソッドにはオプション引数としてネームスペースを渡すこともできます。返ってくる文字列はネームスペースが各キーを内包する形になります。たとえば、search[q]="how to speed up your CI?"というような形です(もちろんパーセントエンコードされますが)。

query_data = { q: "how to speed up your CI?", tag: ["#devops", "#productivity"], lang: "en" }
query_data.to_query("search")
#=> "search%5Blang%5D=en&search%5Bq%5D=how+to+speed+up+your+CI%3F&search%5Btag%5D%5B%5D=%23devops&search%5Btag%5D%5B%5D=%23productivity"

まとめ

短い記事ですが、みなさんが「この記事を読んだらURI文字列のエンコードに関する疑問が解消された!」と思ってくれたら嬉しいです。もし、みなさんのRuby/Railsプロジェクトでは何か別の方法を使っているなら、コメント欄にてその方法も教えてください。

そしてもし、みなさんのプロジェクトでCIのビルドが遅いことにお困りでしたら、ぜひKnapsack Proをチェックしてみてください。その問題を解消します。

(翻訳はここまで)

訳者による補足

日本語や"%"が含まれる場合のエンコード結果について

クエリ文字列に日本語が含まれる場合や、文字列に%が含まれる場合のエンコード結果も調べてみました。
結果としてはURI.encodeを使った場合も、URI.encode_www_form_componentURI.encode_www_formを使った場合も同じでした。

# 日本語をエンコードする場合
str = "あいう"

URI.encode(str)
#=> "%E3%81%82%E3%81%84%E3%81%86"

URI.encode_www_form_component(str)
#=> "%E3%81%82%E3%81%84%E3%81%86"

URI.encode_www_form([['query', str]])
#=> "query=%E3%81%82%E3%81%84%E3%81%86"
# %を含む文字列をエンコードする場合
str = "10%"

URI.encode(str)
#=> "10%25"

URI.encode_www_form_component(str)
#=> "10%25"

URI.encode_www_form([['query', str]])
#=> "query=10%25"

公式リファレンスのリンク等

各メソッドの公式リファレンスはこちらです。

また、公式リファレンスではURI.encodeの移行先として、encode_www_form_component以外にも以下のようなメソッドが紹介されています。

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

Gem::MissingSpecVersionErrorでrails serverできない

問題

「rails server」を実行しようとしたら、エラーが出た。

$ rails server
(Gem::MissingSpecVersionError)
To update to the latest version installed on your system, run `bundle update --bundler`.
To install the missing version, run `gem install bundler:2.1.2`

解決策

以下のコマンドを実行する。

$ bundle update --bundler
$ gem install bundler:2.1.2

僕の場合、2つ目のコマンド「gem install bundler:2.1.2」でまたエラーが出たので対処する。

問題

「gem install bundler:2.1.2」を実行しようとすると、またエラーが出た。

$ gem install bundler:2.1.2
ERROR:  While executing gem ... (Gem::FilePermissionError)
    You don't have write permissions for the /Library/Ruby/Gems/2.6.0 directory.

解決策

まずはgemやrubyがどのパスを指しているのか現状の確認をする。
以下の結果からわかるように/usr/binというシステムのパスを指していることがわかる。

$ which ruby                 
/usr/bin/ruby
$ which gem                  
/usr/bin/gem

調べると、システムのrubyを利用しているため、権限不足でgemのインストールができない可能性が高いみたいです。「gem installでpermissionエラーになった時の対応方法」が参考になりました。

rbenvでrubyを管理する

まずはrbenvのインストールする。

$ brew update
$ brew install rbenv ruby-build

続いて、rbenvの管理下にrubyをインストールする。
僕の場合は、Railsチュートリアルを進めているので、今回は2.6.1をインストールする。

rbenv install 2.6.1

globalで利用できるように変更する。

$ rbenv global 2.6.1

rbenvにパスを通すため、シェルの設定ファイル(.bashrcや.zshrc)に以下を追加する。

[[ -d ~/.rbenv  ]] && \
  export PATH=${HOME}/.rbenv/bin:${PATH} && \
  eval "$(rbenv init -)"

シェルを再起動後、以下コマンドを実行して、もう一度gemとrubyのパスを確認してみる。

$ which ruby                 
$ which gem                  

はじめはシステムのパスを指していましたが、以下のようにrbenvのパスを指していることがわかる。

rails serverを実行する

$ rails server                 
rbenv: rails: command not found

The `rails' command exists in these Ruby versions:
  2.7.0

Railsが見つからない?と言ってそうなので、Railsのバージョンを指定してインストールする。

$ gem install -v 5.1.6 rails 

もう一度rails serverを実行する。

$ rails server  
.
.
.
Use Ctrl-C to stop

立ち上がったっぽいので、http://localhost:3000/にアクセスして画面が表示されるか確認する。

”無事に画像も表示されて、サーバーを立ち上げることができました!”

参考

gem installでpermissionエラーになった時の対応方法

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

【jQuery】RailsでValidation Pluginを使った動的なバリデーションチェックの実装 〜詳細実装/Bootstrap編〜

はじめに

前回の記事では導入編をまとめましたので本記事では詳細実装編をまとめます。後半では以下の場合についてもまとめています。

  • Bootstrapを使用している場合
  • deviseを使用している場合
  • 正規表現チェックメソッドのサンプル一覧

開発環境

Ruby 2.5.1
Rails 5.0.7.2
jQuery 3.4.1
jQuery Validation Plugin 1.19.1
Bootstrap 4.3.1

実装手順

入力フォームを実装済み、プラグインを導入済みであることを前提としています。

パスワードと確認用パスワードのバリデーションチェック

完成イメージ

Image from Gyazo

解説・サンプルコード

eqaulToはデフォルトで使えるメソッドです。指定したidの入力欄と入力値が一致しているかをチェックできます。以下が本箇所のJSファイルの記述サンプルです。

jquery.validate.handler.user.js
$(function () {
  // メソッドの定義
  var methods = {
    password: function (value, element) { // パスワードの正規表現 
      return this.optional(element) || /^(?=.*?[a-z])(?=.*?\d)[a-z\d]{8,100}$/i.test(value);
    },
  }
  // メソッドの追加
  $.each(methods, function (key) {
    $.validator.addMethod(key, this);
  });
  // バリデーションの実行
  $("#signup-form, #charge-form").validate({
    // ルール設定
    rules: {
      "user[password]": {
        required: true, // 入力必須
        password: true // 正規表現
      },
      "user[password_confirmation]": {
        required: true, // 入力必須
        password: true, // 正規表現
        equalTo: "#password" // パスワードと確認用パスワードが一致しているかチェック
      },
    },
    // エラーメッセージの定義
    messages: {
      "user[password]": {
        required: "パスワードを入力してください",
        password: "英字と数字両方を含むパスワードを入力してください"
      },
      "user[password_confirmation]": {
        required: "確認用パスワードを入力してください",
        password: "英字と数字両方を含むパスワードを入力してください",
        equalTo: "パスワードが一致していません"
      },
    },
    errorClass: "invalid",
    errorElement: "p",
    validClass: "valid",
  });
  // 入力欄をフォーカスアウトしたときにバリデーションを実行
  $("#password, #password_confirmation").blur(function () {
    $(this).valid();
  });
});

プルダウンリストの選択状況確認

プルダウンリストのバリデーションチェックを実装します。
OK/NGの基準を以下のように設けました。

  • OK:プルダウンダウンリストが選択されて初期値から値が変わっている
  • NG:初期値から値が変わっていない
sample.html.haml
= form_tag(signup_index_path, method: :post, id:"charge-form", name: "inputForm", class: "pay_way__main__form") do
  %div.pay_way__main__form__content
    %div.pay_way__main__form__content__group
      %label.pay_way__main__form__content__group__label  有効期限
      %span.pay_way__main__form__content__group__require   必須
      .pay_way__main__form__content__group__expire
        .pay_way__main__form__content__group__expire__select
          %i.fas.fa-chevron-down.fa-lg.pay_way__main__form__content__group__expire__select__icon
          %select#exp_month{name: "exp_month", type: "text", class: "pay_way__main__form__content__group__expire__select__pulldown", name: "exp_month" }
            %option{value: ""} --
            %option{value: "1"}01
            %option{value: "2"}02
            %option{value: "3"}03
            %option{value: "4"}04
            %option{value: "5"}05
            %option{value: "6"}06
            %option{value: "7"}07
            %option{value: "8"}08
            %option{value: "9"}09
            %option{value: "10"}10
            %option{value: "11"}11
            %option{value: "12"}12
        %span.pay_way__main__form__content__group__expire__select__text.pay_way__main__form__content__group__expire
        .pay_way__main__form__content__group__expire__select
          %i.fas.fa-chevron-down.fa-lg.pay_way__main__form__content__group__expire__select__icon
          %select#exp_year{name: "exp_year", type: "text", class:"pay_way__main__form__content__group__expire__select__pulldown", name: "exp_year" }
            %option{value: ""} --
            %option{value: "2019"}19
            %option{value: "2020"}20
            %option{value: "2021"}21
            %option{value: "2022"}22
            %option{value: "2023"}23
            %option{value: "2024"}24
            %option{value: "2025"}25
            %option{value: "2026"}26
            %option{value: "2027"}27
            %option{value: "2028"}28
            %option{value: "2029"}29
        %span.pay_way__main__form__content__group__expire__select__text#exp_date_error
jquery.validate.handler.user.js
$(function () {
  // メソッドの定義
  var methods = {
    valueNotEquals: function (value, element, arg) { // プルダウンリストが選択されているかの確認
      return arg !== value;
    },
  }
  // メソッドの追加
  $.each(methods, function (key) {
    $.validator.addMethod(key, this);
  });
  // バリデーションの実行
  $("#charge-form").validate({
    // ルール設定
    rules: {
      exp_month: {
        valueNotEquals: ""
      },
      exp_year: {
        valueNotEquals: ""
      }
    },
    // エラーメッセージの定義
    messages: {
      exp_month: {
        valueNotEquals: "有効期限を選択してください"
      },
      exp_year: {
        valueNotEquals: "有効期限を選択してください"
      }
    },
    groups: { //グループ化
      exp_date: "exp_month exp_year"
    },
    errorClass: "invalid",
    errorElement: "p",
    validClass: "valid",
    // エラーメッセージ表示位置のカスタム設定
    errorPlacement: function (error, element) {
      if (element.attr("name") == "exp_month" || element.attr("name") == "exp_year") {
        error.insertAfter("#exp_date_error");
      }
      else {
        error.insertAfter(element);
      }
    }
  });
  // 選択欄をフォーカスアウトしたときにバリデーションを実行(ウィザードページ毎)
  $("#exp_month, #exp_year").blur(function () {
    $(this).valid();
  });
});

エラーメッセージの表示位置の設定

入力欄が横並びになっている場合、エラーメッセージはデフォルトでは各入力欄の直後にエラーメッセージが表示されます。そのため、入力欄が縦並びに変わってしまいます。そのようなときは本設定でメッセージの位置を指定できます。

完成イメージ

Image from Gyazo

解説・サンプルコード

以下のようにエラーメッセージを表示させたい場所の直前にidを付与した要素を設けます。

sample.html.haml
= f.text_field :lastname, class: "クラス名", placeholder:"例)山田", id: "lastname"
= f.text_field :firstname, class: "クラス名", placeholder:"例)彩", id: "firstname"
%div.#name_error
# 〜エラーを表示させたい場所〜

errorPlacementを使用して場所を指定します。

jquery.validate.handler.user.js
$(function () {
  // バリデーションの実行
  $("#signup-form").validate({
    // ルール設定
    rules: {
      "user[lastname]": {
        required: true
      },
      "user[firstname]": {
        required: true
      }
    },
    // エラーメッセージの定義
    messages: {
      "user[lastname]": {
        required: "姓を入力してください"
      },
      "user[firstname]": {
        required: "名を入力してください"
      },
    errorClass: "invalid",
    errorElement: "p",
    validClass: "valid",
    // エラーメッセージ表示位置のカスタム設定
    errorPlacement: function (error, element) {
      if (element.attr("name") == "user[lastname]" || element.attr("name") == "user[firstname]") {
        error.insertAfter("#name_error"); // 指定した要素の後ろにエラーを表示
      } else {
        error.insertAfter(element);
      }
    }
  });
  // 入力欄をフォーカスアウトしたときにバリデーションを実行
  $("#lastname, #firstname").blur(function () {
    $(this).valid();
  });
});

Bootstrapを使用している場合

Bootstrapを使用している場合、バリデーションチェック後のクラス名追加にBootstrapのValidationのclass名を指定することで使用することができます。

Bootstrap 公式リファレンス(forms)
Bootstrap 日本語リファレンス(forms)

完成イメージ

Image from Gyazo

解説・サンプルコード

Bootstrapを適用したフォームを用意します。

app/views/devise/sessions/new.html.erb
<div class="form-label-group">
  <%= f.email_field :email, placeholder: "Email Address", class: 'form-control' %>
  <%= f.label :email %>
</div>

<div class="form-label-group">
  <%= f.password_field :password, placeholder: "Password", class: 'form-control' %>
  <%= f.label :password %>
</div>

JSファイルでerrorClassとvalidClassを下記のように設定します。

jquery.validate.handler.user.js
// 〜省略〜
errorClass: "is-invalid"
validClass: "is-valid"
// ~省略〜

deviseを使用している場合

deviseを使用している場合でユーザー情報の変更において下記2つの入力パターンが想定されます。

  • パスワードを変更しない場合:現在のパスワードの入力が必須
  • パスワードを変更する場合:確認用パスワードが必須、現在のパスワードの入力は不要

バリデーションチェックを上記どちらでも対応できるように実装します。

完成イメージ

パスワードを変更しない場合:現在のパスワードの入力が必須

Image from Gyazo

パスワードを変更する場合:確認用パスワードが必須、現在のパスワードの入力は不要

Image from Gyazo

解説・サンプルコード

jquery.validate.handler.user.js
// 〜省略〜
"user[password]": { // requiredは設定しない
  password: true
},
"user[password_confirmation]": { // requiredは設定しない
  password: true,
  equalTo: "#user_password" // 新しいパスワードと一致しているか確認
},
"user[current_password]": {
  password: true,
  required: function (element) { // 新しいパスワード欄が空欄の場合は入力必須にする
    return $("#user_password").val() == "";
  }
},
// 〜省略〜

正規表現チェックメソッド一覧

今回の開発で様々な正規表現チェックを実装したので、それもまとめたいと思います。

jquery.validate.handler.user.js
  // メソッドの定義
  var methods = {
    email: function (value, element) { // メールアドレスの正規表現 
      return this.optional(element) || /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/i.test(value);
    },
    password: function (value, element) { // パスワードの正規表現 
      return this.optional(element) || /^(?=.*?[a-z])(?=.*?\d)[a-z\d]{8,100}$/i.test(value);
    },
    phone: function (value, element) { // 電話番号の正規表現
      return this.optional(element) || /^0\d{9,10}$/.test(value);
    },
     // クレジットカード番号の正規表現
     // VISA, MasterCard, Discover, Diners, Amex, JCBの番号規則に対応
    cardNumber: function (value, element) {
      return this.optional(element) || /^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6011[0-9]{12}|3(?:0[0-5]|[68][0-9])[0-9]{11}|3[47]{13}|(?:2131|1800|35[0-9]{3})[0-9]{11})$/.test(value);
    },
    cvc: function (value, element) { // セキュリティコードの正規表現
      return this.optional(element) || /^\d{3,4}$/.test(value);
    },
    postalCode: function (value, element) { // 郵便番号の正規表現
      return this.optional(element) || /^\d{3}[-]\d{4}$/.test(value);
    },
    kana: function (value, element) { // カタカナの正規表現
      return this.optional(element) || /^[ァ-ヴ]+$/.test(value);
    },
  }

まとめ

デフォルトで様々なメソッドが準備されていますが、カスタムメソッドを作ることができるため様々なバリデーションチェックが実装できます。Bootstrapのクラス名を組み込めばBootstrapと連携可能です。

参考URL

正規表現を可視化してまとめたチートシート
jquery.validate.jsでセレクトボックスのチェック、他カスタマイズ色々

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

【Rails】 独自 Validation 作成方法(複数モデル適用)

はじめに

バリデーションの作成方法はモデル内にprivateメソッドを作って、そのメソッドをvalidateの引数に指定する方法が一般的かと思います。
今回は、複数のモデルで同じバリデーションを適用したいケースへの対応方法をまとめました。

独自バリデーション作成方法

やること

開始日時カラムと終了日時カラムを持ったモデルの入力フォームに、
どちらのカラムも入力するか、どちらのカラムも入力しないバリデーションをかけたい。

Concern

まずは、app/models/concernsの直下にバリデーション専用のクラスを作成する。
Concernsを使用することで、同じカラムを持った他のモデルにも適用することができ、さらに細かい継承関係を考えなくてもよくなります。

app/models/concerns/work_datetime_validation.rb
class WorkDatetimeValidation < ActiveModel::Validator
  # record には、インスタンスが入る
  def validate(record)
    return if record.work_datetime_begin && record.work_datetime_end
    return if !record.work_datetime_begin && !record.work_datetime_end
    record.errors[:base] << '開始日時と終了日時どちらも入力するか、どちらも空にしてください'
  end
end

Model

次にModelにvalidates_withを用いて、先ほど作成したクラスを指定する。

他のModelにも適用させたい場合は、validates_withを他のクラスに書けばバリデーションが適用されます。

app/models/work.rb
class Work < ApplicationRecord
  validates_with WorkDatetimeValidation
end

以上となります。

まとめ

時間に関するバリデーションは複数のモデルで使用したいというニーズがあると思いますので、ぜひ活用してみてください。

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

Railsアプリ起動時に突然「Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)」になった時の対処法

はじめに

Railsアプリをローカルで起動させた際に、MySQLのConnectionErrorが発生しました。先日まで問題なく起動していたのですが……。

スクリーンショット 2020-01-19 22.35.58.png

mysqlサーバーに接続する際、mysql.sockファイルを使って接続するらしいのですが、
なんらかの原因により、このファイルが消えることがあるそうです。
エラー文で指定されているところに、mysql.sockファイルを作成して再度接続してみました。

$ sudo touch /tmp/mysql.sock
$ sudo mysql.server restart
Starting MySQL
. ERROR! The server quit without updating PID file (/usr/local/var/mysql/MBP-2.local.pid).

スクリーンショット 2020-01-20 19.17.18.png

エラー画面の(2)(38)に変わっただけです。
検索するとこの類のエラーは結構頻発するらしく、まずは権限周りから触ってみました。

$ sudo chown mysql:mysql /tmp

$ sudo chmod 777 /tmp/mysql.sock

$ mysql.server start
Starting MySQL
... ERROR! The server quit without updating PID file (/usr/local/var/mysql/MBP-2.local.pid).

$ sudo touch MBP-2.local.pid

$ sudo rm /tmp/mysql.sock

$ chown -R _mysql:_mysql mysql

$ sudo chown UserName /tmp/mysql.sock
$ mysql.server start
Starting MySQL
.. ERROR! The server quit without updating PID file (/usr/local/var/mysql/マシン名.local.pid).

以上の内容を色々試してみたのですが解決せず。Macを再起動しても何も変化なしでした。
MySQLをhomebrewでインストールしていたので/usr/local/var/mysqlをディレクトリごと消去して再インストールしました。

$ sudo rm -rf /usr/local/var/mysql

$ brew uninstall mysql@5.7
Uninstalling /usr/local/Cellar/mysql@5.7/5.7.28... (319 files, 232.2MB)

$ brew install mysql@5.7
・
・
mysql@5.7 is keg-only, which means it was not symlinked into /usr/local,
because this is an alternate version of another formula.
If you need to have mysql@5.7 first in your PATH run:
  echo 'export PATH="/usr/local/opt/mysql@5.7/bin:$PATH"' >> ~/.zshrc
・
・
?  /usr/local/Cellar/mysql@5.7/5.7.29: 319 files, 232.3MB

再インストールだけだとパスが通っていないのでexportコマンドでパスを通すように設定します。

$ echo 'export PATH="/usr/local/opt/mysql@5.7/bin:$PATH"' >> ~/.zshrc
$ sudo vi ~/.zshrc
export PATH=/usr/local/bin:$PATH
export PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)"
export PATH="/usr/local/opt/mysql@5.7/bin:$PATH"
$ source ~/.zshrc

まずはMySQLがインストールされているか確認します。

$ mysql --version
mysql  Ver 14.14 Distrib 5.7.29, for osx10.15 (x86_64) using  EditLine wrapper

続いてMySQL5.7を起動させます。

$ brew services start mysql@5.7
==> Successfully started `mysql@5.7` (label: homebrew.mxcl.mysql@5.7)

起動させるRailsアプリのデータベース設定ファイルは以下のようになっています。

database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: test-user
  password: password-example
  socket: /tmp/mysql.sock

指定しているユーザーでMySQLに接続してみます。

$ mysql -u test-user -ppassword-example
ERROR 1045 (28000): Access denied for user 'test-user'@'localhost' (using password: YES)

接続エラーとなりました。MySQLを再インストールしたためにtest-userが消去されているようです。
試しに現在のユーザーリストを確認すると、

$ mysql -u root -p
・
・
・
mysql> SELECT user, host FROM mysql.user;
+------------------+-----------+
| user             | host      |
+------------------+-----------+
| mysql.infoschema | localhost |
| mysql.session    | localhost |
| mysql.sys        | localhost |
| root             | localhost |
+------------------+-----------+
4 rows in set (0.00 sec)

確かに、ユーザーリストにtest-userが存在していませんので再度ユーザーを作成します。

$ mysql -u root -p
・
・
・
mysql> CREATE USER 'test-user'@'localhost' IDENTIFIED BY 'password-example';
Query OK, 0 rows affected (0.12 sec)


mysql> SELECT user, host FROM mysql.user;
+------------------+-----------+
| user             | host      |
+------------------+-----------+
| mysql.infoschema | localhost |
| mysql.session    | localhost |
| mysql.sys        | localhost |
| root             | localhost |
| test-user        | localhost |
+------------------+-----------+
5 rows in set (0.00 sec)

ユーザーの作成ができたので権限付与も合わせて行います。今回はテストなので全てのデータベースにアクセスできる権限を付与しました。

mysql> GRANT ALL ON *.* TO 'test-user'@'localhost';
Query OK, 0 rows affected (0.05 sec)

再度、MySQLに接続してみます。

$ mysql -u test-user -ppassword-example
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  
・
・
・
mysql>

接続できましたので、続いてデータベースを作成します。

$ bundle exec rails db:create
Created database '[アプリケーション名]_development'
Created database '[アプリケーション名]_test'

未実行のマイグレーションファイルを全て実行し、データベースにテーブルを作成します。

$ bundle exec rails db:migrare
== 20200117122858 DeviseCreateUsers: migrating ================================
-- create_table(:users)
   -> 0.0093s
-- add_index(:users, :email, {:unique=>true})
   -> 0.0302s
・
・
・

以上で設定終了です。再度Railsアプリを立ち上げてみます。
スクリーンショット 2020-01-25 6.40.58.png

無事に立ち上がりました。急にエラーが出て結構焦りましたが、いい勉強になりました。

参考記事

https://qiita.com/tosite0345/items/3f346780e14feca48f55
https://weblabo.oscasierra.net/mysql-57-homebrew-install/
https://qiita.com/gatapon/items/92b942fa7081cfe17482
https://qiita.com/kskumgk63/items/b308c0a688c358b17162
https://qiita.com/pugiemonn/items/718b7360028286c5b626

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

Rails6 データベースのカラム作成を行う際の概要

目的

  • カラムを作成したり削除したりする時の概要をまとめる

間違えてマイグレートしてしまった時はこちらを参考にロールバックを行う

Rails6 マイグレーションファイルの記載ミスでマイグレートしてしまったらrollbackを使おう

作業概要(カラムを追加する)

  1. カラムを追加するテーブル名を確認
  2. 追加するカラム名と型を決定
  3. マイグレーションファイルの作成
  4. 追加カラム情報の記載
  5. マイグレート

作業詳細(カラムを追加する)

  1. カラムを追加するテーブル名を確認
    1. これからカラムを追加するテーブル名を確認する。
  2. 追加するカラム名と型を決定
    1. 追加する任意のカラム名とデータ型を決める。
  3. マイグレーションファイルの作成

    1. 下記コマンドを実行してマイグレーションファイルの作成を行う。

      $ cd Railsで作成したアプリのルートフォルダ
      $ rails g migration change_カラムを追加するテーブル名_columns
      
    2. アプリ名/db/migrate直下にYYYYMMDDHHMM_change_カラムを追加するテーブル名_columns.rbというマイグレーションファイルが作成される。

  4. 追加カラム情報の記載

    1. 先に作成されたYYYYMMDDHHMM_change_カラムを追加するテーブル名_columns.rbファイルにカラムを追加する記載を記入する。 下記にusersテーブルにpassword_digestカラムをstring型で追加する時の記載の例を書く

      class ChangeUsersColumns < ActiveRecord::Migration[6.0]
        def change
         add_column :users, :password_digest, :string
        end
      end
      
  5. マイグレート

    1. 下記コマンドを実行してマイグレートを行う。

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

Rubyではメソッドにreturnの記述要らない?

Railsで開発している際に既存コードにreturnが書かれていなかったり、returnを書いてrubocopに指摘されたりしたので調べました。
rubyでは不要であればreturnは書かない方針のようです。

RubyではReturnの記述は不要

Rubyのメソッドでは、最後に評価された値が返るという仕様になっています。
例えば以下のような文字列を返すメソッドがあります。

def hoge(is_hoge)
  if is_hoge
    "hoge"
  else
    "fuga"
  end
end

最後に評価された値が返るので、それぞれ以下を返します。

hoge(true)  # "hoge"

hoge(false) # "fuga"

後置ifでは注意が必要

def hoge(is_hoge)
  "fuga"
  "hoge" if is_hoge
end
hoge(true) # "hoge"

hoge(false) # nil

なんとなくhoge(false)でfugaが帰って来そうですが、最後で評価された値が返るのでnilが帰ってきます。

後置ifでは、ifの右側の値が評価されたあと、trueならば左側が評価されます。
falseであればnilを返します。

例の場合、hoge(false)if is_hogeは成立しないので、左側のfugaは評価されず、
"hoge" if is_hogeが最後に評価された値となり、nilを返します。

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

Rails4系で統合テストをDocker環境内で行う

はじめに

今回Railsのバージョンアップに向けて不足していた箇所のテストを書いていました。
その一環で統合テストを書こうとして軽く詰まったので似たような境遇方のためになればと思い(こんなレアケースに遭遇する人は少ないと思いますが)記事にしました。

なぜ統合テストなのか

プロダクトで使用している外部サービスのAPIがjsにしか対応しておらず、プロダクト内で重要な機能の一部に組み込まれていたため。

環境

Rails 4系
Ruby 2.5.7
Rspec 3.9.1
capybara 3.30.0

対象

  • すでにRspecのテスト環境が整っている。
  • dockerを用いて開発を行なっている。
    • dockerを用いていない場合はローカルにインストールされているブラウザを使用すれば簡単に実装できると思います。

Railsアプリケーションが入っているコンテナにchromeなどを導入する

ブラウザ用にコンテナを分けるか迷いましたが、circleciにブラウザが導入されているRubyのイメージがあったため開発環境下でもRailsアプリケーションが入っているコンテナに導入することにしました。

Dockerfileに以下のchromeやseleniumなどをインストールするためのコマンドを書き足します。

Dockerfile
FROM ruby:2.5.7
# 下記の内容については現在の設定内容に合わせて変更してください。

# googleが用意している公開鍵をaptに追加
RUN wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | apt-key add -

# aptに安定版chromeがインストールできるレポジトリgoogle-chrome.listを追加します。
RUN echo 'deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main' | tee /etc/apt/sources.list.d/google-chrome.list

# aptで必要なパッケージをインストールします。
# seleniumをpipでインストールするため一緒にインストールします。
RUN apt-get update -qq && apt-get install -y [nodejsやRDBMSのクライアントなど] google-chrome-stable python3-pip

# seleniumでchromeを動かすためのchromedriverをダウンロードします。
# installしているchromeのバージョンに対応したchromedriverをインストールする必要があるため
# http://chromedriver.storage.googleapis.com/LATEST_RELEASE
# でchromeの安定バージョンを取得することができるため、その値を用いてchromedriverのバージョンを指定しています
RUN LATEST_RELEASE=$(curl -sS chromedriver.storage.googleapis.com/LATEST_RELEASE) &&\
    wget http://chromedriver.storage.googleapis.com/$LATEST_RELEASE/chromedriver_linux64.zip

# ダウンロードしたchromedriverを解凍します。 このときPATHが通っている階層に配置しましょう。
RUN unzip chromedriver_linux64.zip -d /bin/

# pipでseleniumをインストールします。
RUN pip3 install selenium

# これより下はRailsのインストールなど既存のコードになるかと思います。

Rails側で統合テストを動かす設定

Gemfileに以下を追加

Gemfile
gem 'selenium-webdriver'

rails_helper.rbに以下を追加

rails_helper.rb
require 'selenium-webdriver'

以下の内容を設定ファイルを作成して記述する。(rails_helper.rbなどに書いても可)

spec/support/capybara.rb
Capybara.register_driver :selenium do |app|
  option = Selenium::WebDriver::Chrome::Options.new(
    args: %w[--headless --disable-gpu --no-sandbox]
  )
  Capybara::Selenium::Driver.new(
    app,
    browser: :chrome,
    options: option,
    timeout: 600, # この設定がないとテスト内容によってはcircleciで Net::ReadTimeout となってしまう
    desired_capabilities: { accept_insecure_certs: true }
  )
end
Capybara.javascript_driver = :selenium

以上の設定で統合テストが実行できる環境が出来上がったと思います。

さいごに

Rails4系で統合テストのやり方を調べるとcapybara-webkitを使用した記事しか出てこなかったり、良さげなやり方を見つけてもsystem testに対応していなかったりとなにから導入していいのか調べるところからで少し詰まってしまいました。。。
また、せっかくdockerを使用しているので初めはブラウザ用のコンテナを用意しましたがコンテナ間の接続に証明書が必要でした。
証明書の発行まで書こうかと思いましたがcircleciでブラウザーが含まれたimage(今回だとcircleci/ruby:2.5.7-node-browsers)があったため分けずに構築してみました。
初めての内容ばかりだったのでおそらく改善できる点がたくさんあると思います。
改善点や気になったことがあればコメントで教えていただけると嬉しいです!

参考記事

https://qiita.com/zo30005/items/a5dcede868a3d1cca4a8
https://www.google.com/linuxrepositories/
https://www.linuxbabe.com/ubuntu/install-google-chrome-ubuntu-18-04-lts
https://circleci.com/docs/2.0/circleci-images/#language-image-variants

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

joinsで結合したモデルのscopeを使ってデータを取得する方法

inner joinかつ別モデルのscopeを利用してそのモデルの状態を条件にデータを取得したい。
例えば、「紐づくuserのstatusがtrueであるtweet」を取得したいときは以下のように書ける。

Tweet.joins(:user).merge(User.available)

user.rb

class User < ApplicationRecord
  has_many :tweets
  scope :available, -> {
    where(status: true)
  }
end

tweet.rb

class Tweet < ApplicationRecord
  belongs_to :user
end
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む