勉強メモ

主にプログラミングの勉強メモ

Rails のbundle install で mysql2 のエラーでハマった

Rails で mysql2 をbundle install しようとして躓いたのでメモ。

インストールしようとした mysql2 のバージョンは 0.4.9。

エラー内容

Installing mysql2 0.4.9 with native extensions
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

...
中略
...

-----
Setting rpath to /usr/local/Cellar/mysql/8.0.12/lib
-----
creating Makefile

current directory:
/Users/macbookpromid2010/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/mysql2-0.4.9/ext/mysql2
make "DESTDIR=" clean

current directory:
/Users/macbookpromid2010/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/mysql2-0.4.9/ext/mysql2
make "DESTDIR="
compiling client.c
client.c:886:10: error: use of undeclared identifier 'MYSQL_SECURE_AUTH'; did you mean
'MYSQL_DEFAULT_AUTH'?
    case MYSQL_SECURE_AUTH:
         ^~~~~~~~~~~~~~~~~
         MYSQL_DEFAULT_AUTH
/usr/local/Cellar/mysql/8.0.12/include/mysql/mysql.h:188:3: note: 'MYSQL_DEFAULT_AUTH' declared here
  MYSQL_DEFAULT_AUTH,
  ^
client.c:1315:38: error: use of undeclared identifier 'MYSQL_SECURE_AUTH'; did you mean
'MYSQL_DEFAULT_AUTH'?
  return _mysql_client_options(self, MYSQL_SECURE_AUTH, value);
                                     ^~~~~~~~~~~~~~~~~
                                     MYSQL_DEFAULT_AUTH
/usr/local/Cellar/mysql/8.0.12/include/mysql/mysql.h:188:3: note: 'MYSQL_DEFAULT_AUTH' declared here
  MYSQL_DEFAULT_AUTH,
  ^
2 errors generated.
make: *** [client.o] Error 1

make failed, exit code 2

...
中略
...

An error occurred while installing mysql2 (0.4.9), and Bundler cannot continue.
Make sure that `gem install mysql2 -v '0.4.9' --source 'https://rubygems.org/'` succeeds before
bundling.

In Gemfile:
  mysql2

解決方法

mysql2 0.4.9 に対応している mysql のバージョンは 5.x.x だったので、 mysql@5.7 をインストールして bundle install すればよかった。 のだが、brew link しないといけないのがわからずハマった。

brew uninstall mysql
brew install mysql@5.7
brew link mysql@5.7 --force #これが必要

keg-only なパッケージをインストールする場合は、brew install しても、/usr/local/bin 等にシンボリックリンクが作られない。 このため brew link してリンクを作る必要があるらしい。

Homebrew についても勉強する必要を感じた。 こちらの記事が参考になりそうだ。

qiita.com

プロを目指す人のためのRuby入門 第二章 メモ

初めて知ったことをメモ。

数値

  • 数値にアンダーバーを入れて書ける。桁数が多い数値を記述する場合にカンマ替わりにして見やすくするなどの用途がある。
a = 1_000_000 #=> 1000000
  • 少数の計算を行う場合は、Rational 型を使用すると、誤差を防げる。

文字列

  • ヒアドキュメントの <<識別子 は、式としてみなせる。文字列メソッドを適用したり、文字列を引数にとる関数に渡したりできる。

  • 「文字」と「文字列」の違いはない。

  • 以下のような表記で、一文字だけの文字列を生成できる。

真偽値、条件分岐

  • if 文は最後に評価された式を戻り値として返す。この性質を利用して次のように変数に代入も可能。
b = 1
a =
if b == 1
  "aは1だよ"
else
  "aは1じゃないよ"
end
puts a #=> "aは1だよ"
  • 論理演算子の評価の優先順位は以下。
1. !
2. &&
3. ||
4. not
5. or, and
  • 優先順位の違いにより、等価に見える式も返す値が異なることがある。
t = true
f = false

# (!t) || f  と同じ
!t or f #=> false

# not (t || f ) と同じ
not t || f  #=> true  
  • 論理演算子を使った式の戻り値は、式全体の真偽値が確定した時点での、最後に評価した式の戻り値を返す。 trueやfalse を返すとは限らない。
1 && 2 && 3 #=> 3
1 && nil && 3 #=> nil

t1, t2 = true
f = false
# or と and は優先順が同じため先頭から評価される
t1 or t2 and false #=>false
  • and , or は制御フローを書くのに向いている。
# ユーザーが有効なら何か処理
# && を使って書くと mail_to(user) とする必要がある。
user.valid? and mail_to user

# a が真でなければ 文字列を返して関数を抜ける
def func(a,b)
  a or return "Invalid arg"
  # a について処理...
  ...
end

メソッド

  • デフォルト引数には関数の戻り値など、動的な値を指定することもできる。
def hoge(a = Time.now)
  "Input time : #{a}"
end

puts hoge #=>Input time : 2018-10-11 23:41:51
  • ! で終わるメソッドは、使用に注意が必要なメソッド。どんな注意が必要になるかは、明確な定義はない。 必ずしも破壊的メソッドだけに付くわけではない。

その他

  • Ruby の変数はオブジェクト参照を格納している。どのオブジェクトを指しているかは object_id メソッドで確認できる。

  • requireruby を実行したディレクトリを基準としてファイルを読みこむ。 require_relative は そのファイルを起点とした相対パスでファイルを読み込む。

  • puts, print, p メソッドは微妙に異なる。基本的には puts, print は一般ユーザー向けの、p は開発者向けの用途で用いる。

  • puts, print メソッドは内部的に to_s メソッドを呼び出して値を出力する。 p メソッドは inspect メソッドを内部的に呼び出している。

Rails で bundle install するときは --path を指定するといい

bundle install で gem をインストールするときは --path でインストールディレクトリを指定するのがいい。 --path なしの場合はシステムに gem がインストールされるが、 --path でディレクトリを指定することでアプリケーションごとに gem を設定できる。 vendor ディレクトリの下にインストールしてやるといい感じ。

bundle install --path vendor/bundle

なお、このオプションを実行するのは初めて bunel install を実行するときだけでいい。 このオプションを実行すると、インストールに関するオプションは .bundle/config ファイルに以下のように設定される。

BUNDLE_PATH: vendor/bundle
BUNDLE_DISABLE_SHARED_GEMS: '1'

参考ページ railsでbundle installする時にインストールパスを指定

Ruby ハッシュの主なメソッド

ハッシュに関するメソッドのメモ。

初期化

{key => val}, {symbol : val}

基本的な指定の仕方。

h1 = {"a" => "b"}
h2 = {a: "b"}

h.new, h.new(val)

新しくハッシュを作る。 引数を指定すると、登録されていないキーを指定した場合に返す値を設定できる。

値を取り出す

h.fetch(key), h.fetch(key, default)

key を探し、見つかればkeyに対応する値を返す。 見つからない場合、引数が一つならエラー、引数が二つならdefaultの値を返す。

each_keys{ |key| ... }

key を順に取り出し、ブロックを実行する。

each_value{ |value| ... },

値を順に取り出してブロックを実行する。

each{ |key, value| ... }, each{|配列| ... }

key, value 同時取り出し。配列として取り出すこともできる。

key, value を持つか調べる

h.key?(key), h.has_key?(key), h.include?(key), h.member?(key)

key を持つか調べる。どれも同じ。

h.value?(value), h.has_value?(value)

value を持つか調べる。どちらも同じ。

h.empty?

ハッシュが空なら true を返す。

要素の削除

h.delete(key), h.delete(key){ |key| ... }

キーを指定して要素を削除する。 ブロックを引数に取る場合は、キーが存在しなかった場合、ブロックの実行結果を返す。 ¯

h.delete_if{ |key, val| ... }, h.reject!{ |key, val| ... }

各キーと値についてブロックを実行し、ブロックで指定した条件が true なら要素を削除する。 reject! では、条件に当てはまるものがなければ nil を返す。

h.clear

ハッシュを空にする。コピーを作らず、一度使ったハッシュを空にして再利用するときに使う。

Ruby 文字列の主なメソッド

文字列に関するメソッドのメモ。

生成

ダブルクォート、シングルクォートで囲んで生成する方法以外にもいろいろある。

%Q %q

ダブルクォートなどを含んだ文字列を簡単に作れる

str1 = %Q|aaa bbb "ccc" 'ddd'|
str2 = %q{あああ bbb ccc}
p str1 #> "aaa bbb \"ccc\" 'ddd'"
p str2 #> "あああ bbb ccc"

ヒアドキュメント

# 変数に代入
str =<<- "EOF"
aaa
bbb
ccc
EOF

10.times do |i|
print(<<-"EOF") # シングルクォートで囲むと i は展開されない
i: #{i}
EOF
end

sprintf, format

成形した文字列を返す。 フォーマット指定方法は以下を参照。 https://docs.ruby-lang.org/ja/latest/doc/print_format.html

文字列の長さ

length, size

文字数を返す。日本語の場合も文字数を返す。

bytesize

バイト数を返す。

文字列をつなげる

a + b

文字列a,b をつなげて、新しい文字列を作る

a.concat(b), a << b

文字列a にbをつなげる。破壊的メソッド。 + を使うより効率がいいので、理由がなければこちらを使うのがよい。

文字列を分割する

a.split(pattern, limit)

文字列または正規表現で分割する。

a = "hoge bbb ccc,aaaa.ddd"
p a.split() #>["hoge", "bbb", "ccc,aaaa.ddd"]
p a.split(' ', 2)
p a.split(/a+/) #>["hoge bbb ccc,", ".ddd"]

chop, chomp

chop は文字列の末尾を削る。 chomp は改行文字の場合のみ削る。

# ファイルから一行ずつ読み込むときによく使う。
f.each_line do |line|
  line.chomp!
  # 何か処理
end

検索と置換

a.index(str), a.rindex(str)

文字列が存在する場合は、そのインデックスを返す。

a.include?(str)

a に str が含まれる場合は true を返す。 インデックスが不要ならこちらを使う。

a.sub(pattern, str), a.gsub(pattern, str)

文字列a で pattern マッチした個所をstr で置き換える。 sub は一か所だけ置き換え、 gsub はマッチした個所すべてを置き換える。どちらもブロックを引数にとり、マッチした個所に処理を加えて返すことができる。

str = "abcdefgabc"
nstr = str.sub(/.a/) do |matched|
  '<' + matched.upcase + '>'
end
p nestr #=>"abcdef<GA>bc"

a.scan(pattern)

pattern にマッチした個所を返す。

str = "akasatanahamararawa"
p str.scan(/.a/) #=>["ka", "sa", "ta", "na", "ha", "ma", "ra", "ra", "wa"]

# 正規表現キャプチャとの組み合わせ
p str.scan(/(.)(a)(/) #=>[["k", "a"], ["s", "a"], ["t", "a"], ["n", "a"], ["h", "a"], ["m", "a"], ["r", "a"], ["r", "a"], ["w", "a"]]

Ruby 配列の主なメソッド

よく使いそうなものをまとめておく。 実行環境 ruby 2.3.7

要素を加える

unshift(item)

先頭に新しい要素を付け加える

a << item, a.push(item)

配列の末尾に要素を付け加える。

a.concat(b), a+b

配列 a に 配列 b を付け加える。 concat は破壊的メソッド、 a+b は新しい配列を作る。

a = [1,2,3,4]
a.concat([5,6])
p a #=> [1,2,3,4,5,6]

a[n] = item, a[n..m] = item, a[n, len] = item

配列の指定した要素を item に置き換える

a = [1,2,3,4,5,6]
a[2..4] = 0
p a #=> [1, 2, 0, 6]
a[1, 3] = 9
p a #=> [1, 9]

a.compact, a.compact!

配列から要素が nil の物を取り除く。

a.delete(x)

配列から要素 x を取り除く。xが存在しない場合は nil を返す。

a.delete_if{|item| ...}, a.reject {|item| ... } a.reject! {|item| ... }

配列a の各要素について、ブロックを実行した結果が真だった場合、a から item を取り除く。 delete_if と rejecr! は破壊的メソッド。

a = [1,2,3,4,6,8,9]
a.reject! {|item| item % 2 == 0 }
p a #> [1,3,9]

a.slice!(n), a.slilce!(n..m), a.slice!(n, len)

a から指定された部分を取り除き、取り除いた値を返す。

a = [1,2,3,4]
p a.slice!(0..2) #> [1,2,3]
p a #> [4]

a.uniq, q,uniq!

a の重複する要素を削除する。

a.shift, a.pop

それぞれ a の先頭、末尾を取り除き、取り除いた値を返す。

要素を書き換える

a.collect {|item| ... }, a.map {|item| ... }

配列の各要素についてブロックを実行し、その結果を集めて新しい配列を作る。! をつけた破壊的メソッドもある。

a = [1,2,3,4]
p a.map{|item| item*2} #> [2,4,6,8]

a.fill(value), a.fill(value, begin), a.fill(value, begin, len), a.fill(value, n..m)

配列の要素をvalue に置き換える。 引数が一つの場合は全てvalueに置き換える。 引数が二つの場合は、beginから配列の末尾まで、引数が三つの場合はbeginからlen個までをvalueにする。 二つ目の引数に range を指定した場合は、その範囲をvalue にする。

a.flatten

配列の中に配列が入れ子になっている場合、全て展開して一つの配列にまとめる。(平坦化)

a.reverse

a の要素を逆順にする。

a.sort, a.sort{|i,j| ...}

a の各要素を並べ替える。並べ替え方はブロックで指定可能。ブロック指定がない場合は <=> 演算子で比較する。 ! を使った破壊的メソッドもある。

a.sort_by {|i| ... }

a を並べ替える。結果は全ての要素についてブロックの結果を評価した結果で行われる。

a = [2,4,1,3,6,0]
p a.sort_by{|i| -i } #> [6, 4, 3, 2, 1, 0]
p a.sort_by{|i| i } #> [0, 1, 2, 3, 4, 6]  大小比較して結果が小さい順になる

その他

a.each { |item| ... }, a.each_with_index {|item, index| ... }

配列の各要素についてブロックを実行する。インデックスも使用するときは each_with_indexで。

a.zip(b, c,,,) {|item_b, item_c, ... | ... }

配列a,b,c... の要素を一つづつ取り出し、その度にブロックを実行する。

エラー解決メモ ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR: relation テーブル名 does not exist

実行環境

開発環境の場合 db:reset 実行後 db:migrate しようとしたら発生した。 以下のコマンドで解決。

bin/rails db:environment:set RAILS_ENV=development
rails db:schema:load
rails db:migrate

heroku 本番環境の場合 heroku にデプロイ時にも発生した。 解決方法は開発環境とほぼ同じだが、heroku に環境変数を指定する必要がある。

heroku run bin/rails db:environment:set RAILS_ENV=production
heroku config:set DISABLE_DATABASE_ENVIRONMENT_CHECK=1
eroku run rake db:schema:load RAILS_ENV=production
heroku run rails db:migrate
  • 参考

Rails 5に入ったDB破壊系taskの防止処理について | 日々雑記