20191024のRubyに関する記事は11件です。

【Rails】mysqlオプションを付けた新たなアプリケーション作成時のエラー対処(Mac)

//////////////////////////////////////////

MacOS Mojave ver.10.14.6
Ruby 2.5.3p105
Rails 6.0.0

//////////////////////////////////////////

はじめに

railsプロジェクト作成の際に、
railsインストールしてrails newをしたところエラーが発生しました。
苦戦したため、備忘のため記録残します。
※悪戦苦闘しながら急ぎ作成したため少し伝わりにくいところもあるかと思います。
時間のあるときに修正を加えていきたいと思います。

対処方法(要約)

今回の経験とネット情報をまとめますと、以下の対処が良いかと思います。
試してみてください。

・権限付加を問われたら

$ sudo chown -R [ユーザ名]:staff /Users/[ユーザ名]/.rbenv

・ERROR: Error installing mysql2 みたいなのが出たら

$  bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl/lib --with-cppflags=-I/usr/local/opt/openssl/include"

※それでもダメなら、再インストール

起こったこと(長いです)

「blog」という名前のファイルをmysqlオプション付きで作成するため、以下のコマンドを実行

$ rails _6.0.0_ new blog -d mysql

すると、以下のような表示がされました

      create  
      create  README.md
      create  Rakefile
      create  .ruby-version
      create  config.ru
      create  .gitignore
      create  Gemfile
         run  git init from "."
Initialized empty Git repository in /Users/xxx/projects/blog/.git/
      create  package.json
      create  app
      create  app/assets/config/manifest.js
      create  app/assets/stylesheets/application.css
      create  app/channels/application_cable/channel.rb
      create  app/channels/application_cable/connection.rb
      create  app/controllers/application_controller.rb
      create  app/helpers/application_helper.rb
      create  app/javascript/channels/consumer.js
      create  app/javascript/channels/index.js
      create  app/javascript/packs/application.js
      create  app/jobs/application_job.rb
      create  app/mailers/application_mailer.rb
      create  app/models/application_record.rb
      create  app/views/layouts/application.html.erb
      create  app/views/layouts/mailer.html.erb
      create  app/views/layouts/mailer.text.erb
      create  app/assets/images/.keep
      create  app/controllers/concerns/.keep
      create  app/models/concerns/.keep
      create  bin
      create  bin/rails
      create  bin/rake
      create  bin/setup
      create  bin/yarn
      create  config
      create  config/routes.rb
      create  config/application.rb
      create  config/environment.rb
      create  config/cable.yml
      create  config/puma.rb
      create  config/spring.rb
      create  config/storage.yml
      create  config/environments
      create  config/environments/development.rb
      create  config/environments/production.rb
      create  config/environments/test.rb
      create  config/initializers
      create  config/initializers/application_controller_renderer.rb
      create  config/initializers/assets.rb
      create  config/initializers/backtrace_silencers.rb
      create  config/initializers/content_security_policy.rb
      create  config/initializers/cookies_serializer.rb
      create  config/initializers/cors.rb
      create  config/initializers/filter_parameter_logging.rb
      create  config/initializers/inflections.rb
      create  config/initializers/mime_types.rb
      create  config/initializers/new_framework_defaults_6_0.rb
      create  config/initializers/wrap_parameters.rb
      create  config/locales
      create  config/locales/en.yml
      create  config/master.key
      append  .gitignore
      create  config/boot.rb
      create  config/database.yml
      create  db
      create  db/seeds.rb
      create  lib
      create  lib/tasks
      create  lib/tasks/.keep
      create  lib/assets
      create  lib/assets/.keep
      create  log
      create  log/.keep
      create  public
      create  public/404.html
      create  public/422.html
      create  public/500.html
      create  public/apple-touch-icon-precomposed.png
      create  public/apple-touch-icon.png
      create  public/favicon.ico
      create  public/robots.txt
      create  tmp
      create  tmp/.keep
      create  tmp/cache
      create  tmp/cache/assets
      create  vendor
      create  vendor/.keep
      create  test/fixtures
      create  test/fixtures/.keep
      create  test/fixtures/files
      create  test/fixtures/files/.keep
      create  test/controllers
      create  test/controllers/.keep
      create  test/mailers
      create  test/mailers/.keep
      create  test/models
      create  test/models/.keep
      create  test/helpers
      create  test/helpers/.keep
      create  test/integration
      create  test/integration/.keep
      create  test/channels/application_cable/connection_test.rb
      create  test/test_helper.rb
      create  test/system
      create  test/system/.keep
      create  test/application_system_test_case.rb
      create  storage
      create  storage/.keep
      create  tmp/storage
      create  tmp/storage/.keep
      remove  config/initializers/cors.rb
      remove  config/initializers/new_framework_defaults_6_0.rb
         run  bundle install
The dependency tzinfo-data (>= 0) will be unused by any of the platforms Bundler is installing for. Bundler is installing for ruby but the dependency is only for x86-mingw32, x86-mswin32, x64-mingw32, java. To add those platforms to the bundle, run `bundle lock --add-platform x86-mingw32 x86-mswin32 x64-mingw32 java`.
Fetching gem metadata from https://rubygems.org/............
Fetching gem metadata from https://rubygems.org/.
Resolving dependencies...
Using rake 13.0.0
Using concurrent-ruby 1.1.5
Using i18n 1.7.0
Using minitest 5.12.2
Using thread_safe 0.3.6
Using tzinfo 1.2.5
Using zeitwerk 2.2.0
Using activesupport 6.0.0
Using builder 3.2.3
Using erubi 1.9.0
Using mini_portile2 2.4.0
Using nokogiri 1.10.4
Using rails-dom-testing 2.0.3
Using crass 1.0.5
Using loofah 2.3.1
Using rails-html-sanitizer 1.3.0
Using actionview 6.0.0
Using rack 2.0.7
Using rack-test 1.1.0
Using actionpack 6.0.0
Using nio4r 2.5.2
Using websocket-extensions 0.1.4
Using websocket-driver 0.7.1
Using actioncable 6.0.0
Using globalid 0.4.2
Using activejob 6.0.0
Using activemodel 6.0.0
Using activerecord 6.0.0
Using mimemagic 0.3.3
Using marcel 0.3.3
Using activestorage 6.0.0
Using mini_mime 1.0.2
Using mail 2.7.1
Using actionmailbox 6.0.0
Using actionmailer 6.0.0
Using actiontext 6.0.0
Using public_suffix 4.0.1
Using addressable 2.7.0
Fetching bindex 0.8.1
Installing bindex 0.8.1 with native extensions
Errno::EACCES: Permission denied @ dir_s_mkdir -
/Users/xxx/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/extensions/x86_64-darwin-18/2.5.0-static/bindex-0.8.1
An error occurred while installing bindex (0.8.1), and Bundler
cannot continue.
Make sure that `gem install bindex -v '0.8.1' --source 'https://rubygems.org/'`
succeeds before bundling.

In Gemfile:
  web-console was resolved to 4.0.1, which depends on
    bindex
         run  bundle binstubs bundler
Could not find gem 'mysql2 (>= 0.4.4)' in any of the gem sources listed in your
Gemfile.
         run  bundle exec spring binstub --all
bundler: command not found: spring
Install missing gem executables with `bundle install`
       rails  webpacker:install
Could not find gem 'mysql2 (>= 0.4.4)' in any of the gem sources listed in your Gemfile.
Run `bundle install` to install missing gems.

エラー部分から和訳すると

ネイティブ拡張を使用したbindex 0.8.1のインストール
Errno :: EACCES:許可が拒否されました

bindex(0.8.1)およびBundlerのインストール中にエラーが発生したため続行できません。

bundle installする前に`gem install bindex -v '0.8.1' --source 'https://rubygems.org/'`がうまくいくか確認してください。

Gemfile:
web-consoleは4.0.1に解決されました。

bindex
bundlerで一連のGemのBinstubのインストールを実行します。
Gemfileにリストされているgemソースのいずれにもgem 'mysql2(> = 0.4.4)'が見つかりませんでした。

bundle exec spring binstub --allを実行します
Bundler:springのコマンドが見つかりません

`bundle install`で見つからないgem実行可能ファイルをインストールします
rails webpacker:install
Gemfileにリストされているgemソースのいずれにもgem 'mysql2(> = 0.4.4)'が見つかりませんでした。

`bundle install`を実行して、欠落しているgemをインストールします。

と言った感じです。
※間違ってたらご指摘ください。

まずは、最初の指示通り

$  gem install bindex -v '0.8.1'

を実施。
すると、

Building native extensions. This could take a while...
ERROR:  While executing gem ... (Errno::EACCES)
    Permission denied @ dir_s_mkdir - /Users/xxx/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/extensions/x86_64-darwin-18/2.5.0-static/bindex-0.8.1

まさかのエラー。。。
和訳すると

ネイティブ拡張の構築。 これにはしばらく時間がかかる可能性があります...
エラー:gemの実行中...(Errno :: EACCES)
     許可が拒否されました@ dir_s_mkdir-/Users/xxx/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/extensions/x86_64-darwin-18/2.5.0-static/bindex-0.8.1v

なぜ、許可されない。。。
権限の問題か?
ということで、root権限でコマンドを実行することに

$  sudo gem install bindex -v '0.8.1'

すると
「Password:」とパスワードを要求されるので」、
自分のパソコンのパスワードを入力

すると

Building native extensions. This could take a while...
Successfully installed bindex-0.8.1
Parsing documentation for bindex-0.8.1
Installing ri documentation for bindex-0.8.1
Done installing documentation for bindex after 0 seconds
1 gem installed

が表示!!
お、お?! 激しく動揺

手が震えてタイピングが、、、
Google先生、和訳をお願いします!!

command + C
command + V

ネイティブ拡張の構築。 これにはしばらく時間がかかる可能性があります...
bindex-0.8.1が正常にインストールされました
bindex-0.8.1の解析ドキュメント
bindex-0.8.1のRIドキュメントのインストール
0秒後にbindexのドキュメントのインストールを完了しました
1つのgemがインストールされました

インストール成功!!

さっそく、確認!!

$ cd blog  (blogはファイル名です)
$ bundle install

どうだ!

Fetching msgpack 1.3.1
Installing msgpack 1.3.1 with native extensions
Errno::EACCES: Permission denied @ dir_s_mkdir -
/Users/xxx/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/extensions/x86_64-darwin-18/2.5.0-static/msgpack-1.3.1
An error occurred while installing msgpack (1.3.1), and Bundler
cannot continue.
Make sure that `gem install msgpack -v '1.3.1' --source 'https://rubygems.org/'`
succeeds before bundling.

In Gemfile:
  bootsnap was resolved to 1.4.5, which depends on
    msgpack

なんと、別のエラー。。。

が、しかし
指示通り実行するだけだ!

$  sudo gem install msgpack -v '1.3.1'

※またしても許可されなかったため、root権限で実行してます

Building native extensions. This could take a while...
Successfully installed msgpack-1.3.1
Parsing documentation for msgpack-1.3.1
Installing ri documentation for msgpack-1.3.1
Done installing documentation for msgpack after 0 seconds
1 gem installed

OK!
さっそく、確認!!

$ bundle install
Fetching bootsnap 1.4.5
Installing bootsnap 1.4.5 with native extensions
Errno::EACCES: Permission denied @ dir_s_mkdir -
/Users/xxx/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/extensions/x86_64-darwin-18/2.5.0-static/bootsnap-1.4.5
An error occurred while installing bootsnap (1.4.5), and Bundler
cannot continue.
Make sure that `gem install bootsnap -v '1.4.5' --source
'https://rubygems.org/'` succeeds before bundling.

In Gemfile:
  bootsnap

はい次!

$ sudo gem install bootsnap -v '1.4.5'
Building native extensions. This could take a while...
Successfully installed bootsnap-1.4.5
Parsing documentation for bootsnap-1.4.5
Installing ri documentation for bootsnap-1.4.5
Done installing documentation for bootsnap after 0 seconds
1 gem installed

はい確認!!

$ bundle install
Fetching byebug 11.0.1
Installing byebug 11.0.1 with native extensions
Errno::EACCES: Permission denied @ dir_s_mkdir -
/Users/xxx/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/extensions/x86_64-darwin-18/2.5.0-static/byebug-11.0.1
An error occurred while installing byebug (11.0.1), and Bundler
cannot continue.
Make sure that `gem install byebug -v '11.0.1' --source 'https://rubygems.org/'`
succeeds before bundling.

In Gemfile:
  byebug

はい次!

$ sudo gem install byebug -v '11.0.1'
Building native extensions. This could take a while...
Successfully installed byebug-11.0.1
Parsing documentation for byebug-11.0.1
Installing ri documentation for byebug-11.0.1
Done installing documentation for byebug after 12 seconds
1 gem installed

はい確認!!

$ bundle install
Fetching ffi 1.11.1
Installing ffi 1.11.1 with native extensions
Errno::EACCES: Permission denied @ dir_s_mkdir -
/Users/xxx/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/extensions/x86_64-darwin-18/2.5.0-static/ffi-1.11.1
An error occurred while installing ffi (1.11.1), and Bundler cannot
continue.
Make sure that `gem install ffi -v '1.11.1' --source 'https://rubygems.org/'`
succeeds before bundling.

In Gemfile:
  spring-watcher-listen was resolved to 2.0.1, which depends on
    listen was resolved to 3.1.5, which depends on
      rb-inotify was resolved to 0.10.0, which depends on
        ffi

はい次!

$ sudo gem install ffi -v '1.11.1'
Building native extensions. This could take a while...
Successfully installed ffi-1.11.1
Parsing documentation for ffi-1.11.1
Installing ri documentation for ffi-1.11.1
Done installing documentation for ffi after 19 seconds
1 gem installed

はい確認!!

$ bundle install
Fetching mysql2 0.5.2
Installing mysql2 0.5.2 with native extensions
Errno::EACCES: Permission denied @ dir_s_mkdir -
/Users/xxx/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/extensions/x86_64-darwin-18/2.5.0-static/mysql2-0.5.2
An error occurred while installing mysql2 (0.5.2), and Bundler
cannot continue.
Make sure that `gem install mysql2 -v '0.5.2' --source 'https://rubygems.org/'`
succeeds before bundling.

In Gemfile:
  mysql2

はい次!

$ sudo gem install mysql2 -v '0.5.2'
Building native extensions. This could take a while...
ERROR:  Error installing mysql2:
    ERROR: Failed to build gem native extension.

    current directory: /Users/xxx/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/mysql2-0.5.2/ext/mysql2
/Users/xxx/.rbenv/versions/2.5.3/bin/ruby -I /Users/xxx/.rbenv/versions/2.5.3/lib/ruby/site_ruby/2.5.0 -r ./siteconf20191024-7974-ialg44.rb extconf.rb
checking for rb_absint_size()... yes
checking for rb_absint_singlebit_p()... yes
checking for rb_wait_for_single_fd()... yes
-----
Using mysql_config at /usr/local/opt/mysql@5.6/bin/mysql_config
-----
checking for mysql.h... yes
checking for errmsg.h... yes
checking for SSL_MODE_DISABLED in mysql.h... no
checking for MYSQL_OPT_SSL_ENFORCE in mysql.h... no
checking for MYSQL.net.vio in mysql.h... yes
checking for MYSQL.net.pvio in mysql.h... no
checking for MYSQL_ENABLE_CLEARTEXT_PLUGIN in mysql.h... yes
checking for SERVER_QUERY_NO_GOOD_INDEX_USED in mysql.h... yes
checking for SERVER_QUERY_NO_INDEX_USED in mysql.h... yes
checking for SERVER_QUERY_WAS_SLOW in mysql.h... yes
checking for MYSQL_OPTION_MULTI_STATEMENTS_ON in mysql.h... yes
checking for MYSQL_OPTION_MULTI_STATEMENTS_OFF in mysql.h... yes
checking for my_bool in mysql.h... yes
-----
Don't know how to set rpath on your system, if MySQL libraries are not in path mysql2 may not load
-----
-----
Setting libpath to /usr/local/opt/mysql@5.6/lib
-----
creating Makefile

current directory: /Users/xxx/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/mysql2-0.5.2/ext/mysql2
make "DESTDIR=" clean

current directory: /Users/xxx/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/mysql2-0.5.2/ext/mysql2
make "DESTDIR="
compiling client.c
compiling infile.c
compiling mysql2_ext.c
compiling result.c
compiling statement.c
linking shared-object mysql2/mysql2.bundle
ld: library not found for -lssl
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [mysql2.bundle] Error 1

make failed, exit code 2

Gem files will remain installed in /Users/xxx/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/mysql2-0.5.2 for inspection.
Results logged to /Users/xxx/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/extensions/x86_64-darwin-18/2.5.0-static/mysql2-0.5.2/gem_make.out

またエラー;
ひとまず順に和訳する。

ネイティブ拡張の構築。 これにはしばらく時間がかかる可能性があります...
エラー:mysql2のインストールエラー:
     エラー:gemネイティブ拡張のビルドに失敗しました。
~
-----
/usr/local/opt/mysql@5.6/bin/mysql_configでmysql_configを使用する
-----
~
-----
MySQLライブラリがパスされずmysql2がロードされませんない場合、システムにrpathを設定する方法がわからない
-----
-----
libpathを/usr/local/opt/mysql@5.6/libに設定する
-----
Makefileの作成

現在のディレクトリ:/Users/xxx/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/mysql2-0.5.2/ext/mysql2
「DESTDIR =」をクリーンにする

~

clang:エラー:リンカコマンドが終了コード1で失敗しました(呼び出しを確認するには-vを使用してください)

make:*** [mysql2.bundle]エラー1

失敗、終了コード2

Gemファイルは、検査のために
/Users/xxx/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/mysql2-0.5.2
にインストールされたままになります。

結果のログ
/Users/xxx/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/extensions/x86_64-darwin-18/2.5.0-static/mysql2-0.5.2/gem_make.out

とりあえずわかるのは
mysql2で何かしらのエラー

これ、StackOverFlowにて対策が投稿されていたので、参照してみる
https://stackoverflow.com/questions/30834421/error-when-trying-to-install-app-with-mysql2-gem

For anybody still experiencing the issue:

When you install openssl via brew, you should get the following message:

Apple has deprecated use of OpenSSL in favor of its own TLS and crypto libraries

Generally there are no consequences of this for you. If you build your own software and it requires this formula, you'll need to add to your build variables:

LDFLAGS: -L/usr/local/opt/openssl/lib
CPPFLAGS: -I/usr/local/opt/openssl/include
PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig

You can set these build flags (for the local application) by running the following:



bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl/lib --with-cppflags=-I/usr/local/opt/openssl/include"

和訳すると

まだ問題が発生している場合:

brew経由でopensslをインストールすると、次のメッセージが表示されます。

Appleは、独自のTLSおよび暗号ライブラリを支持して、OpenSSLの使用を廃止しました

通常、これによる影響はありません。 
独自のソフトウェアをビルドし、この式が必要な場合は、ビルド変数に追加する必要があります。

LDFLAGS:-L / usr / local / opt / openssl / lib
CPPFLAGS:-I / usr / local / opt / openssl / include
PKG_CONFIG_PATH:/ usr / local / opt / openssl / lib / pkgconfig

以下を実行して、これらのビルドフラグを設定できます(ローカルアプリケーション用)。

bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl/lib --with-cppflags=-I/usr/local/opt/openssl/include"

ということで、以下を実行!!

$  bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl/lib --with-cppflags=-I/usr/local/opt/openssl/include"
You are replacing the current local value of build.mysql2, which is currently nil

和訳する!

現在nilであるbuild.mysql2の現在のローカル値を置き換えています

何か実行はされたみたい!
いけたのか?

さっそく確認!!

$ bundle install
Fetching mysql2 0.5.2
Installing mysql2 0.5.2 with native extensions
Errno::EACCES: Permission denied @ dir_s_mkdir -
/Users/xxx/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/extensions/x86_64-darwin-18/2.5.0-static/mysql2-0.5.2
An error occurred while installing mysql2 (0.5.2), and Bundler
cannot continue.
Make sure that `gem install mysql2 -v '0.5.2' --source 'https://rubygems.org/'`
succeeds before bundling.

In Gemfile:
  mysql2

同じエラー!!
変わってないやん!!

本来はこの辺りでうまくいくらしいが、どうやら最新のVerはそんな生ぬるくないらしい、、、

もうこうなったら
アンインストールして、再インストールしかない!!
※手順はこちらを参照させていただきました
https://qiita.com/akiko-pusu/items/aef52b723da2cb5dc596

そして再インストールを実行!

Fetching mysql2 0.5.2
Installing mysql2 0.5.2 with native extensions
Errno::EACCES: Permission denied @ rb_sysopen -
/Users/maedamasaki/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/mysql2-0.5.2/CHANGELOG.md
An error occurred while installing mysql2 (0.5.2), and Bundler
cannot continue.
Make sure that `gem install mysql2 -v '0.5.2' --source
'https://rubygems.org/'` succeeds before bundling.

In Gemfile:
  mysql2

変わらず!!
でも、ここで指摘されているのは結局権限!!

こちらのサイト (http://infinity108.com/114/) を参照させていただくと
どうやら

$ sudo gem install

に問題があるみたい。
そこで、今度は以下の方法で権限を付加します。

$ sudo chown -R [ユーザ名]:staff /Users/[ユーザ名]/.rbenv

↓↓↓

$  sudo chown -R xxx ~/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/gems/mysql2-0.5.2

$  sudo chown -R xxx ~/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/extensions/x86_64-darwin-18/2.5.0-static/mysql2-0.5.2

そして確認!!

$ bundle install
Fetching mysql2 0.5.2
Installing mysql2 0.5.2 with native extensions
Fetching puma 3.12.1
Installing puma 3.12.1 with native extensions
Errno::EACCES: Permission denied @ dir_s_mkdir - /Users/xxx/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/extensions/x86_64-darwin-18/2.5.0-static/puma-3.12.1
An error occurred while installing puma (3.12.1), and Bundler cannot continue.
Make sure that `gem install puma -v '3.12.1' --source 'https://rubygems.org/'` succeeds before bundling.

In Gemfile:
  puma

おー、違うエラーが!!

$ sudo chown -R xxx ~/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/extensions/x86_64-darwin-18/2.5.0-static/puma-3.12.1
chown: /Users/xxx/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/extensions/x86_64-darwin-18/2.5.0-static/puma-3.12.1: No such file or directory

と出たので、以下でチャレンジ!

$ sudo chown -R xxx ~/.rbenv/versions/2.5.3/lib/ruby/gems/2.5.0/extensions/x86_64-darwin-18/2.5.0-static

よし!
さっそく確認!

$ bundle install
The dependency tzinfo-data (>= 0) will be unused by any of the platforms Bundler is installing for. Bundler is installing for ruby but the dependency is only for x86-mingw32, x86-mswin32, x64-mingw32, java. To add those platforms to the bundle, run `bundle lock --add-platform x86-mingw32 x86-mswin32 x64-mingw32 java`.
Fetching gem metadata from https://rubygems.org/............
Fetching gem metadata from https://rubygems.org/.
Resolving dependencies...
Using rake 13.0.0
Using concurrent-ruby 1.1.5
Using i18n 1.7.0
Using minitest 5.12.2
Using thread_safe 0.3.6
Using tzinfo 1.2.5
Using zeitwerk 2.2.0
Using activesupport 6.0.0
Using builder 3.2.3
Using erubi 1.9.0
Using mini_portile2 2.4.0
Using nokogiri 1.10.4
Using rails-dom-testing 2.0.3
Using crass 1.0.5
Using loofah 2.3.1
Using rails-html-sanitizer 1.3.0
Using actionview 6.0.0
Using rack 2.0.7
Using rack-test 1.1.0
Using actionpack 6.0.0
Using nio4r 2.5.2
Using websocket-extensions 0.1.4
Using websocket-driver 0.7.1
Using actioncable 6.0.0
Using globalid 0.4.2
Using activejob 6.0.0
Using activemodel 6.0.0
Using activerecord 6.0.0
Using mimemagic 0.3.3
Using marcel 0.3.3
Using activestorage 6.0.0
Using mini_mime 1.0.2
Using mail 2.7.1
Using actionmailbox 6.0.0
Using actionmailer 6.0.0
Using actiontext 6.0.0
Using public_suffix 4.0.1
Using addressable 2.7.0
Using bindex 0.8.1
Using msgpack 1.3.1
Using bootsnap 1.4.5
Using bundler 2.0.2
Using byebug 11.0.1
Using regexp_parser 1.6.0
Using xpath 3.2.0
Using capybara 3.29.0
Using childprocess 3.0.0
Using ffi 1.11.1
Using jbuilder 2.9.1
Using rb-fsevent 0.10.3
Using rb-inotify 0.10.0
Using ruby_dep 1.5.0
Using listen 3.1.5
Using method_source 0.9.2
Using mysql2 0.5.2
Fetching puma 3.12.1
Installing puma 3.12.1 with native extensions
Fetching rack-proxy 0.6.5
Installing rack-proxy 0.6.5
Using thor 0.20.3
Using railties 6.0.0
Using sprockets 3.7.2
Using sprockets-rails 3.2.1
Using rails 6.0.0
Fetching rubyzip 2.0.0
Installing rubyzip 2.0.0
Fetching sass-listen 4.0.0
Installing sass-listen 4.0.0
Fetching sass 3.7.4
Installing sass 3.7.4
Fetching tilt 2.0.10
Installing tilt 2.0.10
Fetching sass-rails 5.1.0
Installing sass-rails 5.1.0
Fetching selenium-webdriver 3.142.6
Installing selenium-webdriver 3.142.6
Fetching spring 2.1.0

ついに完了!!!!

長かった!!!

メモ

※with native extensions
gemの中には、ruby以外の言語(ネイティブ:C、C++)に依存しているものもあり、そのような依存関係のあるものをインストールする場合に表示される。
https://kossy-web-engineer.hatenablog.com/entry/2019/01/23/202225

※bundler, bundle install
https://www.sejuku.net/blog/19426#bundler

※root権限(sudo)
https://www.atmarkit.co.jp/ait/articles/1611/28/news036.html

※その他、参考になりそうなリンクも念の為貼っておきます。勉強します。
・gem installでpermission deniedされました
 https://qiita.com/tokimari/items/feda1ed61f2d8b5b317c

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

Rubyの基本箇所についての復習③(gets.chomp)

はじめに

前回に引き続き、Rubyの基礎について書いていきます。

内容

変数をいちいちコードに書かなくて済むようにします。

実行

前回は変数を使った、文章の出力について書かせていただきました。
もし'私の趣味は読書です'という文章を出力したい場合は、

hoby = "読書"
puts "私の趣味は#{hoby}です"

とすれば良いのでした。

しかし、これでは違う文章を出力する場合は、その度にコードを書き換えなくてはいけません。
そこで、今回はhobyの中身をコードに書くのではなく、ターミナルから直接入力するようにします。

直接入力するには、gets.chompというメソッドを使えばいいです。
これを使ってコードを書き換えると、

hoby = gets.chomp.to_s
puts "私の趣味は#{hoby}です"

gets.chompの後に.to_sが追加されていますが、これは「文字のみを入力する」という事になります。
仮に数字を入力しても、文字として扱われます。
ちなみに、数字のみを入力したい場合は.to_iを追加します。

このコードを書いてプログラムを実行すると、ターミナル上で文字を入力できるようになります。
ここで例えば'旅行'と入力してみると、'私の趣味は旅行です'と出力されます。

この状態だと、入力する際に何も表示されず、入力していいのかどうかわかりにくいので、コードを以下の様に書き換えます。

puts "あなたの趣味はなんですか?"
hoby = gets.chomp.to_s
puts "私の趣味は#{hoby}です"

このプログラムを実行すると、'あなたの趣味はなんですか?'と出力され、先ほどと同じように文字を入力できるようになります。
このように、良いプログラムを書くためには、使い手の使いやすさを考える必要も出てきます。

終わりに

ここまで変数の使い方を見てきましたが、現状では一つの変数に一つの値しか代入できていません。
しかし、変数には一つだけでなく、もっと多くの値を代入することができます。
次回はその方法について書いていきたいと思います。

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

【Ruby】配列に入れるハッシュを使いまわしてみた

この記事でしていること

配列の中にハッシュを入れる際、奇妙な挙動をしたのでそれについて検証しました。
具体的には配列に対してハッシュを追加した後、ハッシュの中身を変更して再度配列に追加しました。

中身を変更する前に空のハッシュを再宣言しなかったらどうなるか?が今回の記事になります。

経緯

Rubyの簡単な記述を練習していた時に

  1. 配列を宣言
  2. ハッシュを宣言
  3. ハッシュに中身を追加
  4. ハッシュを配列に入れる
  5. 空のハッシュを再度宣言
  6. ハッシュに中身を追加
  7. ハッシュを配列に入れる

という一連の流れの中で「5.は削れるのでは?」と思い実際に削ってみました。
すると期待している動きと違っていた・・・どころか謎の挙動をしていたので、検証してみました。

再現

Before

配列の中にハッシュを入れる際は下記のような手順を踏んでいくことが一般的かと思います。

test.rb
# 空の配列とハッシュを宣言する
array = []
hash = {}

# ハッシュに【キー:num 値:1】を入れ、ハッシュを配列に入れる
hash[:num] = 1
array << hash

# 再度空のハッシュを宣言し、同じキーに別の値「2」を入れる
hash = {}
hash[:num] = 2
array << hash

# 配列の中身を出力
puts array
ターミナル
$ ruby test.rb
{:num=>1}
{:num=>2}

これが通常の結果です。
配列の中に一個目と二個目のハッシュが入っていることがわかります。

After

続いて空のハッシュの宣言を抜いてみます。

test.rb
array = []
hash = {}

hash[:num] = 1
array << hash

# ここでハッシュを宣言しない

hash[:num] = 2
array << hash

puts array
期待していた結果
ターミナル
$ ruby test.rb
{:num=>1}
{:num=>2}
実際の結果
ターミナル
$ ruby test.rb
{:num=>2}
{:num=>2}

前に入れた「1」はどこいった。
そしてなんで「2」は2つも入っとるんや・・・

検証

確認

まずは下記の時にどのような値が入っているのか確認します。

[1.] 1つ目のハッシュを配列に入れた時
[2.] ハッシュの中身を入れ替えた時
[3.] 中身を入れ替えたハッシュを再び配列に入れた時

test.rb
array = []
hash = {}

hash[:num] = 1
array << hash
puts array # [1.]
puts "---------------"

hash[:num] = 2
puts array # [2.]
puts "---------------"

array << hash
puts array # [3.]
puts "---------------"
ターミナル
$ ruby test.rb
{:num=>1} 
---------------
{:num=>2}
---------------
{:num=>2}
{:num=>2}
---------------

[2.]の結果を見てびっくりしました。
えっ・・・一度配列に入れたのにハッシュの中身を入れ替えたら配列の中の方も変わってしまうの・・・?
そして[3.]の結果を見ていただくとわかる通り、配列の追加をすると同じ中身でも配列内に積載されるため、結果として「{:num=>2}」が2つも入ってしまっていたようです。

検証

結果は理解したけどまだちょっと納得いかない!
ということで検証してみました。

検証1:空のハッシュを使わない

test.rb
array = []

hash = {:num => 1}
array << hash
puts array
puts "---------------"

hash = {:num => 2}
puts array
puts "---------------"

array << hash
puts array
puts "---------------"
ターミナル
$ ruby test.rb
{:num=>1}
---------------
{:num=>1}
---------------
{:num=>1}
{:num=>2}
---------------

・・・あれ?うまくいったぞ

検証2:変数

test.rb
array = []

num = 1
array << num
puts array
puts "---------------"

num = 2
puts array
puts "---------------"

array << num
puts array
puts "---------------"
ターミナル
$ ruby test.rb
1
---------------
1
---------------
1
2
---------------

変数も期待通りの動きだ・・・

考察

今回は配列の中身をハッシュと変数で試しましたが、検証の結果を踏まえた仮説は以下になります。

hash[:すでに配列に入っているハッシュのキー] = 

→すでに宣言されているハッシュのキーの値の『変更』という扱いになってしまう

hash = {:すでに配列に入っているハッシュのキーと同名のキー => }
変数 = 

→上記はどちらもその都度ハッシュまたは変数を『新しく宣言』している扱いになるため、すでに宣言されたハッシュまたは変数の値には影響しない

上記の違いがあったために期待した結果にならなかったのだと思いました。

最後に

今回の内容はあえて通常しない記述をしているため、実務においてはあまり問題になることはないと思われますがQiitaの投稿練習も兼ねてまとめてみました。
内容に誤りがある場合やさらに詳しい情報をお持ちの方がいらっしゃいましたら教えていただけると嬉しいです。

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

Rails6で追加されたinsert_allとimport(とその他)のパフォーマンス検証

前回書いた記事で、activerecord-importとRails6で追加されたinsert_allのパフォーマンスを比べたところ、importの方が速そうだったのでもう少しちゃんと検証してみました。

検証方法

速度検証

1,000件のユーザーを様々な方法でバルクインサートします。
1回のバルクインサートだと数msで終わってしまうので、上記を100回実行したときの合計時間で比較します。
計測はbenchmarkを使用します。

メモリ使用量検証

こちらも同様に1,000件のユーザーを様々な方法でバルクインサートします。
計測はmemory_profilerを使用します。

環境

Ruby: 2.6.5
Rails: 6.0.0
rspec-rails: 3.9
factory_bot_rails: 5.1.1

対象

activerecord-import

Railsでバルクインサートできるようにするもっとも有名なgemではないでしょうか。
生成したモデルの配列を渡すだけで簡単にバルクインサートできます。

users = (1..100).map { User.new(name: 'name') }
User.import users

github
https://github.com/zdennis/activerecord-import

insert_all

Rails6.0.0で追加されたバルクインサート用のメソッド。
ハッシュを渡すことで簡単にバルクインサートできます。
importと異なり、created_atとupdated_atを明示的に指定する必要があるので注意が必要です。

users = (1..100).map { { name: 'name', created_at: Time.current, updated_at: Time.current } }
User.insert_all users

doc
https://edgeapi.rubyonrails.org/classes/ActiveRecord/Persistence/ClassMethods.html#method-i-insert_all

素のクエリー

Railsではクエリーをそのまま実行できるのでクエリーを文字列で生成して実行します。

sql = "INSERT INTO users (name, created_at, updated_at) VALUES ('name', NOW(), NOW()),('name', NOW(), NOW())...;"
ActiveRecord::Base.connection.execute sql

検証

実装

benchmarkで検証するbenchmark_bulk_insertとMemoryProfilerで検証するprofiler_bulk_insertを作りました。
純粋にバルクインサートの処理を検証したかったので、データ作成等はBenchmark外で生成しています。

app/models/user.rb
class User < ApplicationRecord
  class << self
    def benchmark_bulk_insert
      # create data
      import_data = []
      1_000.times { import_data << new(name: 'name', created_at: Time.current, updated_at: Time.current) }

      insert_data = []
      1_000.times { insert_data << { name: 'name', created_at: Time.current, updated_at: Time.current } }

      values = []
      1_000.times { values << "('name', '#{Time.current.to_s(:db)}', '#{Time.current.to_s(:db)}')" }
      sql = "INSERT INTO users (name, created_at, updated_at) VALUES #{values.join(',')}"

      require 'benchmark'
      Benchmark.bm 15 do |r|
        transaction do
          r.report 'sql' do
            100.times { bulk_insert_using_sql(sql) }
          end
          raise ActiveRecord::Rollback
        end

        transaction do
          r.report 'insert_all' do
            100.times { bulk_insert_using_insert_all(insert_data) }
          end
          raise ActiveRecord::Rollback
        end

        transaction do
          r.report 'import' do
            100.times { bulk_insert_using_import(import_data) }
          end
          raise ActiveRecord::Rollback
        end
      end
    end

    def profiler_bulk_insert
      # create data
      import_data = []
      1_000.times { import_data << new(name: 'name', created_at: Time.current, updated_at: Time.current) }

      insert_data = []
      1_000.times { insert_data << { name: 'name', created_at: Time.current, updated_at: Time.current } }

      values = []
      1_000.times { values << "('name', '#{Time.current.to_s(:db)}', '#{Time.current.to_s(:db)}')" }
      sql = "INSERT INTO users (name, created_at, updated_at) VALUES #{values.join(',')}"

      p '################# sql ########################'
      transaction do
        report = MemoryProfiler.report do
          bulk_insert_using_sql(sql)
        end
        report.pretty_print(retained_strings: 0, allocated_strings: 100, normalize_paths: true)
        raise ActiveRecord::Rollback
      end

      p '################# insert_all ########################'
      transaction do
        report = MemoryProfiler.report do
          bulk_insert_using_insert_all(insert_data)
        end
        report.pretty_print(retained_strings: 0, allocated_strings: 100, normalize_paths: true)
        raise ActiveRecord::Rollback
      end

      p '################# import ########################'
      transaction do
        report = MemoryProfiler.report do
          bulk_insert_using_import(import_data)
        end
        report.pretty_print(retained_strings: 0, allocated_strings: 100, normalize_paths: true)
        raise ActiveRecord::Rollback
      end
    end

    def bulk_insert_using_import(users)
      import users
    end

    def bulk_insert_using_insert_all(users)
      insert_all users
    end

    def bulk_insert_using_sql(sql)
      connection.execute sql
    end
  end
end

結果

rails consoleで実行しました。

irb(main):080:0> User.benchmark_bulk_insert;nil
                      user     system      total        real
sql               0.000000   0.010000   0.010000 (  0.601744)
insert_all        8.900000   0.030000   8.930000 (  9.951685)
import           10.870000   0.210000  11.080000 ( 12.255004)

irb(main):080:0> User.profiler_bulk_insert
"################# sql ########################"
Total allocated: 4152 bytes (23 objects)
Total retained:  928 bytes (1 objects)

"################# insert_all ########################"
Total allocated: 4493518 bytes (67974 objects)
Total retained:  145088 bytes (2005 objects)

"################# import ########################"
Total allocated: 7187421 bytes (91961 objects)
Total retained:  1824536 bytes (13654 objects)

まず処理時間を見てimportが速いというのは勘違いだったとわかりました。。。ちゃんと調査しないとダメですね。
メモリー使用量を見ると、処理時間と比例して増えています。importでは処理の過程で様々なオブジェクトを生成しているので他の処理より遅いと思われます。
前回の記事でinsert_allの方が遅かったのはbuild_listで生成したオブジェクトを変換するところも計測に入っていたからですね。
そしてimportやinsert_allよりも素のsqlがパフォーマンス最強ということがわかりました。
オブジェクトを生成すればするほど遅くなるので文字列をDBに投げるだけだとかなりパフォーマンスに差がでますね。
素のsqlで実装すると可読性や生産性が落ちるので乱用はしたくないですが、ここぞというときに使うと良さそうです。

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

【Rails】Ransackを使わずにソート機能を実装する

目次

  • 1. 環境
  • 2. 要件
  • 3. カスタムヘルパー実装
    • 3-1. StudentHelper
    • 3-2. ApplicationHelper
  • 4. コントローラー実装
  • 5. ビュー実装
  • 6. 結果(生徒コードでソート)

1. 環境

  • rails 5.2.0
  • ruby 2.6.2
  • MacOS Version 10.14.6

2. 要件

  • 学生テーブル students学生コード (student_code)学生名 (name)学年 (grade_id) でソートしたい。
  • 一覧画面に実装するが、検索フォームがあるのでその結果を保持する。
  • 学生テーブル以外にも今後適用するので、共通処理は纏めておく。

3. カスタムヘルパー実装

3-1. StudentHelper

モデル別にカスタムヘルパーをモジュールを切って実装する。

module StudentHelper
  def student_sort_link(column)
    search_params = search_students_params.empty? ? {} : { search_students_form: search_students_params }
    sort_link(Student.human_attribute_name(column), column, search_params)
  end
end
  • カラム名を引数に取る。
  • 検索パラメータが空の場合、空のハッシュを返す。さもなくばキー値のハッシュを返す
  • 共通処理の sort_link に値を渡す
    • 第一引数: ソート用のリンク文字列。辞書ファイルで日本語に翻訳
    • 第二引数: クエリ文字列 column=[column] を生成する
    • 第三引数: 検索パラメーターのキー値のハッシュ

3-2. ApplicationHelper

共通の処理を記述。

module ApplicationHelper
  def sort_link(column_name, column, **additional_params)
    if params[:column] != column.to_s || params[:direction].nil?
      link_to column_name, { column: column, direction: :asc, **additional_params }
    elsif params[:column] == column.to_s && params[:direction] == 'asc'
      link_to "#{column_name} ▲", { column: column, direction: :desc, **additional_params }
    elsif params[:column] == column.to_s && params[:direction] == 'desc'
      link_to "#{column_name} ▼", { column: column, direction: :asc, **additional_params }
    end
  end
end
  • 第三引数の検索結果のパラメーターは可変長で受け取る
  • 条件分岐は以下の3パターン
    • 現在ソートがかかっているカラムと指定されたカラムが一致しない、もしくは現在ソートがされていない
      • => 指定したカラムで昇順でソートする
    • 現在ソートがかかっているカラムとソート対象のカラムが一致し、なおかつ現在昇順でソートされている
      • => 指定したカラムで降順でソートし、「▲」マークを付ける
    • 現在ソートがかかっているカラムとソート対象のカラムが一致し、なおかつ現在降順でソートされている
      • => 指定したカラムで昇順でソートし、「▼」マークを付ける

4. コントローラー実装

受け取ったクエリ文字列に従ってSQLを走らせる。

def index
  @students = Student.search(@search_form).order(sort_column => sort_direction).preload(:grade)
end

...

private

def sort_column
  params[:column].in?(%w(student_code name grade_id)) ? params[:column] : :id
end

def sort_direction
  params[:direction].in?(%w(asc desc)) ? params[:direction] : :asc
end
  • order は キー => 値 = ソート対象カラム => ソート順 のハッシュを引数にとる
  • sort_column: 指定したカラムがホワイトリストにあればそれをorder のキーに指定し、なければ id を指定する。
  • sort_direction: 指定したソート順がホワイトリストにあればそれをorder の値に指定し、なければ昇順を指定する。

5. ビュー実装

呼び出し元では以下のように引数にシンボルを指定する。

<th class="col-sm-2"><%= student_sort_link(:user_code) %></th>
<th class="col-sm-3"><%= student_sort_link(:name) %></th>
<th class="col-sm-2"><%= student_sort_link(:grade_id) %></th>

6. 結果(生徒コードでソート)

  • デフォルト

クエリ文字列: なし

デフォルト.png

  • 昇順

クエリ文字列: ?column=user_code&direction=asc

昇順.png

  • 降順

クエリ文字列: ?column=user_code&direction=desc

降順.png

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

Rails6 のちょい足しな新機能を試す99(association extension編)

はじめに

Rails 6 に追加された新機能を試す第99段。 今回は、 association extension 編です。
Rails 6 では、 define_extensions で定義される module が model 内の module として定義されるようになっています。
実際の例を見た方がわかりやすいです。

Ruby 2.6.5, Rails 6.0.0 で確認しました。

$ rails --version
Rails 6.0.0

今回は、 Author モデル と Book モデルを定義して、rails console で確認します。
Author は Book を複数持ちます( has_many )。

Rails プロジェクトを作る

$ rails new rails_sandbox
cd rails_sandbox

Author モデルを作る

name を持つ Author モデルを作ります。

$ bin/rails g model Author name

Book モデルを作る

title, published, author_id を持つ Book モデルを作ります。

$ bin/rails g model Book title published:boolean author:references

Author モデルを修正する

Author モデルを修正します。
2つの has_many アソシエーションを定義します。
1つ目の has_many では、 ブロックで ordered メソッドを定義します。
2つ目の scope published_booksextending を使って ordered メソッドを利用できるようにします。
extending の引数が BooksAssociationExtension になっていることに注意してください。

app/models/author.rb
class Author < ApplicationRecord
  has_many :books do
    def ordered
      order(:title)
    end
  end

  has_many :published_books, -> { where(published: true).extending(BooksAssociationExtension) }, class_name: 'Book'
end

seed データを作成する

Author と Book の seed データを作成します。

db/seeds.rb
author = Author.create(
  {
    name: 'Dave Thomas'
  }
)

Book.create(
  [
    { title: 'Programming Ruby', author: author, published: true },
    { title: 'Pragmatic Programmer', author: author, published: true },
    { title: 'Agile Web Development with Rails 6', author: author, published: false }
  ]
)

データベースを作成し、 seed データを登録する

$ bin/rails db:create db:migrate db:seed

rails console で確認する

rails console で確認します。

まずは、1つ目の has_many を確認します。

irb(main):001:0> Author.first.books.ordered
  Author Load (0.3ms)  SELECT "authors".* FROM "authors" ORDER BY "authors"."id" ASC LIMIT $1  [["LIMIT", 1]]
  Book Load (0.3ms)  SELECT "books".* FROM "books" WHERE "books"."author_id" = $1 ORDER BY "books"."title" ASC LIMIT $2  [["author_id", 1], ["LIMIT", 11]]
=> #<ActiveRecord::AssociationRelation [#<Book id: 3, title: "Agile Web Development with Rails 6", published: false, author_id: 1, created_at: "2019-10-12 09:09:58", updated_at: "2019-10-12 09:09:58">, #<Book id: 2, title: "Pragmatic Programmer", published: true, author_id: 1, created_at: "2019-10-12 09:09:58", updated_at: "2019-10-12 09:09:58">, #<Book id: 1, title: "Programming Ruby", published: true, author_id: 1, created_at: "2019-10-12 09:09:58", updated_at: "2019-10-12 09:09:58">]>

2つ目の has_many を確認します。

irb(main):002:0> Author.first.published_books.ordered
  Author Load (0.8ms)  SELECT "authors".* FROM "authors" ORDER BY "authors"."id" ASC LIMIT $1  [["LIMIT", 1]]
  Book Load (0.8ms)  SELECT "books".* FROM "books" WHERE "books"."author_id" = $1 AND "books"."published" = $2 ORDER BY "books"."title" ASC LIMIT $3  [["author_id", 1], ["published", true], ["LIMIT", 11]]
=> #<ActiveRecord::AssociationRelation [#<Book id: 2, title: "Pragmatic Programmer", published: true, author_id: 1, created_at: "2019-10-12 09:09:58", updated_at: "2019-10-12 09:09:58">, #<Book id: 1, title: "Programming Ruby", published: true, author_id: 1, created_at: "2019-10-12 09:09:58", updated_at: "2019-10-12 09:09:58">]>

Author::BooksAssociationExtension が定義されていることを確認します。

irb(main):003:0> Author::BooksAssociationExtension
=> Author::BooksAssociationExtension

Rails 5 では

Rails 5.2.3 では、 Author::BooksAssociationExtension ではなく、 AuthorBooksAssociationExtension が定義されます。
以下のように extending の引数を AuthorBooksAssociationExtension と書く必要があります。

app/models/author.rb
class Author < ApplicationRecord
  ...
  has_many :published_books, -> { where(published: true).extending(AuthorBooksAssociationExtension) }, class_name: 'Book'
end

Rails 5.2.3 ではグローバルなモジュールとして定義されるのに対し、Rails 6 では、 Author モデルの中のモジュールとして定義されるので、 Author モデルで利用するときは、Author をつけずに、 BooksAssociationExtension と簡潔に書くことができるようになっています。

試したソース

試したソースは以下にあります。
https://github.com/suketa/rails_sandbox/tree/try099_association_extension

参考情報

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

【Ruby】attrメソッドとその仲間たち

attrメソッド

attr(name, writable = false)

第一引数nameにはインスタンス変数名
第二引数をtrueにすると書き込みも可能なメソッドを定義できる。

使い方例.rb
class Book
 attr :title

 def initialize(title)
  @title = title
 end
end

book = Book.new("たのしいRuby")
puts book.title
=>"たのしいRuby"

この時点で以下を入れても書き込めないのでエラーとなる
book.title = "経営学入門"

書き込みを定義した例.rb
class Book
 attr :title,true  #writable=falseのところをtrueにした!

 def initialize(title)
  @title = title
 end
end

book = Book.new("たのしいRuby")
puts book.title
=>"たのしいRuby"

#書き込み可能にしたので以下は問題なく動く
book.title = "経営学入門"
puts book.title
=>"経営学入門"

じゃぁ複数のインスタンス変数を読み書き可能にするには??

attr :title, :price, true

とすれば可能か?
答えはどうやらNoである。

attr_accessorを使う

使い方例.rb
class Book
  attr_accessor :title, :price

  def initialize(title, price)
    @title = title; @price = price
  end
end

book = Book.new("たのしいRuby", 2310)
puts book.title
  =>"たのしいRuby"
book.price = 2000 #priceの書き換え
puts book.price
 => 2000  #2310が2000に書き換えられた!

ついでに
attr_readerはインスタンス変数の読み出し専用
attr_writerはインスタンス変数の書き込み専用をそれぞれ定義します。

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

#Ruby の begin end while で 変数代入なしでループ処理する ( 後方 while )

  • a に 10が代入されるまでランダムな値を代入し続ける例。
  • 何回も処理を繰り返して a == 10 になったタイミングでループを抜ける。
  • while は必ず1回は実行されて a 変数が定義される。コード的には後方にあるけど最初に評価される。後方 if とかと同じノリかな。
  • begin rescue での例外キャッチの処理とは全く関係ない。たぶん。キーワードは似ているけれど。
i = 0

begin
  a = rand(99)
  i += 1
end while a != 10

a # 10
i # => 156

どういうこと?

  • これとだいたい同じ。
a = nil

while a != 10
  a = rand(99)
end

p a #10

whileだけじゃ無理なの?

  • a を定義していないと未定義エラーが起こる。
  • 最初に a = nil とか定義しておくのと同じ。
while a != 10
  a = rand(99)
end

# NameError: undefined local variable or method `a' for main:Object

while とは違い、必ず一回は実行されるっぽい

begin
  puts :a
end while false

# a

begin rescue end とは違うの?

例外をキャッチしたいわけではないらしい。そもそも rescue って書いてないし。

begin
  raise
end while true

# RuntimeError:

Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/2625

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

Ruby 入門#3(配列)

Rubyの勉強アウトプット
今回は、配列について記載します。

定義

配列名 = [要素,要素,…] と定義します。
要素番号は0から始まります。
要素を取得、変更したい場合は配列名[要素番号]と指定します。

names = ["田中","加藤","佐藤"]
puts names[1] # => 加藤
names[1] = "宮城"
puts names[1] # => 宮城

追加

push、<<を使い、末尾に追加

names = ["田中","加藤","佐藤"]

names.push("太田")
puts names[3] # => 太田

names << "大谷"
puts names[4] # => 大谷

削除

削除するメソッドは複数ありますが、今回は
「delete」、「delete_at」メソッドを紹介します。

delete
引数に削除する要素を指定して削除します。

numbers = [1,2,3,1,4]
numbers.delete(1)
p numbers # => 2,3,4

delete_at
引数に削除する要素番号を指定して削除します。

numbers = [1,2,3,1,4]
numbers.delete_at(1)
p numbers # => 1, 3, 1, 4

配列メソッド

配列のメソッドから、
「each」、「length」、「empty」メソッドを紹介します。

each
配列の要素をブロックパラメーターに順番に入れ、参照することができます。

配列名.each do |ブロックパラメーター|
end

と記述します。

names = ["佐藤", "太田", "中田"]
names.each do |name|
  print name + ","
end
# => 佐藤,太田,中田,

length
配列の要素数を調べることができます。

names = ["佐藤", "太田", "中田"]
puts names.length # => 3

empty
配列が空かどうかを調べる

names = ["佐藤", "太田", "中田"]
puts names.empty? # => false

fruit = []
puts fruit.empty? # => true
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【エラー】bundle実行時にmysql2がインストールされない

環境

  • Mac OS
  • Ruby 2.6.3
  • Rails 5.2.3
  • MySQL 8.0

エラー内容

Dockerを使ってRails+MySQLでの環境構築をした後に
bundle installを実行すると

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

といったような
mysql2がインストールできないというエラーが発生しました。

対処方法

$ bundle config --local build.mysql2 "--with-cppflags=-I/usr/local/opt/openssl/include"
$ bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl/lib"

上記二つのコマンドを実行し、
bundlerの設定をするとエラーが解決できて
無事mysql2がインストールできました!

感じたこと

エラー発生時なかなか解決できず困りましたが
とにかく色々と調べた結果上記の対処方法で解決できました!(汗)

Dockerを使って新しく環境構築するとこのエラーが発生するので
環境構築をし終えたら毎度このコマンドを実行してます!

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

Railsのslim導入方法

slimについて

slim
doctype html
html
  head
    title
      | Sample
    = csrf_meta_tags
    = csp_meta_tag
    = stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload'
    = javascript_include_tag 'application', 'data-turbolinks-track': 'reload'
  body
    = yield

上記のような記述方法のRuby制の軽量なテンプレートエンジン。

【1】gemの追加

gem 'slim-rails'
gem 'html2slim'

Gemfileに上記のコードを追加する。

その後、bundle installを実行する。

$ bundle

【2】erbをslimに変換する

$ bundle exec erb2slim app/views/layouts/ --delete

上記のコマンドを打つと
app/views/layouts内のerb形式のファイルがslimに変換される。
以上でslimの導入が完了です。

感じたこと

erbよりも記述量が減り

  • HTMLタグを省略でき効率よく書ける
  • 軽量で動作が速い
  • 全体がすっきりまとまっていてメンテナンスがしやすくなる

など様々なメリットを感じたので積極的に導入してます!!

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