20200519のRubyに関する記事は30件です。

[rails]deviseのヘルパーメソッドbefore_action :authenticate_user!の使い方

before_action :authenticate_user!について

deviseを簡単に説明すると、ログイン系をやってくれるgemです。

そのdeviseのヘルパーメソッドauthenticate_user!メソッドは、コントローラーにbefore_actionで記載することで、そのコントローラーで行われる処理はログインユーザーのみ実行可能とすることができるメソッドです。

before_action :authenticate_user!の使い方

authenticate_user!メソッドはコントローラーに記載します。

class PostsController < ApplicationController
  before_action :authenticate_user!

  def index
  end

end

このように記載するとposts_controllerでの処理をすることができるのはログインユーザーのみとなります。

一部の処理を未ログインユーザーでも行えるようにする

class PostsController < ApplicationController
  before_action :authenticate_user!, only: [:show]

  def index
  end

  def show
  end

end

このように記載することで、showアクションのみを未ログインユーザーが使用できないようにできます。

間違いなどがありましたらご指摘いただければ幸いです。
最後までご覧いただきありがとうございました。

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

駆け出しエンジニアのためのRuby便利メソッド

はじめに

駆け出しエンジニアの私が、AtCoderやpaizaでアルゴリズム問題を解いていく中で、とても便利だったメソッドを書き残す。

puts, p, printの違い

自分の言葉で説明しようと思ったが、web上に山ほど記事があったので、止めることにする。

【Ruby超入門】print、puts、pの違い
https://yukimasablog.com/ruby-print-puts-p
【Ruby】p, puts, printメソッドの違い
https://qiita.com/rkkmshde/items/daf75aca9675f5a01d17

デバッグの時に使いこなせると、複雑なコードを書く時にかなり効率よくエラーやその原因に気づける。

三項演算子

if 〜 else 〜 end
をもっと効率よく書くことができる。

number = 24
if number.even? 
    n = "偶数"
else
    n = "奇数"
end
puts n  
# => 偶数

この処理が、、、

number = 24
n = number.even? ? "偶数" : "奇数"
puts n  
# => 偶数

こうなる。

条件 ? (条件がtrueだった時の処理) : (条件がfalseだった時の処理)

という構造だ。

map

# 入力値
# 12 30 40
input = gets.split.map(&:to_i)
# 出力値
# [12, 30, 40]
# という風な配列になる。

入力値の数値や文字列を一つ一つの要素に分けて配列にしたい時に使うことができる。

"&:"メソッドの説明については、今回は割愛させていただく。
詳しくは、
https://qiita.com/soma_sekimoto/items/a828b8f88b78aac2e7df
こちらの記事を参考に。

any? と all? と one?

繰り返し処理を使って条件を満たしているかどうかを確かめたい時に、これらのメソッドがとても役に立つ。

これを知らなかった頃は、全てeachで代用しようとしていたので、コードがとんでもないことになってしまっていた。

array = [30, 14, 23, 15]
array.any? {|num| num % 7 == 0} # 7で割り切れる要素(14)がある
# => true  

any?: 各要素の中で、1つでも条件に合うものがあればtrueを返す。

all?: 全ての要素が条件に合えばtrueを返す。

one?: 各要素の中で、条件に合うものが一つだけであればtrueを返す。

reduce

(1..10).reduce(5) {|a, n| a + n}
# => 5 + 1 = 6, この6が次の処理のaとなる。
# つまり、2回目の処理は、6 + 2となる。
# 処理結果 => 60

reduceメソッドでは、ブロック処理内の引数を2つ(aとn)設定する。
aは初期値(ここでは5)、nは各要素(ここでは、1から10の整数)になる。

between?

23.between?(0, 30)
# => true

'G'.between?('A', 'F')
# => false

指定した値(ここでは、23 と 'G')が範囲内(0〜30 と A〜F)に入っているかどうかを判断するメソッド

index

array = ["ruby", "java", "php"]
p array.index("java")
# => 1
# "java"のindex番号が返される。

transpose

配列に要素として他の配列が格納されている場合に、配列を行列と見なし、行と列を入れ替えるメソッド

array = [[1,2,3,4], [5,6,7,8], [9,10,11,12]]
p array.transpose
# => [[1,5,9], [2,6,10], [3,7,11], [4,8,12]]

行と列の考え方を使うアルゴリズム問題でとても活躍してくれた。

chars

greeting = "hello"
p greeting.chars
# => ["h", "e", "l", "l", "o"]

上記のように、文字列を1文字ずつに分割して配列として返す。

また、こういう書き方もできる。

num = "19800".chars.map(&:to_i)
p num
# => [1, 9, 8, 0, 0]

桁ごとの数字を処理したい時などに使える。

zip

複数の配列を同時に処理したい時は、このzipメソッドが便利だ。

number = [1, 2, 3, 4, 5]
alphabet = ["a", "b", "c", "d", "e"]
p number.zip(alphabet)
number.zip(alphabet) do |num, alpha|
    p num
    p alpha
end

# => [[1, "a"], [2, "b"], [3, "c"], [4, "d"], [5, "e"]]

# => 1
# => "a"
# => 2
# => "b"
...
# => 5
# => "e"

上記のように、配列として返すこともできるし、複数の配列にeachメソッドを用いたような処理の仕方もできる。

select, reject

select: {}ブロック内の式がtrueになる要素だけを抽出する。
reject: {}ブロック内の式がfalseになる要素だけを抽出する。

p [1, 2, 3, 4, 5, 6].select { |n| n % 2 == 0 }
p [1, 2, 3, 4, 5, 6].reject { |n| n % 2 == 0 }
# => [2, 4, 6]
# => [1, 3, 5]

おわりに

rubyは他の言語と比べると、メソッドの数が多いので、直感的なコードが書けることに気がつき、さらにrubyが好きになった。

皆さんもぜひ、rubyを用いてアルゴリズムを書く際は、参考にしてもらいたい。

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

Railsでグループ機能(掲示板)を作ってみた

Railsでグループ機能(掲示板風)の作成

<開発環境>
1. ruby 2.6.3
2. Rails 5.1.6
3. AWS Cloud9
4. GitHub
6. sqlite3(develop環境)

設計構想

ユーザーは自由にグループを作成でき、また他のユーザーが作成したグループに所属することもできます。
また、グループに参加したメンバーはグループ内で自由に発言することも可能になります。

この仕組みをテーブルに落とし込むと、
ユーザーとグループは多対多の関係になるので中間テーブルを用いることとします。
そして、ユーザーとグループ内での投稿も多対多の関係となる為、こちらも中間テーブルを用います。
IMG_8162 (1).jpg

ER図はこんな感じになりました。(手書きですいません・・・)

モデル

先ほどのER図は以下のようなアソシエーションとなりました。

group.rb
class Group < ApplicationRecord
  validates :name, presence: true, uniqueness: true

  has_many :group_users
  has_many :users, through: :group_users
  has_many :groupposts
  accepts_nested_attributes_for :group_users
end
group_user.rb
class GroupUser < ApplicationRecord

  belongs_to :group
  belongs_to :user
end
grouppost.rb
class Grouppost < ApplicationRecord
  belongs_to :group
  belongs_to :user
end

コントローラー

groups_controller.rb
class GroupsController < ApplicationController
  def new
    @group = Group.new
    @group.users << current_user
  end

  def create
    if Group.create(group_params)
      redirect_to groups_path, notice: 'グループを作成しました'
    else
      render :new
    end
  end

  def index
    @groups = Group.all.order(updated_at: :desc)
  end

  def show
    @group = Group.find_by(id: params[:id])

    if !@group.users.include?(current_user)
      @group.users << current_user
    end

    @groupposts = Grouppost.where(group_id: @group.id).all
  end

  private
  def group_params
    params.require(:group).permit(:name, :user_id [])
  end

  def grouppost_params
    params.require(:grouppost).permit(:content)
  end

end

基本的な設計はユーザー周りと同じです。

def show
.
.

  if !@group.users.include?(current_user)
   @group.users << current_user
  end
end

このようにグループのリンクを踏んだ人がそのグループに所属できるようにしています。

grouppost_controller.rb
class GrouppostsController < ApplicationController

  def new
    @grouppost = current_user.groupposts.new
    @group = Group.find_by(id: params[:group_id])
  end

  def create
    @group = Group.find_by(id: params[:group_id])
    @grouppost = current_user.groupposts.new(grouppost_params)
    @grouppost.group_id = params[:group_id]
    if @grouppost.save
      redirect_to group_path(@group.id)
    end
  end

  private
    def grouppost_params
      params.require(:grouppost).permit(:content)
    end
end

こちらも以前作成した投稿機能と同じ形にしています。

以上で2chちっくなグループ機能(掲示板風)が完成しました。
今後の課題としては、グループ作成時に鍵をかけることができ、招待制のグループを作ることができるようにしたいと考えています。

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

paizaランクDの達成方法

はじめに

paizaランクDを達成するにはどうすれば良いか?
目安を解説しました。

前提

筆者がRubyを主に学習しているので、Rubyで解説しています。

実行

例えば、好きな数値を入力して、それを出力するには次のようなコードを書きます。

x = gets.chomp.to_i
puts x

二つ以上の数値を入力するには、getsを少し書き換える必要があります。

x = gets.split().map(&:to_i)
puts x

splitメソッドを使えば、複数の入力値を配列として取得できます。
mapメソッドを使えば、配列の中身を簡単に変換することができます。
引数を&:to_iとすれば、入力値を全て数値として取得できます。

ここで、入力した値を二つの場合、一つ目の入力値と二つ目の入力値の差を求めるには次のようにします。

x = gets.split().map(&:to_i)
puts x[0] -x[1]

xは配列として取得されているので、入力された値の差を計算するには、配列の要素同士の演算子を利用すれば良いです。

以上の事が使いこなせれば。paizaランクDの達成するのは目前です。

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

個人アプリの制作日記

本日の積み上げ
①個人アプリの構想
②DB設計

①個人アプリの構想

■ 個人アプリ名:スタサポ <= 突っ込まれるかも

■ どんなアプリか
ユーザーがメンターさんにわからないところをすぐに聞けるマッチングアプリ

 ▶ 手立て
 質問したいときに質問フォーマットにそってユーザーがメンターさんにビデオ通話を申し込む。
 グループチャットを通じて勉強し合う。
 ユーザーやメンター評価を搭載している。
 自分の学びをアウトプットがすることができる。

 ▶ 経緯
 昨今はコロナウィルスの影響でオンライン学習が増えている。が動画だけの学習だと受け身になりがちで質問
 したいところが聞けない。
 1対1のビデオチャットなら好きな質問ができると考えた。
 某スクールの学びを通して、わからないところだけ聞く自分がわかっていることを
 遠慮なく聞けるサービスに感動から。

 ▶ ユーザー側のメリット
 周りに気にしないで、わからないところだけ聞きたい。
 動画では整理されていて分かりやすいが、その場の疑問が解決しずらい。
 自分がどこまで分かっているのアウトプットしながら確認ができる。
 自宅で簡単に取り組むことができる。
 コメントや評価を通じて自分の理解度を可視化でき、承認欲求が満たされる。

 ▶メンター視点でのメリット
 隙間時間に行うことができる。
 教えることに携わりたい人が気軽な気持ちでできる。(その場にいればよい)
 その人だけに教えることができる。
 誰かに知識を伝える・教えること一番のアウトプット。

 ▶実装したいこと
 ビデオ通話での応答
 コメント機能
 ログイン機能(メンター・生徒)
 評価機能(メンター・生徒)
 応答可能かどうか
 質問フォーム
 非同期通信(ビデオ通話、メッセージ)
 今日の積み上げページ(アウトプット)

■開発環境
rails 5.0.7.2
ruby 2.5.1
gem device

② DB設計

usersテーブル
Column Type Options
name string null: false, unique: true
email string null: false, unique: true
password string null: false
my-image string

introduction text

profile text

subject string

rate float

Association
has_many :groups_users
has_many :groups, through: :user_groups
has_many :messages
has_many :tweets
has_many :teaches
groupsテーブル
Column Type Options
name string null: false, unique: true
Association
has_many :user_groups
has_many :users, through: :user_groups
has_many :messages
user_groupsテーブル
Column Type Options
group_id integer null: false, foreign_key: true
user_id integer null: false, foreign_key: true
Association
belongs_to :group
belongs_to :user
groupmessagesテーブル
Column Type Options
comment text null: false
image string

group_id integer null: false, foreign_key: true
user_id integer null: false, foreign_key: true
Association
belongs_to :group
belongs_to :user
Tweetsテーブル
Column Type Options
title string null: false
body text null: false
image string

user_id integer null: false, foreign_key: true
Association
belongs_to :user
tweetmessagesテーブル
Column Type Options
comment text null: false
image string

tweet_id integer null: false, foreign_key: true
user_id integer null: false, foreign_key: true
Association
belongs_to :tweet
belongs_to :user
teachテーブル
Column Type Options
title string

image string

body text

user_id integer null: false, foreign_key: true
Association
has_many :teach_tags
has_many :tags, through: :teach_tags
teach_tagsテーブル
Column Type Options
title string

image string

teach_id integer null: false, foreign_key: true
tag_id integer null: false, foreign_key: true
Association
belongs_to : teach
belongs_to :tag
tegsテーブル
Column Type Options
text string

Association
has_many :teach_tags
has_many :teaches, through: :teach_tags

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

RailsにFixturesで初期データを入れるためのyamlをCSVから作るスクリプト

Railsのデータベースにデータを投入する方法はfixtures用のyamlファイルを作って、railsコマンドで入れる方法などがよく知られています。
ですが、現実的にはExcelなどで元データを用意してCSV等で扱うことが多いと思われます。
yamlコンバータなども試してみたけどfixtures keyを入れるのがうまくいかなかったので、自分で作りました。
エスケープ文字の処理とかなにもやってないので、元データがそういうものを扱う場合は適宜加工してください。

たとえば、1行目にカラム名が入ったこんな感じのCSVファイルがあったとして。

fruits.csv
id,item,price
1,りんご,100
2,みかん,80
3,バナナ,60
4,メロン,2000
5,いちご,300

Fixturesで扱うにはこういうyamlファイルが必要になります。

fruits.yml
data1:
  id: 1
  item: りんご
  price: 100

data2:
  id: 2
  item: みかん
  price: 80

data3:
  id: 3
  item: バナナ
  price: 60

data4:
  id: 4
  item: メロン
  price: 2000

data5:
  id: 5
  item: いちご
  price: 300

data1:のところがfixtures keyというやつで、データベースには反映されないけど、レコードごとにハッシュとしてユニークな値をつけなければいけないようです。

スクリプトはこんな感じです。
ExcelからCSVに変換したら、UTF-8でBOMが付いてしまったので、ファイルをopenするときにオプションが付いてます。

csv2yaml.rb
#!/use/bin/env ruby

filename = ARGV[0]

# UTF-8のBOMを消すオプション
file = open(filename, 'r:BOM|UTF-8')

# CSVファイルの先頭行を取得
column = file.gets.chomp.split(",")

# fixtures keyのプレフィックス(data)とそのあとに付けるカウンタ(num)
prefix = "data"
num = 1
str = ""

file.each do |line|
  unless line.strip == ""             ## 空白行を無視する
    str += "#{prefix}#{num}:\n"
    (0 .. column.length - 1).each do |i|
      str += "  #{column[i]}: #{line.chomp.split(",")[i]}\n"
    end
    str += "\n"
    num += 1
  end
end
print str

Shellから実行する時はこんな感じです。

$ ./csv2yaml.rb fruits.csv > fruits.yml

500行くらいのCSVデータの変換して問題なかったし、fixturesでも取り込めたので大丈夫なようです。
カラムが異なる複数のCSVファイルでも変換できました。

yamlのライブラリなどを使えばもっと簡単に作れるかも。

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

deviseを導入したが更にカラムを増やしたい時

deviseを使ってみて

deviseを導入したがカラムこれだけって時ありませんか?

今回はカラムの追加方法について説明します!!

1.usersテーブルにカラムを追加します

今回はnameカラムを追加します。
ターミナルで以下のコマンドを実行しましょう。

$ rails g migration AddNameToUsers name:string

$ rails db:migrate

2.application_controller.rbを編集

application_controller.rbを以下のように編集しましょう。
これでユーザー登録時にnameカラムが保存されるようになりました。

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

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

※今のままでは登録時にしかnameカラムが入っていないので、編集でnameを変更しても変更されません。

3.編集時に追加したカラムの編集もできるようにしましょう!

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

  protected
  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
    <!-- 以下のように編集時の対応する記述も追加してあげましょう -->
    devise_parameter_sanitizer.permit(:account_update, keys: [:name])
  end
end

これで編集時にデータが反映される様になりました:point_up_tone2:

この記事が少しでも参考になれば嬉しいです:pray_tone2:

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

active_hashの使い方について!!

某プログラミングスクールでフリマアプリを作成する際にactive_hashを使ってみたので是非見て下さい!!
初学者の書いた記事ですが参考になれば嬉しいです:pray_tone2:

そもそもactive_hashとは?

・DBにデータとして保存しておくほど重要ではない。
・基本的に変更されない。
・Active_Recordのように読み込み専用情報をまとめたハッシュを扱うことができるものです。

1.gem 'active_hash'をインストール

アプリのGemfileに以下を記述

gem 'active_hash'

ターミナルでbundle installを実行

$ bundle install

2.Active_Hash::Baseを継承しているモデルを作成する

ActiveHash::Baseを継承したモデルを自作する。

今回は良くactive_hashが利用される事の多いprefecture(都道府県)モデルを作成していきます。

app/models/prefecture.rbという感じで自作します。

prefecture.rb
class Prefecture < ActiveHash::Base
  self.data = [
      {id: 1, name: '北海道'}, {id: 2, name: '青森県'}, {id: 3, name: '岩手県'},
      {id: 4, name: '宮城県'}, {id: 5, name: '秋田県'}, {id: 6, name: '山形県'},
      {id: 7, name: '福島県'}, {id: 8, name: '茨城県'}, {id: 9, name: '栃木県'},
      {id: 10, name: '群馬県'}, {id: 11, name: '埼玉県'}, {id: 12, name: '千葉県'},
      {id: 13, name: '東京都'}, {id: 14, name: '神奈川県'}, {id: 15, name: '新潟県'},
      {id: 16, name: '富山県'}, {id: 17, name: '石川県'}, {id: 18, name: '福井県'},
      {id: 19, name: '山梨県'}, {id: 20, name: '長野県'}, {id: 21, name: '岐阜県'},
      {id: 22, name: '静岡県'}, {id: 23, name: '愛知県'}, {id: 24, name: '三重県'},
      {id: 25, name: '滋賀県'}, {id: 26, name: '京都府'}, {id: 27, name: '大阪府'},
      {id: 28, name: '兵庫県'}, {id: 29, name: '奈良県'}, {id: 30, name: '和歌山県'},
      {id: 31, name: '鳥取県'}, {id: 32, name: '島根県'}, {id: 33, name: '岡山県'},
      {id: 34, name: '広島県'}, {id: 35, name: '山口県'}, {id: 36, name: '徳島県'},
      {id: 37, name: '香川県'}, {id: 38, name: '愛媛県'}, {id: 39, name: '高知県'},
      {id: 40, name: '福岡県'}, {id: 41, name: '佐賀県'}, {id: 42, name: '長崎県'},
      {id: 43, name: '熊本県'}, {id: 44, name: '大分県'}, {id: 45, name: '宮崎県'},
      {id: 46, name: '鹿児島県'}, {id: 47, name: '沖縄県'}
  ]
end

3.アソシエーションを組みます

今回はフリマアプリを作成しているので、商品の配送先を登録するときに都道府県をactive_hashを使って表示します。
product.rbにアソシエーションを組んでいきます。

product.rb
class Product < ApplicationRecord
  extend ActiveHash::Associations::ActiveRecordExtensions
  belongs_to_active_hash :prefecture
end

4.表示します

商品を登録するフォームなどでcollection_selectを使う際は以下のように表示できます。

Image from Gyazo

= f.collection_select :prefecture_id, Prefecture.all, :id, :name, {prompt:"選択してください"}, {class:""}

5.登録した情報を表示したいとき

= @product.prefecture.name

この様な感じでactive_hashを使う事ができます!!

最後まで見て頂きありがとうございます:pray_tone2:

少しでも参考になって頂ければ嬉しいです:thumbsup_tone2:

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

Ruby と Python と numpy で解く AtCoder ABC054 B 行列演算

はじめに

AtCoder Problems の Recommendation を利用して、過去の問題を解いています。
AtCoder さん、AtCoder Problems さん、ありがとうございます。

今回のお題

AtCoder Beginner Contest B - Template Matching
Difficulty: 828

今回のテーマ、行列演算

2次元配列ですが、行列のライブラリを使用すると演算が簡単になることがあります。

Ruby

ruby.rb
require 'matrix'

class Matrix
  # v2.3 では代入不可
  def []=(i, j, x)
    @rows[i][j]=x
  end
end

n, m = gets.split.map(&:to_i)
rows = Array.new(n + m){gets.chomp.chars.map{|c| (c == '#') ? 1 : 0}}
a = Matrix.rows(rows.shift(n))
b = Matrix.rows(rows)
(n - m + 1).times do |i|
  (n - m + 1).times do |j|
    if a.minor(i, m, j, m) == b
      puts "Yes"
      exit
    end
  end
end
puts "No"
matrix.rb
require 'matrix'

class Matrix
  # v2.3 では代入不可
  def []=(i, j, x)
    @rows[i][j]=x
  end
end

require 'matrix'で行列のライブラリを呼び出します。
ローカル環境のv2.7.1では行列の要素に代入できるのですが、AtCoder環境のv2.3.3では代入できないのでメソッドを追加しています。
標準ライブラリに対してもこういうことができるのがRubyの面白い所でもあります。

minor.rb
    if a.minor(i, m, j, m) == b

minorで部分行列を取得し行列の比較を行っています。

error.rb
(n - m).times do |i|
  (n - m).times do |j|

(n - m + 1).times do |i|
  (n - m + 1).times do |j|

1 x 1の行列の時、行列の比較がうまくいかないので、それに対応した処理が入っています。(n - m)は間違いで(n - m + 1)が正解でした。

追記
2次元配列版については、コメント欄を参照願います。

Python

import numpy

n, m = map(int, input().split())
a = numpy.zeros([n, n], dtype=int)
b = numpy.zeros([m, m], dtype=int)
for i in range(n):
    s = input()
    for j in range(n):
        if s[j] == '#':
            a[i, j] = 1
for i in range(m):
    s = input()
    for j in range(m):
        if s[j] == '#':
            b[i, j] = 1
for i in range(n - m + 1):
    for j in range(n - m + 1):
        if numpy.all(a[i: i + m, j: j + m] == b):
            print("Yes")
            exit()
print("No")
all.py
        if numpy.all(a[i: i + m, j: j + m] == b):

numpyの行列の比較は、例えば[[True, True], [True, True]]を返しますので、all関数を用いて全てTrueかどうかを調べています。

Ruby (Matrix) Ruby (Array) Python (numpy)
コード長 (Byte) 420 288 534
実行時間 (ms) 22 10 166
メモリ (KB) 3196 1788 12512

まとめ

  • ABC 054 B を解いた
  • Ruby に詳しくなった
  • Python に詳しくなった
  • numpy に詳しくなった
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

0 から始める Jekyll 超入門 #1 - 環境構築編

この記事は 0 から始める Jekyll 超入門 の 1番目の記事です。
- #1 環境構築編 <- 今回
- #2 独自テーマ作成編


はじめに

このシリーズでやること

  1. とりあえず Jekyll でサイトを作ってみる
  2. 自分でテンプレートを作ってみる
  3. 完成したサイトを netlify にデプロイして公開してみる

対象

  • 独自のデザインで 0から Jekyll でサイトを作りたい人

前提知識

  • HTML, CSS はなんとなくわかる
  • JavaScript も存在くらいは知ってる
  • markdown の書き方がわかる
  • 静的サイトジェネレータが何をするかわかっている
  • git を使える
  • CUIでの操作もなんとなくできる

なお Ruby をインストールする必要がありますが、本シリーズはプラグインの作成などまで含めるとは考えていないので、
とりあえず Ruby がかける/わかる 必要はありません。

Jekyll を動かすために必要な環境(必須)

環境構築についてはそれほど難しくも無いと思うので、ここでは説明はしません。

  • Ruby v2.5.0 以上 : ruby -v で確認できます。
  • RubyGems : gem -v で確認できます。
  • GCC と make : gcc -v/g++ -vmake -v で確認できます。

Jekyll の公式 Docs より。
https://jekyllrb.com/docs/installation/#requirements

プロジェクトを作成してみる

まずはプロジェクトを作成するところから始まります。
適当な場所にプロジェクト用のフォルダを作成してみてください。
以下、プロジェクト用のフォルダを プロジェクトルート とか 作業ルートディレクトリで とか適当な言葉で読んでいますが、全て読み替えてください。

必要なライブラリのインストール

bundler というツールを使います。これによってプロジェクトごとの gem の管理が簡単になります。

以下を作業用ルートディレクトリで実行します。

$ gem install bundler
$ bundle init

Gemfile というファイルが生成されたら成功です。
次に、Gemfile を以下のように編集します。

Gemfile
# frozen_string_literal: true

source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

gem "jekyll"

できたら以下を実行します。

$ bundle config set path 'vendor/bundle'
$ bundle install

vendor/bundle に色々とファイルが増えていくと思うので、じっと見守ります。(結構時間がかかります)
完了したら、次を実行します。

$ bundle exec jekyll -v

次のように返ってくれば成功です。

jekyll x.x.x

Jekyll プロジェクトの作成

Jekyll プロジェクトの作成をします。次のコマンドを実行します。

$ bundle exec jekyll new . --force
$ bundle install

少々省略していますがだいたいこんな感じの構成になると思います。

./
├── 404.html
├── Gemfile
├── Gemfile.lock
├── _config.yml
├── _posts
│   └── 2020-05-19-welcome-to-jekyll.markdown
├── about.markdown
└── index.markdown

これでプロジェクトの作成は完了です。試しに動かしてみましょう。

次のコマンドを実行します。

$ bundle exec jekyll s
...中略
...
 Auto-regeneration: enabled for '<path-to-project-folder>'
    Server address: http://127.0.0.1:4000/
  Server running... press ctrl-c to stop.

このような形になれば成功しています。
試しに http://localhost:4000/ にアクセスしてみましょう。
デフォルトだと minima というテーマが適用されているので、すでにしっかりとしたページが生成されているはずです。

ちなみに jekyll は静的サイトジェネレータですので、実行することによって、静的なサイトのソースコードが吐き出されます。
/_site をみると、吐き出されたサイトのソースコードをみることができます。

Jekyll Admin を追加してみる

Jekyll では Jekyll Admin というプラグイン(ツール)を使用することによって、 CMS のような管理画面を使って記事を管理したりすることができます。
なくても動きますが、比較的わかりやすく扱えるので導入してみましょう。

gemfile を編集します。

Gemfile
source "https://rubygems.org"

gem "jekyll", "~> 4.0.1"

# .. 略 ..

group :jekyll_plugins do
  gem "jekyll-feed", "~> 0.12"
  gem "jekyll-admin" # <- 追加
end

# .. 略 ..

gem "wdm", "~> 0.1.1", :install_if => Gem.win_platform?

Gemfile を編集した場合は、以下のコマンドを実行することによってインストールすることができます。

$ bundle install

完了した後再び実行してみます。

$ bundle exec jekyll s

http://localhost:4000/admin にアクセスしてみましょう。

image.png

このような画面になっている場合成功です。
※なお、この画面にアクセスできるのはローカル環境で jekyll s をしてサーバーを立ち上げている時のみなのでご安心ください。

横のタブから posts という画面をみてみると、記事の確認ができると思います。

記事を追加してみる

お試し的に、記事を追加してみましょう。
Jekyll では /_posts ディレクトリ配下に md ファイルを追加することで、記事を追加することができますが、その他にも Jekyll Admin からも記事を追加できます。

Jekyll Admin も最終的には自動で /_ppstsにファイルを作成するので実際やっていることは変わりませんが、設定やファイルの命名などを自動でやってくれたりするので、初めは Jekyll Admin を利用するのが良いかもしれません。

今回は Jekyll Admin 経由で追加してみます。
Jekyll Admin の横のタブから posts ページを開き、 New Posts を押すことで新しいページを追加することができます。

タイトルにタイトルを入力して、 Body に記事の内容を書きます。
Jekyll は基本的に markdown記法で書きます。
markdown についてはたくさん記事が上がっているので、ここでは説明を省きます。
こんな感じです。

image.png

完成したら最後に、"New metadata field" をクリックして、 Key に layout と打ち込み、
"post" を選択します。

これは自動でインストールされているテーマ(minima)の post レイアウトを使用する、という意味になります。
詳細は後ほど説明しますので、ここではおまじない(ど定番のごまかしの言葉)という軽い感じでOKです。

image.png

ここまで完了したら、 Create をクリックします。
View というボタンが出てくると思うので、それもクリックすると、無事記事が追加されていることがわかると思います。

image.png

トップページの post にも追加されています。
image.png

とりあえず環境構築とプロジェクトの作成ができたので、今回はこの辺にしようかと思います。
現時点では、まだ minima という標準で用意されるテーマを使用していますが、
自分の好きなようなデザインにしたい!という方もたくさんおられると思います。

GitHub などでたくさんテーマが公開されてたりするので、お好みのものを探してみるのも一手です。
ですが、やはり自分が作ってこそ!というところもあると思います。

次回では、自分で記事を作る方法を解説しようと思います。
(頑張って書くぞ!!!

それではまた今度!

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

Rails AWSデプロイ エラー遭遇まとめ

参考文献

Rubyインストール編

rbenv インストールエラー

$ rbenv install -v 2.6.5
configure: error: in `/tmp/ruby-build.202005191817.10626/ruby-2.6.5':
configure: error: no acceptable C compiler found in $PATH

解決コマンド

$ sudo yum install gcc openssl-devel
$ sudo yum install -y gcc-6 bzip2 openssl-devel libyaml-devel libffi-devel readline-devel zlib-devel gdbm-devel ncurses-devel
$ sudo yum erase ruby.noarch
$ sudo yum install gcc

MySQL編

root初期パスワード在り処

$ cat /var/log/mysqld.log | grep password
A temporary password is generated for root@localhost: ************

初期パスワードログイン

$ mysql_secure_installation
Enter password for user root: ************
New password: ************
Re-enter new password: ***********

RMgick編

RMagickインストールエラー

$ bundle install --path vendor/bundle
An error occurred while installing rmagick (3.0.0), and Bundler cannot continue.
Make sure that `gem install rmagick -v '3.0.0' --source 'https://rubygems.org/'`

解決コマンド

$ sudo yum -y install ImageMagick
$ sudo yum -y install ImageMagick-devel

Nginx編

Nginxインストールエラー

$ sudo yum install nginx
読み込んだプラグイン:extras_suggestions, langpacks, priorities, update-motd
パッケージ nginx は利用できません。
エラー: 何もしません

解決コマンド

$ sudo amazon-linux-extras install nginx1.12
                 or
$ sudo yum install http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm -y
$ sudo yum install nginx -y

nginx.conf設定後のpostメソッド対策

$ cd /var/lib
$ sudo chmod -R 775 nginx
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

現在作業しているCurrentBranchにMasterBranchの情報を反映させたい時

背景

プログラミングスクールにてフリマアプリをチーム開発している時でした。

現在作業しているブランチにマスターブランチの情報を持ってきたい・・・・

こんな時の解決法を今回紹介します。

以下の4つのコマンドをターミナルで入力するだけで大丈夫です!!

※注意点

コマンドを実行する前の注意点として、編集途中のファイル等がある場合は、一度コミット&プッシュして何もない状態にしておきましょう。

<!-- 開発中ブランチからmasterブランチへ移動 -->
$ git checkout master

<!-- リモートのmasterを反映 -->
$ git pull origin master

<!-- masterブランチから開発中のブランチへ移動 -->
$ git checkout 開発中のブランチ名

<!-- maserの内容を開発中ブランチに取り込む -->
$ git merge origin master

これで作業ブランチにマスターブランチの情報が反映されていると思います!!

最後まで記事を読んで頂きましてありがとうございます!!

参考になれば幸いです:pray_tone2:

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

atomのerbでrailsのコードが上手く反応してくれない

atom.png

ruby on railsを勉強している初心者です。progateのruby on rails のすべて終了後、自分でコードを書いているのですが、index.html.erbに<% >を追加したところ、以下のhtmlコードはすべて反応しなくなりました。このような時はどのような対応をすればよいでしょうか。atomでコードを書いています。

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

AtCoderでRuby学習7【Contest168 Triple Dots】

はじめに

Ruby学習の一環として「競技プログラミング(競プロ)」に挑戦します。
そのための学習の中で学んだことをアウトプットしていきます。
今回は「AtCoder Beginners Contest168」の二問目(Triple Dots)より。
https://atcoder.jp/contests/abc168/tasks/abc168_b

今回の自分の解答と、解答に使ったメソッド・記法を紹介していきます。

問題

英小文字からなる文字列 S があります。
S の長さが K 以下であれば、Sをそのまま出力。
S の長さが K を上回るのであれば、先頭から K 文字だけを切り出し、末尾に"..."を加えて出力すること。

制約
・K は1以上100以下の整数
・S は英小文字からなる文字列
・S の長さは1以上100以下

入力は以下の形で与えられる。

K
S

入力例
7
nikoandsolstice
出力例
# 上記例の場合
=> nikoand...

解答

まずは僕が最初に書いたコードです。

k = gets.to_i
s = gets.chomp
print s.length > k ? "#{s[0...k]}..." : s

Atcoderへの挑戦を初めて、初期の頃に学んだ三項演算子を使っての解答です。
AtCoder Beginners SelectionでRuby学習【Product】様々な解法から学ぶ
文字列がの長さをlengthメソッドで出した上で K と比較し、
K より大きかった場合式展開を使って"..."を加えて出力、K 未満だった場合はそのまま出力という流れです。

では、今回使ったメソッド、記法について以下にまとめます。

lengthメソッド(Stringクラス)

文字列の長さを返します。

#例
print "test".length
=> 4

ちなみに、Arrayクラスのlengthメソッドは要素の数を返します。

文字列の一部を取得する方法①[first...end]

文字列の中から、開始位置(first)から終了位置(end)で挟まれた範囲を文字列として返します。
位置の指定は、1文字目の前を「0」として、1文字目と2文字目の間が「1」という形で指定出来ます。

a = "test"

#位置指定方法(イメージ)
0 t 1 e 2 s 3 t 4

#例
print a[0...3]
=> tes
#上記の位置指定方法での、0から3の間を文字列として返す

文字列の一部を取得する方法②[first, length]

ちなみに、[1, 3]という形で指定すると、「1」の位置から3文字を返します。

a = "test"

#例
print a[1, 3]
=> est

終了位置を位置指定ではなく、開始位置からの文字数という形で指定したい場合に使います。

最後に

以上、「AtCoder Beginners Contest168」の二問目(Triple Dots)から学んだメソッドをご紹介しました。

もし間違いなどございましたら、ご指摘いただけると嬉しいです。

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

Dockerの開発環境で通常の開発言語のコマンドで実行する方法

Dockerの開発環境ではDockerの開発環境特有のコマンドでの操作が必要になりますが、スクリプト言語のコマンドをローカル環境で実行するときと同じコマンドで開発ができる方法を紹介します。

前提

Docker 19.03.8
Ruby 2.5
Rails 5.2

Dockerとローカルの開発環境で実行するときの違い

例えば以下のRuby on Railsの開発で用いられるコマンド

$ rails db:migrate

このコマンドをDockerで実行する場合

$ docker-compose run web rails db:migrate

このようなコマンドになります。
それ以外にも操作方法がありますが、Ruby on Railsで開発するならRubyやRailsの通常のコマンドの方が楽ですよね。その場合は以下の手順でコマンドを実行します。

Rubyの通常のコマンドで開発を行うための準備

Dockerを立ち上げます。

$ docker-compose start

コンテナ名を調べます。

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
a9b19e00552e        recipegram_web      "entrypoint.sh bash …"   44 hours ago        Up 11 seconds       0.0.0.0:3000->3000/tcp   recipegram_web_1
975875c12c76        postgres            "docker-entrypoint.s…"   46 hours ago        Up 12 seconds       5432/tcp                 recipegram_db_1

コンテナ名を入れて下記のコマンドを実行します。

$ docker exec -it a9b19e00552e bash

そうするとこのように切り替わるのでこの状態で今回であればRubyやRailsの実行コマンドで開発が行えます^_^

root@a9b19e00552e:/myapp#
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

大学生Railsエンジニアが、1人でWebとアプリをリリースするまでの3ヶ月間の話

Qiita初投稿なのでお手柔らかに。

自分は大学生ながら都内のスタートアップでエンジニアをしています。

普段はRailsでのWebサービス開発がメインで、SwiftもKotlinも触ったことすらありませんでした。

経験ゼロのReact NativeとExpoでリリースまでに得た知見を残していきます。

開発したサービス

top_image.jpg
SportsLab | スポーツをより深く楽しめる新しいメディア

コメントと共にスポーツのニュースを読めるサービスです。

Webとアプリの両方を1人で開発・運用しています。スタートアップあるあるですね笑。

使用技術

ざっくり使用している技術を紹介します。

Web: Rails 5.0, jQuery

アプリ: React Native, Expo, (TypeScript)

インフラ: ElasticBeanstalk(AWS)

認証: Firebase Auth

CI: Circle CI

スタートアップではよくある感じの技術構成だと思います。

Railsのエコシステムや周辺ライブラリの豊富さには助けられました。

アプリについては僕がSwiftやKotlinをかけないため泣く泣くReact Nativeを採用しました。

開発スケジュールを振り返る

開発の時間軸としては

12/24
記念すべきfirst commit
1/1
年明けにEC2にデプロイ
1/2
ドメインを取得してWeb版をローンチ
1/4
アプリを開発開始
2/1
Appleに初めて申請
2/13
朝起きたらアプリが公開されてました!
2/20
安定版がストアで公開される

一人で開発して良かった事

今までのJSの経験を生かす事が出来た

React Native & Expoを採用した事でSwift, Kotlinを勉強する事なく純粋にJavaScript(TypeScript)を書くだけでモバイルアプリを開発できた、というのが一番ですね。

OTAアップデートで簡単に更新できる

また、ExpoにはOTAアップデート機能があるのでそちらを使えばストアに申請する事なくユーザのアプリを強制的にアップデートできるのも魅力の1つです。

デザインについても Native BaseReact Native Elements といったUIライブラリが揃っているのでCSSをほとんど書く事なく開発を進められたのも大きかったです。

一人で開発して辛かった事

気軽にストア申請できない

ユーザによって使うアプリのバージョンがまちまちになってしまうので、API側でルーティングの変更などの仕様を変えられないのが辛いです。

TypeScript難しい?

React Nativeは完全に独学で、今も付け焼き刃の状態でコードを書いているのでアプリの挙動が不安定なのがネックでした。

少しでもバグを減らすためにTypeScriptを導入しましたが、動的型付けであるRubyしか書いてこなかったので、そもそも型ってなんですか?というレベルで、TypeScriptの恩恵を十分に受けられてないです。

これから勉強していきます!

ファイルの肥大化

useEffectで通信処理をViewにベタガキしてるのでファイルが巨大化してカオスofカオス。

Reduxや, Redux-sageなどのミドルウェアの学習と導入が待たれる。。。(そう言えば、つい最近FaceBookが新しい状態管理ライブラリを出してきましたね!)

申請が通らない!!!

最初App Storeの申請で数週間悩まされました。理由はこいつでした。

4.2 minimum functionality We found that the usefulness of your app is limited by the minimal features it includes.

どうも調べたところお前の作ったアプリは⚪️ミだからアウト!っていう意味らしいです。

Push通知実装したり、記事の検索機能つけたりいろいろしたのですがダメでした。

ではどうやって通したかというと・・・

ウォークスルーを実装しました!!!

スクリーンショット 2020-05-19 01.55.07.png

スクリーンショット 2020-05-19 01.54.25.png

それだけです。

正直なんで通ったのか分からないです。

どうやらアプリでないと得られないUXを訴求したのが良かったっぽいです。

同じ理由でリジェクトされてる人が一人でも多く救われますように。

ExpoをアップグレードしたらFacebookでログインできなくなった

ふと朝起きると同僚からSlackで同僚からメンションが来ていました。

Facebookでログインしようとするとアプリがクラッシュするんだけど

報告を受けた瞬間、顔面蒼白になりました。

急いで調査を開始するも、全く原因を特定できませんでした。

焦りを加速させたのはSentry経由でSlackにエラー通知も流れてこないという事でした。

つまり具体的にどこのコードでクラッシュしてるのか検討がつかない。

公式ドキュメント通りに実装してるし、どこが悪いのか悩む日々。

分からなさすぎてExpoにIssueまで立てちゃう始末。

Problem login with Facebook and Firebase

そのあともう一度Expo37のchangelogを調べていくと・・・ありました!!!

https://github.com/expo/expo/pull/7931/files

読んでいくと、途中にこんな記述が。

- In the Expo Client, all of your Facebook API calls will be made with Expo's Facebook App ID. This means you will not see any related ad info in your Facebook developer page while running your project in the Expo Client.
- To use your app's own Facebook App ID (and thus see any related ad info in your Facebook developer page), you'll need to [build a standalone app](../../distribution/building-standalone-apps/).

どうやら開発環境ではFacebookログインはできなくなったようです。

なのでビルドして動作確認する必要があるようでした。

ちなみに僕はこれに気付かず

Possible Unhandled Promise Rejection (id: 0):
[Error: Unsuccessful debug_token response from Facebook: {"error":{"message":"(#100) The App_id in the input_token did not match the Viewing App","type":"OAuthException","code":100,"fbtrace_id":"********"}}]

というエラーを3日間眺める羽目になりました。。。

1人でRailsでAPIを作った感想

JSONの整形にはActive Model Serializerが神

デフォルトでインストールされてるjbuilderは評判悪そうなのでActive Model Serializerを採用しました。

スター数も多いし大丈夫そうって思ってた矢先、更新が止まるという。。。

しばらくはこれで行く予定です。

Netflixが出してるfast_jsonapiっていうのが来てるらしいのですが学習コストが高そうなので断念しました。

Active Moel SerializerはActive Recordベースでかけるため直感的ですがSerializer側に値を渡す時のやり方が分からなくて最初苦労しました。

検索してもヒットするのが古いバージョンの記事ばかりで諦めかけていた、そのとき!

ActiveModelSerializers(0.10系)のインスタンス生成時に引数を渡してSerializerクラス内で使う方法

こちらの記事を発見しました。これに全て書いてあります。神!!!

重い腰を上げてFat Controllerを解決

あと初心者Railsエンジニアあるあるですね。

これどうしようかつい最近まで悩んでいたのですが

実務で学んだRailsの設計・リファクタリング

こちらを参考にさせて頂きました。

POROでサービスクラス(上記の記事ではWorkflows)を作ってそこに切り出そうというアプローチです。

あとControllerを分けてCRUDしかメソッドが作成されないようにする。

試してみましたがいい感じです。自分の書き方が合ってるか自信ありませんが。。。

突然のDockerの導入

実はWeb版のCSSは弊社のCEOが自ら書いています。

で、そのCEOのPCで環境構築しようとしたらなぜか環境構築で詰まりまして。。。

試行錯誤した結果、初めてDockerなるものを導入しました。

と言っても、開発環境でDockerfile書いただけです。

本番環境でのECSやFargateを使ったDockerの運用はリリース後のお楽しみという事で・・・。

Docker for Mac予想以上に重かった!

PCは高いやつを買おうと心に決めました。

こんな感じです!

最後に

今も一人でアプリ、バックエンド、インフラまで面倒見てます!
一緒にコードかきたい方は僕のTwitterアカウントまでDMどうぞ!!!
https://twitter.com/Katsukiniwa

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

AtCoderでRuby学習6【Contest168 Therefore】

はじめに

Ruby学習の一環として「競技プログラミング(競プロ)」に挑戦します。
そのための学習の中で学んだことをアウトプットしていきます。
今回は「AtCoder Beginners Contest168」の一問目(Therefore)より。
https://atcoder.jp/contests/abc168/tasks/abc168_a

自分が使った解法と、公式から公開された解説をもとにまとめていきます。

問題

日本語で鉛筆を数える時には数の後ろに助数詞として「本」がつきます。
この助数詞はどんな数につくかで読み方が異なります。
999以下の整数について、「N本」と言う時の「本」の読み方は、

・Nの1の位が「2,4,5,7,9」の時は'hon'
・Nの1の位が「0,1,6,8」の時は'pon'
・Nの1の位が「3」の時は'bon'

Nが与えられるので、対応する「本」の読み方を出力しなさい。

制約
Nは999以下の正の整数

入力は以下の形で与えられる。

N

# 例
16

上記の例だと最大2回割ることができるので

出力例
# 上記例の場合
=> pon

解答①

まずは僕が最初に書いたコードです。

a = gets.to_i.modulo(10)
if [2,4,5,7,9].include?(a)
  print "hon"
elsif [0,1,6,8].include?(a)
  print "pon"
else
  print "bon"
end

moduloメソッドを使って、入力から一の位のみを受け取り、
if文とinclude?メソッドで判定を行っていきます。
include?メソッドについては、以下の記事について一度書いたので、
AtCoder Beginners SelectionでRuby学習【Some Sums】使えるメソッドを増やす
ここでは、moduloメソッドについて触れておきます。

moduloメソッド

指定した数で割った余りを返します。
解答では、整数を10で割ることで一の位を余りとして取り出しています。

#例
13.modulo(4)
=> 1
42.modulo(10)
=> 2

解答② case文

コンテスト後に配布された解説では、
case文による、より直感的に記述できる方法が紹介されています。

以下ではcase文で解答した後に、case文の紹介をしていきます。

n = gets.to_i.modulo(10)
case n
when 2,4,5,7,9
  print 'hon'
when 0,1,6,8
  print 'pon'
else
  print 'bon'
end

最初の解答では、条件を配列に入れてinclude?メソッドで判定をしていましたが、
case文を使うことで、「一の位がもし2,4,5,7,9だったら…」と考えたままのコードが書けています。
確かにこっちの方が良さそうです。

case文

一つの値に対して複数の候補の中から一致するものを探す時に便利です。
whenで指定するものに一致するかどうかを「===」演算子によって判定します。

case object
when value1
  # object === value1の時に実行する文
when value2
  # object === value2の時に実行する文
else
  # 全てに合致しなかった場合に実行する文
end

ここで出てきた「===」演算子は、
上記で言うobjectが文字列や数値の場合は、「==」として、
正規表現の場合は「=~」として、
範囲の場合はinclude?のようにその中にvalueを含むかと、言う形で判定してくれるようです。
柔軟で、使い勝手が良さそうです。

最後に

以上、「AtCoder Beginners Contest168」の一問目(Therefore)から学んだメソッドをご紹介しました。

もし間違いなどございましたら、ご指摘いただけると嬉しいです。

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

【Rails】gem devise インストール時の流れ

はじめに

Qiita初投稿です。
拙い文章で恐縮ですが、ご一読いただけますと幸いです。
よろしくお願いします。

ユーザー管理機能のためのgem deviseをインストール

1. Gemfileの最終行に以下のように追記

Gemfile
# 省略
gem 'devise'  # 最終行に追記してください

2. ターミナルで bundle install を実行

ターミナル
$ bundle install

3. Gemfile.lockで devise がインストールされたか確認

Gemfile.lock
# 省略
devise

deviseの適用

インストールが完了したら、devise専用のコマンドを利用して設定ファイルを作成

4. ターミナルで rails g devise:install を実行

ターミナル
# deviseの設定ファイルを作成
$ rails g devise:install

新規作成されるファイル

  • config/initializers/devise.rb
  • config/locales/devise.en.yml

5. ターミナルで rails g devise user を実行

ターミナル
# deviseコマンドでモデルを作成
$ rails g devise user

新規作成されるファイル

  • app/models/user.rb
  • db/migrate/20XXXXXXXXXXXX_devise_create_users.rb
  • test/fixtures/users.yml
  • test/models/user_test.rb

また、config/routes.rbにdevise_for :usersの記述が自動的に追記されます。

config/routes.rb
Rails.application.routes.draw do
  devise_for :users
# 省略

6. ターミナルで rails db:migrate を実行

ターミナル
# 作成されたマイグレーションファイルを実行
$ rails db:migrate

7. ターミナルで rails g devise:views を実行

ターミナル
# devise用のビューを作成
$ rails g devise:views

新規作成されるファイル

  • app/views/devise/shared
  • app/views/devise/shared/_error_messages.html.erb
  • app/views/devise/shared/_links.html.erb
  • app/views/devise/confirmations
  • app/views/devise/confirmations/new.html.erb
  • app/views/devise/passwords
  • app/views/devise/passwords/edit.html.erb
  • app/views/devise/passwords/new.html.erb
  • app/views/devise/registrations
  • app/views/devise/registrations/edit.html.erb
  • app/views/devise/registrations/new.html.erb
  • app/views/devise/sessions
  • app/views/devise/sessions/new.html.erb
  • app/views/devise/unlocks
  • app/views/devise/unlocks/new.html.erb
  • app/views/devise/mailer
  • app/views/devise/mailer/confirmation_instructions.html.erb
  • app/views/devise/mailer/email_changed.html.erb
  • app/views/devise/mailer/password_change.html.erb
  • app/views/devise/mailer/reset_password_instructions.html.erb
  • app/views/devise/mailer/unlock_instructions.html.erb

以上、gem devise のインストール時の流れを説明させて頂きました。
少しでも多くの方の参考になれば幸いです。

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

荒木さん

あらきさんなのです

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

Ruby public protected private

public

デフォルトの設定、クラスの外部からでも呼び出せる。

protected

外部から隠す
そのメソッドを定義したクラス自身と、そのサブクラスのインスタンスメソッドからレシーバ付きで呼び出せる

private

外部から隠す
クラスの内部とサブクラスでのみ使用できるメソッド
レシーバを指定して呼び出すことはできない

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

OSX Catalinaにアップデート後、sassできなくなった

似たような状況に見舞われた同様記事ありますが個人用にもメモ。

状況と解決方法

表題の通りなんですが、OSXをCatalinaにアップデート後、sassコマンドを打つと以下のようなエラーが出た。

bash: /usr/local/bin/sass: /System/Library/Frameworks/Ruby.framework/Versions/2.3/usr/bin/ruby: bad interpreter: No such file or directory

どうやらCatalinaにアップデートするとOSにビルトインされているRubyのバージョンが上がって古いのが削除されていることが原因のよう。

以下の記事を参考にrbenvをインストール後、別のバージョンのRubyを入れてそこにパスを通すと解決!!

https://qiita.com/nishina555/items/63ebd4a508a09c481150

余談

実際はPhpstormのプラグインからの実行でエラーが出てて、慌ててPhpstormのサポートに連絡したらSCSSの実行はPhpstormとは関係ないですよー、と言われた。そらそうだ。(ビルトインな気がしたがそうではないみたい)

でそのメールにRuby Sassは非推奨なのでDart Sass使ってくださいねー、と親切なアドバイスも。
Dartに切り替えたほうが良いかなー。

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

dmk

dwa

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

RSpec3のフォーマッタの基本と自作入門

概要

RSpec を実行したときに標準出力される内容は、使用するフォーマッタで決定します。本記事ではRSpec3 におけるフォーマッタの基本を抑えてから、カスタムフォーマットを実装して体験をしてみる。

バージョン情報

version
ruby 2.6.5
rspec 3.9.1

使用するテスト対象コード

本記事では以下のシンプルなクラスを対象にテストを実行します。

class Calculator
  def initialize(initial_value)
    @answer = initial_value
  end

  def add(number)
    @answer += number
  end

  def sub(number)
    @answer -= number
  end
end

使用するテストコード

前項の Calculator クラスのシンプルな単体テストを用意します。

コメントを記載している通り、4つのテストケースのうち1つは意図的に落ちるものを含んでいます。クラスを使う側は引き算の結果が負数にならないものだと想定していたという設定です。

describe Calculator do
  subject { described_class.new(initial_value) }

  describe '#add 足し算' do
    context '初期値が0の場合' do
      let(:initial_value) { 0 }

      it '10を足すと10が戻る' do
        expect(subject.add(10)).to eq 10
      end
    end

    context '初期値が5の場合' do
      let(:initial_value) { 5 }

      it '10を足すと15が戻る' do
        expect(subject.add(10)).to eq 15
      end
    end
  end

  describe '#sub 引き算' do
    context '初期値が0の場合' do
      let(:initial_value) { 0 }

      # 落ちるテスト
      it '10を引くと0が戻る' do
        expect(subject.sub(10)).to eq 0
      end
    end

    context '初期値が30の場合' do
      let(:initial_value) { 30 }

      it '10を引くと20が戻る' do
        expect(subject.sub(10)).to eq 20
      end
    end
  end
end

ビルトインフォーマッタについて

Rspec3 では最初から使えるいくつかのビルトインフォーマッタが用意されています。

デフォルトでは後述のProgressフォーマッタが使用されますが、--format または単に -fオプションを用いて、フォーマッタを指定することで使い分けることができます。

Progress formatter

デフォルトのフォーマッタです。テストごとに成功の場合は . を、失敗の場合は F をリアルタイムに表示していき、最後に失敗したテストのレポートを表示します。

$ rspec -f p spec/calculator_spec.rb 
..F.

Failures:

  1) Calculator#sub 引き算 初期値が0の場合 10を引くと0が戻る
     Failure/Error: expect(subject.sub(10)).to eq 0

       expected: 0
            got: -10

       (compared using ==)
     # ./spec/calculator_spec.rb:41:in `block (4 levels) in <top (required)>'

Finished in 0.06725 seconds (files took 2.14 seconds to load)
4 examples, 1 failure

Failed examples:

rspec ./spec/calculator_spec.rb:40 # Calculator#sub 引き算 初期値が0の場合 10を引くと0が戻る

Documentation formatter

テストコードに基づくドキュメントを出力します。RSpecは振る舞い駆動でテストを記述できるので、このフォーマッタを意識してテストを書くことで、テスト結果をそのままドキュメントとして利用することができます。

$ rspec -f d spec/calculator_spec.rb
Calculator
  #add 足し算
    初期値が0の場合
      10を足すと10が戻る
    初期値が5の場合
      10を足すと15が戻る
  #sub 引き算
    初期値が0の場合
      10を引くと0が戻る (FAILED - 1)
    初期値が30の場合
      10を引くと20が戻る

Failures:

  1) Calculator#sub 引き算 初期値が0の場合 10を引くと0が戻る
     Failure/Error: expect(subject.sub(10)).to eq 0

       expected: 0
            got: -10

       (compared using ==)
     # ./spec/calculator_spec.rb:42:in `block (4 levels) in <top (required)>'

Finished in 0.12273 seconds (files took 2.53 seconds to load)
4 examples, 1 failure

Failed examples:

rspec ./spec/calculator_spec.rb:41 # Calculator#sub 引き算 初期値が0の場合 10を引くと0が戻る

json formatter

テスト結果を、元ソースコードの情報などのメタデータを含めたJSON形式で出力します。通常はこのまま利用するのでなく、他の解析ツールなどに受け渡してテストレポートの見える化を行ったりします。

$ rspec -f j spec/calculator_spec.rb 
 {
    "version": "3.9.1",
    "examples": [
        {
            "id": "./spec/calculator_spec.rb[1:1:1:1]",
            "description": "10を足すと10が戻る",
            "full_description": "Calculator#add 足し算 初期値が0の場合 10を足すと10が戻る",
            "status": "passed",
            "file_path": "./spec/calculator_spec.rb",
            "line_number": 22,
            "run_time": 0.0069776,
            "pending_message": null
        },
        {
            "id": "./spec/calculator_spec.rb[1:1:2:1]",
            "description": "10を足すと15が戻る",
            "full_description": "Calculator#add 足し算 初期値が5の場合 10を足すと15が戻る",
            "status": "passed",
            "file_path": "./spec/calculator_spec.rb",
            "line_number": 30,
            "run_time": 0.0001513,
            "pending_message": null
        },
        {
            "id": "./spec/calculator_spec.rb[1:2:1:1]",
            "description": "10を引くと0が戻る",
            "full_description": "Calculator#sub 引き算 初期値が0の場合 10を引くと0が戻る",
            "status": "failed",
            "file_path": "./spec/calculator_spec.rb",
            "line_number": 41,
            "run_time": 0.0454084,
            "pending_message": null,
            "exception": {
                "class": "RSpec::Expectations::ExpectationNotMetError",
                "message": "\nexpected: 0\n     got: -10\n\n(compared using ==)\n",
                "backtrace": [
                    "/usr/local/bundle/gems/rspec-support-3.9.2/lib/rspec/support.rb:97:in `block in <module:Support>'",
                    "/usr/local/bundle/gems/rspec-support-3.9.2/lib/rspec/support.rb:106:in `notify_failure'",
                    "(以下略)"
                ]
            }
        },
        {
            "id": "./spec/calculator_spec.rb[1:2:2:1]",
            "description": "10を引くと20が戻る",
            "full_description": "Calculator#sub 引き算 初期値が30の場合 10を引くと20が戻る",
            "status": "passed",
            "file_path": "./spec/calculator_spec.rb",
            "line_number": 49,
            "run_time": 0.0002024,
            "pending_message": null
        }
    ],
    "summary": {
        "duration": 0.0632882,
        "example_count": 4,
        "failure_count": 1,
        "pending_count": 0,
        "errors_outside_of_examples_count": 0
    },
    "summary_line": "4 examples, 1 failure"
}

(※実際のJSONは整形されていません)

html formatter

$ rspec -f h spec/calculator_spec.rb 

テスト結果をHTMLで出力します。そのままだとタダのHTMLテキストなので、保存してブラウザで開くと以下のように結果を確認できます。

スクリーンショット 2020-05-15 0.44.42.png

フォーマッタを自作する

これまで -f オプションを使って、フォーマッタの指定をしてきましたが、ここにその他のフォーマッタのクラス名を指定することで、任意のフォーマッタを利用することができます。

自作フォーマッタを動かしてみる

まずは最低限のフォーマッタを作成してみます。

my_formatter.rb
class MyFormatter
  RSpec::Core::Formatters.register self, :example_passed, :example_failed

  def initialize(output)
    @output = output
  end

  def example_passed(notification)
    @output << "【#{notification.example.description}\t成功!!\n"
  end

  def example_failed(notification)
    @output << "【#{notification.example.description}\t失敗!!\n"
  end
end

以下のように、-rオプションでrequireするファイルを指定し、そこで読み込まれたクラスをフォーマッタに指定します。

$ rspec -r ./my_formatter.rb -f MyFormatter spec/calculator_spec.rb

良い感じに独自のフォーマットでテスト結果が出力されました!

【10を足すと10が戻る】  成功!!
【10を足すと15が戻る】  成功!!
【10を引くと0が戻る】   失敗!!
【10を引くと20が戻る】  成功!!

カスタムフォーマットクラスについて

上記のカスタムクラスでは

RSpec::Core::Formatters.register self, :example_passed, :example_failed

という見慣れないコードがはじめに出てきます。

これはRpsecが通知する情報のうち、どの分類についてこのフォーマッタで受け取るかを宣言しており、ここではexample_passed example_failed の2種類を受け取っています。

そして、受け取った通知ごとに、同様のメソッドを実装し、そこで通知内容を元に出力内容を決定しているわけですね。

  def example_passed(notification)
    @output << "【#{notification.example.description}\t成功!!\n"
  end

ちなみに全ての通知を受け取りたいからってこの行を省略すると以下のような警告が出ます。警告内容の通り、現在はちゃんとregisterメソッドを通さないとイケないようですね。

Deprecation Warnings:

 The MyFormatter formatter uses the deprecated formatter interface not supported directly by RSpec 3.  To continue to use this formatter you must install the `rspec-legacy_formatters` gem, which provides support for legacy formatters or upgrade the formatter to a compatible version.  Formatter added at: /usr/local/bundle/gems/rspec-core-3.9.1/exe/rspec:4:in `<top (required)>'


If you need more of the backtrace for any of these deprecations to
identify where to make the necessary changes, you can configure
`config.raise_errors_for_deprecations!`, and it will turn the
deprecation warnings into errors, giving you the full backtrace.

1 deprecation warning total

通知の種類

RSpec::Core::Formatters.register で受け取れる通知は以下のようなものがあります(全てではありません)

名称 タイミング 引数
start テストスイート開始時 StartNotification
stop テストスイート終了時 ExamplesNotification
example_group_started テストグループ開始時 GroupNotification
example_started テスト開始時 ExampleNotification
example_passed テスト成功時 ExampleNotification
example_failed テスト失敗時 FailedExampleNotification

start

  def start(notification)
    puts "読み込み時間: #{notification.load_time}"
    puts "項目数: #{notification.count}"
  end
読み込み時間: 1.757944
項目数: 4

stop

終了時に実施した全てのテスト内容を確認することができます。

def stop(notification)
  puts "#{notification.failed_examples.count}/#{notification.examples.count}個のテストに失敗しました"
end
1/4個のテストに失敗しました

example_group_started

GroupNotification は、 ExampleGroup つまり describecontext といったテストのグループのオブジェクトを取得できます。

def example_group_started(notification)
  puts "[#{notification.group.metadata[:scoped_id]}] #{notification.group.description}"
end
[1] Calculator
[1:1] #add 足し算
[1:1:1] 初期値が0の場合
[1:1:2] 初期値が5の場合
[1:2] #sub 引き算
[1:2:1] 初期値が0の場合
[1:2:2] 初期値が30の場合

example_started

ExampleNotificationは、個々のテストを表すExampleを取得できます。

def example_started(notification)
  puts "#{notification.example.description}:\t#{notification.example.location}"
end
10を足すと10が戻る:     ./spec/calculator_spec.rb:22
10を足すと15が戻る:     ./spec/calculator_spec.rb:30
10を引くと0が戻る:      ./spec/calculator_spec.rb:41
10を引くと20が戻る:     ./spec/calculator_spec.rb:49

example_passed

example_startedと同じくExampleが取得できるが、こちらはテスト成功後の Example なので、実行結果のExecutionResultを利用できます。

def example_passed(notification)
  example = notification.example
  result = example.execution_result
  puts "[#{example.description}] run_time: #{result.run_time}"
end
[10を足すと10が戻る] run_time: 0.0019845
[10を足すと15が戻る] run_time: 0.0001931
[10を引くと20が戻る] run_time: 0.0001662

example_failed

概ね example_passed と同じですが、 FailedExampleNotification では具体的な失敗理由を取得することができます。

def example_failed(notification)
  puts "[#{notification.description}]"
  puts notification.exception
end
[Calculator#sub 引き算 初期値が0の場合 10を引くと0が戻る]

expected: 0
     got: -10

(compared using ==)

ちなみにエラー通知の内容はReporter というまた別概念が関わってきますが本記事では割愛します。

ビルドインフォーマッタっぽいものを再現する

前項で紹介した仕組みを使って、ビルトインフォーマッタの一つあるドキュメンテーションっぽいフォーマッタを作ってみましょう。

(あくまで「っぽいもの」です)

class MyFormatter
  RSpec::Core::Formatters.register self, :start, :example_group_started, :example_passed, :example_failed, :stop

  def initialize(output)
    @output = output
  end

  def start(notification)
    @load_time = notification.load_time
  end

  def example_group_started(notification)
    group = notification.group
    description = group.description
    output_with_space(description, get_nest_num(group.metadata))
  end

  def example_passed(notification)
    example = notification.example
    description = example.description
    output_with_space(description, get_nest_num(example.metadata))
  end

  def example_failed(notification)
    example = notification.example
    description = "#{example.description} (FAILED)"
    output_with_space(description, get_nest_num(example.metadata))
  end

  def stop(notification)
    failure_notifications = notification.failure_notifications
    @output.puts "\nFailures: \n\n" if failure_notifications.present?

    failure_notifications.each_with_index do |fn, i|
      @output.puts "#{i + 1}) #{fn.description}"
      @output.puts fn.exception
      @output.puts "# #{fn.formatted_backtrace.first}"
    end

    total_run_time = notification.examples.sum { |e| e.execution_result.run_time }
    @output.puts "\n"
    @output.puts "Finished in #{total_run_time} seconds (files took #{@load_time} seconds to load)"
    @output.puts "#{notification.examples.count} examples, #{notification.failed_examples.count} failure"
  end

  private

    def get_nest_num(metadata)
      metadata[:scoped_id].count(':')
    end

    def output_with_space(description, nest_num)
      @output.puts "#{'  ' * nest_num}#{description}"
    end
end

実行結果

$ rspec -r ./my_formatter.rb -f MyFormatter spec/calculator_spec.rb
Calculator
  #add 足し算
    初期値が0の場合
      10を足すと10が戻る
    初期値が5の場合
      10を足すと15が戻る
  #sub 引き算
    初期値が0の場合
      10を引くと0が戻る (FAILED)
    初期値が30の場合
      10を引くと20が戻る

Failures: 

1) Calculator#sub 引き算 初期値が0の場合 10を引くと0が戻る

expected: 0
     got: -10

(compared using ==)
# ./spec/calculator_spec.rb:42:in `block (4 levels) in <top (required)>'

Finished in 0.084687 seconds (files took 1.7904404 seconds to load)
4 examples, 1 failure

やや冗長なコードにはなりましたが、結果はそれっぽいんじゃないでしょうか??

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

Ruby on rails を初心者向けに解説② ~リンクの作成~

はじめに

今回は前回の記事の続きになります。

Ruby on rails を初心者向けに解説①

頑張っていきましょう。

ルーティングの変更

ルーティングは自分の好きなように設定することができます。

例えば、/pocomaruと書いたときに、home#top(homeコントローラーのtopアクション)が行われるようにしましょう。

ルーティングを以下のように変更します。

routes.rb
Rails.application.routes.draw do
  get "pocomaru" => "home#top"
end

この状態で、以下のようにURLを打ちます。

http://localhost:3000/pocomaru

このようにすると、http://localhost:3000/pocomaruというURLはhome#top(homeコントローラーのtopアクション)という命令に置き換えられます。

ルーティングは、localhost:3000以降のURLに対して行います。

実行すると、以下の画面になりました。

image.png

リンクの作成

それでは、リンクを作成していきましょう。

top.html.erbというファイルに、test.html.erbファイルへのリンクを張ります。

以下のようなファイル構造になっています。
image.png

test.html.erbファイルの中身は次のようにします。

test.html.erb
<h1>テスト</h1>

このファイルへのリンクを作成していきましょう。

リンクをクリックすると別のファイルになぜ飛ぶか

しかし、リンクをクリックして、それがユーザーに送られるとはどういうことでしょうか。

一度、何が起きているのかを考えてみましょう。以下の図をみてください。

image.png

リンクをクリックして別のファイルに飛ぶということは、上の図の赤く囲った部分の話になります。

ユーザーがURLをサーバーに送り、そのURLに応じてコントローラーがviewファイルを探し出し、アクションに書いてある処理をした後、viewファイルをユーザーに送ります。

このように、ユーザーがサーバーにviewファイルを要求することをgetリクエストを送ると呼びます。

ユーザーがURLをサーバーに送る動作は様々です。リンクが貼られている文字をクリックしたり、IDを打ち込んだ後に送信などと書かれたボタンを押したりする、などがあります。

そのようなURLが送られてきた後、サーバーはルーティングにより翻訳を行うのでしたね。

image.png

ルーティングにより、どのコントローラーのどのアクションを行うかを指定します。

また、これらのアクションは、viewファイルに対応しています。

例えば、ルーティングによりhomeコントローラーのtopアクションが呼ばれると、app >> views 配下のhomeディレクトリのtop.html.erbファイルが呼ばれます。

つまり、何故リンクをクリックすると別ファイルに飛ぶのかを考えると以下のように答えることができます。

リンクをクリックすると、URLがルーティングにより変換され、どのコントローラーのどのアクションを行うかが指定され、そのアクションに応じたviewsファイルがユーザーに送られてくるから

実際にリンクを作成

Ruby on railsのリンクの作成方法は大きく分けて以下の2つがあります。

  • htmlのaタグのhrefで指定する
  • Railsのlink_toメソッドを使う

せっかくなので、2つの方法で実装してみましょう。

top.html.erbファイルを以下のように書き換えました。

top.html.erb
<h1>Hello World</h1>
<a href="test">test by href</a>
<%= link_to("test by link_to", "test") %>

image.png

二行目のリンクの書き方は、典型的なhtmlのリンクの書き方ですね。

三行目の書き方に注目してください。

<%= %>という形で囲むと、これはRubyのコードだよ!と伝えることになります。link_toを使ったコードは、htmlのコードではなくRubyのコードなので、このように囲む必要があります。

ちなみに、<% %>で囲っても、Railsのコードであると伝えることになります。

<%%>で囲むのか、<%=%>で囲むのかについて解説と、link_toの使い方の解説を以下で行います。

<%= %>と<% %>の違い

実は.html.erbのerbとはEmbedded RuByの略称になります。つまり、Rubyを埋め込んだhtmlファイルであるという意味です。

つまり、このhtml.erbファイルの内部にはRubyのスクリプトを埋め込むことができます。

<%= %>と<% %>の2つは、html.erbファイルにおいてrubyのコードを書くときに使うことになります。

しかし、htmlファイルにrubyスクリプトを埋め込むときに、別にブラウザに表示する必要がない処理を行う場合があります。

そのようなときに、この2つを使い分ける必要があります。ざっくりと以下のように覚えてください。

  • ブラウザに表示させたいときは<%= %>を使う
  • ブラウザに表示させたくないときは<% %>を使う

link_toの使い方

link_toはRubyのコードであるので、<% %><%= %>で囲む必要があります。

今回はクリックしたらどこかに飛ぶリンクを作成したいので、当然ブラウザに表示する必要があります。

<%= %>で囲みましょう。

link_toは、第一引数にブラウザに表示する文字を取り、第二引数にURLを取ります。

今回は、testというURLを取ることにしました。

ここからは、ユーザーからリンクがクリックされた、つまりURLが送られてきたときに、test.html.erbファイルを送る方法について解説します。

まず、最初にルーティングを変更しましょう。

ルーティングを変更

以下のようにルーティングを変更してください。

routes.rb
Rails.application.routes.draw do
  get "pocomaru" => "home#top"
  get "test" => "home#test"
end

新しく、testとうURLが送られてきた場合にhome#topというルーティングに変換するコードを追記しました。

つまり、ユーザーからtestというURLがクリックされると、homeコントローラーのtopアクションが実行されるようになります。

次は、homeコントローラーにtopアクションを追記しましょう。

コントローラーにアクションを追記

homeコントローラにtestアクションを追記しましょう。

hoem_controller.rb
class HomeController < ApplicationController
    def top
    end

    def test
    end
end

このようなコードが追記されることで、ユーザーからhome#testというルーティングが呼ばれたときに、homeコントローラーのtestアクションを行い、view >> home >> test.html.erbファイルをユーザに送り返すことができるようになります。

image.png

終わりに

今回はここまでになります。

ここまでお付き合い頂きありがとうございました。

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

Railsデータベース基礎

テーブル

表形式の収納場所でデータベースの中にいくつも作成することができる。
データベースが存在していても、このテーブルがなければデータを保存することはできません。

レコードとカラム

テーブルは表形式になっていますが、その横一行のことをレコードと言います。また。縦一列のことをカラムと言います。
テーブルのレコードを特定するために、idというカラムが用意されています。

DOA

DOAとはデータ中心アプローチのことで、プログラムよりも前にデータ設計を先に行う方法のことです。
サービス開発がより効率的になることが期待されます。

データベース設計

手順としては
1.テーブルの抽出
 途中でテーブルを追加すると関係性を見直さなければいけなくなる。
 予約語は使わないように。

2.テーブルの定義
 各テーブルが持つカラムを決める。途中で追加するとコードを書き直したり、ビューを変更しなくてはいけない場合が出てくるからです。
 予約語は使わないように。

3.テーブル構造を整理
 同じカラム名を同じテーブル内に作ってはいけません。
そのような場合は別でテーブルを作りましょう。
EX)同じテーブルに imageカラム、 image2カラムなど。この場合はimageテーブルを作る。

4.ER図の作成
テーブル同士の関係をわかりやすく表した図。
IE表記法という書き方で書く。

モデル

モデルの命名規則
モデルクラス名は先頭は大文字の単数形
モデルクラスのファイル名は、先頭小文字の単数形
テーブル名は先頭小文字の複数形
EX)Animal モデルクラス名
animal モデルクラスのファイル名
animals テーブル名

これらモデルファイルとテーブルを作成するコマンドがあります。
それが rails g modelコマンドです。このコマンドの後に作成したいモデルクラスの名前を全て小文字で続けます。
EX)rails g model animal

このコマンドを叩くとテーブルが作成されると言いましたが、テーブルの設計図ができているだけでテーブル自体はまだできていません。テーブルの設計図のことをマイグレーションファイルと言います。

マイグレーションファイル

changeメソッドを使って作成するカラムを指定できます。

カラムの型
integer 数字 idなど
string 少なめの文字 ユーザー名、パスワード
text 多めの文字 投稿文
boolean 真か偽か 真偽フラグ
datetime 日付と時刻 作成日時、更新日時

マイグレーションファイルの設定

2020XXXXXXXXXXXXXXXX_create_XXXX.rb
class CreateXxxxxx < ActiveRecord::Migration[5.2]
  def change
    create_table :xxxxs do |t|
      t.string    :name
      t.text      :text
      t.text      :image
      t.timestamps null: false
    end
  end
end

マイグレーションファイルの実行

rake db:migrate
このコマンドを行うと、ファイルが更新されます。
スキーマファイルには最新のマイグレーションファイルのバージョンが記録される。

schema_migrationsはデータベースの変更履歴のようなもので、どのマイグレーションファイルまでが実行されているかが記録されています。

マイグレーションファイルはschema_migrationsと齟齬が生じる恐れがあるので消してはいけません。
マイグレーションファイルは一度rake db:migrateで実行してしまうと、中身を書き換えて再実行はできません。
rake db:rollbackでデータベースの状態を最新のmigrationファイルを実行する前に戻せます。

Active Record

Active RecordはRubyのGemの一種です。このGemはRailsにデフォルトでインストールされており、このGemのおかげでモデルとテーブルをつなぎ合わせられています。そのことによりRailsからテーブルのレコードにアクセスできます。
Actice Recordを利用するにはApplicationRecordというクラスを継承する必要があります。
ApplicationRecordを継承することでallメソッド、newメソッド、saveメソッド、findメソッドなどが利用できるようになります。

SQL

データベースに保存されているデータをデータベースに要求するときに使う言語です。
RailsではActive Recordのおかげで簡単にデータを要求することができます。

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

Ruby と Python と networkx で解く AtCoder ABC168 C 隣接リスト

はじめに

AtCoder Problems の Recommendation を利用して、過去の問題を解いています。
AtCoder さん、AtCoder Problems さん、ありがとうございます。

今回のお題

AtCoder Beginner Contest D - .. (Double Dots)
Difficulty: 750

今回のテーマ、隣接リスト

隣接リストから幅優先探索をするのですが、部屋1に近い部屋から道しるべを記録し、記録した部屋をスキップすることにより最短経路を取得します。

Ruby

ruby.rb
n, m = gets.split.map(&:to_i)
a = Array.new(n){[]}
m.times do
    x, y = gets.split.map(&:to_i)
    a[x - 1] << y - 1
    a[y - 1] << x - 1
end
c = Array.new(n){0}
que = []
que << 0
while que.size > 0
  e = que.shift
  a[e].each do |i|
    next if c[i] > 0
    c[i] = e + 1
    que << i
  end
end
puts "Yes", c[1..-1]
index.rb
    a[x - 1] << y - 1
    a[y - 1] << x - 1

配列のインデックスが0から始まることに適応させています。

Python

pypy.py
from collections import deque

n, m = map(int, input().split())
a = [[] for _ in range(n)]
for i in range(m):
    x, y = map(int, input().split())
    a[x - 1].append(y - 1)
    a[y - 1].append(x - 1)
c = [0] * n
que = deque([])
que.append(0)
while len(que) > 0:
    e = que.popleft()
    for i in a[e]:
        if c[i] > 0:
            continue
        c[i] = e + 1
        que.append(i)
print("Yes")
for i in range(1, n):
    print(c[i])

Python (networkx)

networkx.py
import networkx

n, m = map(int, input().split())
g = networkx.Graph()
g.add_nodes_from(list(range(n)))
for i in range(1, m + 1):
    a, b = map(int, input().split())
    g.add_edge(a, b)
#print(g.nodes())
#print(g.edges())
print("Yes")
for i in range(2, n + 1):
    print(networkx.shortest_path(g, 1, i)[-2])
shortest_path.py
    print(networkx.shortest_path(g, 1, i)[-2])

networkx.shortest_pathで最短経路が取得できます。幅優先探索なんていりません
幸い、この問題ではTLEになりますが、networkx凄いですね。

Ruby Python PyPy Python (networkx)
コード長 (Byte) 335 459 459 321
実行時間 (ms) 335 696 451 TLE
メモリ (KB) 32748 36920 94388 187248

まとめ

  • ABC 168 D を解いた
  • Ruby に詳しくなった
  • Python に詳しくなった
  • networkx に詳しくなった

参照したサイト
networkx Tutorial
Python3 キュー操作 (collections.deque)
PythonでABC168Dを解く

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

Ruby と Python と networkx で解く AtCoder ABC168 D 隣接リスト

はじめに

AtCoder Problems の Recommendation を利用して、過去の問題を解いています。
AtCoder さん、AtCoder Problems さん、ありがとうございます。

今回のお題

AtCoder Beginner Contest D - .. (Double Dots)
Difficulty: 750

今回のテーマ、隣接リスト

隣接リストから幅優先探索をするのですが、部屋1に近い部屋から道しるべを記録し、記録した部屋をスキップすることにより最短経路を取得します。

Ruby

ruby.rb
n, m = gets.split.map(&:to_i)
a = Array.new(n){[]}
m.times do
    x, y = gets.split.map(&:to_i)
    a[x - 1] << y - 1
    a[y - 1] << x - 1
end
c = Array.new(n){0}
que = []
que << 0
while que.size > 0
  e = que.shift
  a[e].each do |i|
    next if c[i] > 0
    c[i] = e + 1
    que << i
  end
end
puts "Yes", c[1..-1]
index.rb
    a[x - 1] << y - 1
    a[y - 1] << x - 1

配列のインデックスが0から始まることに適応させています。

Python

pypy.py
from collections import deque

n, m = map(int, input().split())
a = [[] for _ in range(n)]
for i in range(m):
    x, y = map(int, input().split())
    a[x - 1].append(y - 1)
    a[y - 1].append(x - 1)
c = [0] * n
que = deque([])
que.append(0)
while len(que) > 0:
    e = que.popleft()
    for i in a[e]:
        if c[i] > 0:
            continue
        c[i] = e + 1
        que.append(i)
print("Yes")
for i in range(1, n):
    print(c[i])

Python (networkx)

networkx.py
import networkx

n, m = map(int, input().split())
g = networkx.Graph()
g.add_nodes_from(list(range(n)))
for i in range(1, m + 1):
    a, b = map(int, input().split())
    g.add_edge(a, b)
#print(g.nodes())
#print(g.edges())
print("Yes")
for i in range(2, n + 1):
    print(networkx.shortest_path(g, 1, i)[-2])
shortest_path.py
    print(networkx.shortest_path(g, 1, i)[-2])

networkx.shortest_pathで最短経路が取得できます。幅優先探索なんていりません
幸い、この問題ではTLEになりますが、networkx凄いですね。

Ruby Python PyPy Python (networkx)
コード長 (Byte) 335 459 459 321
実行時間 (ms) 335 696 451 TLE
メモリ (KB) 32748 36920 94388 187248

まとめ

  • ABC 168 D を解いた
  • Ruby に詳しくなった
  • Python に詳しくなった
  • networkx に詳しくなった

参照したサイト
networkx Tutorial
Python3 キュー操作 (collections.deque)
PythonでABC168Dを解く

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

Deviseで認証メールを手動で送信したい

再送方法

Qiita - deviseの確認メールの実装で困ったとき
RubyDoc - Module: Devise::Models::Confirmable

ほぼここに書いてあるとおりで、Devise参照先も書いてあるとおりなんですがこれです。

User.find(1).send_confirmation_instructions # manually send instructions

この操作をするシチュエーション

  • メーラー側でなんらかの不具合がありメールが送信されなかった
  • Workerが止まってしまいメール送信用のキューをロストした

等が考えられます。
結構運用中に発生しがちで毎回どうやって再送するんだっけ?って調べてたので書きました。

以上です。

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

[Rails5] Rspec -validation編-

はじめに

今回はModelのvalidationを対象にRspecを書きます

・name,email,passwordがあれば有効である事
・name,email,passwordが無ければ無効である事

以上の2点をテストしたいと思います。

1. テスト対象

validates :name,
       presence: true,   
validates :email,
       presence: true,   
validates  :password,
       presence: true,

テスト対象はUser登録時のvalidationを対象にします。
今回はvalidationの有効性のみ検証したいので、上記の様に簡素なコードとします。

2.実装

require 'rails_helper'

Rspec.decribe User, type: model do
  describe '#validates' do
    context '名前、メアド、パスワードが正しければ' do
      it '有効である事'  do
        @user = User.new ({
          name: "テスト太郎",
          email: "xxx@yyy.jp",
          password: "111111",
        })
        expect(@user).to be_valid
      end   
    end

    context '名前、メアド、パスワードが正しくなければ' do
      it 'validateされる事' do
        @user = User.new ({
          name: "",
          email: "",
          password: "",
        })
        expect(@user.valid?).to be_falsy
      end
    end
  end
end

インスタンス変数にそれぞれ正しいオブジェクトと正しくないオブジェクトを代入します。

validationgが有効であるかテストする為にbe_valid(プレディカットマッチャ)を使い、反対に有効では無い時はfalseが返ってくる事を確認する為にbe_falsyを使っています。

*オブジェクトを作る時のnewメソッド直後の波括弧はvalue,括弧はkeyそれぞれに与えてあげないといけない見たいです。個人的にちょっと嵌りました。

3.テスト結果

2 examples, 0 failures

通りましたね。

validation対象のRspecはシンプルな記述ができるので理解し易いと感じました。

最後に

今回はまとめて実装して見ましたが本来各カラム毎にテストを走らせる必要があると思います。

それとコード叩いてて思ったのは自分自身、各括弧 (){}[] をそれぞれ感覚で使っていたので改めて理解する必要があるなと感じました。また記事にしたいと思います。

ps→
日本うなぎの稚魚はオーストラリアから海流に乗ってやってくるらしい。

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

【備忘録】Rails3ルーティング確認

はじめに

今回はタイトルの通りにRailsにおけるルーティングの確認方法を残します。
触れているシステムのバージョンが古いため、Webブラウザでの確認が出来ずに詰まりました・・・。

環境

Rails 3.0.19
docker-compose version 2

Dockerコンテナからコマンドで確認する

1. サービス用コンテナを起動する

docker-compose up -d

-d:デタッチド・モード: バックグラウンドでコンテナを実行し、新しいコンテナ名を表示

2. railsがインストールされているコンテナに入る(今回はappコンテナ)

docker-compose run app /bin/bash

dockerやRailsにバージョンによって、コマンドが変わります。
直近で多く見られるコマンドは以下の通り。

docker-compose exec app bash

3. ルーティング確認コマンドを実行する

[root@[コンテナID] trunk]# bundle exec rake routes

上記コマンドですと全件出力されてしまい見づらいため、grepコマンドを利用すると見やすいです。

[root@[コンテナID] trunk]# bundle exec rake routes | grep [絞り込みたい文字列]

参考

Docker ドキュメント日本語化プロジェクト
docker-composeコマンド

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