20210113のMySQLに関する記事は5件です。

Laravelで手軽にログイン認証機能を実装する

【前提条件】
Lamp環境が正常にインストール出来ている。
Node.jsのインストールが出来ている。
データ・ベースの設定が出来ている。
artisanコマンドがある程度扱える。

Node.jsがインストール出来ていない方は@seiba様の記事を参照して下さい
【引用リンク】
https://qiita.com/seibe/items/36cef7df85fe2cefa3ea

1、バージョンを確認する

まずはLaravelのバージョンを確認しましょう、以下のコマンドを入力して下さい。

php artisan --version

Laravelのバージョンが6系か7系かを確認します。

2、Laravel/uiをインストールする。

6系の場合は以下のコマンドでインストール

composer require laravel/ui:^1.0 --dev

7系の場合は以下のコマンドでインストール

composer require laravel/ui:^2.4

3、認証機能を実装する

6系、7系共通で以下のコマンドを入力してログイン機能を実装する

php artisan ui vue --auth

この時点ではログイン機能は完成していません、この時点でREGISTER場面を
見てみると………フロントエンド部分が実装されていません。
authtest.png

4、フロントエンド部分を実装する〜完成

npmをインストールする

npm install

npmをビルドする

npm run dev

最期に忘れずにmigrationコマンドででログイン情報を格納するテーブルを作成する。

php artisan migration

完成です
Laravelを立ち上げてみて右端のRegisterをクリックしてみる
authtest1.png
すると先程は実装されていなかったフロントエンド部分の実装がなされている。
authtest2.png
実際に登録してみる
authtest3.png

実際にログインに成功するとログイン後のページに遷移できる。
authtest4.png

番外編:どのようにデータが格納されているか

実際にパスワードが格納されているテーブルを見てみるとパスワードが暗号化されて格納されており、手軽に実装出来てかなり高度な認証機能である事がわかる。

|  1 | ララベルユーザー       | laravel@gmail.com | NULL |
 $2y$10$KPPRJJH0fOYl1JocEdQscu3NNl5BrJU.MpEu4AY1I2ye6F5z18Zsq | NULL           | 2021-01-13 12:40:02 | 2021-01-13 12:40:02 |
+----+--------------------+-------------------+-------------------+--------------------------------------------------------------+----------------+---------------------+---------------------+

参考サイト
【公式版】Laravel公式チュートリアル日本語訳
https://readouble.com/laravel/7.x/ja/authentication.html

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

Mysql2::Error: Incorrect string valueのエラーの対処

はじめに

データベースを作成してマイグレーションも実行し、「いざ、データ(日本語)を入れて動かそう!」としたところで、以下のようなエラーが。。。

Mysql2::Error: Incorrect string value: '\xE3\x82\xB2\xE3\x82\xB9...' for column 'name' at row 1

どうやら文字コードが不適切らしい。。。
ということで、本記事では、このエラーについて、僕が試したことや解決策を書いていこうと思います!

技術・環境

Docker/docker-compose
ruby 2.7.2
rails 6.0.2.3

試したこと

テーブルの文字コードを調べてみました。

まずは、MySQLに接続する。

$ docker-compose run web rails db

次に、データベースの文字コードを調べてみる。

> show variables like '%char%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8mb4                    |
| character_set_connection | utf8mb4                    |
| character_set_database   | latin1                     |
| character_set_filesystem | binary                     |
| character_set_results    | utf8mb4                    |
| character_set_server     | latin1                     |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+

やはり、データベースの文字コードが「latin1」だった。。。
※MySQLはdefaultで「latin1」が文字コードに設定されています。

データベースの文字コードをutf8mb4に修正
僕はDockerを使用していたので、以下のようにdocker-compose.ymlを修正。
※以下の公式ドキュメントを参考にしました。
https://hub.docker.com/_/mysql

docker-compose.yml
version: "3"
services:
  db:
    image: mysql:5.7
    # この下の一行を追記しました
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_USER: root
    ports:
      - "3306:3306"
    volumes:
      - ./db/mysql/volumes:/var/lib/mysql

  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/share-read
    ports:
      - "3000:3000"
    depends_on:
      - db
volumes:
  mysql-data:
    driver: local

データベースの文字コードを再度調べてみる。

> show variables like '%char%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8mb4                    |
| character_set_connection | utf8mb4                    |
| character_set_database   | utf8mb4                    |
| character_set_filesystem | binary                     |
| character_set_results    | utf8mb4                    |
| character_set_server     | utf8mb4                    |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+

「よし!修正完了!」と思ったが、まだエラーが出てしまう。
もしかしたらテーブル自体の文字コードが「latin1」のまま?と思い調べてみると。。。

> SHOW CREATE TABLE users;

| users | CREATE TABLE `users` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `email` varchar(255) DEFAULT NULL,
  # 中略
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |

やはり、テーブルの文字コードが変わっていなかった。。。

テーブルの文字コードをutf8mb4に修正
ということで、テーブルの文字コードを修正するのですが、10個くらいテーブルがあって一つ一つ修正するのは大変!
また、まだテーブルにデータを格納してなかったこともあり、今回はマイグレーションをやり直そうことにしました。

$ docker-compose run web rails db:reset
$ docker-compose run web rails db:migrate

ということで無事解決しました。
もし同じようなエラーが出てしまった方は、参考にしてみてください。

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

Bitnami Mantis のDBリストアについて

DBのリストア

テーブルがすでに存在するということで、怒られる

>mysql -u root -p bitnami_mantis < bitnami_mantis.sql
Enter password: ********
ERROR 1050 (42S01) at line 30: Table 'mantis_api_token_table' already exists

DB再作成

DBへ接続、DROP、確認

>mysql -u root -pパスワード
mysql> drop database bitnami_mantis;
Query OK, 32 rows affected (0.36 sec)
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.02 sec)
mysql> quit
Bye

DB作成

mysql> create database bitnami_mantis;
Query OK, 1 row affected (0.01 sec)

mysql> quit
Bye

DUMPをリストア

>mysql -u root -pパスワード -D bitnami_mantis < bitnami_mantis.sql
mysql: [Warning] Using a password on the command line interface can be insecure.

#参考)

データのみバックアップ

>mysqldump -u root -pパスワード -t bitnami_mantis > hogehoge.dump

リストア(なんかエラーが出る)

>mysql -u root -p bitnami_mantis < hogehoge.dump
Enter password: ********
ERROR 1062 (23000) at line 33: Duplicate entry '1' for key 'mantis_bug_file_table.PRIMARY'
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Formオブジェクトを用いて作成したデータを、特定のデータのみ削除する方法

要点

  • メルカリクローンのアプリを作るときの参考に
  • dependent: :destroy を用いて外部キーの削除制限を外す
  • 下記のエラーを解消する方法
ActiveRecord::InvalidForeignKey (Mysql2::Error: Cannot delete or update a parent row: a foreign key constraint fails (`-アプリ名-_development`.`-中間テーブル名-`, CONSTRAINT `fk_rails_~~~~~` FOREIGN KEY (`-商品のテーブル名-_id`) REFERENCES `-商品のテーブル名-` (`id`))):

はじめに

メルカリのようなフリマアプリを作成中で、Formオブジェクトを用いて商品にタグ付けして出品できる機能を実装する所まで行いました
各モデルとコントローラーは以下のようになります

  • Item/商品
  • Tag/タグ
  • TagItemRelation/商品とタグの中間テーブル
  • TagsItem/ ItemとTagを同時に保存するためのFormオブジェクト
/app/model/item.rb
class Item < ApplicationRecord
  has_many :tag_item_relations
  has_many :tags, through: :tag_item_relations
end
/app/model/tag.rb
class Tag < ApplicationRecord
  has_many :tag_item_relations
  has_many :items, through: :tag_item_relations
  validates :tag_name, uniqueness: true
end
/app/model/tag_item_relation.rb
class TagItemRelation < ApplicationRecord
  belongs_to :item
  belongs_to :tag
end
/app/form/tags_item.rb
class TagsItem
  include ActiveModel::Model
  attr_accessor :item_name,
                :tag_name

  with_options presence: true do
    validates :item_name
  end

  def save
    item = Item.create(item_name: item_name)
    tag = Tag.where(tag_name: tag_name).first_or_initialize
    tag.save
    TagItemRelation.create(item_id: item.id, tag_id: tag.id)
  end
end

コントローラー

/app/controller/items_controller.rb
class ItemsController < ApplicationController
  def index
    @items = Item.all.order('created_at ASC')
  end

  def new
    @item = TagsItem.new
  end

  def create
    @item = TagsItem.new(items_params)
    if @item.valid?
      @item.save
      redirect_to root_path
    else
      render :new
    end
  end

  private

  def items_params
    params.require(:tags_item).permit(
      :item_name,
      :tag_name
    )
  end
end

その後商品閲覧機能と
問題の商品削除機能を実装した

/app/controller/items_controller.rb
class ItemsController < ApplicationController
  before_action :set_item, only: [:show, :destroy]

###  中略

  def  show
    @tags_item = TagItemRelation.find(params[:id])
  end

  def destroy
    if current_user.id == @item.user_id
      @item.destroy
      redirect_to root_path
    else
      render :show
    end
  end

private

###  中略

  def set_item
    @item = Item.find(params[:id])
    @tag = Tag.find(params[:id])
  end
end

しかし実際に出品した商品を削除してみると、、、

ActiveRecord::InvalidForeignKey (Mysql2::Error: Cannot delete or update a parent row: a foreign key constraint fails (`-アプリ名-_development`.`tag_item_relations`, CONSTRAINT `fk_rails_~~~~~~` FOREIGN KEY (`item_id`) REFERENCES `items` (`id`))):

のエラーが出てしまい、商品の削除ができませんでした

調べたこと

エラー内容をよく読んでみると、商品idは中間テーブルの外部キー(foreign key)に含まれて
デリートやアップデートができないよ!と書かれているのがわかります

そこで外部キーについて調べてみると、、、
外部キー(外部制約キーとも)は、よくマイグレーションファイルなどに書いてるデータベースのキーで
データベースの特定の項目に好き勝手な値を入れることを防ぎ、外部の項目から選んで入れる制約を持ち
主に外部キーのテーブルから主キーのテーブルのデータに対して、変更を制限するものだそうです
今回の場合外部キーのテーブルはtag_item_relations、主キーのテーブルはitemになることが分かりますね

外部キーの設定変更

今回のエラーの原因はマイグレーションファイルに記載した外部キー(foreign_key: trueのやつ)でした
ですがマイグレーションファイルごと書き換えてしまうと別の不具合が起きてしまう恐れがあります
今回はdestoryで外部キーとして設定している項目を削除させるように、dependent: :destroyを設定しようと思います
この簡単な設定により不具合なく商品の削除ができるようになります

/app/model/item.rb
class Item < ApplicationRecord
  has_many :tag_item_relations, foreign_key: :item_id, dependent: :destroy
  has_many :tags, through: :tag_item_relations
end

参考にしたサイト

外部キー (foreign key)とは

関連記事

外部キー制約でハマったので(rails)
外部キーを持つデータのdestroyを行うための設定

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

多対多リレーションを修正するストアドプロシージャ

下の画像の右側と左側が多対多のテーブルのレコードで、真ん中の薬のカプセルみたいなやつが、中間テーブルのレコードとします。

具体的にいうと、左側の「LIZ」、「LITA」はアーティストで、右側の「KING」というのは楽曲です。

「KING」という2つのレコードは同じものを意図しているのにもかかわらず、IDが異なるので違うものとして扱われてしまっています。

なのでMAINを残し、SUBを消すために、以下のように中間テーブルをUPDATEしたのち、いらなくなったSUBレコードを削除します。

IMG_8042.jpg

これをするSQLは以下のようになります。

-- 左側のテーブル : artists
-- 中間テーブル : music_artists
-- 右側のテーブル : music
update music_artists set music_id = {main} where music_id = {sub};
delete from music where id = sub;

これでうまくいきそうですが、以下のような場合にうまくいきません。
UPDATEすると複合主キーの主キー制約に反するので、UPDATEできないのです。

IMG_8043.jpg

上記のパターンが

  • UPDATE → DELETE

のパターンが必要であるのに対し、今回のパターンでは

  • DELETE → DELETE

する必要があります。

IMG_8044.jpg

これを振り分けるためには、ストアドプロシージャでカーソル操作する必要があります。
MySQLです。

CREATE PROCEDURE `join_music`(main INT, sub INT)
BEGIN
  DECLARE current_artist_id INT;

  DECLARE done INT DEFAULT FALSE;

  DECLARE cur CURSOR FOR SELECT artist_id FROM music_artists WHERE music_id = sub;

  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

  OPEN cur;


  cur_loop: LOOP
    IF done THEN
      LEAVE cur_loop;
    END IF;

    FETCH cur INTO current_artist_id;

    IF EXISTS (SELECT * FROM music_artists WHERE artist_id = current_artist_id AND music_id = main) THEN
        DELETE FROM music_artists WHERE artist_id = current_artist_id AND music_id = sub;
    ELSE
        UPDATE music_artists SET music_id = main WHERE artist_id = current_artist_id AND music_id = sub;
    END IF;
  END LOOP;

  CLOSE cur;

  DELETE FROM music WHERE id = sub;
END

ちょっとパターンを考慮するだけでこんな複雑になるんですね。

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