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

Mysql2::Error::ConnectionError: Access denied for user 'root'@'localhost' (using password: YES)への対処

記事の目的

rails db:migrateやrails sをするも以下のようなエラーが出て、解決に時間がかかってしまいました?
必要な経過だけ記事で共有させて頂き、誰かのお役に立てれば幸いです。

Mysql2::Error::ConnectionError: Access denied for user 'root'@'localhost' (using password: YES)

Mysql2::Error::ConnectionError: Access denied for user 'root'@'localhost' (using password: YES)はどういう時にエラーが出る?(結論:rootユーザのパスワードが正しくない)[現状把握①]

このエラーが何なのかしっかり言及している記事が見当たらなかったのですが、公式のリファレンスや英文の記事で把握できました。(using password: NOの場合の記事は多くあった気がする。。)

公式リファレンス(以下URL参照)には、「誤ったroot パスワードを使用していることを示しています。」と書かれている。
また、英文の記事(以下URL参照)には、「rootユーザがデータベースにアクセスするのに十分な権限を持っていない」「rootユーザのパスワードが正しくない」「rootユーザのパスワードが設定されていない」「rootユーザが十分な権限を持っていない」のいずれかと書かれています。

私の場合のエラーの原因の結論としては、
両方で言及されている「rootユーザのパスワードが正しくない」のが正解でした。

MySQLリファレンスマニュアル:https://dev.mysql.com/doc/refman/5.6/ja/access-denied.html
英文のページ:https://www.yawintutor.com/access-denied-for-user-root-localhost/
(調べたら、インドのプログラミングスクールの記事みたいです。会社の要求スキルと求職者のギャップを埋める為に運営してるそう。笑)

rootユーザのパスワードが正しくないのかを確認する[現状把握②]

MySQLのrootユーザーのパスワードの確認の為に、どのパスワードでログインできるかを確認します。
自身は、bash.profileに記載したパスワードをMySQLにおいても設定していると思いこんでいた為、確認しておらず時間がかかってしまいました。(ここで、パスワードが正しくないことに気づく。。)

$ mysql -u root -p
Enter password: ←(bash.profile記載のパスワードを入力するも入れない、、)
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)

空欄を入れてみると、ログインできたのでrootユーザーのパスワードは「空欄」であることの確認がとれました。

$ mysql -u root -p
Enter password: ←(パスワードを空欄にすると入れた!)
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 16
Server version: 5.7.32 Homebrew

解決策(結論:MySQLのパスワードとbash.profile記載のパスワードを一致させる)

database.ymlは、データベースと接続する為の設定ファイルです。
ここに書かれているユーザ名とパスワードを利用してRailsからMySQLにアクセスしますので、ここをMySQLのパスワードと合わせます。
私の場合は、bash.profileに環境変数を定義して、database.ymlにて環境変数の呼出をすることでdatabase.ymlへのユーザ名とパスワードの直書きを避けていました。

bash.profileに間違って定義しているパスワードを削除し、MySQLに設定されているパスワードを記載します。(今回は空欄)。viコマンドでファイルを開き、インサートモード(i入力)にして編集して保存(:wq)します。

$ vi ~/.bash_profile
(viコマンドで表示される画面↓)
export PATH="~/.rbenv/bin:$PATH"
eval "$(rbenv init -)"
alias =ls
export DB_USERNAME="root" 
export DB_PASSWORD="" (←空欄に変更)
~                                                                                                                                                                                                                                                                                                                                      
"~/.bash_profile" [readonly] 5L, 170C
database.yml
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: <%= ENV["DB_USERNAME"] %>(←ここでbash.profileで定義してる環境変数を呼出している)
  password: <%= ENV["DB_PASSWORD"] %>(←ここでbash.profileで定義してる環境変数を呼出している)
  host: localhost

database.ymlに直にユーザ名とパスワードを書かれている方は、セキュリティ上よくないので
以下の記事でbash_profileに記述する方法、.envファイルに記述する方法が書かれているので、そちらに記載するといいかもしれません。環境ごとで異なる環境変数を持ちたいときは.envへの記述をするようですね。

https://qiita.com/yuichir43705457/items/7cfcae6546876086b849

これで、MySQLのユーザ名とパスワードとdatabase.ymlに記載しているユーザ名とパスワードが一致している状態となりました。
rails db:migrate及びrails sを再度実行してみます。(エラーは出ないはず、、、)

rails db:migarate及びrails sを再度実行

実行する前に!!こちら忘れないで下さい。
以下のコマンドをせず、再度エラーが出てしまい「パスワードが違う以外の原因なのか??」と無駄に色々調べてしまいました。

$ source ~/.bash_profile

sourceコマンドは、設定ファイルの変更を反映させるコマンドとなります。
.bash_profileの変更を反映していなかったから、引き続きエラーが出たのですね。
最後、実行します。

rails db:migrateを実行...できました!!

$ rails db:migrate
== 20201113061351 AddConfirmableToDevise: migrating ===========================
-- add_column(:users, :confirmation_token, :string)
   -> 0.0814s
-- add_column(:users, :confirmed_at, :datetime)
   -> 0.0514s
-- add_column(:users, :confirmation_sent_at, :datetime)
   -> 0.0503s
-- add_column(:users, :unconfirmed_email, :string)
   -> 0.0457s
== 20201113061351 AddConfirmableToDevise: migrated (0.2292s) ==================

rails sも実行...できました!!

$ rails s
=> Booting Puma
=> Rails 6.0.3.3 application starting in development 
=> Run `rails server --help` for more startup options
Puma starting in single mode...
* Version 4.3.6 (ruby 2.6.3-p62), 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

めでたしめでたし。

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

Rails書評アプリ RSpec導入編

RSpec導入

Railsの標準で入っているminitestではなく、実務に置いてminitestより採用率の高いRSpecを導入する。
テストの手法であるTDD(Test Driven Development),BDD(Behavior Driven Development)に関しては追々学んでいく。

各種設定

Capybara・・・webアプリケーションのブラウザ操作をシミュレーションできる
FactoryBot・・・テスト用のデータベースの作成をサポートするgem

各Gemインストール

group :development, :test do
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
  gem 'rspec-rails',       '~> 4.0.0'
  gem 'factory_bot_rails', '~> 4.11'
  gem 'capybara',          '~> 2.13'
end

$bundle
$bin/rails g rspec:install
minitestのディレクトリを削除
$rm -r ./test
testの実行結果が見やすいように以下の記述を.rspec内に書いておく
--format documentation
色付け
--color

Capybarの初期準備

spec/spec_helper.rb
require 'capybara/rspec'

RSpec.configure do |config|
  config.before(:each, type: :system) do
    driven_by :selenium_chrome_headless
  end

webdriversのセッティング

ChromeDriverをかんたんに導入してくれるwebdriversをインストールする
gem 'webdrivers' 追記
$ mkdir spec/support
$ touch spec/support/driver_setting.rb

spec/support/driver_setting.rb
RSpec.configure do |config|
  config.before(:each, type: :system) do
    # Spec実行時、ブラウザが自動で立ち上がり挙動を確認できる
    # driven_by(:selenium_chrome)

    # Spec実行時、ブラウザOFF
    driven_by(:selenium_chrome_headless)
  end
end

FactoryBotでテストデータを作成できるように準備する

通常FactoryBotをつけないと、メソッドを呼べない
user = FactoryBot.create(:user)

上の設定を追加することで、FactoryBotの記述が省略できる。
user = create(:user)

spec/rails_helper.rb
require "support/factory_bot"
spec/support/factory_bot.rb
RSpec.configure do |config|
  # FactoryBotの呼び出し簡略化
  config.include FactoryBot::Syntax::Methods

  # springが原因でfactoryが正しく読み込まれないことを防ぐ
  config.before :all do
    FactoryBot.reload
  end
end
spec/rails_helper.rb
# このコードのコメントアウトを外す
# Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f }

Userのファクトリを定義する
「ファクトリ(Factory)」とはデータを作成することを簡単にする仕組みのこと

spec/factories/users.rb
FactoryBot.define do
  factory :user do
    name { 'テストユーザー' }
    email { 'test1@example.com' }
    password { 'password' }  
  end
end

Reviewのファクトリを定義する

spec/factories/reviews.rb
FactoryBot.define do
  factory :review do
    title { "MyString" }
    author { "MyString" }
    description { "MyText" }
    user
  end
end

spring-commands-rspecを導入する

このgemによってテストの起動時間が早くなる

group :development do
  gem 'spring-commands-rspec'
end

bundle installし、次にbundle exec spring binstub rspecをするとbinディレクトリにrspecファイルが生成される

#!/usr/bin/env ruby
begin
  load File.expand_path('../spring', __FILE__)
rescue LoadError => e
  raise unless e.message.include?('spring')
end
require 'bundler/setup'
load Gem.bin_path('rspec-core', 'rspec')

Shoulda Matchersの設定

Shoulda Mathersとは、RSpecやMinitestにワンライナーのテストのシンタックスを追加することで、簡潔かつ直感的にテストを書けるようになるgem

group :test do
  gem 'shoulda-matchers'

  # rails5以降の場合、 
  gem 'shoulda-matchers', git: 'https://github.com/thoughtbot/shoulda-matchers.git', branch: 'rails-5'
end
spec/support/shoulda_matchers.rb
Shoulda::Matchers.configure do |config|
  config.integrate do |with|
    with.test_framework :rspec
    with.library :rails
  end
end
spec/rails_helper.rb
require "support/shoulda_matchers"
config/application.rb
require_relative 'boot'
require 'rails/all'
require 'uri'

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module BookReviewApp
  class Application < Rails::Application
    config.load_defaults 5.1
    config.generators.template_engine = :slim
    config.i18n.default_locale = :ja
    config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}').to_s]

    config.generators do |g| 
      g.test_framework :rspec,
        fixtures: false, 
        view_specs: false, 
        helper_specs: false, 
        routing_specs: false
    end
  end
end

モデルテストのコードを書いてみる

specフォルダの中にmodelsというフォルダを作成して、modelsフォルダの中にuser_spec.rbファイルを作って以下のコードを書く
$ mkdir spec/models
$ touch spec/models/user_spec.rb

spec/mogels/user_spec.rb
require 'rails_helper'

RSpec.describe User, type: :model do
  pending "add some examples to (or delete) #{__FILE__}"

  context "if name is entered" do              
    it 'if user registration is successful' do 
    end
  end

  context "if name is not entered" do          
    it 'if user registration fails' do
    end
  end

  context 'if email is entered' do
    it 'if user registration is successful' do
    end
  end

  context 'if email is not entered' do
    it 'if user registration fails' do
    end
  end

  context "if password is entered" do
    it 'if user registration is successful' do
    end
  end

  context "if password is not entered" do
    it 'if user registration fails' do
    end
  end
end
 # テストの説明文の言語は構文によって変える

 # example構文
example '日本語' do
  # コードを記述する
end

  # it構文
it 'English' do
  # コードを記述する
end

このファイルだけをテストしたい場合、ファイルを指定する必要がある
$ bundle exec rspec spec/models/user_spec.rb

examples:存在するテスト / failures:失敗したテスト / pending:実行されなかったテスト

レビューの一覧表示機能のSystem Spec

$ mkdir spec/system/
$ touch spec/system/reviews_spec.rb

まずはコメントでSpecの大枠を作る

spec/system/reviews_spec.rb
require 'rails_helper'

describe 'レビュー管理機能', type: :system do
    describe '一覧表示機能' do
        before do 
        # ユーザーAを作成しておく
        # 作者がユーザーAであるレビューを作成しておく
        end

context 'ユーザーがログインしているとき' do
    before do 
        # ユーザーAがログインする
    end

    it 'ユーザーAが作成したレビューが表示される' do
        # 作成済みのレビューのタイトルが画面上に表示されていることを確認
    end
  end
 end
end

describeには、「何について仕様を記述しようとしているのか」(テストの対象)を記述する。
一番外側のdescribeには、そのSpecファイル全体の主題を記述する。
階層の深いdescribeにはより細かいテーマを記述する。

contextは、テスト内容を「状況・状態」のバリエーションごとに分類するために利用する。
様々な条件で正しく動くか試す必要があるテストを整理して見やすくすることができる。

beforeは、その領域全体の「前提条件」を実行するためのコードを記述する場所。
describeやcontext内にbeforeを記述すると、対応するdescribeやcontextの領域内のテストコードを実行する前に、beforeのブロック内に書かれたコードを実行してくれる。

itは、期待する動作を文章と、ブロック内のコードで記述する。itの中に書いた期待する動作通りに対象が動作すれば、テストは成功となる。


※以下の順番でコードが実行される
最初のbefore
・ユーザーAを作成しておく(テストデータの準備)
・作成者がユーザーAであるレビューを作成しておく(テストデータの準備)
2つめのbefore
・ユーザーAでブラウザからログインする(前提となっているユーザーの操作をしておく)
it
・ユーザーAの作成したレビューのタイトルが画面上に表示されていることを確認


1つ1つのコメントを、実際のコードに置き換えていく

spec/system/reviews_spec.rb
require 'rails_helper'

describe 'レビュー管理機能', type: :system do
    describe '一覧表示機能' do
        before do 
        # ユーザーAを作成しておく
        user_a = create(:user, name: 'ユーザーA', email: 'a@example.com')
        # 作者がユーザーAであるレビューを作成しておく
        create(:review, name: '最初のレビュー', user: user_a)
        end

context 'ユーザーがログインしているとき' do
    before do 
        # ユーザーAがログインする
        visit login_path
        fill_in 'メールアドレス', with: 'a@example.com'
        fill_in 'パスワード', with: 'password'
        click_button 'ログインする'
    end 

    it 'ユーザーAが作成したレビューが表示される' do
        # 作成済みのレビューのタイトルが画面上に表示されていることを確認
        expect(page).to have_content '最初のレビュー'
    end
  end
 end
end
 # テストが失敗した場合
$ bundle exec rspec spec/system/reviews_spec.rb

レビュー管理機能
  一覧表示機能
    ユーザーがログインしているとき
      ユーザーAが作成したレビューが表示される (FAILED - 1)

Failures:

  1) レビュー管理機能 一覧表示機能 ユーザーがログインしているとき ユーザーAが作成したレビューが表示される
     Failure/Error: user_a = FactoryBot.create(user, name: 'ユーザーA', email: 'a@example.com')

     NameError:
       undefined local variable or method `user' for #<RSpec::ExampleGroups::Nested::Nested::Nested:0x00007fed26346f28>

     [Screenshot]: tmp/screenshots/failures_r_spec_example_groups_nested_nested_nested_ユーザーaが作成したレビューが表示される_412.png



     # ./spec/system/reviews_spec.rb:7:in `block (3 levels) in <top (required)>'

Finished in 4.19 seconds (files took 5.32 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/system/reviews_spec.rb:21 # レビュー管理機能 一覧表示機能 ユーザーがログインしているとき ユーザーAが作成したレビューが表示される

レビューの新規作成機能のSystem Spec

spec/system/reviews_spec.rb
.
.
.
describe 'レビュー新規作成機能' do
    let(:login_user) { :user_a }

    before do 
        visit new_review_path
        fill_in 'タイトル', with: review_name
        click_button '投稿する'
    end

    context '新規投稿画面でタイトルを入力したとき' do
        let(:review_name) { '新規投稿のテストを書く' }

        it '正常に投稿される' do
            expect(page).to have_selector 'alert-success', text: '新規投稿のテストを書く'
        end
    end

    context '新規投稿画面でタイトルを入力しなかったとき' do
        let(:review_name) { '' }

        it 'エラーになる' do
            within '#error_explanation' do
            expect(page).to have_content 'タイトルを入力してください'
        end
      end
    end
  end
end

letは「before処理でテストスコープの変数に値を代入する」のに近いイメージで利用できる機能(実際に変数を作るわけではない)
let(定義名){ 定義の内容 }

have_selectorというマッチャを使うと、HTML内の特定の要素をセレクタ(CSSセレクタ)で指定することができる
have_selector

withinというメソッドを使うと、withinのブロックの中でpageの内容を検査することで、探索する範囲を画面内の特定の範囲に狭めることができる
within '範囲を指定' do

Userモデルのテスト

コメントで大枠を作る

spec/models/user_spec.rb
 # validations
 describe "validations" do
   # 存在性
   describe "presence" do
     # 名前、メールアドレス
     it "name and email should not ro be empty/falsy"
     # パスワード、パスワード確認
     context "when password and confirmation is not present" do
       it "@user is invalid"
     end
    end
   # 文字数 charesters
   describe "charesters" do
     # 名前: 最大 20 文字
     context "when name is too long"
       it "@user is inavlid"
     # パスワード、パスワード確認: 最小 6 文字
     describe "when password is too short"
       it "@user is inavlid"
   end
 # email のフォーマット
 describe "email format" do
   # invalid なフォーマット
   context "when invalid format" do
     it "@user is inavlid"
   # valid なフォーマット
   context "when valid format" do
     it "@user is valid"
   end
   end
  end
end

コメントを埋めていく

spec/models/user_spec.rb
RSpec.describe User, type: :model do
  # 保留されたテンプレート
  pending "add some examples to (or delete) #{__FILE__}"

 # validations
 describe "validations" do
   # 存在性
   describe "presence" do
     # 名前、メールアドレス
     it { should validate_presence_of :name }
     it { should validate_presence_of :email }
     # パスワード、パスワード確認
     context "when password and confirmation is not present" do
       before { user.password = user.password_confirmation = " " } 
       it { should_not be_valid }
     end
    end
   # 文字数 charesters
   describe "charesters" do
     # 名前: 最大 20 文字, パスワード: 最小 6 文字
     it { should validate_length_of(:name).is_at_most(20) }
     it { should validate_length_of(:password).is_at_least(6) }
   end
 # email のフォーマット
 describe "email format" do
   # invalid なフォーマット
   context "when invalid format" do
     # 無効なオブジェクト
     it "should be invalid" do
       invalid_addr = %w[user@foo,com user_at_foo.org example.user@foo. foo@bar_baz.com foo@bar+baz.com]
       invalid_addr.each do |addr|
         user.email = addr
         expect(user).not_to be_valid
       end
      end
    end
  end
   # valid なフォーマット
   context "when valid format" do
     # 有効なオブジェクト
     it "should be valid" do
       valid_addr = %w[user@foo.COM A_US-ER@f.b.org frst.lst@foo.jp a+b@baz.cn]
       valid_addr.each do |addr|
         user.email = addr
         expect(user).to be_valid
       end
     end
   end
  end
end

↓テスト結果↓

console.log
$ bundle exec rspec spec/models/user_spec.rb

User
  add some examples to (or delete) /Users/kiyokawakouji/Rails-app/book_review_app/spec/models/user_spec.rb (PENDING: Not yet implemented)
  validations
    presence
      is expected to validate that :name cannot be empty/falsy
      is expected to validate that :email cannot be empty/falsy
      when password and confirmation is not present
        example at ./spec/models/user_spec.rb:17 (FAILED - 1)
    charesters
      is expected to validate that the length of :name is at most 20
      is expected to validate that the length of :password is at least 6
    email format
      when invalid format
        should be invalid (FAILED - 2)
    when valid format
      should be valid (FAILED - 3)

Pending: (Failures listed here are expected and do not affect your suite's status)

  1) User add some examples to (or delete) /Users/kiyokawakouji/Rails-app/book_review_app/spec/models/user_spec.rb
     # Not yet implemented
     # ./spec/models/user_spec.rb:5


Failures:

  1) User validations presence when password and confirmation is not present 
     Failure/Error: before { user.password = user.password_confirmation = " " }

     NameError:
       undefined local variable or method `user' for #<RSpec::ExampleGroups::User::Validations::Presence::WhenPasswordAndConfirmationIsNotPresent:0x00007fd1586e2770>
     # ./spec/models/user_spec.rb:16:in `block (5 levels) in <top (required)>'

  2) User validations email format when invalid format should be invalid
     Failure/Error: user.email = addr

     NameError:
       undefined local variable or method `user' for #<RSpec::ExampleGroups::User::Validations::EmailFormat::WhenInvalidFormat:0x00007fd15831d6f8>
     # ./spec/models/user_spec.rb:34:in `block (6 levels) in <top (required)>'
     # ./spec/models/user_spec.rb:33:in `each'
     # ./spec/models/user_spec.rb:33:in `block (5 levels) in <top (required)>'

  3) User validations when valid format should be valid
     Failure/Error: user.email = addr

     NameError:
       undefined local variable or method `user' for #<RSpec::ExampleGroups::User::Validations::WhenValidFormat:0x00007fd1582d5790>
     # ./spec/models/user_spec.rb:46:in `block (5 levels) in <top (required)>'
     # ./spec/models/user_spec.rb:45:in `each'
     # ./spec/models/user_spec.rb:45:in `block (4 levels) in <top (required)>'

Finished in 0.61427 seconds (files took 5.94 seconds to load)
8 examples, 3 failures, 1 pending

Failed examples:

rspec ./spec/models/user_spec.rb:17 # User validations presence when password and confirmation is not present 
rspec ./spec/models/user_spec.rb:31 # User validations email format when invalid format should be invalid
rspec ./spec/models/user_spec.rb:43 # User validations when valid format should be valid

以下テスト結果の解説
pandingはコメントアウトでも書かれている通り、RSpecの書き方を示しているテンプレート(今回はあえて消さずに起こしておいた)なのでスルー。
(FAILED - 数字)がテストコードが失敗したことを示している。今回は3カ所のテストコードが失敗したことになる。
Failures:~はテストが失敗した該当コードとエラー内容が出力されている。
Failures example:~はテストが失敗したファイルの該当コードの行と期待する動作が出力されている。
今回はモデルのテストなのでvalidatesを確認していく

app/models/user.rb
class User < ApplicationRecord
 devise :database_authenticatable, :rememberable, 
        :validatable, :timeoutable, :registerable, :confirmable

 # nameの値が空でないか?
 validates :name, presence: true
 # nameの値が20文字以下か?
 validates :name, length: { maximum: 20 }
 # emailアドレスをデータベースに保存する際にメールアドレスを小文字にする
 before_save { self.email = email.downcase }
 VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
 # emailがその確認用の入力と一致しているか?
 validates :email, { presence: true, format: { with: VALID_EMAIL_REGEX } }
 validates :email, :encrypted_password, confirmation: true
 # passwordの値が空でないか?
 validates :password, presence: true
 # passwordの値が6文字以上か?
 validates :password, length: { minimum: 6 }
 # データベース上でUserとReviewを紐づける
 has_many :reviews, dependent: :destroy, foreign_key: :review_user_id
end

番外編

失敗したテストだけを再実行できる(--only-failuresオプション)の設定

spec_helper.rb
RSpec.configure do |config|
  config.example_status_persistence_file_path = "./spec/examples.txt"
end

------------------------------------------------------------------

gitを使っている場合は .gitignore に以下の設定も追記します。
spec/examples.txt

$ bundle exec rspec --only-failures

rspecのオプション

rspecのオプション一覧表示
$ rspec --help

テストの一覧を実行せずに出力
$ rspec --dry-run

テストの警告を出力
$ rspec --warnings
このコマンドはspecファイル中の警告を表示する。スペルミスなどがあればそれも警告の内に入れ、出力する

試しに$ rsoec --warningsをした際に以下の出力がされた

WARN: Unresolved or ambiguous specs during Gem::Specification.reset:
      diff-lcs (>= 1.2.0, < 2.0)
      Available/installed versions of this gem:
      - 1.4
      - 1.3
WARN: Clearing out unresolved specs. Try 'gem cleanup <gem>'
Please report a bug if this causes problems.
~~省略~~

同一のgemが複数のバージョンでインストールされていて、システムでどれを扱うか決められないと言われている。
旧バージョンのgemを削除して、一つに絞るか、具体的なバージョンを決める必要がある。

テストの種類

全体的なテスト
・システムテスト(System Spec/Feature Spec)
・統合テスト(Request Spec)
・機能テスト(Controller Spec)
個々の部品テスト
・モデル(Model Spec)
・ルーティング(Routing Spec)
・ビュー(View Spec)
・ヘルパー(Helper Spec)
・メーラー(Mailer Spec)
・ジョブ(job Spec)

テストコード自体の信頼性

テストコードが意図した通りに動いていることを確認しなければならない。これは「テスト対象のコードでいろいろ試すアプローチ(exercising the code under test)」としても知られている。
誤判定ではないことを証明するためには例えば、toto_notに変えてエクスペクテーションを反転させる。

spec/models/user_spec.rb
 # 名がなければ無効な状態であること(成功)
 it "is invalid without a first name" do
   user = User.new(first_name: nil)
   user.valid?
   expect(user.errors[:first_name]).to include("can't be blank")
 end

 # 名がなければ無効な状態であること(失敗)
 it "is invalid without a first name" do
   user = User.new(first_name: nil)
   user.valid?
   expect(user.errors[:first_name]).to_not include("can't be blank")
 end

参考

Rails RSpecの準備とテストコード基礎
【Rails】『RSpec + FactoryBot + Capybara + Webdrivers』の導入&初期設定からテストの書き方まで
Rails + Selenium + DockerでSystemSpecの環境構築
https://github.com/everydayrails/everydayrails-rspec-2017
使えるRSpec入門・その1「RSpecの基本的な構文や便利な機能を理解する」
RSpec 設定
Rspecの便利なオプション
苦しめられてやっと理解できたRailsコールバックの使い方

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

トップページにおしゃれな背景画像を使うだけでそれっぽいサイトになる説を検証してみた

はじめに

なぜやるか

就活用のポートフォリオを作っていて第一印象がなんだか安っぽいな〜と感じたので少し手を加えてみる

作っているもの

記事投稿アプリ(Qiitaに近い)

before

スクリーンショット 2020-11-13 20.33.52.png

非ログインユーザーでも閲覧できるようにしたいので、頭にログインページは設けず。
その結果、初めてのユーザーにとってどうしたらいいの?というインターフェースになってしまっている。

after

スクリーンショット 2020-11-13 20.34.22.png

とりあえず背景画像とゲストログインボタンを設置してみた。
うん、非常に改善されたと思う。

手順

ここからは画像の加工やCSSに慣れていない初心者向けに書きます。

おしゃれ画像はUnsplash一択

画像に困ったらとにもかくにもUnsplash。
世界中の美しい写真がログイン不要かつ無料でダウンロードできる。

Unsplash

加工はKeynote

MacユーザーであればKeynoteで事足ります。

新規スライド
  ↓
スライドサイズ設定
  ↓
画像を挿入
  ↓
画像サイズ調整

<--- ここまでで写真のトリミングが完了 --->

スクリーンショット 2020-11-13 20.57.17.png

縦200px,横600pxでトリミング

画像に透かしを入れる

  • 黒い透かし

写真の上に四角形を重ねる
  ↓
四角形の色を黒にする
  ↓
不透明度を調節する

スクリーンショット 2020-11-13 21.01.18.png

  • 白い透かし

色を白にしたらこんな感じ

スクリーンショット 2020-11-13 21.02.39.png

加工が終わったら

ファイル
 ↓
書き出す
 ↓
イメージ

から好きなファイル形式を選んで出力

トップページに配置

viewファイル

index.html.erb
<div class='guest-login-box'>
  <%= link_to 'ゲストログイン', users_guest_sign_in_path, method: :post, class:'guest-login-btn' %>
</div>

CSS

index.css
.guest-login-box {
  height: 30vw;
  width: 100vw;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background-image: url("/images/guest_login_box_background.png");
  background-position: center;
  background-size: cover;
}

.guest-login-btn {
  border: 2px solid #fff;
  padding: 8px 20px;
  color: #fff;
}

画像はとりあえずpublic/imagesに配置しました。

以上で、トップ画像の完成です。

おわりに

ログインさせるためだけのトップページはユーザーファーストじゃない気がしていて(構造的にログイン不可欠なアプリは別ですが)

だからと言って、そのまんま出しすると???なUIになるし、第一印象がノペーっとしてパンチ弱くなるなと思いました。

誰かの参考になればうれしい

✔︎

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

Railsで検索バーを設ける〜複数テーブルを結合させて検索を行う

はじめに

今回は、投稿データ(Post)を検索バーでキーワード検索を行い、表示させる。また、複数のテーブルを結合させて、その範囲で検索できるように実装していきます。

完成イメージ

※後日掲載予定

環境

MacOS 10.15.7
ruby 2.6.5
Ruby on Rails 6.0.0

執筆者の状況

テーブル

searchFunction1.png

利用者を「User」、投稿を「Post」、画像を「Image」、都道府県を「Prefecture」(seedデータ)としてテーブルを作成しております。
(テーブルの中身は投稿用に簡略化してます)

リレーションは次の通りです。

user.rb
has_many :posts, dependent: :destory
post.rb
belongs_to :user
belongs_to :prefecture

has_many :images, dependent: :destory


accepts_nested_attributes_for :images, allow_destroy: true
image.rb
belongs_to :post

mount_uploader :image, ImageUploader
prefecture.rb
has_many :posts

このような形になっています。userとimageも紹介してはいるのですが、今回は関わりが無いので説明を省略します。
prefectureはpost(投稿)を複数持っているので、「has_many :posts」としています。
postはprefectureに属しているので、「belongs_to :prefecture」になります。

作業していきます!

①検索バーの設定〜機能実装

①-1 検索バーの作成

このようにして検索バーを作成します。

index.html.erb
<%= form_with(url: search_posts_path, local: true, method: :get, class: "rootpageSearchForm") do |form| %>
  <%= form.text_field :keyword, placeholder: "キーワードを入力", id: 'Search_Form', class: "rootpageSearchForm__content" %>
  <%= form.submit "検索", class: "rootpageSearchForm__bottum" %>
<% end %>
index.scss
.rootpageSearchForm {
  width: auto;
  &__content {
    width: 40vw;
    height: 30px;
    color: #000000;
    border-radius: 5px;
    border-color: #008bbb;
  }
  &__bottum {
    margin-left: 0.5vw;
    height: 30px;
    width: 150px;
    border-radius: 20px;
    background-color: #87cefa;
    border: none;
    box-shadow: 0 0 8px gray;
    color: #ffffff;
    -webkit-transition: all 0.3s ease;
    -moz-transition: all 0.3s ease;
    -o-transition: all 0.3s ease;
    transition: all 0.3s ease;
  }
  .rootpageSearchForm__bottum:hover {
    background-color: #00bfff;
  }
}

以上となります。完成イメージはこんな感じです。
searchForm.png

①-2 searchアクションの作成

routes.rbにsearchアクションを新規で定義します。今回はpostアクションにネストさせた形で定義します。
以下のように定義します。

routes.rb
Rails.application.routes.draw do
  resources :posts do
    collection do
      get 'search'
    end
  end
  下記一部省略...
end

今回、検索のキーワードで該当する投稿を一覧として表示させるので、idが不要なため

collection do
  get 'search'
end

と定義します。

仮にidを必要とする場合(投稿の詳細ページなど)はcollectionではなく、memberを用いて定義します。
collectionとmemberの違いはURLにidが付くか、付かないかの違いです。

collection ・・・ ルーティングにidが付かない。
member ・・・ ルーティングにidが付く。

①-3 searchメソッドをpostモデルに定義

class Post < ApplicationRecord
  ...上記一部省略
  def self.search(search)
    if search != ""
      Post.where('content LIKE(?) OR title LIKE(?), "%#{search}%", "%#{search}%")
    else
      Post.all
    end
  end
  下記一部省略...
end

whereメソッドを使って、引数に記述した条件を基に、テーブル内の「条件に一致したレコードのインスタンス」を配列の形で取得。

LIKE句を使い、曖昧な文字列を検索するようにしています。

文字列 意味
任意の文字列(空白文字列含む)
_ 任意の1文字

実行例

実行例 意味
where('title LIKE(?)', "a%") aから始まるタイトル
where('title LIKE(?)', "%b") bで終わるタイトル
where('title LIKE(?)', "d_") cが含まれるタイトル
where('title LIKE(?)', "%b") dで始まる2文字のタイトル
where('title LIKE(?)', "_e") eで終わる2文字のタイトル

引数searchは、検索フォームから送信されたパラメーターが入る。
そのため、if search != ""と記述し、検索フォームに何か値が入力されていた場合を条件とする。

検索フォームに何も入力されない(空の状態)で検索ボタンが押されると、引数に渡されるsearchの中身が空になるので、その場合の処理をelse文内で記述。
今回はPost.allとして、全ての投稿を取得して表示させます。

テーブルとのやりとりに関するメソッドはモデルに置くのが基本!

①-4 コントローラーを記述

posts_controller.rbにsearchアクションを定義します。

posts_controller.rb
class PostsController < ApplicationController
  ...上記一部省略...
  def search
    @posts = Post.search(params[:keyword]).order(created_at: :desc)
  end
  ...下記一部省略...

searchメソッドの引数にparams[:keyword]と記述して、検索結果を渡します。

また、検索結果を投稿が新しい順で並べるため、order(created_at: desc)と記述してます。

①-5 search.html.erbを作って、検索結果を表示させる

あとは、検索結果画面を表示させるsearch.html.erbを作って完了です。

search.html.erb
<div class="wrapper">
  <% @posts.each do |post| %>
    <div class='contents row'>
    ...以下省略...
  <% end %>
</div>

①-6 完成!

これで、検索バー並びにキーワード検索により、検索結果を表示できるようになりました。
ここまでの設定では、Postテーブルの「content(投稿文)」と「title(投稿タイトル)」が検索対象になっている状態です。

② 他のテーブルを結合させて、検索対象に追加する。

今回、都道府県名でも検索できるように、検索対象にPrefectureテーブルの「name(都道府県名)」を追加していきたいと思います。

postモデルに記述を追加していきます。

class Post < ApplicationRecord
  ...上記一部省略
  def self.search(search)
    if search != ""
      Post.joins(:prefecture).where('content LIKE(?) OR title LIKE(?) OR prefectures.name LIKE(?)', "%#{search}%", "%#{search}%", "%#{search}%")
    else
      Post.all
    end
  end
  下記一部省略...
end

prefectureテーブルも検索対象にするために、joins(:prefecture)として追加しています。
joinメソッド複数のテーブルを1つに結合したいときに使うメソッドです。
今回の場合は、postテーブルとprefectureテーブルを結合させて、1つのテーブルとして扱います。

whereメソッドの引数の部分には、OR prefectures.name LIKE(?)'を追加して都道府県名を検索対象に指定しています。この分の"%#{search}%"も1つ追加して完了です。

最後に

初学者のため、間違い等ありましたらご指摘いただけますと幸いです。
最後までご覧いただきありがとうございました。

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

rbenvを用いて任意バージョンのRubyの環境構築を行う方法

この記事では rbenv を用いて任意のバージョンの Ruby 環境を構築する方法を紹介します。

rbenv とは?

rbenv とはバージョンの異なるrubyをまとめて管理するツールのことです。

rbenvを利用することで異なるバージョンのrubyを一元管理することができ、
さらに任意のバージョンにいつでも切り替えられるようになるため
任意のバージョンで Ruby を使うことができます。

例えば自己学習を進めているときに、例えばある教材では ruby 2.5.2 を使うといっているのに
別な教材では ruby 2.7.0 を使うように指示が出ていると、バージョン間の差異によりエラーが発生して詰まることがあります。

rbenv を使うことで、いつでも好きなバージョンを使うことが出来るので
少なくともバージョン間の差異によるエラーは抑制することができます。

rbenv のセットアップ

それでは実際に rbenv をセットアップしていきましょう。

rbenv をインストール

rbenv は HomeBrew でインストールできます。
以下のコマンドを叩きましょう。

$ brew install rbenv

rbenv の初期設定

rbenv のインストールが終わったら初期設定を行うため rbenv init を入力します。

$ rbenv init

入力し Enter を押すと以下のように指示が表示されるので、指示に従っていきます。
ここでは ~/.bash_profile に eval ~ という行を追加するようにいっています。

$ rbenv init
# Load rbenv automatically by appending
# the following to ~/.bash_profile:

eval "$(rbenv init -)"

vi コマンドで .bash_profile を開き、末尾に eval ~ を追加しましょう。
※vimなどの操作に慣れていない場合は、隠しファイルとはなりますが直接 .bash_profile を編集してもよいです。

$ vi ~/.bash_profile

保存し終わったら一度ターミナルを終了し、再度ターミナルを開きます。
これで rbenv をどこからでも使えるようになりました。

rbenv のテスト

その後、rbenv がちゃんと機能しているかをチェックするために以下のコマンドを実行します。
(rbenv の公式サイトに紹介されています))

$ curl -fsSL https://github.com/rbenv/rbenv-installer/raw/master/bin/rbenv-doctor | bash
Checking for `rbenv' in PATH: /usr/local/bin/rbenv
Checking for rbenv shims in PATH: OK
Checking `rbenv install' support: /usr/local/bin/rbenv-install (ruby-build 20170523)
Counting installed Ruby versions: none
  There aren't any Ruby versions installed under `~/.rbenv/versions'.
  You can install Ruby versions like so: rbenv install 2.2.4
Checking RubyGems settings: OK
Auditing installed plugins: OK

上記の例のように、すべて OK と表示されていれば rbenv の準備は完了です。

Ruby のセットアップ

rbenv で Ruby のバージョン管理をできるようになったので、Ruby をインストールしていきます。

rbenv で Ruby をインストール

rbenv install xxxx を入力して Ruby をインストールします。
今回は執筆時点で最新安定バージョンである ruby 2.7.0 をインストールします。

$ rbenv install 2.7.0

インストールされている Ruby の一覧を確認

インストール済みのバージョンを確認するには rbenv version を入力します。

$ rbenv versions
  system
* 2.5.1 (set by /Users/xxxxxx/.rbenv/version)
  2.6.3
  2.7.0
  • がついているバージョンが、現在つかっている ruby のバージョンです。 つまり 2.7.0 はインストールされただけであり、まだ切り替わっていないことを表しています。 ※上記の例は既に rbenv で他のバージョンをインストールしている時のものです

バージョンの切り替え

インストールした 2.7.0 に切り替えるためには rbenv global コマンドを使います。

$ rbenv global 2.7.0

ruby -v を入力し、どの Ruby バージョンを使っているかを確認しましょう。

$ ruby -v
ruby 2.7.0p0 (2019-12-25 revision 647ee6f091) [x86_64-darwin19]

2.7.0 と表示されているので、無事に ruby 2.7.0 をインストールし、環境を構築することができました。

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

[Rails][ActiveStorage] 特定のuserがavatarを持っているかどうか調べる

あるuserがavatarを持っていない場合、 user.avatar にアクセスしようとすると例外が発生する。これを防ぐには user.avatar.attached? として事前にファイルが添付されているか調べるようにする。

class User < ApplicationRecord
  has_one_attached :avatar
end

user = User.last
user.avatar.attached?
=> false

# 添付がないのにアクセスしようとすると例外が発生
user.avatar.url
=> Module::DelegationError: url delegated to attachment, but attachment is nil

# 以下のようにすることで回避できる
user.avatar.url if user.avatar.attached?
=> nil

メモ:このコミットで例外が発生しないように対応されるよう
https://github.com/rails/rails/commit/f002be148e1377709ed28b8e80c5db76ee2fa410

追記:v6.1.0.rc1に上記コミットが入っていることを確認

user = User.last
user.avatar.attached?
=> false

# Rails 6.1.0.rc1 では例外発生しないように対応済み
user.avatar.url
=> nil

参考URL

Railsガイド
https://railsguides.jp/active_storage_overview.html

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

【Rails】collection_selectでCSSが適用されない時は、classを指定できてるか確認しよう

はじめに

  • オリジナルアプリ開発で発見したことについて、定着と備忘のためにまとめていきます。

結論

  • CSS書けてるはずなのに変化がないときは、以下を確認してみよう
    • class名が間違っていないか
    • 記述したことが開発ツール上でも表示されているか
  • collection_selectのoptionとHTML属性には {} を付けよう

経緯

やりたいこと

  • collection_selectで作ったセレクトボックスのスタイリングをしたい

作成したコード(誤り)

#erbファイル
<div class="search-field">
  <%= f.label :occupation_id, "職種", class:"search-label" %>
  <%= f.collection_select(:occupation_id, Occupation.all, :id, :name, selected: @search_params[:occupation_id], include_blank: "選択しない", class:"search-occupation") %>
</div>

検索フォームの一部でoccupationモデルから選択出来るようにしています。
collection_selectの具体的な使い方はガイド内をご確認下さい → Railsドキュメント

オプションで下記のものを指定しています。
selected: → 遷移後に@search_paramsの値が選択されるようにしています
include_blank: → 初期状態(選択していない状態)の値を指定しています

次の箇所で問題が発生しました。
3行目のclass:search-occupationに対して下記のCSS記述しましたが、適用されませんでした。

#scssファイル
.search-occupation {
    width: 100%;
    padding: 8px 8px 5px;
    outline: none;
}

開発ツールで確認すると、class:"search-occupation"が指定できていないことが分かりました。(画像3行目)

スクリーンショット 2020-11-13 18.08.41.png

HTMLでclassが指定できていないため、CSSが無効になっている訳ということですね。
対応には下記の記事を参考にさせて頂きました。
ActionView::Helpers::FormOptionsHelper
【Rails】完全理解 formでセレクトボックスをつくるselectの使い方
railsでf.selectにclassを設定する

今回の対応

collection_selectについて調べていく中で、どうやらoptionHTML属性には{}が必要と分かりました。(上述のコードのうち、引数の:nameより後ろの部分)
また、今回のようにoptionが2つある場合は、同じ{}内に記述する必要があります。

  • OK { selected: 〇〇, include_blank: 〇〇}
  • NG { selected: 〇〇}, {include_blank: 〇〇}ArgumentErrorでした

修正したコード

3行目を修正しています

<div class="search-field">
  <%= f.label :occupation_id, "職種", class:"search-label" %>
  <%= f.collection_select(:occupation_id, Occupation.all, :id, :name, {selected: @search_params[:occupation_id], include_blank: "選択しない"}, {class:"search-occupation"}) %>
</div>

おわりに

  • 引数が多いhelperのため、まずは落ち着いてルールを確認したことでスムーズに解決出来ました。
  • また、大元の検索機能はこちらの記事を参考にさせて頂きました。
  • 初学者ゆえ、記事内に誤りがあるかもしれません。ご指摘等ありましたら、お手数ですがコメントを頂けると幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails]データベースのデータ型種類について勉強してみた!

はじめに

データベースのデータ型ってメッチャ種類があって、ややこしいですよね。
当方、まだまだプログラミング駆け出しの身なので、
「えっ、この場合はどれを使えばいいの?」
ってなることが非常に多く、その度にGoogle検索をするのですが、丁度良い解説に巡り会えなかったので、アウトプットも兼ねて記事を書きます!
よろしくお願いします。

データ型種類一覧

データ型 種類
integer 整数型(4バイト)
bigint 整数型(8バイト)
decimal 固定長整数型(精度の高い小数)
float 数値(浮動小数点数)
string 文字列(1 〜 255文字)
text 長い文字列(1 〜 4,294,967,296文字)
date 日付(1000-01-01 〜 9999-12-31)
datetime 日付と時刻(1000-01-01 00:00:00.000000 〜 9999-12-31 23:59:59.999999)
time 時刻 (-838:59:59 〜 838:59:59)
timestamp タイムスタンプ ('1970-01-01 00:00:01' UTC ~ '2038-01-19 03:14:07' UTC)
binary バイナリ文字列型
boolean 真偽
primary_key プライマリーキー(主キー)

本当は全てに対して解説をするべきですが、個人的に気になった部分のみ取り上げてます!
載っていない項目に関しては、ご自身でググってみてください。

integerとbigintってどう違うの?

integer:整数型(4バイト)
bigint:整数型(8バイト)

いきなり最初からよく分かりませんね。
どうやら、昔は整数型といえばintegerのみだったのですが、大規模なSNSサイト等になると、会員数だけでもかなりの数になってしまい、integerでは対応できなくなってしまったのが背景にあるようです。

そこで、Rails5.1からidカラムがbigintに変更になるようになりました。
新規でアプリケーションを作成する際は、特段問題が発生しないのですが、既存のアプリでintegerを使用していた場合、システム補修時にエラーが発生することがあるようです。

textとstringってどういう風に使い分けるの?

一般的な分類方法では、以下のように使用されるのが多いです。

string(1 〜 255文字)
・名前
・住所
・パスワード
text(1 〜 4,294,967,296文字)
・コメント
・投稿文

作成するサイトによって事情は様々だと思いますので、あくまで一例ということで。

timestampとdatetimeって何が違うの?

timestamp:タイムスタンプ ('1970-01-01 00:00:01' UTC ~ '2038-01-19 03:14:07' UTC)
datetime:日付と時刻(1000-01-01 00:00:00.000000 〜 9999-12-31 23:59:59.999999)

皆様はご存知でしょうか、2038年問題を!
よく見れば気付く方もいると思いますが、timestampは現状、2038年までしか対応していないのです...
なぜこうなったのかは分かりませんが、日時を記録する時には、datetimeを使うという方向性にシフトしているようです。
2038年は世界が荒れそうですね。

binaryとは何のこと?

そもそも「バイナリ」とはコンピュータ用語で、データが「0」と「1」で表現されているデータ形式です。
Railsでは、「テキストではない情報でデータが書かれているファイル」という認識になるかもしれません。

バイナリファイルの主なものとしては、
・ 音声ファイル
・ 画像ファイル
・ 圧縮ファイル
などがあります。
バイナリデータは、人間が読み取れる文字で記載してあるわけではありません。
そのため、テキストエディタではバイナリデータを開くこともできません。
使いどころがよく分かりませんね。

booleanとは?

これもよく分からない概念ですよね。
一般的には、真(true)と偽(false)のような2つの状態を表すデータ型を表します。

おわりに

データ型だけには、かなりの種類があるんだな、ということを再認識。
こうやって自分でまとめてみないと、なかなか知り得なかったこともあって、非常に勉強になりました。

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

【GitHub】masterブランチを過去の情報にすり替える方法(個人開発のみ推奨)

備忘録です。
masterブランチを過去の状態に直し復活させることを実現します。

経緯

デプロイ時に全く予測のできないエラーと遭遇し、ログを読み仮説・検証をしても解決されませんでした。全くエラーの原因が予想できなかったため、エラーが起きる直前に戻したいと思いました。しかし、個人開発ということもあり、簡単にたくさんのマージしてしまった(慎重に行うべきでした、反省です)ので、masterブランチを過去の状態に戻すしか方法が考えられませんでした。

注意

この方法は個人開発のみ推奨です。チームで開発の場合は推奨しません。
(そもそも過去の情報にすり替えることは推奨されません。)←ここ重要!

また、マイグレーションファイル(あるいはschemaやその他)の情報とのズレに気をつけてください。テスト環境でデータベースが壊れた場合や、syntax errorが起きて手に負えなくなった場合、database.yml等を修正して、他のデータベースを作成して、そこで保存する様にしてください。

私自身約2ヶ月前にプログラミングの勉強を始めたばかりの初学者です。
実行した行動を思い出しながら書いているため、内容に誤りがあると思いますので、今後内容修正するかもしれませんが、ご理解の程よろしくお願いいたします。

やり方

GitHubの画面から、Settings→Branchesをクリックし、Default Branchの設定画面に飛ぶ。
スクリーンショット 2020-11-13 16.16.05.png

デフォルトのブランチ(masterブランチ)がセットされた状態では削除できないため、masterブランチ以外を選択。なお、ここでは新しくmasterとして扱いたいコードを持つブランチを選択しUpdateすると良いでしょう。

そして、以下のコマンドを実行し、元々のmasterを削除する。

% git push origin :master

Github Desktop上で、元々のmasterブランチを選択した状態で以下のコマンドを実行し、任意の名前に変える。
(元々のmasterはもう必要ないので、本当にテキトーな名前で大丈夫です。)

% git branch -m <任意の名前>

次に、masterブランチにしたい情報を持つブランチをCurrent Branchとしてセットした状態で、以下のコマンドを実行する。

% git branch -m master

新しいmasterブランチとしてプッシュする

% git push origin master 

これで、過去に作ったブランチの情報を元に、新しいmasterを生成することができました。

リモートリポジトリを確認すると
スクリーンショット 2020-11-13 16.59.10.png

masterの元となるブランチと、新しく作ったmasterブランチの情報が等しくなりました。
再度Default Branchの設定画面で、ブランチを新しいmasterに切り替えておくおことを忘れない様にしましょう。

新しいmasterのFetchとPushについて

今回の様な形で新しくmasterを作った場合は、通常通りの方法でPushができなくなります。
masterを最新の状態にする場合は、必ず新しいブランチを用いて下記の手順を踏んでください。

① masterブランチを選んだ状態で、Choose a branch to merge into master

スクリーンショット 2020-11-13 18.24.22.png

② 更新した最新のブランチを選択して、Merge 最新のブランチ into master

スクリーンショット 2020-11-13 18.29.25.png

補足

今までデプロイをしてきた場合、過去の情報にすり替えたもので上書きすることはできません。そういった場合は、デプロイしたアプリを一度削除し、再度アプリをデプロイし直す必要があります。
また、冒頭でも述べました様に、マイグレーションファイル等とのズレが起きてしまう可能性があることを留意し実行してください。

参考記事

https://qiita.com/suin/items/96c110b218d919168d64
https://qiita.com/pugiemonn/items/34b56b1aa757e33133e4

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

【GitHub】リモートmasterブランチを過去の情報にすり替える方法(個人開発のみ推奨)

備忘録です。
リモートmasterブランチを過去の状態に直し復活させることを実現します。

経緯

デプロイ時に全く予測のできないエラーと遭遇し、ログを読み仮説・検証をしても解決されませんでした。全くエラーの原因が予想できなかったため、エラーが起きる直前に戻したいと思いました。しかし、個人開発ということもあり、簡単にたくさんのマージしてしまった(慎重に行うべきでした、反省です)ので、masterブランチを過去の状態に戻すしか方法が考えられませんでした。

注意

この方法は個人開発のみ推奨です。チームで開発の場合は推奨しません。
(そもそも過去の情報にすり替えることは推奨されません。)←ここ重要!

また、マイグレーションファイル(あるいはschemaやその他)の情報とのズレに気をつけてください。テスト環境でデータベースが壊れた場合や、syntax errorが起きて手に負えなくなった場合、database.yml等を修正して、他のデータベースを作成して、そこで保存する様にしてください。

私自身約2ヶ月前にプログラミングの勉強を始めたばかりの初学者です。
実行した行動を思い出しながら書いているため、内容に誤りがあると思いますので、今後内容修正するかもしれませんが、ご理解の程よろしくお願いいたします。

やり方

GitHubの画面から、Settings→Branchesをクリックし、Default Branchの設定画面に飛ぶ。
スクリーンショット 2020-11-13 16.16.05.png

デフォルトのブランチ(masterブランチ)がセットされた状態では削除できないため、masterブランチ以外を選択。なお、ここでは新しくmasterとして扱いたいコードを持つブランチを選択しUpdateすると良いでしょう。

そして、以下のコマンドを実行し、元々のmasterを削除する。

% git push origin :master

Github Desktop上で、元々のmasterブランチを選択した状態で以下のコマンドを実行し、任意の名前に変える。
(元々のmasterはもう必要ないので、本当にテキトーな名前で大丈夫です。)

% git branch -m <任意の名前>

次に、masterブランチにしたい情報を持つブランチをCurrent Branchとしてセットした状態で、以下のコマンドを実行する。

% git branch -m master

新しいmasterブランチとしてプッシュする

% git push origin master 

これで、過去に作ったブランチの情報を元に、新しいmasterを生成することができました。

リモートリポジトリを確認すると
スクリーンショット 2020-11-13 16.59.10.png

masterの元となるブランチと、新しく作ったmasterブランチの情報が等しくなりました。
再度Default Branchの設定画面で、ブランチを新しいmasterに切り替えておくおことを忘れない様にしましょう。

新しいmasterのFetchとPushについて

今回の様な形で新しくmasterを作った場合は、通常通りの方法でPushができなくなります。
masterを最新の状態にする場合は、必ず新しいブランチを用いて下記の手順を踏んでください。

① masterブランチを選んだ状態で、Choose a branch to merge into master

スクリーンショット 2020-11-13 18.24.22.png

② 更新した最新のブランチを選択して、Merge 最新のブランチ into master

スクリーンショット 2020-11-13 18.29.25.png

補足

今までデプロイをしてきた場合、過去の情報にすり替えたもので上書きすることはできません。そういった場合は、デプロイしたアプリを一度削除し、再度アプリをデプロイし直す必要があります。
また、冒頭でも述べました様に、マイグレーションファイル等とのズレが起きてしまう可能性があることを留意し実行してください。

参考記事

https://qiita.com/suin/items/96c110b218d919168d64
https://qiita.com/pugiemonn/items/34b56b1aa757e33133e4

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

【Ruby On Rails】masterブランチを過去の情報にすり替える方法(個人開発のみ推奨)

備忘録です。
masterブランチを過去の状態に直し復活させることを実現します。

経緯

デプロイ時に全く予測のできないエラーと遭遇し、ログを読み仮説・検証をしても解決されませんでした。全くエラーの原因が予想できなかったため、エラーが起きる直前に戻したいと思いました。しかし、個人開発ということもあり、簡単にたくさんのマージしてしまった(慎重に行うべきでした、反省です)ので、masterブランチを過去の状態に戻すしか方法が考えられませんでした。

注意

この方法は個人開発のみ推奨です。チームで開発の場合は推奨しません。
(そもそも過去の情報にすり替えることは推奨されません。)←ここ重要!

また、マイグレーションファイル(あるいはschemaやその他)の情報とのズレに気をつけてください。テスト環境でデータベースが壊れた場合や、syntax errorが起きて手に負えなくなった場合、datavase.yml等を修正して、他のデータベースを作成して、そこで保存する様にしてください。

私自身約2ヶ月前にプログラミングの勉強を始めたばかりの初学者です。
実行した行動を思い出しながら書いているため、内容に誤りがあると思いますので、今後内容修正するかもしれませんが、ご理解の程よろしくお願いいたします。

やり方

GitHubの画面から、Settings→Branchesをクリックし、Default Branchの設定画面に飛ぶ。
スクリーンショット 2020-11-13 16.16.05.png

デフォルトのブランチ(masterブランチ)がセットされた状態では削除できないため、masterブランチ以外を選択。なお、ここでは新しくmasterとして扱いたいコードを持つブランチを選択しUpdateすると良いでしょう。

そして、以下のコマンドを実行し、元々のmasterを削除する。

% git push origin :master

Github Desktop上で、元々のmasterブランチを選択した状態で以下のコマンドを実行し、任意の名前に変える。
(元々のmasterはもう必要ないので、本当にテキトーな名前で大丈夫です。)

% git branch -m <任意の名前>

次に、masterブランチにしたい情報を持つブランチをCurrent Branchとしてセットした状態で、以下のコマンドを実行する。

% git branch -m master

新しいmasterブランチとしてプッシュする

% git push origin master 

これで、過去に作ったブランチの情報を元に、新しいmasterを生成することができました。

リモートリポジトリを確認すると
スクリーンショット 2020-11-13 16.59.10.png

masterの元となるブランチと、新しく作ったmasterブランチの情報が等しくなりました。
再度Default Branchの設定画面で、ブランチを新しいmasterに切り替えておくおことを忘れない様にしましょう。

新しいmasterのFetchとPullについて

今回の様な形で新しくmasterを作った場合は、通常通りの方法でFetch Origin→Pullができなくなります。
masterを最新の状態にする場合は、必ず新しいブランチを用いて下記の手順を踏んでください。

① masterブランチを選んだ状態で、Choose a branch to merge into master

スクリーンショット 2020-11-13 18.24.22.png

② 更新した最新のブランチを選択して、Merge 最新のブランチ into master

スクリーンショット 2020-11-13 18.29.25.png

補足

今までデプロイをしてきた場合、過去の情報にすり替えたもので上書きすることはできません。そういった場合は、デプロイしたアプリを一度削除し、再度アプリをデプロイし直す必要があります。
また、冒頭でも述べました様に、マイグレーションファイル等とのズレが起きてしまう可能性があることを留意し実行してください。

参考記事

https://qiita.com/suin/items/96c110b218d919168d64
https://qiita.com/pugiemonn/items/34b56b1aa757e33133e4

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

Railsを使ったToDoリストの作成(1.プロジェクトの立ち上げ)

概要

本記事は、初学者がRailsを使ってToDoリストを作成する過程をPCとの会話を意識して記述したものです。
私自身のような初学者にとって読んでタメになり、私自身の復習にも役立つことを願って執筆しております。

環境

  • ruby 2.6.5p114
  • Rails 6.0.3.4

第1章 プロジェクトの立ち上げ

第1章では、Railsでアプリ開発をするための初期設定を行います。初期設定には、iTermVSCodeSourcetreeGitHubを使用します。

1 iTermでToDoアプリを立ち上げる

iTerm
$ rails new Task-app
=>Webpacker successfully installed ? ?

?‍♂️Task-appというディレクトリ配下にファイルを作成してください
?インストールが完了しファイルを作成しました

ディレクトリ ⇨ フォルダのこと。ファイルを分類するための容れ物であり、複数のファイルを保管する場所である。

2 VSCodeでディレクトリを開く

iTerm
$ cd Task-app
$ code .

?‍♂️Task-appディレクトリに移動してください
?‍♂️今いるディレクトリのVSCodeを開いてください

code .を実行するためにはVSCodeにて以下の設定が必要です。
1. VSCodeにて表示コマンドパレットを開く
2. Shell Command: Install'code'command in PATHを検索し実行する

3 Task-appをGitで管理する

  1. Sourcetreeにてファイル開くTask-appを選択
  2. 保留中のファイルを選択し、'initial commit'としてコミットする
    =>masterブランチが作成される
  3. GitHubのRepositoriesNewを選択し、Repository nameをつけてCreate repositoryを押下する
  4. GitHubのSSHのURLをコピーする
  5. Sourcetreeの設定リモート追加→名前を'origin'、コピーしたURLを貼り付けて設定を完了する
  6. materブランチで右クリックし、プッシュ先originを選択
  7. GitHubの<>codeに反映されていればSourcetreeとGitHubの連携完了
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

10週間終えた202011/13

10週間終えた感想

まずはスタートラインにやっと立てた自分に乾杯
1日1日無駄な時間が無かったです。これは死ぬまで継続すること

継続は力なり

まず朝起きて、今日しなければいけないことを紙に書き出し可視化する(遊びでも仕事でも)
その後、1日でしないといけないことの項目を細分化
細分化した中から、時間を決める。
予定通りに進まなかったら、消去法。
体が覚えるまでひたすら繰り返し

アプリを開発手順

企画→要件定義→設計→開発→保守・運用

これからの人生設計

まずは今回学習したプログラミング言語以外の言語を学ぶ事
そしてオリジナルアプリの制作をする

エラーが出た時はエラー文を読み取り仮説を立てる。
最小限に抑えたいので一つの機能が終わればデプロイする事

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

【Rails】 button_toメソッドを初めて活用してみた

はじめに

Railsでオリジナルアプリを作成しています。indexアクションで表示されるページから直接updateアクションを実行したく、button_toメソッドを活用しました。

※今まで作ったアプリは、ツイートなどの登録一覧情報があるindexから詳細(show)ページに遷移します。そこから編集ページ(edit)に遷移して、情報を更新(update)します。このshow、editアクションを割愛して直接updateアクションを行いました。

開発環境
ruby 2.6.5
Rails 6.0.3.4

目次

1.button_toの使い方
2.link_toとの違い

1.button_toの使い方

よく使うlink_toと似ていて、リンクではなくボタンを作成できます。中身はシンプルでボタン名、パスやアクションそしてオプションで構成されます。デフォルトのHTTPメソッドはpostです。

○○.html.erb
<%= button_to "ボタン名", { パス or コントローラー名とアクション名 }, { オプション } %>

今回作成したのは下記の通り。suggestion_path(suggestion.id)はupdateのルーティングで設定したパスです。updateアクションのHTTPメソッドはpatchなので、デフォルトのpostから変える必要あり。

index.html.erb
<%= button_to "掃除完了", suggestion_path(suggestion.id), method: :patch, class: "register-blue-btn" %>

image.png

2.link_toとの違い

link_toのデフォルトHTTPメソッドはgetです。またlink_toはaタグを使ったリンクの生成に対し、button_toはフォームを生成します。

参考ページ
【Rails】button_toの使い方をどこよりもわかりやすく解説!
以上

所感
まだこの辺りきちんと理解できてないけど、アクションを実行したいならbutton_toなのかな?コントローラーも指定できることから、他コントローラーのアクションも実行できるようです。

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

Rails初心者で自作のvalidationを作りたい人、この指に止〜まれ。

この記事について

rails初心者がrails初心者のために書いた自由な記事。
ここ最近、友達の子どもがやたらと「うんこ!!!うんこ!!!!」と連発してくるので、うんこと言えば面白くなるという甘い考えを排除するためにvalidationをうまく利用してお下品な言葉をこの世に広げないようにするのが目的。

環境

Rails5

事前準備

  • rails newの実行
  • 適当にcontroller、modelやテーブルの作成やらroutingの設定をしておく。

実践

今回はPostモデルのcontentカラムに相応しくない単語(うんこ)が含まれる内容が投稿されそうになったら、検証エラーを出してサービスの愛と平和の世界を守って汚い言葉を広げないようにしていく。

Postsテーブルのカラム

ActiveRecord::Schema.define(version: 2018_06_10_125752) do

  # These are extensions that must be enabled in order to support this database
  enable_extension "plpgsql"

  create_table "posts", force: :cascade do |t|
    t.string "title", null: false
    t.text "content", null: false
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.bigint "user_id", null: false
    t.index ["user_id"], name: "index_tasks_on_user_id"
  end
end

さて、検証を行うためのメソッドをPostモデルに追加してやろう

ステップ1

検証用のメソッドを登録してやる。

class Ppst < ApplicationRecord
  validate :validate_content_not_including_unko

おいおい、変なところがあるやないか

ここである程度Railsの勉強をしてきた人はついついツッコミを入れたくなるはず。
そう!!!validatesではなくvalidateという三人称単数現在形(三単現)のsがついていないということを!!!!
この両者の違いはカスタムか自作のvalidationで使い分けるようだ。

どうやらカスタムのvalidationを使用するときはvalidateを使うみたいや。。。
恐ろしくわかりづらい
https://guides.rubyonrails.org/active_record_validations.html#custom-methods

ステップ2

検証用のメソッドを実装してやる

class Ppst < ApplicationRecord
  validate :validate_name_not_including_unko

  private

  def validate_content_not_including_unko
    errors.add(:content, 'にう○こって書いたらあかん!!!!') if content.include?('うんこ')
  end
end

①private
このメソッドはこのオブジェクトの外側から使われることはないから、private以下に記述

validate_content_not_including_unko
検証メソッドの仕事は「検証エラーを見つけたら、errorsにエラー内容を入れる」こと。
やから、content.include?('うんこ')でcontentカラムにうんこが含まれている場合に、検証エラーの内容をerrors.addで入れている。

この世にうんこが広まらないか確認をする。

スクリーンショット 2020-11-13 14.52.28.png

これであの悪ガキもうんこと言わなくなるでしょう。。。

最後に

この記事を通して全然関係のないことを思ったことが1つある。

Twitterとかで文章を打って投稿ボタンを押したらいきなり投稿できるようにするんじゃなくて、一度確認画面で「干されるような言動をしていませんか??」的なことを一呼吸置くために表示させといたら、感情的に書いてしまって何かしらの悪影響を広げてしまう文章をちょっとぐらいは減らせるのかなって思った。

あと、うんこを連発してしまい申し訳ありませんでした。

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

全角・半角判定 正規表現

pattern: "[^\x01-\x7E]{0,50}|[ -~]{0,100}", title: "*全角50/半角100文字まで入力して下さい"

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

Dockerでherokuにデプロイ(Rails6、MySQL)

1 前提条件

1 クレジットカード登録済みのherokuアカウント
2 docker環境で作成したRailsアプリ(credentials:editを編集する場合はDockerfileにRUN apt-get install -y vimを追加) *こちらの記事を参考https://qiita.com/croquette0212/items/44378e01de18f62d01df
3 heroku cliインストール済み

2 config/environments/development.rbに下記を記載

Rails.application.confiture do
(略)
config.hosts.clear
(略)
end 

3 コンテナ停止&server.pidを削除

$ docker-compose stop
$ rm -f tmp/pids/server.pid

4 heroku準備 

$ cd ディレクトリ名
$ heroku login --interactive
$ heroku container:login 
$ heroku create アプリ名

5 herokuのデータベース設定をMySQLに変更

$ heroku addons:add cleardb
$ heroku config:set DATABASE_URL=`heroku config:get CLEARDB_DATABASE_URL | sed -- s/mysql/mysql2/`

6 herokuにデプロイ

*heroku container:release webの前にheroku run rails db:migrateをするとbash: rails: command not foundのエラーが出ることがあるようです。

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

Rails WebアプリでTimecopを使って時間移動をブラウザ上で行う

時間が関係する挙動確認には時間操作が必要

オンライン英会話などで、
「先生をレッスン予約した後にその時間になったらレッスンが開始される」という画面の確認をしたい場合、
挙動確認をしたいというケースで使えます。

railsにおける時間移動はtimecopがよいです。

# 2020/11/11 21時に移動する
Timecop.travel(Time.zone.parse('2020/11/11 21:00:00'))

ブラウザ上の操作で指定した時刻に飛びたい

コントローラー上に上記の記述を都度書いて温かみのあるデバッグ作業もありですが、
develop modeの場合にブラウザ上で操作できるようにするのが楽です。

デモ

サンプルソースコード

https://github.com/umeyuki/rails-timetraveler-sample

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

万歩計(Ruby編)

Rubyで万歩計を解く!(for文,スコープ,自己代入演算子)

問題

1 日あたりどの程度歩いたのか知りたくなったあなたは、1 日の平均歩数を計算してみることにしました。記録した日数と、歩数のデータが与えられるので、1 日あたりの歩数の平均を求めるプログラムを作成してください。

平均とは与えられた値の合計をデータの数で割った値を指します。

入力される値

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

N
a_1
...
a_N
・1 行目には、記録した日数を表す整数 N が与えられます。
・1 + i ( 1 ≦ i ≦ N )行目には、i 日目に歩いた歩数を表す整数 a_i が与えられます。
・入力は全部で N + 1 行となり、最後に 1 つ改行が入ります。

期待する出力

1 日あたりの歩数の平均を整数で出力してください。ただし、小数点以下は切り捨てるものとします。

入力例1

6
12
7
51
15
50
24

出力例1

27

入力例2

3
1
1
2

出力例2

1

私の答え

a = gets.chomp.to_i
s = 0
for i in 1..a do
    int = gets.chomp.to_i
    s += int
end
print s / a

今回の注目するポイント

1行目で入力値1文字目である入力例(1)の「6」や入力例(2)の「3」に注目する。この数だけ入力値が下に続いている事が分かる。つまり繰り返し処理をしてgetsしないといけないと想像できる。

2行目のs = 0は3~6行目の繰り返し処理外(スコープ外)でも結果を出力できるように定義しています。ここ重要。

3~6行目はfor文を使って入力値の繰り返し処理と変数sに自己代入演算子でint(繰り返される入力値)を足していきますよ!という処理です。

そして7行目の時点で入力値の合計が変数sに代入されているので変数sを変数aで割れば今回の合計値から平均値を求める事ができます。

余談として、小数点以下を切り捨てるメソッドはfloorですのでprint 変数.floorとかで良いかもしれませんね!

以上!

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

before_actionとは?

はじめに

今回はアプリ開発を通じてbefore_actionとはどういう働きをしているのか学習していきます。

before_actonとは?

railsのコントローラーのアクションを実行する前に処理を行いたいときや、同じ記述の処理をまとめたい時に使います。

基本的な書き方は以下です

tests_controller.rb
   before_action :処理させたいメソッド名

この場合だと、同じコントローラーに定義されている各メソッドの実行の前に、指定したメソッドによる処理が行われます。

もしくはresourcesメソッドと同じようにonlyやexceptなどでアクションの限定をすることもできます。

tests_controller.rb
before_action :処理させたいメソッド名, only: [:アクション1,:アクション2]

この場合はアクション1と2が実行される前にのみ、指定した「処理したいメソッド」が実行されます。

実際の使用例

categories_controller.rb
class CategoriesController < ApplicationController
  def index
    @categorys = Category.all
    @category = Category.new
  end

  def create
    @category = Category.new(category_params)
    if @category.save
      redirect_to categories_path
    else
      @categorys = Category.all
      render :index
    end
  end

  def edit
    @category = Category.find(params[:id])     ⇦処理が被っている
  end

  def update
    @category = Category.find(params[:id])      ⇦処理が被っている
    if @category.update(category_params)
      redirect_to categories_path
    else
      render :edit
    end
  end

  def search
    @categorys = Category.where(is_valid: true)
    @category = Category.find(params[:id])     ⇦処理が被っている
    @q = @category.notes.all.ransack(params[:q])
    @notes = @q.result(distinct: true)
    @title = @category.name
    render 'notes/index'
  end


  private

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

みてもらうと分かりますが、editとupdateとsearchにおいて記述が被っています

そのため、上記のコードをリファクタリングし、

categories_controller.rb
class CategoriesController < ApplicationController
  before_action :set_category, only: [:edit, :update, :search]    ⇦追加


  def index
    @categorys = Category.all
    @category = Category.new
  end

  def create
    @category = Category.new(category_params)
    if @category.save
      redirect_to categories_path
    else
      @categorys = Category.all
      render :index
    end
  end

  def edit
  end

  def update
    if @category.update(category_params)
      redirect_to categories_path
    else
      render :edit
    end
  end

  def search
    @categorys = Category.where(is_valid: true)
    @q = @category.notes.all.ransack(params[:q])
    @notes = @q.result(distinct: true)
    @title = @category.name
    render 'notes/index'
  end


  private

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

  def set_category
    @category = Category.find(params[:id])       ⇦共通の処理をまとめている
  end
end

共通の処理をset_categoryというメソッドでまとめ、updateアクションとeditアクションとsearchアクションの実行の際にbefore_actionで呼び出しています。

authenticate_user!

before_action :authenticate_user!

上記はdeviseを導入した際に使えるようになるメソッドである「authenticate_user!」があります。ログインしていない場合はログイン画面に遷移させるメソッドです。

よく、Amazonなどの通販サイトなどを使用していると分かりますが、商品の閲覧はログインしていなくても出来るけど、購入に進むとログインを求められますよね。

このように何らかのアクションを実行する前に行なって欲しい共通の処理をbefore_actionでは指定します。

最後に

今回はbefore_actionがどういう働きをしているのか何となくわかりました。
参考になれば幸いです。
他にもわかったことがあれば随時更新していきます。

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

【Rails】シンプルカレンダー(Simplecalendar )の追加イベントに確認画面を挟み込む

はじめに

個人開発中の予約管理のアプリケーションにカレンダーを導入しました。
また、イベントを追加する際、一旦確認するための画面のも実装しました。

シンプルカレンダー(Simplecalendar)の作り方と「確認画面」の作り方はこちらです。
参考にしてみて下さい。

【Rails】シンプルカレンダー(Simple Calendar)のミニアプリをカスタマイズ仕様で作ってみた
https://qiita.com/AKI3/items/109d54a35c98328d9155

【Rails】「入力」→「確認画面」→「保存」→「表示」
https://qiita.com/AKI3/items/cbdd77d604fe6aeb47d8

目次

1.シンプルカレンダー導入(CRUDとMVC作成)
2.イベント追加画面
3.確認画面
4.保存と表示
5.カレンダーに予約内容を反映

開発環境

ruby 2.6.5
rails 6.0.0
simple_calendar 2.0

実装

それでは実装して行きます〜

1.シンプルカレンダー導入(CRUDとMVC作成)

ターミナル.
gem 'simple_calendar', '~> 2.0'
ターミナル.
bundle install
ターミナル.
rails g controller events index new create show edit update destroy

コントローラーにCRUD全てのアクションを自動で記述して、ビューも自動で生成してくれます。

スクリーンショット 2020-10-30 17.11.05.png

自動生成してくれました。

config/routes.rb
Rails.application.routes.draw do
  get 'events/index'
  get 'events/new'
  get 'events/create'
  get 'events/show'
  get 'events/edit'
  get 'events/update'
  get 'events/destroy'
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end
app/contorollers/events_controller.rb
class EventsController < ApplicationController
  def index
  end

  def new
  end

  def create
  end

  def show
  end

  def edit
  end

  def update
  end

  def destroy
  end
end

スクリーンショット 2020-10-30 17.16.00.png

ひとまずサーバーを立ち上げて確認します。

ターミナル.
rails s

http://localhost:3000/events/index

モデルを作成

ターミナル.
rails g model event

マイグレーションファイルを編集

2020XXXXXXX_create_events.rb
class CreateEvents < ActiveRecord::Migration[6.0]
  def change
    create_table :events do |t|
      t.string  :plan
      t.integer :number
      t.string  :option
      t.date    :plan_day
      t.string  :name
      t.string  :tel
      t.integer :price

      t.timestamps
    end
  end
end
ターミナル.
rails db:migrate

evensテーブルができました。

ルーティング設定

config/routes.rb
  root to: 'events#index'
  resources :events

コントレーラーとビューを編集

app/contorollers/events_controller.rb
class EventsController < ApplicationController
  def index
    @events = Event.all
  end

#省略
app/views/users/index.html.erb
<%= month_calendar events: @events do |date, events| %>
  <%= date.day %>
<% end %>

カレンダーが表示されてるか一旦確認します。

http://localhost:3000/

最後に見た目を整えます。

ターミナル.
rails g simple_calendar:views
app/assets/stylesheets/application.css
#省略
 *= require simple_calendar #←追記
 *= require_tree .
 *= require_self

基本のカレンダー画面作成が完了しました。

2.イベント追加画面

お申し込みフォーム(イベント追加フォーム)を作成します。

コントローラー編集

app/contorollers/events_controller.rb
class EventsController < ApplicationController
  def index
    @events = Event.all
  end

  def new
    @event = Event.new
  end

#省略

ビュー編集

app/views/users/new.html.erb
<h1>お申し込みフォーム</h1>

<%= form_with(model: @event, url:confirm_events_path, local: true) do |form| %>

  <div class="plan">
    <%= form.label :コース %>
    <%= form.text_field :plan %>
  </div>

  <div class="number">
    <%= form.label :参加人数 %>
    <%= form.text_field :number %>
  </div>

    <div class="plan_day">
    <%= form.label :ご希望日 %>
    <%= form.date_select :start_time %>
  </div>

  <div class="name">
    <%= form.label :代表者名 %>
    <%= form.text_field :name %>
  </div>

  <div class="tel">
    <%= form.label :電話番号 %>
    <%= form.text_field :tel %>
  </div>

  <div class="submit">
    <%= form.submit "確認画面へ", class:"#" %>
  </div>

<% end %>

お申し込みフォーム(イベント追加フォーム)作成完了です。

3.確認画面

詳しくはこちらで解説しておりますので、興味がある方は参考にしてみて下さい。

【Rails】「入力」→「確認画面」→「保存」→「表示」
https://qiita.com/AKI3/items/cbdd77d604fe6aeb47d8

ルーティング設定

config/routes.rb
Rails.application.routes.draw do
  root to: 'events#index'
  resources :events do
    collection do
      post :confirm
    end
  end
end

コントローラー編集

app/contorollers/events_controller.rb
class EventsController < ApplicationController
  def index
    @events = Event.all
  end

  def new
    @event = Event.new
  end

  def confirm
    @event = Event.new(event_params)
    render :new if @event.invalid?
  end

#省略

ビュー編集

app/views/users/confirm.html.erb
<h1>確認画面</h1>

  <div class="#">
    <p>コース: <%= @event.plan.name %></p>
  </div>
  <div class="#">
    <p>参加人数: <%= @event.num.name %></p>
  </div>
  <div class="#">
    <p>ご希望日: <%= @event.start_time %></p>
  </div>
  <div class="#">
    <p>代表者名: <%= @event.name %></p>
  </div>
  <div class="#">
    <p>電話番号: <%= @event.tel %></p>
  </div>
  <div class="#">
    <p>料金: <%= @event.price %></p>
  </div>


<%= form_with(model: @event, id: 'charge-form', local: true) do |f| %>
  <%= f.hidden_field :plan_id %>
  <%= f.hidden_field :num_id %>
  <%= f.hidden_field :start_time %>
  <%= f.hidden_field :name %>
  <%= f.hidden_field :tel %>
  <%= f.hidden_field :price %>

  <%= f.submit "予約する" %>
  <%= f.submit "戻る", name: :back %>
<% end %>

確認画面作成完了です。

4.保存と表示

保存後、予約内容を表示します。

コントローラー追記

app/contorollers/events_controller.rb
#省略
  def create
    @event = Event.new(event_params)
    if params[:back]
      render :new
    elsif @event.save!
      redirect_to @event
    else
      render :new
    end
  end

  def show
    @event = Event.find_by(id: params[:id])
  end

#省略

  private

  def event_params
    params.require(:event).permit(:plan_id, :num_id, :start_time, :name, :tel, :price)
  end

ビュー編集

app/views/users/confirm.html.erb
<h1>ご予約完了しました。</h1>

<p>コース: <%= @event.plan.name %></p>
<p>参加人数: <%= @event.number %></p>
<p>ご希望日: <%= @event.start_time %></p>
<p>代表者名: <%= @event.name %></p>
<p>電話番号: <%= @event.tel %></p>
<p>料金: <%= @event.price %></p>

<%= link_to "カレンダーページに戻る" root_path  %>

保存・表示実装完了です。

5.カレンダーに予約内容を反映

最後に、保存した内容をカレンダーに表示します。

ビューに追記

app/views/users/index.html.erb
<%= month_calendar events: @events do |date, events| %>
  <%= date.day %>

#ここから追記
  <ul class="event-list">
    <% events.each do |event| %>
    <li class="list">
      <%= link_to edit_event_path(event.id) do %>
        <%= event.plan %>
        <%= event.name %>
      <% end %>
    </li>
  </ul>

  <% end %>
<% end %>

これで追加したイベントがカレンダーに反映されるようになりました。

完成です!!

まとめ

以上が、シンプルカレンダー(Simplecalendar)の追加イベントに確認画面を挟み込むでした。

決済機能も実装しますので興味がある方は参考にしてみてください。
【JavaScript】非同期で値段表示をさせて決済する機能を実装
後日投稿予定

最後に

私はプログラミング初学者ですが、同じ様に悩んでる方々の助けになればと思い、記事を投稿しております。
それでは、また次回お会いしましょう〜

参考

・シンプルカレンダー(Simple Calendar)公式
https://github.com/excid3/simple_calendar/blob/master/README.md

【Rails】シンプルカレンダー(Simple Calendar)のミニアプリをカスタマイズ仕様で作ってみた
https://qiita.com/AKI3/items/109d54a35c98328d9155

【Rails】「入力」→「確認画面」→「保存」→「表示」
https://qiita.com/AKI3/items/cbdd77d604fe6aeb47d8

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

【Rails】シンプルカレンダー(Simplecalendar)を導入して、追加イベントに「確認画面」を挟み込む

はじめに

個人開発中の予約管理のアプリケーションにカレンダーを導入しました。
また、イベントを追加する際、一旦確認するための画面のも実装しました。

シンプルカレンダー(Simplecalendar)の作り方と「確認画面」の作り方はこちらです。
参考にしてみて下さい。

【Rails】シンプルカレンダー(Simple Calendar)のミニアプリをカスタマイズ仕様で作ってみた
https://qiita.com/AKI3/items/109d54a35c98328d9155

【Rails】「入力」→「確認画面」→「保存」→「表示」
https://qiita.com/AKI3/items/cbdd77d604fe6aeb47d8

目次

1.シンプルカレンダー導入(CRUDとMVC作成)
2.イベント追加画面
3.確認画面
4.保存と表示
5.カレンダーに予約内容を反映

開発環境

ruby 2.6.5
rails 6.0.0
simple_calendar 2.0

実装

それでは実装して行きます〜

1.シンプルカレンダー導入(CRUDとMVC作成)

ターミナル.
gem 'simple_calendar', '~> 2.0'
ターミナル.
bundle install
ターミナル.
rails g controller events index new create show edit update destroy

コントローラーにCRUD全てのアクションを自動で記述して、ビューも自動で生成してくれます。

スクリーンショット 2020-10-30 17.11.05.png

自動生成してくれました。

config/routes.rb
Rails.application.routes.draw do
  get 'events/index'
  get 'events/new'
  get 'events/create'
  get 'events/show'
  get 'events/edit'
  get 'events/update'
  get 'events/destroy'
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end
app/contorollers/events_controller.rb
class EventsController < ApplicationController
  def index
  end

  def new
  end

  def create
  end

  def show
  end

  def edit
  end

  def update
  end

  def destroy
  end
end

スクリーンショット 2020-10-30 17.16.00.png

ひとまずサーバーを立ち上げて確認します。

ターミナル.
rails s

http://localhost:3000/events/index

モデルを作成

ターミナル.
rails g model event

マイグレーションファイルを編集

2020XXXXXXX_create_events.rb
class CreateEvents < ActiveRecord::Migration[6.0]
  def change
    create_table :events do |t|
      t.string  :plan
      t.integer :number
      t.string  :option
      t.date    :plan_day
      t.string  :name
      t.string  :tel
      t.integer :price

      t.timestamps
    end
  end
end
ターミナル.
rails db:migrate

eventsテーブルができました。

ルーティング設定

config/routes.rb
  root to: 'events#index'
  resources :events

コントレーラーとビューを編集

app/contorollers/events_controller.rb
class EventsController < ApplicationController
  def index
    @events = Event.all
  end

#省略
app/views/users/index.html.erb
<%= month_calendar events: @events do |date, events| %>
  <%= date.day %>
<% end %>

カレンダーが表示されてるか一旦確認します。

http://localhost:3000/

最後に見た目を整えます。

ターミナル.
rails g simple_calendar:views
app/assets/stylesheets/application.css
#省略
 *= require simple_calendar #←追記
 *= require_tree .
 *= require_self

基本のカレンダー画面作成が完了しました。

2.イベント追加画面

お申し込みフォーム(イベント追加フォーム)を作成します。

コントローラー編集

app/contorollers/events_controller.rb
class EventsController < ApplicationController
  def index
    @events = Event.all
  end

  def new
    @event = Event.new
  end

#省略

ビュー編集

app/views/users/new.html.erb
<h1>お申し込みフォーム</h1>

<%= form_with(model: @event, url:confirm_events_path, local: true) do |form| %>

  <div class="plan">
    <%= form.label :コース %>
    <%= form.text_field :plan %>
  </div>

  <div class="number">
    <%= form.label :参加人数 %>
    <%= form.text_field :number %>
  </div>

    <div class="plan_day">
    <%= form.label :ご希望日 %>
    <%= form.date_select :start_time %>
  </div>

  <div class="name">
    <%= form.label :代表者名 %>
    <%= form.text_field :name %>
  </div>

  <div class="tel">
    <%= form.label :電話番号 %>
    <%= form.text_field :tel %>
  </div>

  <div class="submit">
    <%= form.submit "確認画面へ", class:"#" %>
  </div>

<% end %>

お申し込みフォーム(イベント追加フォーム)作成完了です。

3.確認画面

詳しくはこちらで解説しておりますので、興味がある方は参考にしてみて下さい。

【Rails】「入力」→「確認画面」→「保存」→「表示」
https://qiita.com/AKI3/items/cbdd77d604fe6aeb47d8

ルーティング設定

config/routes.rb
Rails.application.routes.draw do
  root to: 'events#index'
  resources :events do
    collection do
      post :confirm
    end
  end
end

コントローラー編集

app/contorollers/events_controller.rb
class EventsController < ApplicationController
  def index
    @events = Event.all
  end

  def new
    @event = Event.new
  end

  def confirm
    @event = Event.new(event_params)
    render :new if @event.invalid?
  end

#省略

ビュー編集

app/views/users/confirm.html.erb
<h1>確認画面</h1>

  <div class="#">
    <p>コース: <%= @event.plan.name %></p>
  </div>
  <div class="#">
    <p>参加人数: <%= @event.num.name %></p>
  </div>
  <div class="#">
    <p>ご希望日: <%= @event.start_time %></p>
  </div>
  <div class="#">
    <p>代表者名: <%= @event.name %></p>
  </div>
  <div class="#">
    <p>電話番号: <%= @event.tel %></p>
  </div>
  <div class="#">
    <p>料金: <%= @event.price %></p>
  </div>


<%= form_with(model: @event, id: 'charge-form', local: true) do |f| %>
  <%= f.hidden_field :plan_id %>
  <%= f.hidden_field :num_id %>
  <%= f.hidden_field :start_time %>
  <%= f.hidden_field :name %>
  <%= f.hidden_field :tel %>
  <%= f.hidden_field :price %>

  <%= f.submit "予約する" %>
  <%= f.submit "戻る", name: :back %>
<% end %>

確認画面作成完了です。

4.保存と表示

保存後、予約内容を表示します。

コントローラー追記

app/contorollers/events_controller.rb
#省略
  def create
    @event = Event.new(event_params)
     if params[:back]
       render :new
     else @event.save!
       redirect_to @event
     end
  end

  def show
    @event = Event.find_by(id: params[:id])
  end

#省略

  private

  def event_params
    params.require(:event).permit(:plan_id, :num_id, :start_time, :name, :tel, :price)
  end

ビュー編集

app/views/users/show.html.erb
<h1>ご予約完了しました。</h1>

<p>コース: <%= @event.plan.name %></p>
<p>参加人数: <%= @event.number %></p>
<p>ご希望日: <%= @event.start_time %></p>
<p>代表者名: <%= @event.name %></p>
<p>電話番号: <%= @event.tel %></p>
<p>料金: <%= @event.price %></p>

<%= link_to "カレンダーページに戻る" root_path  %>

保存・表示実装完了です。

5.カレンダーに予約内容を反映

最後に、保存した内容をカレンダーに表示します。

ビューに追記

app/views/users/index.html.erb
<%= month_calendar events: @events do |date, events| %>
  <%= date.day %>

#ここから追記
  <ul class="event-list">
    <% events.each do |event| %>
    <li class="list">
      <%= link_to edit_event_path(event.id) do %>
        <%= event.plan %>
        <%= event.name %>
      <% end %>
    </li>
  </ul>

  <% end %>
<% end %>

これで追加したイベントがカレンダーに反映されるようになりました。

完成です!!

まとめ

以上が、シンプルカレンダー(Simplecalendar)の追加イベントに確認画面を挟み込むでした。

決済機能も実装しますので興味がある方は参考にしてみてください。
【JavaScript】非同期で値段表示をさせて決済する機能を実装
後日投稿予定

最後に

私はプログラミング初学者ですが、同じ様に悩んでる方々の助けになればと思い、記事を投稿しております。
それでは、また次回お会いしましょう〜

参考

・シンプルカレンダー(Simple Calendar)公式
https://github.com/excid3/simple_calendar/blob/master/README.md

【Rails】シンプルカレンダー(Simple Calendar)のミニアプリをカスタマイズ仕様で作ってみた
https://qiita.com/AKI3/items/109d54a35c98328d9155

【Rails】「入力」→「確認画面」→「保存」→「表示」
https://qiita.com/AKI3/items/cbdd77d604fe6aeb47d8

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

Rails6 jQuery 導入

bash
$ yarn add jquery
config/webpack/environment.js
const { environment } = require('@rails/webpacker');

const webpack = require('webpack');

environment.plugins.append('Provide',
  new webpack.ProvidePlugin({
    $: 'jquery/src/jquery',
    jQuery: 'jquery/src/jquery'
  })
);

module.exports = environment;
app/javascript/packs/application.js
// 追加
require('jquery');

デベロッパーツールのコンソールでバージョンが表示されればOK。

console
console.log($.fn.jquery);
// 3.5.1
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む