20210213のRubyに関する記事は18件です。

管理者権限付与後、本番環境にrails db:seedをするまで(Active Storageも含む)

はじめに

管理者権限の付与方法については以下記事に記載しております。

https://qiita.com/narimiya/items/8d21b18db9c75b1dde2d

前提

●管理者権限機能は実装済み

●usersテーブルの情報

XXX_devise_create_users.rb
〜省略〜

      t.string  :email,                null: false, default: ""
      t.string  :encrypted_password,   null: false, default: ""
      t.string  :nickname,             null: false
      t.text    :occupation,           null: false
      t.text    :position,             null: false
      t.date    :birth_day,            null: false
      t.integer :sex_id,               null: false
      t.boolean :admin,                default: false

〜省略〜

バージョン

rubyのバージョン ruby-2.6.5
Railsのバージョン Rails:6.0.0

gemについて

・gem 'devise'
・gem 'rails_admin', '~> 2.0.0.beta'
・gem 'cancancan'

記事の内容

管理者についての情報をseeds.rbに記述し、本番環境にてseeds.rbの内容を
反映するまでの手順を述べています。

実装の全体像

●ローカル環境
①seeds.rbの記述
②rails db:seedの実行

●gitにてマージ

●本番環境
④デプロイ
⑤heroku run rails db:seedの実行

実装の手順

①seeds.rbの記述

Active Storageでimageカラムを取り込んでいるので、usersテーブルにimageカラムをattachする。
※seeds.rb内の一番下の記述
(なお画像についてはimageカラムと定義している。)

db.seeds.rb
user = User.create!(email: "admin@example.jp",
  password:  "abcd1234",
  password_confirmation: "abcd1234",
  nickname:  "管理者",
  occupation: "管理者",
  position: "管理者",
  birth_day: "2000-10-10",
  sex_id: "2",
  admin: true)

  user.image.attach(io: File.open(Rails.root.join("app/assets/images/homekatajiten.png")), filename: "homekatajiten.png")

②rails db:seedの実行

rails db:seedを実行して初期データを投入する。

$ rails db:seed

③デプロイ

$ git push heroku master

④heroku run rails db:seedの実行

本番環境にもlocal同様の初期データを投入する。

$ heroku run rails db:seed

確認

最後は反映されているか確認を行う。

$ heroku open

実行できていれば管理者アカウントでログイン後、(本番環境URL)/adminで以下のような画面になっていれば成功です。

image.png

以上です。

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

【Railsチュートリアル】第7章 ユーザー登録①

第7章 ユーザー登録

はじめに

本章の目的

  • ユーザー登録機能の追加
  • HTML フォームを使ってWebアプリケーションに登録情報を送信
  • ユーザーを新規作成して情報をデータベースに保存
  • ユーザーを表示するためのページを作成
  • 統合テストに対して、 いくつかのテストを追加

7.1 ユーザーを表示する

本節では、ユーザーの名前とプロフィール写真を表示するためのページを作成していく。
ユーザープロフィールページの最終的な目標は、ユーザーのプロフィール写真と基本ユーザーデータ、そしてマイクロポストの一覧を表示すること。

7.1.1 デバッグとRails環境

レイアウトにデバッグ情報を追加する。

app/views/layouts/application.html.erb
      #もしRails.env.development(development=開発環境)だったらデバッグ情報を表示せよ
      <%= debug(params) if Rails.env.development? %>

演習 1

ブラウザから /about にアクセスし、デバッグ情報が表示されていることを確認してください。このページを表示するとき、どのコントローラとアクションが使われていたでしょうか?paramsの内容から確認してみましょう。

debug_info
--- !ruby/object:ActionController::Parameters
parameters: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
  controller: static_pages
  action: about
permitted: false

コントローラ: static_pages, アクション: about

演習 2

Railsコンソールを開き、データベースから最初のユーザー情報を取得し、変数userに格納してください。その後、puts user.attributes.to_yamlを実行すると何が表示されますか? ここで表示された結果と、yメソッドを使ったy user.attributesの実行結果を比較してみましょう。

console
>> user = User.first
   (3.6ms)  SELECT sqlite_version(*)
  User Load (3.4ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> #<User id: 1, name: "Michael Hartl", email: "michael@example.com", created_at: "2021-02-09 06:34:49", updated_at: "2021-02-09 06:34:49", password_digest: [FILTERED]>

>> puts user.attributes.to_yaml
---
id: 1
name: Michael Hartl
email: michael@example.com
created_at: !ruby/object:ActiveSupport::TimeWithZone
  utc: &1 2021-02-09 06:34:49.836041000 Z
  zone: &2 !ruby/object:ActiveSupport::TimeZone
    name: Etc/UTC
  time: *1
updated_at: !ruby/object:ActiveSupport::TimeWithZone
  utc: &3 2021-02-09 06:34:49.836041000 Z
  zone: *2
  time: *3
password_digest: "$2a$12$c6TWZz21VWw7m8bDorgz9uR3XMXaWbMdtzmV.r6krzwzy59OmF7gO"
=> nil

>> y user.attributes
---
id: 1
name: Michael Hartl
email: michael@example.com
created_at: !ruby/object:ActiveSupport::TimeWithZone
  utc: &1 2021-02-09 06:34:49.836041000 Z
  zone: &2 !ruby/object:ActiveSupport::TimeZone
    name: Etc/UTC
  time: *1
updated_at: !ruby/object:ActiveSupport::TimeWithZone
  utc: &3 2021-02-09 06:34:49.836041000 Z
  zone: *2
  time: *3
password_digest: "$2a$12$c6TWZz21VWw7m8bDorgz9uR3XMXaWbMdtzmV.r6krzwzy59OmF7gO"
=> nil

同じ

7.1.2 Usersリソース

ユーザー情報をWebアプリケーション上に表示する。
RESTアーキテクチャ
* データの作成、表示、更新、削除をリソース(Resources)として扱う。
* HTTP標準には、これらに対応する4つの基本操作(POST、GET、PATCH、DELETE)を各アクションに割り当てていく。

ユーザーをリソースとみなす
= id=1のユーザーを参照する
= "/users/1というURLに対してGETリクエストを発行する"

config/routes.rb
resources :users #この行を追加する

ユーザーのURLを生成するための多数の名前付きルート(5.3.3)と共に、RESTfulなUsersリソースで必要となるすべてのアクションが利用できるようになる

演習 1

埋め込みRubyを使って、マジックカラム(created_atとupdated_at)の値をshowページに表示してみましょう(リスト 7.4)。

app/views/users/show.html.erb
<%= @user.name %>, <%= @user.email %>,
<%= @user.created_at %>, <%= @user.updated_at %>

演習 2

埋め込みRubyを使って、Time.nowの結果をshowページに表示してみましょう。ページを更新すると、その結果はどう変わっていますか? 確認してみてください。

Michael Hartl, michael@example.com, 2021-02-09 06:34:49 UTC, 2021-02-09 06:34:49 UTC, 2021-02-12 23:11:30 +0900

(更新後)
Michael Hartl, michael@example.com, 2021-02-09 06:34:49 UTC, 2021-02-09 06:34:49 UTC, 2021-02-12 23:11:53 +0900

更新をかけると、表示時間も更新される。

7.1.3 debuggerメソッド

debuggerメソッドを使う。

演習 1

showアクションの中にdebuggerを差し込み(リスト 7.6)、ブラウザから /users/1 にアクセスしてみましょう。その後コンソールに移り、putsメソッドを使ってparamsハッシュの中身をYAML形式で表示してみましょう。ヒント: 7.1.1.1の演習を参考にしてください。その演習ではdebugメソッドで表示したデバッグ情報を、どのようにしてYAML形式で表示していたでしょうか?

console
(byebug) p = params
<ActionController::Parameters {"controller"=>"users", "action"=>"show", "id"=>"1"} permitted: false>

(byebug) puts p.to_yaml
--- !ruby/object:ActionController::Parameters
parameters: !ruby/hash:ActiveSupport::HashWithIndifferentAccess
  controller: users
  action: show
  id: '1'
permitted: false
nil

演習 2

newアクションの中にdebuggerを差し込み、/users/new にアクセスしてみましょう。@userの内容はどのようになっているでしょうか? 確認してみてください。

console
[1, 10] in /home/vagrant/work/sample_app2/app/controllers/users_controller.rb
    1: class UsersController < ApplicationController
    2: 
    3:   def show
    4:     @user = User.find(params[:id])
    5:   end
    6:   
    7:   def new
    8:     debugger
=>  9:   end
   10: end
(byebug) @user
nil

7.1.4 Gravatar画像とサイドバー

* 各ユーザーのプロフィール写真のあたりをもう少し肉付けし、サイドバーも作り始める。
* Gravatar(Globally Recognized AVATAR)をプロフィールに導入する。

app/views/users/show.html.erb
<% provide(:title, @user.name) %>
<h1>
  #gravatar_forヘルパーメソッドを使い@userのプロフィール画像を表示せよ
  <%= gravatar_for @user %>
  # @userのnameを表示
  <%= @user.name %>
</h1>
console
$ rails console
>> user = User.first
>> user.update(name: "Example User",
?>                        email: "example@railstutorial.org",
?>                        password: "foobar",
?>                        password_confirmation: "foobar")
=> true

emailでGravatar上とRailsチュートリアルのロゴを既に紐付けてある。

app/views/users/show.html.erb
<% provide(:title, @user.name) %>
<div class="row">
  <aside class="col-md-4">
    <section class="user_info">
      <h1>
        <%= gravatar_for @user %>
        <%= @user.name %>
      </h1>
    </section>
  </aside>
</div>

演習 1

(任意)Gravatar上にアカウントを作成し、あなたのメールアドレスと適当な画像を紐付けてみてください。メールアドレスをMD5ハッシュ化して、紐付けた画像がちゃんと表示されるかどうか試してみましょう。

  1. Gravatar
  2. サイト下部の「Gravatarを作成」をクリック
  3. アカウント開設
  4. プロフィールの画像を変更
  5. Rails consoleuserGravatarのメールアドレスをupdate
  6. rails s -b 0.0.0.0で確認。変更されていました。

演習 2

7.1.4で定義したgravatar_forヘルパーをリスト 7.12のように変更して、sizeをオプション引数として受け取れるようにしてみましょう。うまく変更できると、gravatar_for user, size: 50といった呼び出し方ができるようになります。重要: この改善したヘルパーは10.3.1で実際に使います。忘れずに実装しておきましょう。

実装のみなので省略。

演習 3

オプション引数は今でもRubyコミュニティで一般的に使われていますが、Ruby 2.0から導入された新機能「キーワード引数(Keyword Arguments)」でも実現することができます。先ほど変更したリスト 7.12を、リスト 7.13のように置き換えてもうまく動くことを確認してみましょう。この2つの実装方法はどういった違いがあるのでしょうか? 考えてみてください。

動作確認のみなので省略。
コードが完結になるだけだろうか?

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

Rails:モデルの命名規則を破ったらエラーが出ました【NameError】【uninitialized constant】

Rails:モデルの命名規則を破ったらエラーが出ました【NameError】【uninitialized constant】

エラー画面

スクリーンショット 2021-02-13 20.56.14.png

エラー説明

uninitialized constant:「定義したクラスを読むことができないよ」
(Railsでは定数やclassが定義されていないという意味のエラー)
NameError:「そんな名前は定義されてないよ」
(定義されていないローカル変数やメソッドが呼び出されている場合に、発生するRubyのエラー)

原因

classの命名規則が正しくできていなかった

誤:「Deliver_fee」
正:「DeliverFee」

RailsのDBモデルの命名規則

単語が1つの場合

例)モデルの名前が「Deliver」

モデル名:deliver
モデルクラス名:Deliver
ファイル名:deliver.rb
テーブル名:delivers

単語が複数の場合

例)モデル名が「Deliver Fee」

モデル名:deliver fee
モデルクラス名:DeliverFee
ファイル名:deliver_fee.rb
テーブル名:deliver_fees
 
 
Railsは命名規則がきっちりしているので、ファイル名を命名規則に従わせないとファイルが見つからないとエラーが出てしまうようです。
気をつけましょう。

以上です。

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

Jupyter Notebook で Ruby が使えるってま!?

概要

会社でRailsを使って開発をしている関係でRubyのコードを試したいことが多々ありました。
Paizaとかブラウザで実行できるものもあるがPythonみたくJupyter notebookでできないかなと思っていました。

そこで調べるとRubyをJupyter notebookに入れることが出来ることが判明(゚∀゚) 実際に導入する手順がわかったので今後PCが壊れたときのためにインストール方法をメモします。

条件

言語 ver
Ruby 2.10 以上
Jupyter Notebook --

※Ruby と jupyter notebookの道入がまだの人は以下の記事よりそれぞれのインストールを済ませて下さい。

・Rubyのインストール
【完全版】MacでRails環境構築する手順の全て

・Jupyter Noteboookのインストール

① anacondaのインストール
Anaconda(Python3)インストール手順<macOS用>

② anacondaのPATHの通し方
AnacondaのPATHの設定

③ Jupyter notebook のインストール
Installing the Jupyter Software

方法

iRubyのgithubをもとにインストールを進めていきます。

まず、依存関係にあるライブラリのインストールをします。

cmzp の versionによっては動かない可能性あり↓
* Jupyter NotebookにRuby Kernelを追加する方法

terminal
brew install automake gmp libtool wget
brew install zeromq --HEAD
# 1.30以上で動かないとの記事あり
brew install czmq --HEAD
gem install ffi-rzmq
gem install rbczmq

irubyのインストールとjupyterへの登録をします。

terminal
# irubyのインストール
gem install iruby

# irubyの登録
iruby register --force

最後にjupyter notebookの起動をします。

terminal
jupyter notebook

以下のように Ruby が New の中に入っているのを確認して下さい。

image.png

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

Rails6 herokuでデプロイ

初めまして

私は、オリアプを作成しており、そのうちの何個かはherokuでデプロイしています。
そこで、herokuでデプロイする方法を備忘録として残したいと思います。

環境

Rails6
Ruby2.6.5

Herokuを操作します。

まだ、Herokuをインストールしていない方は、どのディレクトリでもいいので下記を実行しましょう。

 % brew tap heroku/brew && brew install heroku

Herokuへログインします。

まだ、Herokuの登録ができていない方は、先に登録してくださいね。

# Herokuへログインするためのコマンド
% heroku login --interactive
  => Enter your Heroku credentials.
# メールアドレスを入力し、エンターキーを押す
  => Email:
# パスワードを入力して、エンターキーを押す
  => Password:

Heroku上にアプリケーションを作成します。

自身のアプリのディレクトリに移動してください。そこで下記を実行します。


% heroku create アプリ名

#git config --list | grep heroku作成できているか確認できます。

Heroku上でDBを使えるようにします。

Heroku上のDBはデフォルトで「PostgreSQL」になっています。
なので、私はローカル環境で「Mysql」を使用していたのでDBの設定を変えます。


% heroku addons:add cleardb
#ClearDbを追加することで「Mysql」を使用できます。

% heroku_cleardb=`heroku config:get CLEARDB_DATABASE_URL`
# ClearDBのURLを変数heroku_cleardbに格納します。。

% heroku config:set DATABASE_URL=mysql2${heroku_cleardb:5}
#DBのURLを再設定します。

Heroku上にmaster.keyを設置します。

Heroku上にmaster.keyを環境変数として設置します。


% EDITOR="vi" bin/rails credentials:edit
#credentials.yml.encをmaster.keyによって復号し、中身を確認しておきます。
# 「escキー」「:」「q」で閉じることが出来ます
% heroku config:set RAILS_MASTER_KEY=`cat config/master.key`
# 本番環境へ設置します。
#heroku config で念のため設定できているか確認しておきます。

アプリケーションをプッシュします。

Herokuで「Stack」を指定します。
※Stackはデプロイされたアプリケーションを読み取り正常に動作させるためのもの

今回私は「Ruby2.6.5」の為、「heroku-18」を使います。


% heroku stack:set heroku-18 -a ご自身のアプリ名

% git push heroku master
# Herokuにプッシュします。

 Heroku上にマイグレーションファイルを上げます。

Heroku上にもDBを反映させなければ正しく動作しませんので反映させます。

% heroku run rails db:migrate

# heroku apps:infoでアプリの情報を見ることが出来ます。

上記の設定でアプリを公開することが出来ているはずです!

Heroku上のアプリを削除したい場合

HerokuのWebサイトから削除することが出来ます。
手順として
①削除したアプリを選択
②「Settings」の一番下の「Delete」を押して、アプリ名を入力し削除

しかし、削除しただけでは全て消えません。
gitのリモートリポジトリにherokuが設定されたままになっています!
下記を実行します。

% git remote rm heroku

最後に

herokuを使えば簡単にアプリケーションの公開ができるのでおすすめです!

ここまで読んでいただきありがとうございました!

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

【Ruby on Rails】返すデータに制限をかけたりかけなかったりするために、七つのアクション以外を定義するのはやめよう...

なぜ書くか

これまたコードレビューの際にご指摘いただきました。
備忘録と、コツコツとプロの開発者としての思考を身につけるためにアウトプットさせていただきます。

脱「動けばいい」精神

まず、前提としては、RailsはApiでのやり取り専用のコントローラ。
iOSアプリケーションからリクエストを受け取り、それぞれのリクエストに応じた処理が実行されます。

実際に問題となった機能を実装する前は、コントローラは下記の様な状態でした。(コードは多少変更しています。)

module Api
  module V1
    class ProductController < ::Api::ApplicationController
      protect_from_forgery except: [:create]

      def index
        render json: Product.trader_filter(params[:trader_id])
      end

      def create
        render json: Product.new(product_params).save
      end

      private

      def product_params
        params.permit(:name, :price)
      end
    end
  end
end

しかしここでiOS側でのとあるページの都合で「その日、当日分の商品情報だけ欲しいな...」といったことが発生しました。(なんの当日分かは置いといて)
すかさず、Railsアプリケーションのコードを追加し、書いたコードは下記の様なコードです。

module Api
  module V1
    class ProductController < ::Api::ApplicationController
      protect_from_forgery except: [:create]

      def index
        render json: Product.trader_filter(params[:trader_id])
      end

      def create
        render json: Product.new(product_params).save
      end

      def acquisition_of_product_data_on_the_day
        render json: Product.trader_release_date_filter(params[:trader_id], params[:release_date])
      end

      private

      def product_params
        params.permit(:name, :price)
      end
    end
  end
end

ルーティングにコレクションを使用し、七つのアクション以外のアクションを定義し、コントローラでモデルのスコープを呼び出しています。
この時は「もうindexは使っちゃってるしなぁ」と安直にアクションを追加し、これでいいと思っていました。

しかし、先輩にレビュー依頼出したところ、ここが指摘されました。

理由としては、検索条件を追加するたびにいちいちアクションを追加していたら、コントローラのメソッドの数がえげつないことになり、いわゆる「fat Controller」になってしまいメンテナンスが難しくなってしまうということでした。

まさに「動くからええやん...」気分で書いたコードでした。
しかし実際に本当にその通りで、検索の内容が変わるたびに「get」のリクエストを増やしまくっていたのでは、いつか維持できなくなります。
「将来的にも追加はそこまでないからいいのでは?」と思ったりもしたのですが、とにかく同じようなメソッドを何個もコントローラーに書くのはスマートではないと。

ではどうするか?

本来コントローラは左から右へ処理、命令を流すだけの役割です。
なので、当日分のデータを返したいのかそうでないのか?といったこともコントローラに考えさせるべきではありません。

なのでindexで、全体取得、本日分のみの取得のリクエストも受け取り、モデルに判断させます。

module Api
  module V1
    class ProductController < ::Api::ApplicationController
      protect_from_forgery except: [:create]

      def index
        render json: Product.trader_filter(params[:trader_id], params[:release_date])
      end

      def create
        render json: Product.new(product_params).save
      end

      private

      def product_params
        params.permit(:name, :price)
      end
    end
  end
end

最初との違いは、indexメソッドに渡すparamsの中身を追加しただけです。つまり取得したい日付のデータですね。

そしてモデルのスコープは以下のように実装します。

scope :trader_filter, ->(trader_id, release_date) do
  if release_date.nil?
    #全件検索の処理
  else
    #当日分のデータ取得の処理
  end
end

これで、コントローラにアクションを増やすことなく、同じ動きを実現できました。
コントローラから、スコープを見に行くだけで、どのようなデータを返すようになっているかも一発で分かるので可読性もこちらの方が高いと思います。

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

[Rails]gretelとパンくず(パンくずリストの作り方)

何を書くのか

railsのgem "gretel"を用いたパンくずリストの作り方

環境

Rails: 6.0.3.4
Ruby: 2.6.5

結論

gretelの力でパンくずを作成し、それをビューで表示する。

パンくずリストとは

スクリーンショット 2021-02-13 午後6.34.56.png

こういう風に、ヘッダーなどに「今どこどこにいますよ!」っていう表示を見た事があるでしょうか。これをパンくずリストと言います。今回は、これを作成していきます。

gretelの導入

今回使うのは、gemのgretelです。
gretelのGithub

最初に、gretelの導入を行います。

Gemfileに記述し、bundle installします。

gem "gretel"

と、記述し、ターミナルで

$ bundle install

を実行します。

そしたらターミナルでこちらのコマンドを実行しましょう。

rails g gretel:install

これを実行すると、"breadcrumbs.rb"というファイルが生成されます。
ファイルの中は、こんな感じになっているかと思います。

breadcrumbs.rb
crumb :root do
  link "Home", root_path
end

# crumb :projects do
#   link "Projects", projects_path
# end

# crumb :project do |project|
#   link project.name, project_path(project)
#   parent :projects
# end

# crumb :project_issues do |project|
#   link "Issues", project_issues_path(project)
#   parent :project, project
# end

# crumb :issue do |issue|
#   link issue.title, issue_path(issue)
#   parent :project_issues, issue.project
# end

# If you want to split your breadcrumbs configuration over multiple files, you
# can create a folder named `config/breadcrumbs` and put your configuration
# files there. All *.rb files (e.g. `frontend.rb` or `products.rb`) in that
# folder are loaded and reloaded automatically when you change them, just like
# this file (`config/breadcrumbs.rb`).

これが確認できれば、準備は完了です。

breadcrumbs.rbの中身を作る

それでは、ここからはパンくずリストの中身、つまり表示する文字列だったりを決めます。
ここでは、gretelの公式で紹介されている例を参考に説明します。

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

# 一覧表示ページ
crumb :issues do
  link "All issues", issues_path
end

# 詳細表示ページ
crumb :issue do |issue|
  link issue.title, issue
  parent :issues
end

説明を加えます。

breadcrumbs.rb
link "Home", root_path

基本の型は、'link "表示する文字列", パス'です。それを

breadcrumbs.rb
crumb :root do
  link "Home", root_path
end

のように、do~endで囲ってあげます。
ちなみに、:rootは、ビューの表示等で利用することになるので、自分が判断しやすい名称に設定しておきましょう。

また、こういうこともできます。

breadcrumbs.rb
#詳細表示ページ
crumb :issue do |issue|
  link issue.title, issue
  parent :issues
end

詳細表示ページには、parent :issuesとあります。これは、「issuesを親に持つよ!」ということを示しています。
これがないと、ページ間のつながりを判断してもらえず、意味がなくなってしまいます。

ビューに表示する

それでは、先ほど作ったパンくずリストの要素等を、ビューで表示していきます。

この例では、app/views/issues/show.html.erbを例にだします。

issues/show.html.erb
<% breadcrumbs :issue, @issue> 
<%= breadcrumbs separator: " &rsaquo; " %>  <%# 矢印を示すオプション %>

基本的に、表示に必要なのは、この二つだけです。1行目で、(コントローラーから送られてきた)@issueを、先ほどcrumbの後ろにシンボルで記述した:issueのバリューとして定義します。あとは、自由にオプションをつけて、完成です。

補足

これは、初歩中の初歩です。公式Githubにはいろいろなオプションが確認できるので、ここからはそちらを参考してください。

最後に

最後まで読んでいただき、ありがとうございます。
ソースコード、記事の書き方について「もっとこうしたほうがいいよ!」というご意見、「そこどうなっているの?」というご質問など、お待ちしております。

参考文献

gretel

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

【Rails】Zeitwork::NameError を解消する

1.はじめに

railsでアプリを作成し、サーバーを立ち上げrails sを行い、http://localhost:3000/XXにアクセスしました。
すると、Zeitwork::NameErrorと表示されました。

2.使用環境

・mac.os バージョン10.15.6
・Ruby 2.6.6
・Rails 6.0.3.5
・psql (PostgreSQL) 12.6

3.実際のエラー

Zeitwerk NameError.png

太字に着目するとPostsContrlllerの定義が変という旨が書かれていますね。

4.結論:スペルミスでした

ということでPostscontrollerクラスの記述をしているposts_controller.rbを確認すると...

posts_controller.rb
class Postcontroller < ApplicationController
  def index
    @posts = Post.all
  end
end

2箇所も間違えておりました。(下記が正しいものです。)

posts_controller.rb
class PostsController < ApplicationController
  def index
    @posts = Post.all
  end
end

5.まとめ:スペルミス気をつけます

とは言え、Rails6.0で新たに導入されたZeitworkモードについて学ぶ良い機会となりました。

6.参考リンク

Railsガイド-定数の自動読み込みと再読み込み (Zeitwerk)

7.最後に

記事の感想や意見、ご指摘等あれば伝えていただけるとありがたいです。
読んでいただき、ありがとうございました。

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

【Rails】rails s したらAddress already in useのエラーが出たので解消する

1.はじめに

railsでアプリを作成し、サーバーを立ち上げrails sを行い、動作確認を試みました。
すると、Address already in useと表示されました。

私:「http://localhost:3000複数立ち上げてないはずだけど...」
複数回このエラーに遭遇したため、備忘録も兼ねてまとめていきます。

2.使用環境

・mac.os バージョン10.15.6
・Ruby 2.6.6
・Rails 6.0.3.5
・psql (PostgreSQL) 12.6

3.実際のエラー

ターミナル.
1: from /Users/hogehoge/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/puma-4.3.7/lib/puma/binder.rb:229:in `new'
/Users/hogehoge/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/puma-4.3.7/lib/puma/binder.rb:229:in `initialize': Address already in
 use - bind(2) for "127.0.0.1" port 3000 (Errno::EADDRINUSE)

「Rails Address already in use」などで調べ、エラーの解消を試みました。

4.解決策

① 別のポートを使う

・URLをhttp://localhost:3000 → 例:http://localhost:3001に変更する
・コマンドをrails sからrails s -p 3001 に変更する

これでしばらくできていたのですが、数回行った後に同様のエラーが出ていたことと、応急処置的な策だと思い、別の方法を試しました。

② 立ち上がっている別のrailsサーバーを落とす

ps -ax | grep rubyとコマンドを入力します。

略称 内容
ps process の略。
OS内部で現在実行されているプロセス一覧を表示する
ax a:端末を持つ全てのプロセスを表示する
x:端末を持たない全てのプロセスを表示する
パイプ コマンドの出力結果を次に渡す処理をする
grep ファイル中の文字列を検索する

※パイプは|のことです。

ターミナル.
hogehoge@hogenoAir sample_app % ps -ax | grep ruby
13657 ??       242:21.97 ruby -I /Users/hogehoge/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib -I /Users/hogehoge
/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/spring-2.1.1/lib -e require 'spring/application/boot'
13666 ??         0:01.28 /Users/hogehoge/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rb-fsevent-0.10.4/bin/fsevent_watch --format
=otnetstring --latency 0.2 /Users/hogehoge/Desktop/sample_app
13667 ??         0:00.69 /Users/hogehoge/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rb-fsevent-0.10.4/bin/fsevent_watch --format
=otnetstring --latency 0.1 /Users/hogehoge/Desktop/sample_app/config/locales
13669 ??         0:00.70 /Users/hogehoge/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rb-fsevent-0.10.4/bin/fsevent_watch --format
=otnetstring --latency 0.1 /Users/hogehoge/Desktop/sample_app/db /Users/hogehoge/Desktop/sample_app/app/channels /Users/
hogehoge/Desktop/sample_app/app/controllers /Users/hogehoge/Desktop/sample_app/app/helpers /Users/hogehoge/Desktop/sample_app/app/jobs /Users/hogehoge/Desktop/sample_app/app/mailers /Users/hogehoge/Desktop/sample_app/app/models
68459 ttys004    0:00.00 grep ruby

プロセスを確認しrailsサーバーの場合はkillします。
(ない場合は、rails以外の別サービスが3000番ポートを使用していますのでそれを切ります。)

killをする場合は、kill 〇〇とコマンドを入力します。
※killは実行しているプロセスを終了するコマンドです。〇〇には、PID(プロセス番号)が入ります。

今回は強制終了のシグナル -9をつけて、killを行いました。

ターミナル.
hogehoge@hogenoAir sample_app % kill -9 13657
hogehoge@hogenoAir sample_app % kill -9 13666
kill: kill 13666 failed: no such process
hogehoge@hogenoAir sample_app % kill -9 13667
kill: kill 13667 failed: no such process
hogehoge@hogenoAir sample_app % kill -9 13669
kill: kill 13669 failed: no such process

13657のみ反応が返ってきていないものの、他は該当のプロセスはなかったようで、failed: no such processと怒られました。

③ 3000番ポートを使用している他のプロセスを探してkillする

lsofコマンドを使用します。lsof [オプション] [パス名]という風に使います。
今回は、lsof -i:3000とコマンドを入力します。

略称 内容
lsof オープンしているファイルを一覧表示する
-i 全てのネットワークソケットを対象にする
※「-i4」でIPv4,「-i6」でIPv6を指定できる
ターミナル.
hogehoge@hogenoAir sample_app % lsof -i:3000
COMMAND   PID     USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
ruby    13924 hogehoge   23u  IPv6 0xc40f37229745897b      0t0  TCP localhost:hbci->localhost:54998 (CLOSE_WAIT)
ruby    13924 hogehoge   24u  IPv6 0xc40f372296a66d3b      0t0  TCP localhost:hbci->localhost:55019 (CLOSE_WAIT)
ruby    15604 hogehoge   12u  IPv6 0xc40f372296a6735b      0t0  TCP localhost:hbci (LISTEN)
ruby    15604 hogehoge   13u  IPv4 0xc40f37228ef3cb4b      0t0  TCP localhost:hbci (LISTEN)
ruby    15604 hogehoge   23u  IPv6 0xc40f372291635d3b      0t0  TCP localhost:hbci->localhost:55859 (CLOSE_WAIT)
ruby    15604 hogehoge   24u  IPv6 0xc40f372297454c3b      0t0  TCP localhost:hbci->localhost:55879 (CLOSE_WAIT)
ruby    15604 hogehoge   30u  IPv6 0xc40f372291632c3b      0t0  TCP localhost:hbci->localhost:55904 (CLOSE_WAIT)
ruby    15604 hogehoge   35u  IPv6 0xc40f37229163261b      0t0  TCP localhost:hbci->localhost:55905 (CLOSE_WAIT)
ruby    15604 hogehoge   37u  IPv6 0xc40f37229b46e97b      0t0  TCP localhost:hbci->localhost:55911 (CLOSE_WAIT)
ruby    15604 hogehoge   40u  IPv6 0xc40f37229b46b25b      0t0  TCP localhost:hbci->localhost:55912 (CLOSE_WAIT)

1392415604がヒットしたので、それぞれkillします。

ターミナル.
hogehoge@hogenoAir sample_app % kill 13924
hogehoge@hogenoAir sample_app % kill 15604

再度確認してみます。

ターミナル.
hogehoge@hogenoAir sample_app % lsof -i:3000
COMMAND   PID     USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
ruby    13924 hogehoge   23u  IPv6 0xc40f37229745897b      0t0  TCP localhost:hbci->localhost:54998 (CLOSE_WAIT)
ruby    13924 hogehoge   24u  IPv6 0xc40f372296a66d3b      0t0  TCP localhost:hbci->localhost:55019 (CLOSE_WAIT)
ruby    15604 hogehoge   12u  IPv6 0xc40f372296a6735b      0t0  TCP localhost:hbci (LISTEN)
ruby    15604 hogehoge   13u  IPv4 0xc40f37228ef3cb4b      0t0  TCP localhost:hbci (LISTEN)
ruby    15604 hogehoge   23u  IPv6 0xc40f372291635d3b      0t0  TCP localhost:hbci->localhost:55859 (CLOSE_WAIT)
ruby    15604 hogehoge   24u  IPv6 0xc40f372297454c3b      0t0  TCP localhost:hbci->localhost:55879 (CLOSE_WAIT)
ruby    15604 hogehoge   30u  IPv6 0xc40f372291632c3b      0t0  TCP localhost:hbci->localhost:55904 (CLOSE_WAIT)
ruby    15604 hogehoge   35u  IPv6 0xc40f37229163261b      0t0  TCP localhost:hbci->localhost:55905 (CLOSE_WAIT)
ruby    15604 hogehoge   37u  IPv6 0xc40f37229b46e97b      0t0  TCP localhost:hbci->localhost:55911 (CLOSE_WAIT)
ruby    15604 hogehoge   40u  IPv6 0xc40f37229b46b25b      0t0  TCP localhost:hbci->localhost:55912 (CLOSE_WAIT)

再度表示されたので、kill -9でkillします。

ターミナル.
hogehoge@hogenoAir sample_app % kill -9 13924
hogehoge@hogenoAir sample_app % kill -9 15604
hogehoge@hogenoAir sample_app %
[1]  - killed     rails s
hogehoge@hogenoAir sample_app % lsof -i:3000
hogehoge@hogenoAir sample_app %

killができたようなので、再度rails sでサーバーを起動します。

ターミナル.
hogehoge@hogenoAir sample_app % rails s
=> Booting Puma
=> Rails 6.0.3.5 application starting in development
=> Run `rails server --help` for more startup options
Puma starting in single mode...
* Version 4.3.7 (ruby 2.6.6-p146), codename: Mysterious Traveller
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://127.0.0.1:3000
* Listening on tcp://[::1]:3000
Use Ctrl-C to stop

ということで、無事エラーを解決することができました。

5.参考リンク

1:【 ps 】コマンド――実行中のプロセスを一覧表示する
2: rails sが通らない
3:パイプでつないでgrep?: Railsチュートリアル備忘録 - 8章
4:grepコマンドの詳細まとめました【Linuxコマンド集】
5:プロセスを終了するkillコマンドの使い方まとめ!【Linuxコマンド集】
6:【kill】Linuxでプロセスを終了させるコマンド
7:【 lsof 】コマンド――オープンしているファイルを一覧表示する
8:知ったかぶりをしていたソケット通信の基礎を改めて学んでみる

6.最後に

記事の感想や意見、ご指摘等あれば伝えていただけるとありがたいです。
読んでいただき、ありがとうございました。

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

【Window限定】Rubyのコードをexe形式で出力する

調べてみたところ、あまり活発ではない手法のようです。

Mac用に書き出せたりもしないので
JavaScriptでElectonとかを使ったほうがスムーズかもしれませんね。

ただ、Rubyを使うだけでexe形式の何かを作れるのは良いと思いました。

> ocra .\sample.rb

さて、雑に上記のようにしますとexe生成には成功しますが次のようなエラーが発生して起動しません。

スクリーンショット 2021-02-13 14.58.13.png

ruby_buiktin_dlls\libssp-0.dll was not found

これを解消しなくてはなりません。

> ocra .\sample.rb --dll ruby_builtin_dlls\libssp-0.dll

これで解決です。

次に ocra は sample.rb 実行して依存関係を調べているような気がします。
なので終了しないスプリクトだと処理が終わらないような気がします。

そこで --no-dep-run (実行しない) を入れます。
公式に --no-dep-run は --gem-full セットでと書いてあったのでそうします。

> ocra .\sample.rb --no-dep-run --gem-full --dll ruby_builtin_dlls\libssp-0.dll

最終的な実行コマンドはこちらです。
これで Windows で実行可能な exe形式のruby製プログラムの作成に成功しました。

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

railsアプリをcapsitranoでdeployする時に自動でseedを実行する。けど必要な時だけする。

本記事のサマリ

capistranoでrailsアプリをdeployする際に、自動的にseedを流すようにすると、deployの運用的には楽になるが、seedの実行時間が待たされるので、seedファイルが描き変わった時だけ動くように工夫するといいかもという話です。

対象読者

  • capistranoをつかって、railsアプリをデプロイしており、seedの実行は手動でやっているような方
  • seedの実行をcapに任せているが、毎回時間かかっているような方

動作確認バージョン

Capistrano Version: 3.11.2 (Rake Version: 10.3.2)
Rails 5.1.6
ruby 2.6.6p146 (2020-03-31 revision 67876) [x86_64-darwin18]

経緯

capistranoでデプロイする際に、seedの実行は変更があったときに、手で実行するのは、面倒です。
なので、そういったものは、自動的にやるようにしたいというのが、怠惰なプログラマな正常な欲求です。
でも、自動的にやってみたのはいいものの、毎回実行していると、seedの肥大化に伴って、実行時間の待ち時間がもったいない。
ならば、seedの変更が会った時だけ実行するようにしようというのが敬意です。

方針

やり方はいろいろあると思いますが、seedファイルの変更を検知するために、seedファイルのmd5のハッシュ値をとっておいて、それが切り替わったら実行するというやり方で実現してみました。

実物

以下のように、独自で定義したcapistranoのタスクを、deploy:migrateの後で実行するようにします。

deploy.rb
# 〜中略〜
# deploy用のスクリプトで、migrateの後にdeploy:seedタスクを実行させる
after 'deploy:migrate', 'deploy:seed'
# 〜中略〜

実際に、seedを実行するタスクは以下のようにして、seedファイルのmd5を保持しておき、それを比較して違っていたらseedを実行するような形で実現します。

deploy.cap
# 〜中略〜
  # seedの実行タスクは以下の通り
  # 前提となる情報
  #  release_path: deployされたアプリのパス
  #  shared_path: 別のリリース時でも共有できる共有ディレクトリのパス
  #  seedファイルは、実行されるたびに、トランザクションを貼って洗い替え(delete & insert)することで、冪等性を担保している。
  desc 'Load seed data into database'
  task :seed do
    on roles(:db) do
      within release_path do
        with rails_env: fetch(:rails_env) do
          command = 'db:seed'
          # rakeのコマンドを元に、seedファイルの相対パスを組み立て
          seed_filepath = 'db/seed.rb'
          new_digest_filepath = shared_path.join("new_#{seed_filepath.gsub('/', '_')}.md5")
          digest_filepath     = shared_path.join("#{seed_filepath.gsub('/', '_')}.md5")
          # digestがなかった時にエラーにしないために、事前にtouch
          execute :touch, digest_filepath
          execute :md5sum, "#{seed_filepath} > #{new_digest_filepath}"
          # md5が違っていたらseedを反映するコマンドを実行する
          execute "if [ \"`cat #{new_digest_filepath}`\" != \"`cat #{digest_filepath}`\" ]; then cd #{release_path}; RAILS_ENV=#{ fetch(:rails_env) } bundle exec rake #{command}; mv #{new_digest_filepath} #{digest_filepath}; fi"
          end
        end
      end
    end
  end
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails6.1開発ハンズオン(1)

ターゲット

  • Rails、Rubyを全く知らない人
  • 何らかのプログラミング言語でコードを書いたことがある人
  • ある程度shellの操作に慣れている人
  • macがなくてwindowsしかない人

目的

Rails6.1で基本的な機能を雑に触れながらそれっぽいアプリを作る

やること

  • Gitの設定
  • ログインなしで書き込めるネット掲示板を作る
  • ベースはこれを使う + vscodeに拡張機能を入れて開発

1. 開発環境を整える

1-1. vscodeを整える

vscodeをインストールする。

Visual Studio Code - コード エディター | Microsoft Azure

これでWSLに接続して開発できる(これ以降の拡張機能は必要に応じてWSL上にインストールされる。)

Remote - WSL - Visual Studio Marketplace

日本語化

Japanese Language Pack for Visual Studio Code - Visual Studio Marketplace

アイコンをわかりやすく表示

Material Icon Theme - Visual Studio Marketplace

Ruby関連

Ruby - Visual Studio Marketplace

補完とかしてくれる言語サーバ solargraphさん

# solargraphをインストール
gem install solargraph

Ruby Solargraph - Visual Studio Marketplace

endを自動で入れてくれる

endwise - Visual Studio Marketplace

draw.ioを使いたい

Draw.io Integration - Visual Studio Marketplace

1-2. Gitを整える

first commit

git config --global user.email "you@example.com"
git config --global user.name "Your Name"

github SSH認証の準備

参考にさせていただくもの:
WSL2 から起動した VSCode DevContainer に SSH agent で Git の鍵を渡す - Qiita

cd ~
ssh-keygen -t ed25519 -P ""
# 何も入れずにEnter
cd .ssh
more id_ed25519.pub
# 内容をコピー

Build software better, together

SSH and GPG keysで「New SSH Key」ボタンを押す。
わかりやすいTitle(WSL2とか)を入力、Keyにコピーした公開鍵を貼り付け、Add

~/.bashrcを開いて以下のコードを追加

if [ -z "$SSH_AUTH_SOCK" ]; then
   # Check for a currently running instance of the agent
   RUNNING_AGENT="`ps -ax | grep 'ssh-agent -s' | grep -v grep | wc -l | tr -d '[:space:]'`"
   if [ "$RUNNING_AGENT" = "0" ]; then
        # Launch a new instance of the agent
        ssh-agent -s &> $HOME/.ssh/ssh-agent
   fi
   eval `cat $HOME/.ssh/ssh-agent`
fi

ssh-add $HOME/.ssh/id_ed25519

github上にリポジトリを新規作成、(ここでは「Rails6.1_hands_on」という名前)

git remote add origin git@github.com:hirorocky/Rails6.1_hands_on.git
git push -u origin master
# Rails6.1だとまだ”master”

2. 掲示板を作る

2-0. Railsの基礎知識:MVCモデル

詳しくは「Rails MVC」で検索!
私は正しく理解している自信はないですが、こんな図を描いてみました↓

Untitled.png
リクエストが来たら、Rails上のroutes.rbがコントローラーとアクション(=メソッド)を決めて、コントローラー上のアクションでモデルからデータを取りながら、ビューを作って、その結果をブラウザに返すイメージです。

2-1. 設計

◆モデル図

(拡張機能により、〇〇.drawioというファイルを作ればvscode上でdraw.ioが使える!)
Untitled 1.png

◆ワイヤーフレーム(?詳しくない)

Untitled 2.png

4枚のページが必要そう。

  • communities_controller#index:トップページ
  • communities_controller#new→#create:コミュニティ作成ページ
  • communities_controller#show:1つのコミュニティ&コメント一覧
  • comments_controller#new→#create:コメント投稿ページ

なぜこのコントローラー×アクションの組み合わせなのかは聞かないでください。

2-2. 実装

2-2-1. モデル

DB上に各テーブルを作る。

' rails generate model <モデル名> <カラム名>:<型>...'

でモデルに関するファイルを自動で作ってくれる。

rails generateはrails gと省略できる。※以降gで書きます。

rails g model Community title:string owner_name:string
rails g model Comment author_name:string content:text community:references

db/migrateフォルダ内に、2つのファイル(マイグレーションファイル)ができる。

以下のコマンドでDBにテーブルを作成する。

# sqlite上にRails用DBを作成
rails db:setup
# DB上にマイグレーションファイルをもとにテーブルを作成
rails db:migrate

app/models/community.rbにて

class Community < ApplicationRecord
  has_many :comments
end

app/models/comment.rbにて

class Comment < ApplicationRecord
  belongs_to :community
end

こうするだけで、RailsのORMがいい感じにしてくれる。

※ちょっと試すにはターミナルでrails console(rails cでも可)コマンド。

irb(main):001:0> commu = Community.create(title: 'コミュニティタイトルです', owner_name: 'たろう')
   (0.4ms)  SELECT sqlite_version(*)
  TRANSACTION (0.1ms)  begin transaction
  Community Create (0.5ms)  INSERT INTO "communities" ("title", "owner_name", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["title", "コミュニティタイトルです"], ["owner_name", "たろう"], ["created_at", "2021-02-13 02:21:28.386695"], ["updated_at", "2021-02-13 02:21:28.386695"]]
  TRANSACTION (5.0ms)  commit transaction
=> #<Community id: 1, title: "コミュニティタイトルです", owner_name: "たろう", created_at: "2021-02-13 02:21:28.386695000 +0000", updated_at: "2021-02-13 02:21:28.386695000 +0000">

irb(main):002:0> commu.title
=> "コミュニティタイトルです"

irb(main):003:0> commu.comments.create(author_name: 'じろう', content: "コメント\nああああ")
  TRANSACTION (0.1ms)  begin transaction
  Comment Create (0.5ms)  INSERT INTO "comments" ("author_name", "content", "community_id", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?)  [["author_name", "じろう"], ["content", "コメント\nああああ"], ["community_id", 1], ["created_at", "2021-02-13 02:26:21.103087"], ["updated_at", "2021-02-13 02:26:21.103087"]]
  TRANSACTION (5.1ms)  commit transaction
=> #<Comment id: 1, author_name: "じろう", content: "コメント\nああああ", community_id: 1, created_at: "2021-02-13 02:26:21.103087000 +0000", updated_at: "2021-02-13 02:26:21.103087000 +0000">

irb(main):004:0> commu.comments.create(author_name: 'じろう', content: "コメント2\nああああ")
  TRANSACTION (0.1ms)  begin transaction
  Comment Create (0.5ms)  INSERT INTO "comments" ("author_name", "content", "community_id", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?)  [["author_name", "じろう"], ["content", "コメント2\nああああ"], ["community_id", 1], ["created_at", "2021-02-13 02:26:35.918169"], ["updated_at", "2021-02-13 02:26:35.918169"]]
  TRANSACTION (7.1ms)  commit transaction
=> #<Comment id: 2, author_name: "じろう", content: "コメント2\nああああ", community_id: 1, created_at: "2021-02-13 02:26:35.918169000 +0000", updated_at: "2021-02-13 02:26:35.918169000 +0000">

irb(main):005:0> commu.comments
  Comment Load (0.2ms)  SELECT "comments".* FROM "comments" WHERE "comments"."community_id" = ? /* loading for inspect */ LIMIT ?  [["community_id", 1], ["LIMIT", 11]]
=> #<ActiveRecord::Associations::CollectionProxy [#<Comment id: 1, author_name: "じろう", content: "コメント\nああああ", community_id: 1, created_at: "2021-02-13 02:26:21.103087000 +0000", updated_at: "2021-02-13 02:26:21.103087000 +0000">, #<Comment id: 2, author_name: "じろう", content: "コメント2\nああああ", community_id: 1, created_at: "2021-02-13 02:26:35.918169000 +0000", updated_at: "2021-02-13 02:26:35.918169000 +0000">]>

ログを見ると、rubyのコードをSQLに変換して、DBを操作しているのがなんとなくわかると思います。

ここでは見ませんが、上記コードだけで、DBに1つのcommunityレコードと2つのcommentレコードができています。

2-2-2. Communityのコントローラー・ビュー

◆コントローラー

rails g controller communities index new create show

設計段階で必要なコントローラーとビューがわかったので、

上記コマンドを入力。すると色々作成される(いらないものもできてしまう...※この辺は設定でいい感じにできますがここでは触れません)

app/controllers/communities_controller.rbのアクションの中にコードを入れる

class CommunitiesController < ApplicationController
  def index
    @communities = Community.all
  end

  def new
    @community = Community.new
  end

  def create
    @community = Community.new(community_params)
    if @community.save
      redirect_to communities_path
    else
      render :new
    end
  end

  def show
    @community = Community.find(params[:id])
    @comments = @community.comments
  end

  private

  def community_params
    params.require(:community).permit(:title, :owner_name)
  end
end

@hogeはインスタンス変数で、この文脈で必要な知識としては、

「インスタンス変数はビューに渡せる」ということです。

community_paramsメソッドはStrong Parameterというやつです。セキュリティ的に必要なもので、詳しくはググってください。

◆ルーティング

Rails.application.routes.draw do
  root to: 'communities#index'
  resources :communities, only: %i[index new create show]
end

自動生成されたものは全部削除、ルートをcommunities_controllerのindexアクションに割りあて、resourcesメソッドでcommunities_controller関連のルーティングを一気に作成。

rails routes

で設定されているルーティングを見ることができ、またもっと見やすくしたいときは、

ブラウザ上で「http://[::1]:3000/rails/info/routes」で見れる。

◆ビュー

ビュー関連はapp/viewsの中に入っている。

自動で作成されたcreate.html.erbはいらないので削除。

早くhamlを使いたい。

一旦、見た目ガン無視の最低限の機能を実装する。

app/views/communities/index.html.erb

<h1>掲示板</h1>

<%= link_to 'コミュニティ作成', new_community_path %>

<% @communities.each do |community| %>
  <div>
    <p><%= link_to community.title, community_path(community) %></p>
    <p><%= community.created_at %></p>
    <p><%= community.owner_name %></p>
  </div>
<% end %>

<% %>の中にrubyのコードを入れることができる。

<%= %>はrubyの評価結果をそのままhtmlに書き出す。

=かそうじゃないかは慣れだと思う。

app/views/communities/new.html.erb

<h1>コミュニティ作成</h1>

<%= form_with model: @community do |form| %>
  <%= form.label :title %>
  <%= form.text_field :title %>
  <%= form.label :owner_name %>
  <%= form.text_field :owner_name %>

  <%= form.submit '作成' %>
<% end %>

※form_withは一時期デフォルトがremote: trueだったが、local: trueになった。

app/views/communities/show.html.erb

<h1><%= @community.title %></h1>

<% @comments.each do |comment| %>
  <div>
    <p><%= comment.author_name %></p>
    <p><%= simple_format(comment.content) %></p>
    <p><%= comment.created_at %></p>
  </div>
<% end %>

2-2-3. Commentのコントローラー・ビュー

◆コントローラー

rails g controller comments new create

app/controllers/comments_controller.rb

class CommentsController < ApplicationController
  before_action :set_community

  def new
    @comment = @community.comments.new
  end

  def create
    @comment = @community.comments.new(comment_params)
    if @comment.save
      redirect_to community_path(@community)
    else
      render :new
    end
  end

  private

  def set_community
    @community = Community.find(params[:community_id])
  end

  def comment_params
    params.require(:comment).permit(:author_name, :content)
  end
end

◆ルーティング

Rails.application.routes.draw do
  root to: 'communities#index'
  resources :communities, only: %i[index new create show] do
    resources :comments, only: %i[new create]
  end
end

rails routesコマンドでこうなる。

Prefix                Verb URI Pattern                                       Controller#Action
                 root GET  /                                                 communities#index
   community_comments POST /communities/:community_id/comments(.:format)     comments#create
new_community_comment GET  /communities/:community_id/comments/new(.:format) comments#new
          communities GET  /communities(.:format)                            communities#index
                      POST /communities(.:format)                            communities#create
        new_community GET  /communities/new(.:format)                        communities#new
            community GET  /communities/:id(.:format)                        communities#show

◆ビュー

app/views/communities/show.html.erb

<%= link_to '←戻る', communities_path %>
<h1><%= @community.title %></h1>

<%= link_to 'コメントする', new_community_comment_path(@community) %>

<% @comments.each do |comment| %>
  <div>
    <p><%= comment.author_name %></p>
    <p><%= simple_format(comment.content) %></p>
    <p><%= comment.created_at %></p>
  </div>
<% end %>

app/views/comments/new.html.erb

<%= link_to '←戻る', community_path(@community) %>
<h1>コメントする</h1>

<%= form_with model: [@community, @comment] do |form| %>
  <%= form.label :author_name %>
  <%= form.text_field :author_name %>

  <%= form.label :content %>
  <%= form.text_area :content %>

  <%= form.submit '投稿' %>
<% end %>

app/views/comments/create.html.erbは削除。

2-2-4. Gemfileの変更

左上に出ている表示が邪魔なので、rack-mini-profilerを削除。

デバッグ用にpry-railsを入れる。

source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '3.0.0'

gem 'rails', '~> 6.1.2', '>= 6.1.2.1'
gem 'sqlite3', '~> 1.4'
gem 'puma', '~> 5.0'
gem 'sass-rails', '>= 6'
gem 'webpacker', '~> 5.0'
gem 'turbolinks', '~> 5'
gem 'jbuilder', '~> 2.7'
# gem 'redis', '~> 4.0'
# gem 'bcrypt', '~> 3.1.7'
gem 'bootsnap', '>= 1.4.4', require: false

group :development, :test do
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
  gem 'pry-rails'
end

group :development do
  gem 'web-console', '>= 4.1.0'
  # gem 'rack-mini-profiler', '~> 2.0'
  gem 'listen', '~> 3.3'
  gem 'spring'
end

gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

ひとまず完成。

次回(?)見た目をそれっぽく整えるの巻。

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

Railsポートフォリオ作成 #3 DB設計

こんにちは:smiley:
今回はDB設計を行いました。(前回記事(#2 画面設計))

私は、前職(ホテルの料飲部)における、コミュニケーションの課題を解決するアプリを作っているのですが、今回は、

DB設計を行いました

ER図はこんな感じになりました。
スクリーンショット DB.png

感じたこと

  • 抜け漏れをなくするのがとても大変
    今回私にとっては、今までにない数のテーブルが登場したため、マインドマップを使い、抜け漏れがないようにと意識しながら、機能、テーブル、カラムを洗い出しました。
    しかし、おそらく抜け漏れがあって、後から泣くことになるだろうなあという感じです。。。
  • ER図を見やすく構成するのが大変
    まず全てのテーブルを書き出し、その後リレーションを考えていってしまったため、最後に見やすく構成し直すという手間が発生してしまいました。
    先に考えておくべきでした。。。

意識したこと

  • 色分け、場所分けで少しでもわかりやすいようにする
  • 少しでもリレーションがごちゃごちゃしないようにする

次は、いよいよアプリケーションの雛形を作っていきます:fist:

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

RubyonRailsでRSpecによるテストコード実行手順メモ

初Qiita投稿で緊張しますが、自分用メモなのであんまり気張らずに書くようにします。
RubyonRailsでRSpecを使ってテストコード実行するときの簡単な手順メモです。
間違ってたり足りない部分があったら適宜アップデートします。

1. Gemfile内のどこの行でもいいので gem 'pry-rails' を追加する。 ※たいていは一番下に追加
2. Gemfileの group :development, :test do 内に下記2行を追加する。
   gem 'rspec-rails'
   gem 'factory_bot_rails' ※FactoryBotを使わない場合は不要
3. ターミナルで bundle install を実行してGemを使えるようにする。
4. ターミナルで rails g rspec:install を実行してRSpecを使えるようにする。
5. .rspecファイルに --format documentation を追加してテストのログを見やすくする。
6. ターミナルでrails g rspec:model [モデル名] を実行してモデルの単体テストコード用ファイルを生成する。
7. spec/factories/モデル名.rb というファイルにFactoryBotで生成するデータを記述する。(要詳細化)
8. spec/models/[モデル名]_spec.rb に単体テストコードを書く。(要詳細化)
9. ターミナルで bundle exec rspec spec/models/モデル名
spec.rb を実行する。

要詳細化にしている部分は記載方法を詳しくメモする必要があるためまた今度・・・。

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

ActiveResourceを使ってRailsアプリ同士をAPI連携させる

ActiveResourceを使う機会があったので、使い方を備忘録として残します。

ActiveResource とは

簡単に言うと、Railsアプリケーション同士を簡単にAPI連携させる機能です。

フロントとバックを分けて実装したい時に使います。

バック側の実装

実装
apiモードでアプリケーションを作成しています。

$ rails new back --api
$ cd back
$ bin/rails g scaffold bookmark title:string url:string comment:text
$ rake db:migrate

起動

$ rails s

フロント側の実装

実装

DBは使わないのでmigrationを削除しています。

$ rails new front
$ cd front
$ bin/rails g scaffold bookmark title:string url:string comment:text
$ rm -f db/migrate/* 

モデルクラス (app/models/bookmark.rb) を書き換える。
親クラスをActiveResource::Baseに変えて、連携先にhttp://localhost:3000/を指定しています。

app/models/bookmark.rb
class Bookmark < ActiveResource::Base
  self.site = 'http://localhost:3000/'
end

Gemを追加。

Gemfile
gem ‘activeresource'
$ bundle install
# 起動
$ rails s -p 3001 #ポートは3001に指定

動作確認

以上で実装、連携は完了です。

ブラウザで "http://localhost:3001/bookmarks" にアクセスして、いくつかブックマークを追加してみましょう。

<参考>
http://webos-goodies.jp/archives/how_to_use_activeresource_1.html

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

【Ruby on Rails】データベース操作まとめ(rails db:**)

データベース本体に関する操作

rails db:create

データベースの作成

<使用可能オプション>

  • rails_ENV
     環境を指定する(デフォルトはdevelopmentとtest)

rails db:drop

データベースの削除

<使用可能オプション>

  • rails_ENV
     環境を指定する(デフォルトはdevelopmentとtest)

テーブルに関する操作

rails db:migrate

migrationファイルを実行し、テーブルを作成する(全てのmigrationファイルが対象)

<使用可能オプション>

  • rails_ENV
     環境を指定する(デフォルトはdevelopmentとtest)
  • VERSION
     指定したバージョン以前のmigrationを全てupに、それより後のmigrationを全てdownにする

rails db:rollback

最新のmigrationを1つdownにする

<使用可能オプション>

  • STEP
     downにするmigrationの数を指定する
  • rails_ENV
     環境を指定する(デフォルトはdevelopmentとtest)

rails db:migrate:status

migrationの状態を表示する

<使用可能オプション>

  • rails_ENV
     環境を指定する(デフォルトはdevelopment)

rails db:migrate:up

VERSIONオプションで指定したmigrationをupにする

<使用可能オプション>

  • VERSION
  • rails_ENV
     環境を指定する(デフォルトはdevelopmentとtest)

rails db:migrate:down

VERSIONオプションで指定したmigrationをdownにする

<使用可能オプション>

  • VERSION
  • rails_ENV
     環境を指定する(デフォルトはdevelopmentとtest)

rails db:schema:dump

現在のデータベースの状態に合わせて、db/schema.rbを更新する

<使用可能オプション>

  • rails_ENV
     環境を指定する(デフォルトはdevelopment)

rails db:schema:load

db/schema.rbにあわせて、データベースを更新する(migrationファイルを参照しない)

<使用可能オプション>

  • rails_ENV
     環境を指定する(デフォルトはdevelopmentとtest)

レコードに関する操作

rails db:seed

dbディレクトリのseeds.rbファイルを実行し、レコードを作成する

<使用可能オプション>

  • rails_ENV
     環境を指定する(デフォルトはdevelopment)

rails r ファイルpath例:rails r db/seeds/test.rb

特定のseedファイルを実行し、レコードを作成する

いくつかの操作をまとめた物

rails db:setup

rails db:create
rails db:schema:load
rails db:seed
をまとめた物

<使用可能オプション>

  • rails_ENV
     環境を指定する(デフォルトはdevelopmentとtest ※seedはdevelopmentのみ)

rails db:reset

rails db:drop
rails db:create
rails db:schema:load
rails db:seed
をまとめた物

<使用可能オプション>

  • rails_ENV
     環境を指定する(デフォルトはdevelopmentとtest ※seedはdevelopmentのみ)

rails db:migrate:redo

rails db:rollback
rails db:migrate
をまとめた物

<使用可能オプション>

  • STEP
     やり直すmigrationの数を指定する
  • rails_ENV
     環境を指定する(デフォルトはdevelopmentとtest)
  • VERSION
     対象のmigrationを指定する

rails db:migrate:reset

rails db:drop
rails db:create
rails db:migrate
をまとめた物

<使用可能オプション>

  • rails_ENV
     環境を指定する(デフォルトはdevelopmentとtest)
  • VERSION
     指定したバージョン以前のmigrationを全てupに、それより後のmigrationを全てdownにする

補足

rakeとrailsの違い

Ruby on Railsのデータベース操作のコマンドを調べていると、rails ~というものとrake ~というものの2種類が見つかります。
これらは、Railsのバージョン4まででは区別をして使用していた物を、バージョン5より区別がなくなったそうなので、バージョン5以降を使用する場合は、全てrails ~で実行できる、とのことです。

schema.rbとは

migrationファイルは、それぞれのテーブルの設計図のような物です。
それに対してschema.rbは、現在のデータベースの構造を表した設計図のような物のようです。
すでに問題なく動いている環境をコピーする場合、migrationファイルではなくschema.rbを元にデータベースを構築した方が間違いの元を減らせる、という風にRailsの公式ドキュメントに記載があります。

参考ページ

Active Record Migrations — Ruby on Rails Guides

rails db:〇〇 まとめ - Qiita

Ruby on Railsでよく使う rake db コマンドまとめ13選 | caramelCase

RoRでseedファイルを指定して実行したい時。 - Qiita

Ruby - 「rake」コマンドと「rails」コマンドの違い|teratail

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

Herokuでrakeコマンドが使えない問題を解決:bundler: failed to load command: rake

エラー内容

HerokuにデプロイしたRuby+Sinatraアプリで heroku run rake db:migrate コマンドを実行すると、bundler: failed to load command: rake という内容のエラーが出てマイグレーションできない。

エラーが起きた環境

  • heroku20
  • ruby 2.6.6

原因

  • 開発環境でのBundlerのバージョンと、heroku環境でのBundlerのバージョンが違う。

解決方法

開発環境のbundlerのバージョンを確認

$ bundle -v
Bundler version 2.2.8

herokuのbundlerのバージョンを確認

$ heroku run bundle -v
Bundler version 2.1.4

開発環境にbundlerのバージョン2.1.4をインストールする

$ gem install bundler -v 2.1.4

herokuのbundlerのバージョンに合わせています。

開発環境でbundle install

$ bundle _2.1.4_ install

herokuにデプロイ

$ git add .
$ git commit -m "changed bundler version"
$ git push heroku master

これで解決できるはずです!

確認

実際にherokuでマイグレーションしてみる

$ heroku run rake db:migrate
migrated

という感じに出力されてマイグレーションが成功したことを確認できました!

まとめ

このエラー解決するのに3時間くらいかけてしまいました、、笑
間違ったことを書いてしまっていたらご指摘いただけると嬉しいです!

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

[Ruby on Rails]編集ページでのエラーメッセージの出し方

自身の失敗を踏まえた備忘録を書いていきます。

エラーメッセージの読み込みの記述

スクリーンショット 2021-02-12 23.47.50.png

上記の記述は別のファイルでエラー文の繰り返し処理を表した記述になります。
  
 
記入すべき所が空欄だったりしたら表示される文章を
エラー文と言います。

new.htmlと一緒のエラー文を、
編集ページedit.htmlでも表示させたい時に書く記述を書いていきます。
 

(例)

編集ページなのでeditとupdateアクションに定義してある
itemのインスタンス変数を使っていきます。
スクリーンショット 2021-02-13 0.02.26.png

ここで大事なのはprefix
item_pathを記述した後のメソッドのpatchです。

PATCH

編集をした情報を送信する際に使用するHTTPメソッドのことです。
  

editやupdateとややこしい所ですが、
今回のpatchは地味に大事なことなので自分も忘れないように覚えておこうと思います。

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