Rails sorcery
やりたいこと
sorceryについて理解を深めたかったので、GitHubを参照し、Wiki等に記載されている内容をまとめます。 実装方法については深く解説していないで、詳しく知りたい方はsorceryのGitHubを参照してください
Userモデルを作成する
bundle exec rails g sorcery:install
class SorceryCore < ActiveRecord::Migration[6.0] def change create_table :users do |t| t.string :email, null: false t.string :crypted_password t.string :salt t.timestamps null: false end add_index :users, :email, unique: true end end
crypted_password
暗号化されたパスワード(crypted_password)。試しにrails consoleでユーザーを作成して、Userテーブルのcrypted_passwordを見てみるとめちゃ長い文字列になっている。
一方,users テーブルには password や password_confirmation というカラムは無い,ということも分かります。
password を暗号化した文字列を作成して crypted_passoword カラムに収めるのは sorcery が自動的にやってくれます。
パスワードが保存される過程は、 以下のように、「仮想的な」passwordフィールドを使用し、データベースに暗号化される前のパスワードをビューで扱う。 →このpassword属性はカラムに対応していないため、平文のパスワード情報がDBに保存されることは無い。 →パスワードは暗号化され、DBに保存される。
modelに記載されている内容
authenticates_with_sorcery! validates :password, length: { minimum: 8 }, if: -> { new_record? || changes[:crypted_password] } validates :password, confirmation: true, if: -> { new_record? || changes[:crypted_password] } validates :password_confirmation, presence: true, if: -> { new_record? || changes[:crypted_password] } validates :email, uniqueness: true
validates :password, confirmation: trueはpasswordというDBに存在しない仮想的な属性(virtual attributes)が追加される。
if: -> { new_record? || changes[:crypted_password] }はユーザーがパスワード以外のプロフィール項目を更新したい場合に、パスワードの入力を省略できるようになる。
Controllerの内容
ログインページのcontorollerを参照しています。
user_sessions_controller.rb
class UserSessionsController < ApplicationController skip_before_action :require_login, only: %i[new create] def new; end def create @user = login(params[:email], params[:password]) if @user redirect_back_or_to(root_path, notice: 'Login success') else render :new end end def destroy logout redirect_to(login_path, notice: 'ログアウトしました') end end
redirect_back_or_to
githubで詳細を見てみると
def redirect_back_or_to(url, flash_hash = {}) redirect_to(session[:return_to_url] || url, flash: flash_hash) session[:return_to_url] = nil end
sessionのreturn to urlがなければこのurlになるみたいなメソッドが書かれている。
例えば、掲示板ページにアクセスしようとしたユーザにログインを要求する場合、require_loginメソッドでユーザをログインページに誘導し、ログインが成功したら、最初に訪れようとしていた掲示板ページにリダイレクトさせるということが可能になる。
参考
Ruby クラスを使う場合と使わない場合の比較
やりたいこと
Rubyでプログラムを作成していた時、クラスを使うメリットを発見したので記載します。
クラスを使わないで実装
users = []
users << { first_name: 'コナン', last_name: '江戸川' }
users << { first_name: '哀', last_name: '灰原' }
def full_name(user)
"#{user[:first_name]} #{user[:last_name]}"
end
users.each do |user|
puts '氏名': "#{full_name(user)}"
end
特に問題なく処理は実行されるのですが、ハッシュは新しくキーを追加したり、内容を変更したりできるので「脆くて壊れやすいプログラム」になりがち。大きなプログラムならなおさらですね。そこでクラスが使われます。
クラスを使って実装
class User attr_reader :first_name, :last_name def initialize(first_name, last_name) @first_name = first_name @last_name = last_name end def full_name "#{first_name} #{last_name}" end end users = [] users << { first_name: 'コナン', last_name: '江戸川' } users << { first_name: '哀', last_name: '灰原' } users.each do |user| puts '氏名': "#{full_name(user)}" end
クラスにすることによっていいメリット
# 勝手に属性を追加できない users[0].adult = '工藤新一' # 勝手にfirst_nameを変更できない users[0].first_name = '小五郎'
クラスはこのように、内部にデータを保持し、自分が保持しているデータを利用する独自のメソッドを持つことができます。データとそのデータに関するメソッドが常にセットになる。プログラムが大規模になる程、データとメソッドを一緒に持ち運べるクラスのメリットが大きくなります。
URL.createObjectURL() オブジェクトURLを用いた画像アップロードのプレビュー画面
やりたいこと
RailsのActiveStorageを使って画像をアップロードしているが、画像を添付した時に添付した画像をプレビュー表示したかったのでJavascriptを用いて実装した。この時使用したURL.createObjectURL()について理解できていなかったので勉強のためアウトプット。
URL.createObjectURL()の説明
今回、プレビュー機能を実装するためURL.createObjectURL()を使用した。この機能について最初説明いたします。
URL.createObjectURL()の引数に渡すと、オブジェクトURLを取得できます。
形式はblob:
以下が例になります。
blob:http://localhost:3000/84cced13-9e4c-4486-8049-9b9058b74099
この文字列(オブジェクトURL)はブラウザがURLとして解釈でき、ブラウザがオブジェクトURLを管理する仕組みに渡すことで、対応するデータを取得します。
const $ImgFile = e.target.files[0]; const data = window.URL.createObjectURL($ImgFile);
URL.createObjectURLを使ってブラウザのメモリに保存されたblobにアクセス可能な一意のURLを生成可能にする。 e.target.files[0]で取得したファイルの情報を定数fileに格納し、URL.createObjectURL(file)で取得した情報をオブジェクトURLに変換し、定数dataに格納します。
URLの参照行為、例えばimgタグのsrcにオブジェクトURLがセットされると、Blob URLストアから一致するものを検索してBlobオブジェクトから、データを取得します。
実装内容
previewImg(e) { // // no-imgをdisplay:noneにする this.$NoImage.style.display = 'none'; // 添付した画像にクラスやデータを付与 const createImage = (data) => { const newImage = document.createElement('img'); newImage.setAttribute('class', 'food_create_preview_img'); // scrのデータをオブジェクトURLに newImage.setAttribute('src', data); // no-img画像に添付した画像を挿入する this.$image.appendChild(newImage); }; // 続けて画像を添付する時、前回の画像を削除する const imageItem = this.$image.querySelector('img') if (imageItem){ imageItem.remove(); } // 取得した画像データを$ImgFileに代入 const $ImgFile = e.target.files[0]; const data = window.URL.createObjectURL($ImgFile); createImage(data); this.$image.onload = () => { URL.revokeObjectURL(data); }; }
ajax通信
やりたいこと
ajaxの理解
ajaxとは
javascriptでサーバー側と非同期通信を行う手法のこと
同期通信と非同期通信について
同期通信
① webブラウザのあるページのリンクをクリックして、別のページに遷移する。その時にWebサーバーにリクエストを送る。
② HTMLファイル、CSSファイル、Javascriptファイルなどが応答として帰ってくる。
③ HTMLファイルやCSSファイルを解読して遷移先のページを表示する。
非同期通信 ajaxを用いた通信
① ajaxの場合は、javascriptでWebサーバーに対してリクエストを投げる
② Webサーバーは受け取ったデータをjavascriptに返す。
③ データの処理結果を表示。
Ajaxは、ページ全体を書き換えなくても、ページの特定の部分のみ表示を書き換えたりすることができる仕組み。
rails newでアプリを立ち上げるまで postgresql
やりたいこと
rails newしてアプリを作成していきたいが、様々なエラーに出くわしたので改善していきます。DBはpostgresqlを使用します。
エラー内容
エラー1
% rails _6.0.4_ new calender --database=postgresql --skip-test 2: from /Users/urakamitakuya/.rbenv/versions/2.7.2/bin/rails:23:in `<main>' 1: from /Users/urakamitakuya/.rbenv/versions/2.7.2/lib/ruby/2.7.0/rubygems.rb:296:in `activate_bin_path' /Users/.rbenv/versions/2.7.2/lib/ruby/2.7.0/rubygems.rb:277:in `find_spec_for_exe': can't find gem railties (= 6.0.4) with executable rails (Gem::GemNotFoundException)
% rails -v Rails 6.0.4
これはエラー文の通り。can't find gem railties (= 6.0.4) gem install railsで解決できました。
gem install rails -v 6.0.4
エラー2
rails _6.0.4_ new . --database=postgresql --skip-test
無事rails newできたのですが、bin/rails db:createを実行するとエラーが発生してしまいます。
% bin/rails db:create
connection to server on socket "/tmp/.s.PGSQL.5432" failed: No such file or directory
Is the server running locally and accepting connections on that socket?
Couldn't create 'calender_development' database. Please check your configuration.
rails aborted!
PG::ConnectionBad: connection to server on socket "/tmp/.s.PGSQL.5432" failed: No such file or directory
以下の記事を参考。 mysql使いがpostgresqlを入れてみた - Qiita
% postgres -D /usr/local/var/postgres 2021-12-10 11:20:09.396 JST [43403] FATAL: database files are incompatible with server 2021-12-10 11:20:09.396 JST [43403] DETAIL: The data directory was initialized by PostgreSQL version 13, which is not compatible with this version 14.0.
% psql -V psql (PostgreSQL) 14.0
どうやらデータベース本体のバージョンと今のpostgresqlのバージョンが合っていなかったようなので、
urakamitakuya@urakamiuyanoMBP calender % brew services list 512 Name Status User File dbus stopped mysql@5.7 started urakamitakuya ~/Library/LaunchAgents/homebrew.mxcl.mysql@5.7.plist postgresql error urakamitakuya postgresql@13 stopped
データベース本体のバージョン13を起動。するとbin/rails db:createが起動し、アプリが立ち上がりました。
% brew services start postgresql@13
linux 標準入出力 リダイレクト
標準入出力
標準入出力は以下の3つに分けられる。
入力:コマンドを打つ際、キーボードを使って入力する。キーボードを使ってコンピュータにデータを渡すこと。
出力:catなどのコマンド入力すると結果が画面に出てくる。このようにコマンドの結果やプログラムを外に出すこと。
標準:linuxコマンドをキーボードで打った時、結果はディスプレイに出力されます。実は入力元と出力先は指定すると変更することができる。指定しない場合、デフォルトで決まっているところに入出力される。このことを標準という。標準では入力はキーボード、出力はディスプレイ
linuxを使えば標準入出力先をファイルに変更することができる。linuxではコマンドの入出力先を抽象化することで、入出力先を柔軟に変更できる。
- 標準エラー出力: プログラムのエラーメッセージを出力する。ディスプレイが通常は使われる。
> リダイレクト 入出力先を変更する
入力のリダイレクト
キーボードの代わりにファイルから入力する機能
$ cat < /etc/hosts
出力のリダイレクト
コマンドの実行結果を画面に表示するのではなくファイルに保存する機能。
ex) lsで長い結果が出力される場合、その結果をファイルにまとめる
$ ls > output.text $ cat > output.text
出力とエラー出力をまとめる 出力をリダイレクトした後に2>&1と書く
2>&1: 標準エラー出力を標準出力と一緒にする。なのでoutput.textに標準エラー出力と標準出力の両方を出すことができる。
% ls / /hoge > output.text 2>&1 % cat output.text ls: /hogeにアクセスできません bin boot dev etc home lib
実際に入出力をしてみよう
% ls home.html index.html
// catの入力先をhome.htmlに変更 % cat < home.html <p>こちら葛飾区亀有公園前派出所</p>%
// その出力先をfile.htmlというファイルにする % cat < home.html > file.html
% ls file.html home.html index.html
% cat file.html <p>こちら葛飾区亀有公園前派出所</p>%
% ls /hoge > file.html ls: /hoge: No such file or directory
ls /hogeの結果、通常の出力は空のメッセージだったのでfile.htmlの内容を上書きしてしまう。エラー出力は画面に表示されていることから、通常の出力とエラー出力は別物。
// ファイルの中身は空 % cat file.html
% ls /hoge 2> file.html
// エラー内容がファイルに保存される % cat file.html ls: /hoge: No such file or directory
Linuxコマンド rm mv cp
rmコマンド ファイルやディレクトリを削除
ファイルの確認。dirディレクトリの中にfileというファイルがあります。
[work] $ ls dir
[work] $ ls dir file
dirをrmコマンドで削除しようとするとディレクトリなので削除できないと表示されます。rmはこのようにファイルを削除するコマンドです。
[work] $ rm dir rm: 'dir' を削除できません:ディレクトリです
ディレクトリを削除するには?
-rコマンドをつける。これでディレクトリを削除することができます。
[work] $ rm -r dir
他にも
-fコマンドをつけることで、ファイルを削除する際に警告文を表示しないようにできたり
[work] $ rm -f file
-iコマンドをつけることで、ファイルの削除前に確認することができます。
[work] $ rm -f file
mvコマンドファイルの移動、ファイル名の変更
mvコマンドは移動先がファイルかディレクトリかで意味が変わってくる。
mv [オプション] <移動元>... <移動先>
ファイル名を変更
[work] $ touch new_file
[work] $ ls new_file
[work] $ mv new_file new_file1 new_fileからnew_file1へとファイル名変更
ファイルを移動
[work] $ mkdir dir
[work] $ mv new_file1 dir/ dirディレクトリ配下にnew_file1が入る
cpコマンド ファイルやディレクトリをコピー
cp [オプション] <コピー元>... <コピー先>
オプション
[work] $ cp -i file new_file 上書きする前に確認する
[work] $ cp -r dir new_dir ディレクトリをコピーする
ファイルをコピー
[work] $ touch file
[work] $ ls file
[work] $ cp file new_file
[work] $ ls file new_file
[work] $ cp new_file dir
[work] $ ls dir new_file dirディレクトリ内にnew_fileがコピーされる
注意が一点! コピー先のファイルがすでにあると上書きするので注意


