20201112のRailsに関する記事は24件です。

RailsのDocker化 〜その1〜

はじめに

Dockerはなんとなく聞いたことがあって、使うと便利なんだなーという印象があると思います。Ruby on RailsをDocker化するとどんなことが便利になるのか、検証していきたいと思います。

Dockerとは

エンジニアでコードを書いたことがある人なら経験があると思いますが、開発環境を作るまでに時間かかりませんか?
* これが足らない!ってなんかエラーが出て進まない!!
* 私はMacだけど、○○さんはWindowsで環境構築してるから勝手が違う!!
* 先輩に私のときはこれでうまく動いたって言われた、、、。

そこでDockerの登場

簡単にいうと、誰かが作ってくれたdockerのimageを使えば、環境に作用されず、ぽんっとコマンドを叩くだけでlocalに開発環境が出来てしまいます!!便利!!

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

Herokuを用いたデプロイに関するDBのエラー

この記事では、Herokuでデプロイをする際に起きたエラーを解決するまでに至った経緯を、わかりやすく書いていきます。

はじめに

・デプロイをしたアプリケーションはTECH_CAMPのカリキュラムで作成したものになります。

・投稿者は初学者ですので誤った情報を投稿してしまうことがあります。その時はぜひ、遠慮会釈なしにご指摘いただけると幸いです。

デプロイのために行った手順

1.Heroku CLIをインストール
 →ターミナルからHerokuへアクセスするため。下記のコマンドをターミナルで実行する。

brew tap heroku/brew && brew install heroku

2.Herokuにログインする下記のコマンドを使用することによってログインが可能。

heroku login --interactive

3.rails_12factor Gem をインストールする。
 →RailsアプリケーションをHeroku上で動かすことために必要なGemのこと。

Gemfile
group :production do
  gem 'rails_12factor'
end
bundle install

4.Heroku上にアプリケーションを作成する。

heroku cretate アプリケーション名

5.Heroku上でMySQLを使えるようにする。
 →HerokuのデフォルトDBはPostgreSQLである。今回のRailsアプリケーションはMySQLでDBを構築したので、適用されるように設定しないといけない。

heroku addons:add cleardb

6.Heroku上でMySQLを使えるようになったが、Gemについても設定変更する必要がある。

heroku_cleardb=`heroku config:get CLEARDB_DATABASE_URL`

これでClearDBデータベースのURLをheroku_cleardbという変数に代入ができた。

heroku config:set DATABASE_URL=mysql2${heroku_creardb:5}

DATABASE_URLがconfig:setによって再設定された。

7.環境変数を用いてmaster.keyの値を設置する。
 →master.keyはセキュリティの都合上、Gitで管理されないため、このままだとHeroku上でデプロイができない。環境変数としてmaster.keyの値を設置することで、Heroku上でも使えるようにする。

heroku config:set RAILS_MASTER_KEY=`cat config/master.key`

8.アプリケーションをプッシュする。

git push heroku master

9.Heroku上でマイグレーションを実行する。
 →heroku runコマンドを用いることにより、Heroku上でもrailsのコマンドを使うことができる。

heroku run rails db:migrate

10.公開を確認する。

heroku apps:info

を実行して表示されたURLに遷移した。

発生したエラーと仮説立て

error massage

URLに遷移すると上記のエラー画面が現れた。

そのため一旦、ターミナルに戻りエラーログの確認作業を行なった。

heroku logs --tail

上記のコマンドでエラーログを表示させた。
まず目についたのが、

2020-11-11T22:07:09.588453+00:00 (中略) dyno=web.1 connect=14ms service=35ms status=500 bytes=1827 protocol=https

status=500 とあることからサーバー側の問題であることがわかる。

もう少し詳しく見ていくと、

 Mysql2::Error::ConnectionError (Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)):

とあったので、MySQLがHeroku上で認識されていないのではないか?と考えた。

仮説をもとに解決

ターミナルのコードを遡ってみると、やはりMySQLの設定のところでおかしな点を見つけた。

nayuta@MacBookPro-Nayuta ajax_app % heroku_cleardb='heroku config:get CLEARDB_DATABASE_URL'
nayuta@MacBookPro-Nayuta ajax_app % heroku config:set DATABASE_URL=mysql2${heroku_creardb:5}
Setting DATABASE_URL and restarting ⬢ ajax-app-30306... done, v5
DATABASE_URL: mysql2

DATABASE_URLが正しく格納されていない。

自分の結果
DATABASE_URL: mysql2
正しい結果
DATABASE_URL: mysql2://000000000000:0aa0000@us-cdbr-east-02.cleardb.com/heroku_aaa00000000?reconnect=true

ここで間違いないと思ったが、手順6で行った作業を見返して見てもコマンドのスペルミスはなく、正しく入力されているように思えた。

自分の入力
heroku_cleardb='heroku config:get CLEARDB_DATABASE_URL'
正しい入力
heroku_cleardb=`heroku config:get CLEARDB_DATABASE_URL`

コードと睨めっこをして、調べて、ようやく判明。

本来ならば ``(バッククォーテーション)で囲わないといけないところを、''(シングルコーテーション)で囲っていました。

とても単純なミスでしたが、スペルミスばかりに気を取られて気が付くのが遅れました。

nayuta@MacBookPro-Nayuta ajax_app % heroku_cleardb=`heroku config:get CLEARDB_DATABASE_URL`
nayuta@MacBookPro-Nayuta ajax_app % heroku config:set DATABASE_URL=mysql2${heroku_cleardb:5}
Setting DATABASE_URL and restarting ⬢ ajax-app-30306... done, v12
DATABASE_URL: mysql2://bf691ece578431:8ce97e09@us-cdbr-east-02.cleardb.com/heroku_b4193d2f6e19e50?reconnect=true

ちゃんと``で囲んであげると、URLの再設定が完了しました。

ただ、このままプッシュしても下記のようなエラーメッセージが出てきてしまうので、

Everything up-to-date

空のコミットを作成して、まとめてプッシュしてもらいました。

 git commit --allow-empty -m "空のcommit"
 git push heroku master 

正常にプッシュされたようなのでURLに遷移すると、作成したアプリケーションがデプロイされていました。

まとめ

入力ミスでエラーが起きることはよくあることなので、スペルミスには気を付けていましたが、''と``の入力間違いが起きるとは想像していませんでした。
非常にしょうもないミスではありましたが、「こういうミスがあってエラーが起きた!」という経験値が増えたので幸運でした。

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

【Rails】devise gemを使用して複数のモデルを管理する

RailsのdeviseというGemを使用してログイン機能等を作る際、
一般の方と企業でログイン画面や管理を分けたいなという時があると思います。

deviseを使用してWebアプリケーションの制作を行ったことはありますが、
今回初めて複数のモデルで実装を行ったため備忘録として残しておきたいと思います。

環境
Ruby:   2.5.6
Rails:  5.2.4
devise: 4.7.3

docker内で作業しますので、bundle execがついていますが、
docker外の方は外して入力してみてください。

devise導入

1.Gemのインストール

今回はFacebook認証も行いたかったので、deviseomniauth-twitterをGemfileへ追加

Gemfile
gem 'devise'
gem 'omniauth-facebook'

そしてbundle install

2.devise関連のファイル作成

ターミナルで下記コマンドを入力

bundle exec rails g devise:install

以下のような文言が出てくると思います

create  config/initializers/devise.rb
      create  config/locales/devise.en.yml
===============================================================================

Depending on your application's configuration some manual setup may be required:

  1. Ensure you have defined default url options in your environments files. Here
     is an example of default_url_options appropriate for a development environment
     in config/environments/development.rb:

       config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

     In production, :host should be set to the actual host of your application.

     * Required for all applications. *

  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:

       root to: "home#index"

     * Not required for API-only Applications *

  3. Ensure you have flash messages in app/views/layouts/application.html.erb.
     For example:

       <p class="notice"><%= notice %></p>
       <p class="alert"><%= alert %></p>

     * Not required for API-only Applications *

  4. You can copy Devise views (for customization) to your app by running:

       rails g devise:views

     * Not required *

===============================================================================

それぞれ内容を確認して追加をしていきます。

1.config/environments/development.rbに以下の文言を追加してねという内容。
  言われた通り、デフォルトのURLを記載します。

config/environments/development.rb
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

2.config/routes.rbにrootでアクセスした時(1で設定したURLにアクセスした時)のURLを設定してねという内容
私はまだ作成していなかったので、ここで作成します。

ターミナル
bundle exec rails g controller Posts(コントローラー名) index

 config/routes.rbにてURLを設定

config/routes.rb
Rails.application.routes.draw do
  root 'posts#index'
end

3.app/views/layouts/application.html.erbにflashメッセージを追加してねという内容
  とりあえず記載されているものを書きました。

app/views/layouts/application.html.erb
.
.
.
  <body>
    <p class="notice"><%= notice %></p>
    <p class="alert"><%= alert %></p>

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

4.viewを生成してねと言われていますが、2パターン作りたいので今は無視します!

devise設定

ログインユーザーを2パターンにするためにconfig/initializers/devise.rbの設定を変更していきます。
元々コメントアウトされているので探してください!

config/initializers/devise.rb(変更前)
.
#config.scoped_views = false
.
.
#config.sign_out_all_scopes = true
.
config/initializers/devise.rb(変更後)
# 複数のmodelでログイン画面を分けるために変更
config.scoped_views = true
# 複数のmodelでをグインしている際、一方をログアウトした時にもう片方もログアウトしてしまうことを防ぐ
config.sign_out_all_scopes = false

deviseモデル作成

今回は一般の方と企業の2パターンを作ろうと思います!

ターミナル
bundle exec rails g devise user
bundle exec rails g devise company

マイグレーションファイルを確認

(モデル名以外同様のファイルが生成されているので、companyモデルのファイルは省略します)

db/migrate/20201112105533_devise_create_users.rb
# frozen_string_literal: true

class DeviseCreateUsers < ActiveRecord::Migration[5.2]
  def change
    create_table :users do |t|
      ## Database authenticatable
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""

      ## Recoverable
      t.string   :reset_password_token
      t.datetime :reset_password_sent_at

      ## Rememberable
      t.datetime :remember_created_at

      ## Trackable
      # t.integer  :sign_in_count, default: 0, null: false
      # t.datetime :current_sign_in_at
      # t.datetime :last_sign_in_at
      # t.string   :current_sign_in_ip
      # t.string   :last_sign_in_ip

      ## Confirmable
      # t.string   :confirmation_token
      # t.datetime :confirmed_at
      # t.datetime :confirmation_sent_at
      # t.string   :unconfirmed_email # Only if using reconfirmable

      ## Lockable
      # t.integer  :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
      # t.string   :unlock_token # Only if unlock strategy is :email or :both
      # t.datetime :locked_at


      t.timestamps null: false
    end

    add_index :users, :email,                unique: true
    add_index :users, :reset_password_token, unique: true
    # add_index :users, :confirmation_token,   unique: true
    # add_index :users, :unlock_token,         unique: true
  end
end

modelファイルを確認

Facebook認証を取り入れるため、:omniauthableomniauth_providers: [:facebook]を追記しました。

models/user.rb
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable, :omniauthable, omniauth_providers: [:facebook]
end

変更や追加ができたところでbundle exec rails db:migrate

ルーディングの確認

config/routes.rbを確認

config/routes.rb
Rails.application.routes.draw do
  devise_for :companies
  devise_for :users
  root 'postss#index'
end

bundle exec rails routesで確認

Controller#Actionの部分がcompanyとuserで同じになってしまっている。
つまり、controllerが同一になってしまっているので変更する必要がある。
(*Controller#Actionだけ離れてしまいました...
  めんどくさくて直せていないので、右にスライドしてください・・・!)

ターミナル
          Prefix Verb             URI Pattern                                                                          Controller#Action
             new_company_session GET      /companies/sign_in(.:format)                                                            devise/sessions#new
                 company_session POST     /companies/sign_in(.:format)                                                            devise/sessions#create
         destroy_company_session DELETE   /companies/sign_out(.:format)                                                           devise/sessions#destroy
            new_company_password GET      /companies/password/new(.:format)                                                       devise/passwords#new
           edit_company_password GET      /companies/password/edit(.:format)                                                      devise/passwords#edit
                company_password PATCH    /companies/password(.:format)                                                           devise/passwords#update
                                 PUT      /companies/password(.:format)                                                           devise/passwords#update
                                 POST     /companies/password(.:format)                                                           devise/passwords#create
     cancel_company_registration GET      /companies/cancel(.:format)                                                             devise/registrations#cancel
        new_company_registration GET      /companies/sign_up(.:format)                                                            devise/registrations#new
       edit_company_registration GET      /companies/edit(.:format)                                                               devise/registrations#edit
            company_registration PATCH    /companies(.:format)                                                                    devise/registrations#update
                                 PUT      /companies(.:format)                                                                    devise/registrations#update
                                 DELETE   /companies(.:format)                                                                    devise/registrations#destroy
                                 POST     /companies(.:format)                                                                    devise/registrations#create
                new_user_session GET      /users/sign_in(.:format)                                                                 devise/sessions#new
                    user_session POST     /users/sign_in(.:format)                                                                 devise/sessions#create
            destroy_user_session DELETE   /users/sign_out(.:format)                                                                devise/sessions#destroy
user_facebook_omniauth_authorize GET|POST /users/auth/facebook(.:format)                                                           devise/omniauth_callbacks#passthru
 user_facebook_omniauth_callback GET|POST /users/auth/facebook/callback(.:format)                                                  devise/omniauth_callbacks#facebook
               new_user_password GET      /users/password/new(.:format)                                                            devise/passwords#new
              edit_user_password GET      /users/password/edit(.:format)                                                           devise/passwords#edit
                   user_password PATCH    /users/password(.:format)                                                                devise/passwords#update
                                 PUT      /users/password(.:format)                                                                devise/passwords#update
                                 POST     /users/password(.:format)                                                                devise/passwords#create
        cancel_user_registration GET      /users/cancel(.:format)                                                                  devise/registrations#cancel
           new_user_registration GET      /users/sign_up(.:format)                                                                 devise/registrations#new
          edit_user_registration GET      /users/edit(.:format)                                                                    devise/registrations#edit
               user_registration PATCH    /users(.:format)                                                                         devise/registrations#update
                                 PUT      /users(.:format)                                                                         devise/registrations#update
                                 DELETE   /users(.:format)                                                                         devise/registrations#destroy
                                 POST     /users(.:format)                                                                         devise/registrations#create

ルーディング修正

config/routes.rb
devise_for :companies, controllers: {
    sessions:      'companies/sessions',
    passwords:     'companies/passwords',
    registrations: 'companies/registrations'
  }
  devise_for :users, controllers: {
    sessions:           'users/sessions',
    passwords:          'users/passwords',
    registrations:      'users/registrations',
    omniauth_callbacks: 'users/omniauth_callbacks'
  }

もう一度bundle exec rails routesで確認していただくと無事controllerの部分が変更されていると思います!

ビューの作成

最初のrails g devise:installを実行した際に対応しなかった部分です。

ターミナル
bundle exec rails g devise:views users
bundle exec rails g devise:views companies

それぞれファイルが生成されたかと思います!

コントローラーの作成

ターミナル
bundle exec rails generate devise:controllers users
bundle exec rails generate devise:controllers companies

こんな感じの実行結果になるかと思います。

create  app/controllers/users/confirmations_controller.rb
      create  app/controllers/users/passwords_controller.rb
      create  app/controllers/users/registrations_controller.rb
      create  app/controllers/users/sessions_controller.rb
      create  app/controllers/users/unlocks_controller.rb
      create  app/controllers/users/omniauth_callbacks_controller.rb
===============================================================================

Some setup you must do manually if you haven't yet:

  Ensure you have overridden routes for generated controllers in your routes.rb.
  For example:

    Rails.application.routes.draw do
      devise_for :users, controllers: {
        sessions: 'users/sessions'
      }
    end

===============================================================================

下の部分、まさかのエラー!?と思いましたが、エラーじゃないです。(ほっ
controllerがこんな感じだから、追加でroutes.rbに以下のような記述が必要だよ〜
と例を出して教えてくれています。

先ほど設定しているので無視で大丈夫です!

おまけ(omniauth認証を導入する方)

このままだとhttp://localhost:3000/users/sign_inにアクセスしてもエラーになると思います。
undefined method `omniauth_authorize_path' for 〜みたいなやつが。。

Facebook認証の設定についてはここに記載しませんが、
app/views/users/shared/links.html.erbの
omniauth_authorize_path(resource
name, provider)の部分がおかしいです。

ルーディングを確認するとomniauth_authorize_pathというpathはなく、user_facebook_omniauth_authorize_pathとなっているはずなので修正しましょう。

asを使用して名前を変更したわけでもないのになんで・・・?と思いましたが、
理由はよくわからなかったです。最初からなのかな・・・?

とりあえず完成

何はともあれ!とりあえず基本的な設定部分は完成です。

http://localhost:3000/users/sign_inhttp://localhost:3000/companies/sign_in
どちらでアクセスしてもログイン画面が出ると思います!

必要であればカラムを増やしたりカスタマイズしてください!

この記事がどなたかのお役に立てたら嬉しいです。
ありがとうございました!

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

yarnのバージョンが低いってばよ

rake routes
error Couldn't find an integrity file                                                                                                                                                              
error Found 1 errors.                                                                                                                                                                              


========================================
  Your Yarn packages are out of date!
  Please run `yarn install --check-files` to update.
========================================


To disable this check, please change `check_yarn_integrity`
to `false` in your webpacker config file (config/webpacker.yml).


yarn check v1.22.10
info Visit https://yarnpkg.com/en/docs/cli/check for documentation about this command.


koyoishikawa@ishikawyounoAir Ruby_on_rails_task_2 % yarn install --check-files  
yarn install v1.22.10
[1/4] ?  Resolving packages...
[2/4] ?  Fetching packages...
[3/4] ?  Linking dependencies...
warning " > webpack-dev-server@3.11.0" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0".
warning "webpack-dev-server > webpack-dev-middleware@3.7.2" has unmet peer dependency "webpack@^4.0.0".
[4/4] ?  Building fresh packages...
✨  Done in 341.25s.

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

link_toメソッドでmethod: :deleteにしても、HTTPがGETになってしまう現象

はじめに

 link_toメソッドを使って、削除機能を実装しようとしたときに、つまずいたこととその解決法についてまとめておく。

エラー内容

 「HTTP[GET]を探したけれど、そんなものないよ」みたいな感じのルーティングエラーが出た。

link_toメソッドのHTTPメソッドのデフォルト

 link_toメソッドはHTMLでいうところのaタグの役割なので、ページを遷移させるときに使いことが主になる。そのため、特にmethodを指定しなければ、HTTPメソッドはGETとなる。

method: :deleteにする理由

先に挙げたように、link_toメソッドはデフォルトでGETになっているので、methodを別に指定する必要があるから。

エラーの解決方法

 荒技になるが、link_toメソッドをbutton_toメソッドに変える。多少、デザインが変わるが、機能は意図したものが実装できる。

最後に

 Rails6では、webpackがデフォルトであり、何やらうまく読み込まなくなってしまっているようだった。今まで、このエラーはでなかったのに、オリジナルアプリケーションを作るようになってから、見かけるようになった…。いまだに原因は謎に包まれている。

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

【自分用メモ】Rspecの導入とエラーメッセージ日本語化

はじめに

自分用の備忘録。
毎回手順を確認するのが面倒なので、自分なりのパッケージをまとめてみる。

手順

Rspec

Gemをインストール

Gemfile
# 中略

group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
  # 追記
  gem 'rspec-rails'
  gem 'factory_bot_rails'
  gem 'faker'
end

# 中略

アプリケーションにRspecをインストール

ターミナル
% rails g rspec:install

rspecファイルの設定

.rspec
--require spec_helper
# 追記
--format documentation

エラーメッセージの日本語化

Gemをインストール

Gemfile
# 最下部
gem 'rails-i18n'

application.rbを編集

config/application.rb
# 中略

module App
 class Application < Rails::Application
   # Initialize configuration defaults for originally generated Rails version.
   config.load_defaults 6.0

   # 追記
   config.i18n.default_locale = :ja
  # 省略
 end
end

ymlファイル作成(devise)

config/locales/devise.ja.yml => 作成

ymlファイル編集(devise)

以下、コピペ

config/locales/devise.ja.yml
ja:
  activerecord:
    attributes:
      user:
        confirmation_sent_at: パスワード確認送信時刻
        confirmation_token: パスワード確認用トークン
        confirmed_at: パスワード確認時刻
        created_at: 作成日
        current_password: 現在のパスワード
        current_sign_in_at: 現在のログイン時刻
        current_sign_in_ip: 現在のログインIPアドレス
        email: メールアドレス
        encrypted_password: 暗号化パスワード
        failed_attempts: 失敗したログイン試行回数
        last_sign_in_at: 最終ログイン時刻
        last_sign_in_ip: 最終ログインIPアドレス
        locked_at: ロック時刻
        password: パスワード
        password_confirmation: パスワード(確認用)
        remember_created_at: ログイン記憶時刻
        remember_me: ログインを記憶する
        reset_password_sent_at: パスワードリセット送信時刻
        reset_password_token: パスワードリセット用トークン
        sign_in_count: ログイン回数
        unconfirmed_email: 未確認Eメール
        unlock_token: ロック解除用トークン
        updated_at: 更新日
    models:
      user: ユーザ
  devise:
    confirmations:
      confirmed: メールアドレスが確認できました。
      new:
        resend_confirmation_instructions: アカウント確認メール再送
      send_instructions: アカウントの有効化について数分以内にメールでご連絡します。
      send_paranoid_instructions: メールアドレスが登録済みの場合、本人確認用のメールが数分以内に送信されます。
    failure:
      already_authenticated: すでにログインしています。
      inactive: アカウントが有効化されていません。メールに記載された手順にしたがって、アカウントを有効化してください。
      invalid: "%{authentication_keys}またはパスワードが違います。"
      last_attempt: もう一回誤るとアカウントがロックされます。
      locked: アカウントは凍結されています。
      not_found_in_database: "%{authentication_keys}またはパスワードが違います。"
      timeout: セッションがタイムアウトしました。もう一度ログインしてください。
      unauthenticated: アカウント登録もしくはログインしてください。
      unconfirmed: メールアドレスの本人確認が必要です。
    mailer:
      confirmation_instructions:
        action: メールアドレスの確認
        greeting: "%{recipient}様"
        instruction: 以下のリンクをクリックし、メールアドレスの確認手続を完了させてください。
        subject: メールアドレス確認メール
      email_changed:
        greeting: こんにちは、%{recipient}様。
        message: あなたのメール変更(%{email})のお知らせいたします。
        subject: メール変更完了。
      password_change:
        greeting: "%{recipient}様"
        message: パスワードが再設定されたことを通知します。
        subject: パスワードの変更について
      reset_password_instructions:
        action: パスワード変更
        greeting: "%{recipient}様"
        instruction: パスワード再設定の依頼を受けたため、メールを送信しています。下のリンクからパスワードの再設定ができます。
        instruction_2: パスワード再設定の依頼をしていない場合、このメールを無視してください。
        instruction_3: パスワードの再設定は、上のリンクから新しいパスワードを登録するまで完了しません。
        subject: パスワードの再設定について
      unlock_instructions:
        action: アカウントのロック解除
        greeting: "%{recipient}様"
        instruction: アカウントのロックを解除するには下のリンクをクリックしてください。
        message: ログイン失敗が繰り返されたため、アカウントはロックされています。
        subject: アカウントの凍結解除について
    omniauth_callbacks:
      failure: "%{kind} アカウントによる認証に失敗しました。理由:(%{reason})"
      success: "%{kind} アカウントによる認証に成功しました。"
    passwords:
      edit:
        change_my_password: パスワードを変更する
        change_your_password: パスワードを変更
        confirm_new_password: 確認用新しいパスワード
        new_password: 新しいパスワード
      new:
        forgot_your_password: パスワードを忘れましたか?
        send_me_reset_password_instructions: パスワードの再設定方法を送信する
      no_token: このページにはアクセスできません。パスワード再設定メールのリンクからアクセスされた場合には、URL をご確認ください。
      send_instructions: パスワードの再設定について数分以内にメールでご連絡いたします。
      send_paranoid_instructions: メールアドレスが登録済みの場合、パスワード再設定用のメールが数分以内に送信されます。
      updated: パスワードが正しく変更されました。
      updated_not_active: パスワードが正しく変更されました。
    registrations:
      destroyed: アカウントを削除しました。またのご利用をお待ちしております。
      edit:
        are_you_sure: 本当によろしいですか?
        cancel_my_account: アカウント削除
        currently_waiting_confirmation_for_email: "%{email} の確認待ち"
        leave_blank_if_you_don_t_want_to_change_it: 空欄のままなら変更しません
        title: "%{resource}編集"
        unhappy: 気に入りません
        update: 更新
        we_need_your_current_password_to_confirm_your_changes: 変更を反映するには現在のパスワードを入力してください
      new:
        sign_up: アカウント登録
      signed_up: アカウント登録が完了しました。
      signed_up_but_inactive: ログインするためには、アカウントを有効化してください。
      signed_up_but_locked: アカウントが凍結されているためログインできません。
      signed_up_but_unconfirmed: 本人確認用のメールを送信しました。メール内のリンクからアカウントを有効化させてください。
      update_needs_confirmation: アカウント情報を変更しました。変更されたメールアドレスの本人確認のため、本人確認用メールより確認処理をおこなってください。
      updated: アカウント情報を変更しました。
      updated_but_not_signed_in: あなたのアカウントは正常に更新されましたが、パスワードが変更されたため、再度ログインしてください。
    sessions:
      already_signed_out: 既にログアウト済みです。
      new:
        sign_in: ログイン
      signed_in: ログインしました。
      signed_out: ログアウトしました。
    shared:
      links:
        back: 戻る
        didn_t_receive_confirmation_instructions: アカウント確認のメールを受け取っていませんか?
        didn_t_receive_unlock_instructions: アカウントの凍結解除方法のメールを受け取っていませんか?
        forgot_your_password: パスワードを忘れましたか?
        sign_in: ログイン
        sign_in_with_provider: "%{provider}でログイン"
        sign_up: アカウント登録
      minimum_password_length: "(%{count}字以上)"
    unlocks:
      new:
        resend_unlock_instructions: アカウントの凍結解除方法を再送する
      send_instructions: アカウントの凍結解除方法を数分以内にメールでご連絡します。
      send_paranoid_instructions: アカウントが見つかった場合、アカウントの凍結解除方法を数分以内にメールでご連絡します。
      unlocked: アカウントを凍結解除しました。
  errors:
    messages:
      already_confirmed: は既に登録済みです。ログインしてください。
      confirmation_period_expired: の期限が切れました。%{period} までに確認する必要があります。 新しくリクエストしてください。
      expired: の有効期限が切れました。新しくリクエストしてください。
      not_found: は見つかりませんでした。
      not_locked: は凍結されていません。
      not_saved:
        one: エラーが発生したため %{resource} は保存されませんでした。
        other: "%{count} 件のエラーが発生したため %{resource} は保存されませんでした。"

ymlファイル作成(一般)

config/locales/ja.yml => 作成

ymlファイル編集(一般)

config/locales/ja.yml
ja:
  time:
    formats:
      default: "%m/%d %H:%M"
  activerecord:
    attributes:
      モデル①:
        カラム①: 対応する日本語
        カラム②: 対応する日本語
      モデル②:
        カラム①: 対応する日本語
        カラム②: 対応する日本語
  # ActiveModelを使用している場合、続けて追記
 activemodel:
    attributes:
      モデル名:
        カラム名: 対応する日本語

おわりに

毎度なにかしら抜けるのでメモリました。

この一連の設定を自動化するプログラムを書けるようになりたいものです。

✔︎

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

ActiveHashの活用

はじめに

Railsでオリジナルアプリを制作しています。このアプリにActiveHashを適用しました。プルダウン形式でActiveHashで設定したデータを選択できるようにしました。忘れても思い出せるよう書き残します。

※ActiveHashは都道府県名一覧のように変更されないデータを扱います。変更されないデータなので、データベースには直接保存する必要がないです(都道府県毎に用意したidは保存されます)。

開発環境
ruby 2.6.5
Rails 6.0.3.4

目次

1.ActiveHashの導入
2.モデルの準備
3.コントローラーの準備
4.ビューの表示

1.ActiveHashの導入

ActiveHashはGemの1つ。Gemファイルに追記し、ターミナルでインストールする。

Gemfile
gem 'active_hash'
ターミナル
bundle install

2.モデルの準備

ここではday(日数)をActiveHashの対象とする。モデル作成時--skip-migrationを追加するとマイグレーションファイルは作成されない。他にもActiveHashの対象があるなら、その数だけモデルを作成する。

ターミナル
rails g model day --skip-migration

モデル内ではActiveHashを継承するすること。self.dataはハッシュ形式のデータが格納された配列になる。ハッシュ内はidとname(日数)が紐づく。

app/models/day.rb
class day < ActiveHash::Base #←ActiveHashを継承する
 self.data = [
   { id: 1, name: '--' },
   { id: 2, name: '1日' },
   { id: 3, name: '1週間' },
 ]
 end

続いて上記で設定した日数のidをデータベースに保存する設定を行う。ActiveHashが紐づくテーブルとしてarticleを例にする。

2020***********_create_articles.rb
class CreateArticles < ActiveRecord::Migration[6.0]
 def change
   create_table :articles do |t|
     t.string     :title        , null: false
     t.text       :text         , null: false
     t.integer    :day_id       , null: false #ActiveHashのidが保存されるカラム 
     t.timestamps
   end
 end
end

忘れずマイグレーションを行う。モデルのアソシエーションも。

app/model/article
validates :day_id # _idをつける
belongs_to_active_hash :day # _idは不要

3.コントローラーの準備

ストロングパラメータにday_idを追加して、保存できるようにする。

article.controller.rb
:
  def new    
    @article = Article.new
  end

  def create    
    @article = Article.new(article_params)
  end

  private
  def article_params
    params.require(:article).permit(:title, :text, :day_id)
  end

ビューの表示

collection_selectによってプルダウン形式で表示できる。引数は第一から第五まである。

引数
第一引数(保存されるカラム ) day_id
第二引数(オブジェクトの配列) Day.all
第三引数(カラムに保存される項目) id
第四引数(選択肢に表示されるカラム名) name
第五引数(オプション) {}
htmlオプション {class:"day-select"}
<%= f.collection_select(:day_id, Day.all, :id, :name, {}, {class:"day-select"}) %>

以上

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

[Rails] devise の使い方 (備忘録)

はじめに

これまでログイン、ログアウトといった認証系の機能は自前で実装していたのですが、今回ポートフォリオを制作するにあたってdeviseを使っておきたいなと思い、その使い方の備忘録として本記事を残します。

実行環境

この記事は以下の環境で動作確認しています。
ruby 2.7.1
rails 6.0.3
devise 4.7.3

インストール

Gemfileに追記。
後半で日本語化するのでそのgemも入れておきます。

Gemfile
gem 'devise'
gem 'devise-i18n'
gem 'devise-i18n-views'

bundle installを実行。

$ bundle install

deviseの設定

関連ファイルを作成。

$ rails g devise:install

するとファイルが作成され、以下のような英文が表示されます。

Running via Spring preloader in process 5911
      create  config/initializers/devise.rb
      create  config/locales/devise.en.yml
===============================================================================

Depending on your application's configuration some manual setup may be required:

  1. Ensure you have defined default url options in your environments files. Here
     is an example of default_url_options appropriate for a development environment
     in config/environments/development.rb:

       config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

     In production, :host should be set to the actual host of your application.

     * Required for all applications. *

  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:

       root to: "home#index"

     * Not required for API-only Applications *

  3. Ensure you have flash messages in app/views/layouts/application.html.erb.
     For example:

       <p class="notice"><%= notice %></p>
       <p class="alert"><%= alert %></p>

     * Not required for API-only Applications *

  4. You can copy Devise views (for customization) to your app by running:

       rails g devise:views

     * Not required *

===============================================================================

1. 環境ファイルにデフォルトのurlオプションを定義します。

config/environments/development.rb
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

2. ルートurlを定義します。

config/routes.rb
root to: 'homes#index'

3. flashを表示させたい場所に以下を記載します。

<p class="notice"><%= notice %></p>
<p class="alert"><%= alert %></p>

4. viewのカスタマイズについては後ほど記載します。

Userモデルの作成

$ rails g devise User

作成されたマイグレーションファイルを見ると、emailとpasswordしかないので追加したいカラムがあれば追記します。追記し終えたらマイグレーションを実行。

$ rails db:migrate

この時点で http://localhost:3000/users/sign_up を開けば新規登録ページが作成されています。
もしカラムの追記を忘れていて後から追加したい場合は以下を実行する。(今回はusernameカラムの追加を想定して行う)

$ rails g migration add_username_to_users username:string

usernameは必ず記入して欲しいので NOT NULL 制約をつけておきます。

db/migrate/XXXXXXXXXXXXXX_add_username_to_users.rb
class AddUsernameToUsers < ActiveRecord::Migration[6.0]
  def change
    add_column :users, :username, :string, null: false
  end
end

deviseに対応したviewの作成

viewのカスタマイズをしたいので以下を実行。

$ rails g devise:views users

viewの編集内容を反映させます。

config/initializers/devise.rb
# 247行目の config.scoped_views = false のコメントアウトを外して true に変更
config.scoped_views = true

sign_upの際にusernameを登録できるようにします。

app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:username])
  end
end

コントローラーを作成し、ルーティングを変更する

$ rails g devise:controllers users

コントローラーファイルと英文が表示されます。

Running via Spring preloader in process 9004
      create  app/controllers/users/confirmations_controller.rb
      create  app/controllers/users/passwords_controller.rb
      create  app/controllers/users/registrations_controller.rb
      create  app/controllers/users/sessions_controller.rb
      create  app/controllers/users/unlocks_controller.rb
      create  app/controllers/users/omniauth_callbacks_controller.rb
===============================================================================

Some setup you must do manually if you haven't yet:

  Ensure you have overridden routes for generated controllers in your routes.rb.
  For example:

    Rails.application.routes.draw do
      devise_for :users, controllers: {
        sessions: 'users/sessions'
      }
    end

===============================================================================

ここで現在のルーティングを確かめておきます。

$ rails routes

Prefix               Verb   URI Pattern                          Controller#Action
new_user_session     GET    /users/sign_in(.:format)             devise/sessions#new
user_session         POST   /users/sign_in(.:format)             devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format)            devise/sessions#destroy
...
new_user_registration GET    /users/sign_up(.:format)       devise/registrations#new

このようにController#Actionの部分が devise/registrations,devise/sessionsになっていると、これから定義するメソッドが反映されません。

コントローラーを作成した際に表示された英文に従ってルートをオーバーライドします。

config/routes.rb
devise_for :users, controllers: {
    registrations: 'users/registrations',
    sessions: 'users/sessions'
  }

オーバーライドできたので現在のルーティングを確認します。

$ rails routes

Prefix               Verb   URI Pattern                    Controller#Action
new_user_session     GET    /users/sign_in(.:format)       users/sessions#new
user_session         POST   /users/sign_in(.:format)       users/sessions#create
destroy_user_session DELETE /users/sign_out(.:format)      users/sessions#destroy
...
new_user_registration GET    /users/sign_up(.:format)      users/registrations#new                   

このようになり、コントローラーのカスタマイズができるようになります。
メソッドを定義します。

app/controllers/users/registrations_controller.rb
  # アカウント作成後のリダイレクト先
  def after_sign_up_path_for(resource)
    root_path
  end

  # アカウント編集後のリダイレクト先
  def after_update_path_for(resource)
    root_path
  end
app/controllers/users/sessions_controller.rb
  # ログアウト後のリダイレクト先
  def after_sign_out_path_for(resource)
    root_path
  end

  # ログイン後のリダイレクト先
  def after_sign_in_path_for(resource)
    root_path
  end

これで全てのリダイレクト先がトップページになりました。

日本語化する

まず、このRailsアプリケーションのデフォルトの言語を日本語にします。

config/application.rb
require_relative 'boot'
require 'rails/all'

Bundler.require(*Rails.groups)

module ConnectStudy
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 6.0

    config.i18n.default_locale = :ja # ここを追記
  end
end

devise の日本語翻訳ファイルを生成します。

$ rails g devise:views:locale ja

これで日本語になります。configを変更した際はサーバーの再起動をお忘れなく。

deviseには便利なヘルパーメソッドもたくさん用意されているのでそれらを利用してアプリ開発を効率よく行っていこうと思います。

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

FactoryBot ActiveStorageを使った画像を紐付ける方法

FactoryBotとは

RSpecにテストを効率化するための機能です。
予め値を設定しておき、それに沿ったインスタンスを生成します。

ActiveStorageで画像を紐付けよう

factories/post.rb
FactoryBot.define do
  factory :post do
    #{ } の値が参照されて保存される。
    text {"テキストです"}

    #afterメソッド。Postインスタンスをbuildした後、画像をつける。
    after(:build) do |post|
      post.image.attach(io: File.open('spec/fixtures/test_image.png'), filename: 'test_image.png', content_type: 'image/png')
    end

  end
end

Postインスタンスのimageカラムに画像をつけるよう記述します。
HTTPリクエスト経由で画像を付けない場合は、

io: File.open('画像ファイル場所指定'), filename: 'ファイルの名前', content_type: 'ファイルのタイプ(imageとかtextとか)/拡張子

と記述します。

以上です!

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

【rails】カラムを確認する簡単な方法

rails c

でコンソールを開く。

User.column_names

でカラムを確認する。
すると下記のように、他の不要な情報を取得せず現在作成しているカラム名だけを取得し確認することができる。

[1] pry(main)> User.column_names
=> ["id",
 "email",
 "encrypted_password",
 "reset_password_token",
 "reset_password_sent_at",
 "remember_created_at",
 "created_at",
 "updated_at"]

ちなみにUser.columns.map(&:name)でも同様の確認が可能です。

[2] pry(main)> User.columns.map(&:name)
=> ["id",
 "email",
 "encrypted_password",
 "reset_password_token",
 "reset_password_sent_at",
 "remember_created_at",
 "created_at",
 "updated_at"]

しかしこれだと記述が長いので、User column_namesで確認するのが良いかと思われます◯

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

[解決]Rails6にVuetifyを導入した時のwebpackerエラー "ActionView::Template::Error Webpacker can't find hello_vue ~"

エラーになった過程

vueをrails6に導入して、vuetifyを追加。→試しにvuetifyのパーツをコピペ。→うまく機能しているかブラウザで確かめるため、rails s→コンパイル時にエラー発生。

エラー内容

ActionView::Template::Error (Webpacker can't find hello_vue in /usr/src/myapp/public/packs/manifest.json. Possible causes:
1. You want to set webpacker.yml value of compile to true for your environment
   unless you are using the `webpack -w` or the webpack-dev-server.
2. webpack has not yet re-run to reflect updates.
3. You have misconfigured Webpacker's config/webpacker.yml file.
4. Your webpack configuration is not creating a manifest.
Your manifest contains:
{
  "application.js": "/packs/js/application-9afcbb5693aa87623e69.js",
  "application.js.map": "/packs/js/application-9afcbb5693aa87623e69.js.map",
  "components/user.js": "/packs/js/components/user-156f569cb5c8b04ee2e1.js",
  "components/user.js.map": "/packs/js/components/user-156f569cb5c8b04ee2e1.js.map",
  "entrypoints": {
    "application": {
      "js": [
        "/packs/js/application-9afcbb5693aa87623e69.js"
      ],
      "js.map": [
        "/packs/js/application-9afcbb5693aa87623e69.js.map"
      ]
    },
    "components/user": {
      "js": [
        "/packs/js/components/user-156f569cb5c8b04ee2e1.js"
      ],
      "js.map": [
        "/packs/js/components/user-156f569cb5c8b04ee2e1.js.map"
      ]
    },
    "main": {
      "js": [
        "/packs/js/main-f6918c73db91592ebf7f.js"
      ],
      "js.map": [
        "/packs/js/main-f6918c73db91592ebf7f.js.map"
      ]
    }
  },
  "main.js": "/packs/js/main-f6918c73db91592ebf7f.js",
  "main.js.map": "/packs/js/main-f6918c73db91592ebf7f.js.map"
}
):
    11: 
    12:   <body>
    13:     <%= yield %>
    14:     <%= javascript_pack_tag 'hello_vue' %>
    15:   </body>
    16: </html>

app/views/layouts/application.html.erb:14
^C- Gracefully stopping, waiting for requests to finish
=== puma shutdown: 2020-11-12 02:56:13 +0000 ===
- Goodbye!

ここにも書いてあるが、→https://github.com/rails/webpacker#vue
下のコマンドを上から実行していくと、エラーが解決しました。

./bin/rails webpacker:install
./bin/rails webpacker:install:vue
bin/webpack
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VScodeでDockerのコンテナから抜ける設定

はじめに

デバッグするときにDockerにattachした際、デタッチ(コンテナから抜ける)するときに
Ctrl+PCtrl + Qを使うと思います。

しかし、VScodeではすでにこれらのショートカットキーが登録されていてそちらが優先されてしまいます。
VScodemでデタッチできるように、VScodeのショートカットキーが効かないように設定を変更してみました。

設定

ショートカットを確認するとctrl+Pctrl+Qがすでに登録されていることが確認できます。
スクリーンショット 2020-11-12 16.02.01.png

VScodeのkeybindings.jsonに下記を記載します。(command+Pでファイル検索を開き、>keybindings.jsonと打つと開きます!)

すでに設定されているcommandに-をつけることでctrl+Pctrl+Qのショートカットキーを削除できます。

keybindings.json
{
    "key": "ctrl+P",
    "command": "-workbench.action.quickOpenSelectPrevious"
  },
  {
    "key": "ctrl+Q",
    "command": "-workbench.action.quickOpenView"
  }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby On Rails】createアクションとdestroyアクションにおいて、redirect_to action: :showができない(使えない)場合の緊急対策

備忘録です。
閲覧いただきありがとうございます。
走り書きのため、説明や記述に間違いなどあればご指摘お願いいたします。

背景

redirect_toで、action: :アクション名を指定してあげることで、そのコントローラー内のアクションを呼び出し実行することができることを学びました。

その学びを生かして、updateされた場合(つまり、編集が更新された場合)はredirect_to action: :showと記述することでshowアクションをリダイレクトすることができました。

  def update
    if @hoge.update(hoge_params)
      redirect_to action: :show
    else
      render :edit
    end
  end

問題点

しかし、createとdestroyアクションで、redirect_to action: :show ではエラーが出てしまいました。

  def create
    @hoge = Hoge.new(hoge_params)
    if @hoge.save
      redirect_to action: :show
    else
      render :new
    end
  end

(中略)

  def destroy
    if @hoge.destroy
      redirect_to action: :show
    else
      render :show
    end
  end

エラー文

ActionController::UrlGenerationError in HogesController#create
No route matches {:action=>"show", :controller=>"hoges"}

対策

rails routesでルーティングを検索し、Prefixのパスを記述し、必要であればkeyを渡してあげました。

  def create
    @hoge = Hoge.new(hoge_params)
    if @hoge.save
      redirect_to hoge_path(current_user.id)
    else
      render :new
    end
  end

(中略)

  def destroy
    if @hoge.destroy
      redirect_to hoge_path(current_user.id)
    else
      render :show
    end
  end

この様にすることで、createアクションで新規作成を行った場合や、destroyアクションで削除を行った後に、showと同じ画面へ遷移できました。

※以上の対策はあくまで緊急回避策であると考えています。(私が学習不足のため)

今後学習すべきこと

なぜ・何が原因で action: :showでリダイレクトできなかったのか、処理の流れを把握できる様にしていくこと。

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

【プロゲート学習後】form_tagと対比しながらform_withをまとめてみた

プロゲートからRailsチュートリアルへ学習を移行する人は多いのではないでしょうか。

プロゲートの中でもフォーム関連って難しいですよね。フォーム使って新規登録するのか、ログインするのか、この辺り本当に難しいです。

ただ、プロゲートはまだわかりやすく書かれています。

form_tagでフォームを作って、でデータ送信をし、そのデータをparamsで受け取る。非常にわかりやすい。

しかし、Railsを本格的に学び始めると、form_tagを使うことがなくなり、form_withを使います。この辺りからRailsの記述量が激減します。理解度も激減します。

本記事は、プロゲートからRailsチュートリアルのような学習ルートを辿っている人で、どうにもform_withが理解できない人向けです。

プロゲートの書き方と、Railsの書き方を対比しながら書いていこうと思います。

結論、プロゲートの書き方は、初学者むけに「一貫性のある書き方」を目指しているのだと思います。本来データベースに変更がある時、form_tagを使いません。form_forを使います。

プロゲートはform_tagヘルパーとinputタグを使った手作り感満載の作り方をする

プロゲートでよく使うform_tagで実装した場合は、非常に手作り感満載になります。

流れとしましては、

1.form_tagとinputタグでデータをコントローラに送信する。
2.createアクションでデータを受け取る
3.saveしてデータベースに書き込む

<%= form_tag("/users/create") do %>
  <p>ユーザー名</p>
    <input name="name" value="<%= @user.name %>">
  <p>メールアドレス</p>
    <input name="email" value="<%= @user.email %>">
    <input type="submit" value="新規登録">
 <% end %>

form_tagでパスを設定します。/users/createにパスを設定します。
この時、ルーティング(routes.rb)に、
post "users/create" => "users#create"

これが書かれていますよね。なので、users_controller.rbの中のcreateアクションが発動されます。createアクションの中身は以下です。

  def create
    @user = User.new(name: params[:name], email: params[:email])
    if @user.save
      flash[:notice] = "ユーザー登録が完了しました"
      redirect_to("/users/#{@user.id}")
    else
      render("users/new")
    end
  end

このようになっています。

流れは掴みやすいですよね。
フォームから送信したものをparamsで受け取り、それを@user.saveを使って保存しているので、1個1個論理的に理解できます。

ここからRailsチュートリアルに進むと、form_tagを使うことはなくなります。

なぜなら、プロゲートの書き方が例外的だからです。

データベースが絡む時はform_forを使う

プロゲートの書き方は使いません。
form_tagはデータベースに新規登録したり、編集したり、削除したりする時は使いません。

データベースを編集する時は、form_forを使います。

引数にモデルオブジェクト(@user=User.newのように、Userモデルに基づいて作られているオブジェクト(インスタンス)のこと)をとります。

form_tagの時は、:idからid情報を取り出して、データベースからレコードを見つけ出し、その情報を編集するという面倒なことをやっていました。

このような過程がありました。

しかし、Railsのすごいところは、@userにユーザーIDも自動s

Railsはブラックボックス化が激しいので、

form_tagで送信先を指定する。

プロゲートでのRuby on Railsでform関連のヘルパーを使う時は、form_tagを使いましたよね。

その時に、僕がどん詰まったのが、省略のおおさ。プロゲートは、とにかく全て書きますよね。フォーム

form_withとは?

form_withとは、form_tagform_forが合体したものですね。
form_tagはパスを指定していました。
form_forはモデルオブジェクト(モデルから作られたインスタンス)を指定していました。

この両方を使えるようになったのが、form_withですね。

form_tagだと、

<%= form_tag 'パス' do %>
  <input・・・・
  <input・・・
<% end %>

と書くのに対して

form_forは、

<%= form_for(@user) do |f| %>
  <%= f.text_field :name %>
  <%= f.submit %>
<% end %>

このように、同じようなフォームなのに、書き方が違うのは面倒臭い。
全部form_withにして書き方を統一しようってことで、1個になりました。

ただ、プロゲートを学んできた人は、form_tagを学習してきたので、

「え? formの引数になんでモデルなの?」

と戸惑ってしまいます。われわれは、アクションを設定して、やってきましたから。

これのすごいところは、form_with model: @userとmodelは、勝手に気を利かせて

form_tagでやると、アクションを指定してましたよね。

<%= form_tag("/users/create") do %>この部分です。createアクションを指定しています。

しかし、model: @userという書き方の時は、

新規ユーザー登録をする時は、勝手に、
newアクションを呼び出してくれるし、

このように、勝手に気を利かせて呼び出すアクションを変えてくれるんです。
Railsはこういう、手間を省いてくれる機能が盛り沢山です。

まず、URLから :id 情報を受け取りますよね。
そして、そのid情報からユーザーを特定

この:idをとってくる作業が全部不要です。実は本来Railsは全て自動でやってくれます。
ただ、プロゲートは、初期学習で全てぶっ飛ばして、

「よくわからないけど、全部Railsがやってくれます」

だと、理解しにくいので、ここをしっかり解説してくれているのです。

まとめ

・form_tagはデータベースに変更がない場合に使う
・form_forはデータベースを更新が伴うフォームを作る時に使う
・form_withで両方の役割を担える

Railsはめっちゃ気を利かせてくれます。勝手に色々やってくれます。

「言われなくてもやっといたよ」

って言ってきます。でも、最初のころ

「え、なんでそう判断したんですか?」

って疑問に思うこともあるでしょう。僕もまだまだRailsの気の利かせっぷりに戸惑うばかりです。

ですが、多分使いこなせるようになると、これほど便利で頼れる存在はいないと思います。頑張って使いこなせるように、頑張りましょう。

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

Q.エレベーター(Ruby編)

エレベーターの階数計算の問題(Ruby編)

問題

エレベーターが何階分の距離を動いたか計算するプログラムを完成させてください。
ただし、エレベーターは最初は必ず 1 階にいるものとします。

1階から3階へ → 2階分移動したことになるので合計2階分
3階から1階へ → 2階分移動したことになるので合計4階分
1階から4階へ → 3階分移動したことになるので合計7階分

入力される値

入力は以下のフォーマットで与えられます。

N
f_1
...
f_N
・1 行目にログの行数を示す整数 N が入力が与えられます。
・続く N 行にエレベーターが止まった階 f_i (1 ≦ i ≦ N) が整数で順に入力されます。
・入力は合計で N+1 行であり、最終行の末尾に改行が 1 つ入ります。

期待する出力

エレベーターが何階分を動いたかを整数で出力してください。

入力例1

3
3
1
4

出力例1

7

私の答え(有志のサイトをみて参考にしました)

n = gets.to_i
i = 1
s = 0
n.times {
    a = gets.to_i
    s += (a - i).abs
    i = a
}
puts s

これで出力結果に間違いはないのですが、{}の中身がいまいち理解できていませんので記事にしました。n.timesで任意の入力値分繰り返される訳ですが6行目のs += (a - i).absがなぜこうなるのかは分かりませんでした。仮に任意の数を全て当てはめてみると、「0 += (3 - 1).abs」となりました。全く意味不明です。また、7行目のi = aというのは当てはめると 1 = 3 みたいになるのですがなぜこうなるのだろう。今回のように任意の入力値がいくつあるかわからない場合のgets.to_iを繰り返す処理をかなり調べてみたが該当サイトはなかなか少なく、初学者の私にとっては難しいコードでした。一つ一つのメソッドは分かるが、プログラミング脳になっていないせいか、今回の6.7行目のようなコードが自分の知識だけではまだまだ書けないという事が分かりました。でも分からないからそこに楽しさがあるという事も。

以上!

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

【Rails】テーブルの作成、カラムの追加、カラムの型の変更方法

はじめに

ポートフォリオを作成していて、あとからカラムを追加したいときや、最初に設定したカラムの型を変更したいときに、どうすればよいのか分からなかったことがあったので、初学者なりに初学者がみてもわかりやすいようにまとめました。
(最初は既にあるマイグレーションファイルに直接追加や変更を加えればよいと思っていました。しかしそれは正しくないので、新たに別のマイグレーションファイルを作成して追加や変更する方法を記述していきます。)

モデルとテーブルの作成

下記のコマンドによりモデルを作成すると、モデルと一緒にこのモデルが担当するテーブルを作成するためのマイグレーションファイルが自動で作成されます。

$ rails g model [モデル名] [カラム名]:[カラムの型]

例えば、Userモデルを作成したい場合、[モデル名]にUser、[カラム名:カラムの型]にはname:string email:stringを指定します。コマンドは以下のようになります。

$ rails g model User name:string email:string

コマンドを実行すると以下のようなマイグレーションファイルが作成されます。

db/migrate/XXXXXXXXXXXXXX_create_users.rb
class CreateUsers < ActiveRecord::Migration[6.0]
  def change
    create_table :users do |t|
      t.string :name
      t.string :email

      t.timestamps
    end
  end
end

上記ファイルが生成されたのを確認し、次のコマンドでマイグレーションを実行します。

$ rails db:migrate

これでUsersテーブルが作成されました。

カラムの追加

既に作成したテーブルにカラムを追加したい場合は、既存のマイグレーションファイルに直接書き込むのではなく、新たにマイグレーションを作成して追加します。

カラムを追加する為のマイグレーションファイルの作成は次のコマンドになります。

$ rails g migration Add[カラム名]To[テーブル名] [カラム名]:[カラム型]

例えば既にあるusersテーブルにintroductionカラム(text型)を追加したい場合は以下になります。

$ rails g migration AddIntroductionToUsers introduction:text

コマンドを実行すると以下のようなマイグレーションファイルが作成されます。

db/migrate/XXXXXXXXXXXXXX_add_introduction_to_users.rb
class AddIntroductionToUsers < ActiveRecord::Migration[6.0]
  def change
    add_column :users, :introduction, :text
  end
end

上記ファイルが生成されたのを確認し、次のコマンドでマイグレーションを実行します。

$ rails db:migrate

これでusersテーブルにintroductionカラム(text型)が追加されました。

カラムの型の変更

既にあるテーブルのカラムの型を変えたいときは、カラム追加と似た手順で変更することができます。

カラムの型を変更する為のマイグレーションファイルの作成は次のコマンドになります。

$ rails g migration change_data_[カラム名]_to_[テーブル名]

例えば既にあるproductionsテーブルのmaterialカラムの型を変更したい場合は以下になります。

$ rails g migration change_data_material_to_productions

コマンドを実行するとマイグレーションファイルが作成されるので、変更したいカラムの型を追記します。
例えば、productionsテーブルのmaterialカラムの型をinteger型に変更したい場合は以下のように追記します。

db/migrate/XXXXXXXXXXXXXX_change_data_material_to_productions.rb
class ChangeDataMaterialToProductions < ActiveRecord::Migration[6.0]
<!-- ***** 以下を追加 ***** -->
  def change
    change_column :productions, :material, :integer
  end
<!-- ***** 以上を追加 ***** -->
end

追記が完了したら、次のコマンドでマイグレーションを実行します。

$ rails db:migrate

これでproductionsテーブルのmaterialカラムの型がinteger型に変更されました。

最後に

この記事は初学者がポートフォリオ作成中に学んだ事を初めてQiitaにまとめました。

内容的に間違いがあればぜひコメントいただけると嬉しいです。

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

deviseの実装の自分まとめ

?初めての投稿です。

?インプット回数は多くアウトプットに時間を費やしていないことに気づき
思考整理のため定期的に書いていこうと思います。
現在ポートフォリオ作成中でdeviseの実装をまとめてみました!

手順


1.$gem install rails -v5.2.3
(railsの最新版 gemをインストールする)

2.$rails -v
(バージョン確認を行いインストールできているのか確認)

3.$rails new アプリケーション名


4.$cd アプリケーション名
(ディレクトリ移動を行う)

5.$rails s
(作成したアプリケーションのサーバーが動いているのか確認)

6. gem 'devise'
(gemfileに追記する deviseというgemを使うということ)

7. $ bundle
(追記したgemを保存する)

8. $ rails g devise:install
(deviseをインストールする)

→ これによりログイン?ログアウト?の機能の箱が出来上がった

→ しかし機能を使うための部品、ものがないので揃えていく(イメージ)

9. $ rails g devise:views
(deviseで生成された機能ファイルに対しファイルを作成する(イメージ))

10. $ rails g devise User
(deviseのなかにUserクラスのデータを作っていくためのもの(イメージ))

→ routes.rbにdevise_for :usersが追記される

→ modelsファイル・migrateファイルが生成される
(migrateファイル=>usersテーブル生成され、devise機能に組み込まれているカラムがすでに記述されている)

→マイグレーションにカラムを追加すること可能
usersはユーザに必要な情報を管理するのでユーザに関する情報は追記していく
(生年月日など)


11. $rails db:migrate
(これにより$rails g devise Userで生成されたデータベース関連のものが読み込まれて、
追記したカラムもデータベースに反映される)

12. $rails g devise:controllers users
(コントローラーの追加を行う)
→deviseのクラスを継承したコントローラファイルを作成する
(デフォルトのコントローラのままだと追加した機能のアクション実行が行えないため、
デフォルトを継承したUserコントローラーを作成している)
(viewsに対応したものが作られる)

13.下記を追記しルーティング設定を行う
(○のように書き直す)
devise_for :users

○devise_for :users, :controllers => {
:registrations => 'users/registrations',
:sessions => 'users/sessions'
}

ここまでが機能を実装のみの工程です!
あとはhome topを作成していき実際に画面表示します

余談ープログラミングを実装していくだけではなく、わかりやすく伝える質問する力、語彙力、PCの様々な機能の使い方などプロブラミング以外にも必要なことがたくさんあり日々学びが多く、苦戦する日々ですが技術だけでは無くいろんな力を身につけてコツコツがんばれたらいいなと思いました。

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

Rails API

はじめに

RailsのAPIモードを利用してAPIを作成する手順をまとめました。

手順

1. APIモードでRailsアプリの作成
2. モデル・コントローラの作成
3. 名前空間を意識したルーティングの設定
4. コントローラの設定
5. ブラウザで確認

APIモードでRailsアプリ作成

$ rails new api-task --api

通常のrails newコマンドの末尾に--apiをつけることでAPIモードでアプリを作成することができます。
(APIに必要ない部分をデフォルトで作成しなくなります。)

モデル・コントローラーの作成

通常のRailsアプリ同様モデルとコントローラを作成します。

rails g model category name:string
rails g model idea category_id:bigint body:text
$ rails db:create
$ rake db:migrate

名前空間を意識したルーティングの設定

最初から以下の様にバージョンで名前空間を作成しておくことで今後のAPIのバージョン管理が容易になります。

config/routes.rb
Rails.application.routes.draw do
  namespace 'api' do
    namespace 'v1' do
      resources :posts
    end
  end
end

コントローラーの設定

ルートで設定した名前空間に合わせてディレクトリの構成は以下のようになります。

---- controllers

      --- api

        -- v1

         - ideas_controller.rb
         - categories_controller.rb

スクリーンショット 2020-11-10 20.29.40.png

class IdeasController < ApplicationController
  def index
    @ideas = Idea.all

     render json: @ideas
  end

  def create
     @idea = Idea.new(idea_params)

    if @idea.save
      render json: @idea, status: :created, location: @idea
    else
      render json: @idea.errors, status: :unprocessable_entity
    end
  end


  private

  def idea_params
    params.require(:idea).permit(:catagory_id,:body)
  end
end

class CategoriesController < ApplicationController
  def index
  end

  def create
    @category = Category.new(idea_params)

    if @category.save
      render json: @category, status: :created, location: @category
    else
      render json: @category.errors, status: :unprocessable_entity
    end
  end

  private

  def category_params
    params.require(:category).permit(:name)
  end
end

ブラウザで確認

Ideaをいくつか作成してブラウザで確認
Get(http://localhost:3000/api/v1/ideas)

スクリーンショット 2020-11-12 11.03.30.png

上記のように表示されればOK!!

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

[Rails]バリデーションのエラーメッセージを非同期通信で実装してみた!

Railsと日々格闘している「超」がつく初心者です。
自分自身の知識の整理のために、共有します。

はじめに

先日、Railsでの非同期通信の実装を学んだのですが、自分の中で消化し切れていない部分があったので、理解を深めるためにも、アウトプットします!
ユーザーオススメの本を投稿するサイトを想定しており、投稿された本に対して、コメントができます。
 ※コメント機能の非同期通信自体は、このページではあまり解説していません。

今回は、コメント欄を空欄で送信ボタンを押してしまった時に、エラーメッセージがコメント欄の真上に出るようにして、かつ、エラーメッセージ自体を非同期通信で実装してみよう、というものです。
それでは早速いきましょう!

バリデーション

models/comment.rb
class BookComment < ApplicationRecord

  belongs_to :user  #Userモデルに紐付け
  belongs_to :book  #Bookモデルに紐付け

  validates :body, presence: true, length: {maximum: 150}
end

コメントモデル内にて、presence: trueを設定したことにより、空欄での投稿を禁止しました。
ついでに、length: {maximum: 150}も併せて設定しています。

さっそく、コントローラーを確認していきましょう!

Commentsのコントローラー

comments_controller.rb
class BookCommentsController < ApplicationController
  before_action :authenticate_user!  #ログイン済ユーザーのみにアクセスを許可する

  def create
    @book = Book.find(params[:book_id])
    @comment = Comment.new(comment_params)  #このタイミングでバリデーションチェックがかかる!
    @comment.book_id = @book.id
    @comment.user_id = current_user.id
    unless @comment.save  #@commentがsaveできなかった場合、
      render 'error'      #comments/error.js.erbを呼び出している(後述)
    end
  end

  private
  def comment_params
    params.require(:comment).permit(:comment)
  end
end

パラメーターを通ってきた値を使用して、newメソッドとsaveメソッドでデータベースに登録しています。
その際に、外部キーであるbook_idとuser_idはパラメーターでは入手ができないので、このタイミングで設定をしてあげています。
まあ、ここまでは大丈夫ですかね。

ここで大事なのは、バリデーションチェックはデータベースに保存される直前にされるので、エラー文で取得するインスタンス変数は
@comment = Comment.new(comment_params)
であるということです。
つまり、パラメータを通過してきた値それ自身に対して、エラーを含んでいるかどうかをチェックしているのです。

続いては、コメント欄はBookの詳細ページに入っているので、Booksのコントローラを確認しましょう!

Booksのコントローラー

books_controller.rb
class BookController < ApplicationController
  before_action :authenticate_user!  #ログイン済ユーザーのみにアクセスを許可する

  def show
    @book = Book.find(params[:id])
    @comment = Comment.new  #Commentsコントローラーに値を渡す為のnewメソッド
  end
end

ここも特に問題ないでしょう!
折り返し地点に到達しました。
このペースで、Bookの詳細ページを確認していきましょう!

Booksのshowページ

app/views/books/show.html.erb
  <div id="comments_error">
    <%= render 'layouts/errors', model: @comment %>
  </div>

  <%= form_with model:[@book,@comment] do |f| %>
    <%= f.text_area :comment %>
    <%= f.submit '送信'%>
  <% end %>

前半のcomments_errorの部分に、layoutsの_errors.html.erbをrenderで呼び出しています。

また、form_withを利用して、コメント入力欄を設けているのですが、非同期通信を設定したいので、local:trueは記述せずにおきます。
尚、form_withの場合はデフォルトで非同期通信になるので、remote: trueをあえて記述する必要はありません。

エラーメッセージのパーシャル部分

app/views/layouts/_errors.html.erb
<% if model.errors.any? %>
  <div id="error_explanation">
    <h3>
      <%= pluralize(obj.errors.count, "error") %> prohibited this model from being saved:
    </h3>

    <ul>
      <% model.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
    </ul>
  </div>
<% end %>

Booksのshowページからrenderで呼び出していたのを覚えていますか。
いよいよ、エラーメッセージの登場です。
errors.full_messagesは全てのエラーメッセージを配列で取得しています。
複数のエラーに引っかかっていることも想定されるので、eachメソッドでループ処理をかけています。
このエラー文はデフォルトで入っているものなので、コメント欄以外にも様々な場面で利用できます。

エラーメッセージの非同期通信で使用するjsファイル

app/views/comments/error.js.erb
$("#comments_error").html("<%= j(render 'layouts/errors', model: @comment) %>");

books/show.html.erbの中で、id="comments_error"の箇所を書き換える処理になります。
$("#comments_error")id = "comments_error"をターゲットとし、render 'layouts/errors'で指定しているlayouts/_errors.html.erbの内容で書き換えています。

なお、ここでmodelに渡している@commentですが、これはどこで定義しているものか分かりますか?
jsファイルは、Commentsコントローラーで呼び出していましたね。
つまり、Commentsコントローラー内の、createアクションで定義している、
@comment = Comment.new(comment_params)
layouts/_errors.html.erbに渡しているのです。

う〜ん、ややこしい!!

(補足)コメント機能自体のjsファイルも記載しておきます

app/views/comments/create.js.erb
$(".comments").html("<%= j(render 'comments/index', book: @book) %>");
$("#comment_comment").val("");

画面のイメージ図

非同期通信を実装したことにより、
image.png
このまま、空欄でコメントを送信しようとすると、
image.png
と、目論見通り怒られてしまいました。
ということはこれで、非同期通信を利用したエラーメッセージの完成!
メッセージ文を日本語に変換したりもできるのですが、誌面の都合上、またの機会に。

おわりに

非同期通信は、コントローラーとか、ページ間遷移とかが多くって、非常にこんがらがりますよね。
何度か読み返してもらえれば、理解に近づけるかと思います。
自分の中で、処理の流れを腹落ちさせれば、実装にかかる時間をどんどん短く出来るかもしれません。
拙文失礼いたしました。
一緒に勉強頑張りましょう!

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

Rails でフォーム送信時のプルダウンメニューの項目をCSV インポートしてDB のデータから表示したい

はじめに

Rails でフォーム送信時のプルダウンメニューの項目をCSV インポートしてDB のデータを使って表示する為の備忘録です。

環境

  • macOS 10.15.6
  • Ruby 2.5.7
  • Rails 5.2.3

参考URL

CSV インポート関連
https://qiita.com/Ryuta1346/items/c21cb70b9879c66c8639
https://qiita.com/SoarTec-lab/items/50e046ea2a2764c12c21
https://docs.ruby-lang.org/ja/latest/class/CSV.html
https://qiita.com/3yatsu/items/416411c0a8f696dbf99e
https://qiita.com/rllllho/items/672e336a03335cba6b34

プルダウンメニュー関連
https://qiita.com/HrsUed/items/56677d6c266d8a53ffa7
https://qiita.com/kawakami_shotaro/items/11a677bf34136cb7686d
https://qiita.com/colorrabbit/items/b58888506e41d1370fd1
https://crieit.net/posts/Rails-collection-select
https://qiita.com/_akira19/items/c218186983f444c2d794

国コード一覧CSV
https://qiita.com/tao_s/items/3yy2b90a2751bfbdd585ea

目標

  1. プルダウンメニューの選択肢をCSV インポートする
  2. プルダウンメニューの選択項目をDB のデータを使い表示する

見た目のイメージです↓
form1.png

プルダウンメニューの選択肢はDB に保存しているカラムの情報を使って表示します↓
form2.png

実装

CSV インポートとフォームのプルダウン化を分けて解説します。

1. プルダウンメニューの選択肢をCSV インポートする

  1. 国名一覧保存用にCountry モデル作成
  2. db/seeds.rb にインポート処理を追加
  3. rails コマンドでインポート処理を実行

Ruby のCSV ライブラリを使用してインポート処理を行います。
今回は以下のようなCSV から国名一覧をインポートしました。
作成したCSV ファイルはルートディレクトリに追加しました。

country.csv
番号,国・地域名,ISO 3166-1に於ける英語名,数,三字,二字,場所,各行政区分
1,アイスランド,Iceland,352,ISL,IS,北ヨーロッパ,ISO 3166-2:IS
2,アイルランド,Ireland,372,IRL,IE,西ヨーロッパ,ISO 3166-2:IE

CSV は国コード一覧CSV を使わせて頂きました。

1. Country モデル作成

下記のようなモデルを作成しました。
region カラムは今回は使っていません。

attribute type
country_name string
region string
# Country モデル作成
$ rails g model Country country_name:string region:string

2. インポート処理を追加

インポート処理はseeds.rb に追記しました。
別途ファイルを作成しrunner コマンドで実行する方法もあるようです。

seeds.rb
require "csv"

# CSV ファイルへのパスは絶対パスで指定
CSV.foreach("country.csv", headers: true) do |row|
  Country.create!(
    country_name: row["国・地域名"],
    region: row["場所"]
  )
end

3. インポート処理を実行

rails コマンドでCSV インポートを実行します。
seed ファイルに他の処理も書いていたので今回はDB 内を全削除してインポートし直しました。

# CSV をインポートしてDB に保存する場合はこれだけ
$ rails db:seed

# DB を消去して全て入れ直す
$ rails db:migrate:reset
$ rails db:seed

# rails コンソールでインポートされたか確認
$ rails c
# インポートした国名の件数を確認
> Country.count
249

2. プルダウンメニューの選択項目をDB のデータを使い表示する

新規投稿時のフォーム送信のView ファイルを修正します。

view/model_names/new.html.erb
# 修正前
<%= form_with model: @model_name do |f| %>
  <%= f.label :country %>
  <%= f.text_field :country %>

  <%= f.submit "送信" %>
<% end %>
view/model_names/new.html.erb
# 修正後
<%= form_with model: @model_name do |f| %>
  <%= f.label :country %>
  <%= f.collection_select :country, Country.all, :id, :country_name, prompt: "国を選択してください" %>

  <%= f.submit "送信" %>
<% end %>
# collection_select の文法
<%= f.collection_select <保存先のカラム名>, <表示用の配列データ>, <保存する値のカラム名>,  <表示用のカラム名>, <オプション> %>
  • 保存先のカラム名: country
  • 表示用の配列データ: Country.all
  • 保存する値のカラム名: id
  • 表示用のカラム名: country_name
  • オプション: prompt オプションで国を選択してくださいを表示

collection_select の使い方についてはこちら解説が非常に分かりやすいです。

学び

  • 検索などその後の処理も考慮してインポートを行う
  • 選択肢が縦に長くなってしまうので、階層を持たせるなどして使いやすさを考慮した使用に変更したい
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RailsでPayjpを使った際の環境変数の設定方法

環境

macOS
Ruby 2.6.5
Rails 6.0.3.2

概要

RailsアプリケーションでPayjpを使用しました。
その際に環境変数の設定方法がわからなかったので備忘録として残しておこうと思います。

達成したいゴール

Payjpを通して環境変数の取り扱いができるようになること。

解決したい問題

秘密鍵や公開鍵をコードに直張りするのはセキュリティの都合上よくありません。
そのため、環境変数を用いて秘密鍵と公開鍵を取り扱ってみたいと思います。

環境変数

環境変数は、Railsからは ENV['<環境変数名>'] という記述でその値を利用することができます。

ローカル環境

Catalina以降であれば、

ターミナル
アプリケーション名 % vim ~/.zshrc

Catalina以前であれば、

ターミナル
アプリケーション名 % vim ~/.bash_profile

ターミナルにて上記を実行。

.zshrc
//まず「i」を押して入力モードにします
export PAYJP_ACCESS_KEY='sk_test_*************'
export PAYJP_PUBLIC_KEY='pk_test_*************'
// その後、escキーを押して:wqで.zshrcから抜けます

アプリケーション名 % source ~/.zshrc

sourceコマンドは、ファイルに書かれたコマンドを現在のシェルで実行するというコマンドです。
主にシェルの設定ファイルを反映させる際に使用します。

環境変数を変えただけでは、railsは変更前の環境変数しか読み込みません。
そのため、アプリケーションを起動している場合には一度終了します。
そして、環境変数を修正したターミナルで再度、rails sでログインし直します。

設定した環境変数を扱うためにはコントローラーに下記のような形で記載していきます。

creditcards_controller.rb
# クレジットカードの保存
  def create
    Payjp.api_key = ENV["PAYJP_PRIVATE_KEY"]
    if params['payjp-token'].blank?
      render :new
    else
      customer = Payjp::Customer.create(
        card: params['payjp-token'],
        metadata: {user_id: current_user.id}
      )
      @card = Creditcard.new(
        user_id: current_user.id,
        customer_id: customer.id,
        card_id: customer.default_card
      )
      if @card.save
        redirect_to root_path, notice: "クレジットカードが登録されました"
      else
        render :new, notice: "クレジットカードの登録に失敗しました"
      end
    end

上記の例文は、フォームに入力したクレジットカード情報をトークン化して保存するための処理です。

本番環境

また、ローカル環境と本番環境では、環境変数を設置するファイルが異なります。

ターミナル
[ec2-user ~]$ sudo vim /etc/environment
/etc/environment
//まず「i」を押して入力モードにします
PAYJP_ACCESS_KEY='sk_test_*************'
PAYJP_PUBLIC_KEY='pk_test_*************'
// その後、escキーを押して:wqで/etc/environmentから抜けます
exit
// 再度sshでec2にログイン

ローカル環境同様、環境変数を設定・修正した際にはunicornの再起動、もしくは再デプロイが必要となります。

終わりに

この記事が少しでもお役に立てる内容になっている幸いです。

参考:
https://wa3.i-3-i.info/word11788.html
https://qiita.com/Richelieu/items/b872dfce81124084b199#%E7%92%B0%E5%A2%83%E5%A4%89%E6%95%B0%E3%81%AB%E6%9B%B8%E3%81%8D%E8%BE%BC%E3%82%80
https://qiita.com/suzy1031/items/7964829086eb929471a6

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

IE11にJavaScriptを対応させるためにしたことまとめ

急にIE11対応を頼まれた

JavaScript初心者の私が、IE11対応を頼まれて苦戦した箇所をまとめます。
修正前と修正後のコードを載せたので、参考になれば嬉しいです。

アロー関数

該当のコード

$button.click((event) => {
    alert('ボタンを押しました');
});

// => SCRIPT1002: 構文エラーです。

修正後のコード

$button.click(function(event) {
    alert('ボタンを押しました');
});

テンプレートリテラル

バッククォートで囲んだ文字列の中で変数展開させるやつ

該当のコード

const age = 20
console.log(`私の年齢は${age}です。`);

// => SCRIPT1014: 文字が正しくありません。

修正後のコード

const age = 20;
console.log('私の年齢は' + age + 'です。');

// => 私の年齢は20です。

isNaN

引数が非数かどうか評価するメソッドらしい

該当のコード

const int = 1000;
console.log(Number.isNaN(int));

// => SCRIPT438: オブジェクトは 'isNaN' プロパティまたはメソッドをサポートしていません。

修正後のコード

const int = 1000;
console.log(isNaN(int));

// => false

.find()

該当のコード

const fruits = ['Apple', 'Orange', 'Banana']
if(fruits.find(function (fruit) {return fruit === 'Grape'})) {
  console.log('りんごだよ!');
}else {
  console.log('りんごじゃないよ!');
}

// => SCRIPT438: オブジェクトは 'find' プロパティまたはメソッドをサポートしていません。

修正後のコード

const fruits = ['Apple', 'Orange', 'Banana']
if(fruits.filter(function (fruit) {return fruit === 'Grape'})[0]) {
  console.log('りんごだよ!');
}else {
  console.log('りんごじゃないよ!');
}

// => りんごじゃないよ!

バージョン情報

IE: 11.418.18362.0

「もっとこうした方がいいよ!」とか「こういう書き方もあるよ!」とか、アドバイスがあればコメントしてくださいm(_ _)m

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

JavaScriptをIE11対応させるためにしたことまとめ

急にIE11対応を頼まれた

JavaScript初心者の私が、IE11対応を頼まれて苦戦した箇所をまとめます。
修正前と修正後のコードを載せたので、参考になれば嬉しいです。

アロー関数

該当のコード

$button.click((event) => {
    alert('ボタンを押しました');
});

// => SCRIPT1002: 構文エラーです。

修正後のコード

$button.click(function(event) {
    console.log('ボタンを押しました');

// => ボタンを押しました
});

テンプレートリテラル

バッククォートで囲んだ文字列の中で変数展開させるやつ

該当のコード

const age = 20
console.log(`私の年齢は${age}です。`);

// => SCRIPT1014: 文字が正しくありません。

修正後のコード

const age = 20;
console.log('私の年齢は' + age + 'です。');

// => 私の年齢は20です。

isNaN

引数が非数かどうか評価するメソッドらしい

該当のコード

const int = 1000;
console.log(Number.isNaN(int));

// => SCRIPT438: オブジェクトは 'isNaN' プロパティまたはメソッドをサポートしていません。

修正後のコード

const int = 1000;
console.log(isNaN(int));

// => false

.find()

該当のコード

const fruits = ['Apple', 'Orange', 'Banana']
if(fruits.find(function (fruit) {return fruit === 'Grape'})) {
  console.log('りんごだよ!');
}else {
  console.log('りんごじゃないよ!');
}

// => SCRIPT438: オブジェクトは 'find' プロパティまたはメソッドをサポートしていません。

修正後のコード

function sample(arg) {
    const fruits = ['Apple', 'Orange', 'Banana']
    if(fruits.filter(function (fruit) {return fruit === arg})[0]) {
      console.log('くだものだよ!');
    }else {
      console.log('くだものじゃないよ!');
    }
}

sample('Banana')
sample('Tomato')

// => くだものだよ!
// => くだものじゃないよ!

2020/11/12追記

indexOfの方がわかりやすく書ける

function sample(arg) {
    const fruits = ['Apple', 'Orange', 'Banana']
    if(fruits.indexOf(arg) !== -1) {
      console.log('くだものだよ!');
    }else {
      console.log('くだものじゃないよ!');
    }
}

sample('Banana')
sample('Tomato')

// => くだものだよ!
// => くだものじゃないよ!

@il9437さんご指摘ありがとうございますm(_ _)m

バージョン情報

IE: 11.418.18362.0

「もっとこうした方がいいよ!」とか「こういう書き方もあるよ!」とか、アドバイスがあればコメントしてくださいm(_ _)m

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

【Rails】Googleアナリティクスを導入する方法【簡単】

今回開発し、リリース間近のWebサービスでデータ収集するために、Googleアナリティスクスを導入したのでその方法を紹介します。
google-analytics-railsというgemがありそちらを使う方法もあるのですが、githubで見てみると2017年の10月あたりで更新が止まっており(一応先月にReadmeは更新されてた)、不安だったので今回はgem無しで導入しました。

【前提条件】
・Googleアナリティクスに登録していること。(登録方法はこちら

導入方法

Googleアナリティクス用の部分テンプレートを用意し、headタグで読み込むだけです。

layauts/_google_analytics.html.haml
%script{async: "", src: "https://www.googletagmanager.com/gtag/js?id=トラッキングID"}
:javascript
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());

  gtag('config', 'トラッキングID');
  if (#{raw current_user.to_json}) {
    gtag('set', {'user_id': #{raw current_user.to_json}.id});
  }
application.html.haml
!!!
%html
  %head
    %meta{:content => "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}
    = stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'
    = javascript_pack_tag 'application', 'data-turbolinks-track': 'reload'
    - if Rails.env.production?
      = render 'layouts/google_analytics'

ここでポイントになるのが、最後のif 文で、これはログインしている場合はcurrent_userをjsonに変換してデータを渡して上げているという点です。
また、エスケープ処理を回避させるためにActionView::Helpers::OutputSafetyHelperのrawメソッドを使っています。html_safeでも同じことができますが、nilだった場合に例外が発生してしまうのでrawメソッドが推奨されているようです。(Railsガイドを見てみると、To insert something verbatim use the raw helper rather tha calling html_safe:とあります。)

参考

https://qiita.com/t1gert1ger/items/b9a197e2d85050b9d7d6

最後まで読んでいただきありがとうございます!

日々学んだことをアウトプットしてます!何かのお役に立てれば幸いです。ご指摘などあればコメントいただけますと幸いです。

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