- 投稿日:2020-02-19T22:06:23+09:00
【初学者のつまずきを記録】RailsでのMySQL接続:mysql.sock問題
はじめに
RailsでのMySQL接続手順について、備忘録的にまとめようと思います。
作業自体はごく基本的な内容かと思いますが、
初学者である僕が実際につまずいたことを重点的に記載しました。
僕と同じ初学者の方のご参考の一助となればうれしいです。
後半部分ではつまずいた原因について検討してみました。※僕自身は「RailsのDBを(初めから| |後から)MySQLに変更する」を参考にしながら進めました。
前準備:MySQLを指定してRailsアプリを作成
Railsの仕様上、データベースを指定しない場合は自動的にSQLiteとなる。
$ rails new アプリ名 -d mysql作成されたconfig/database.ymlを確認。
config/database.ymldefault: &default adapter: mysql2 (略)確かにMySQLとなっていることを確認。
MySQLとの接続
手順通り接続を試みる。が、エラー発生。
$ mysql -u root ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)mysql.sockを通じての接続ができなかったとのこと。
調べてみると、mysql.sockファイル自体が存在しないことが問題らしい。
確かに、tmpフォルダ内を確認してみても存在しない。下記実行で作成。$ sudo touch /tmp/mysql.sockその上で接続を試みても同じようなエラー発生。
$ mysql -u root ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (38)そもそも、mysql.sockファイルとは何だろう?
調べてみると、サーバーとクライアントの間で通信を行う際の仲介役的な役割らしい。
ここで、MySQLサーバーを起動していないことに気づきました。
というかエラー分にもしっかりMySQL server
とありますね。MySQLサーバーを起動。
$ mysql.server start Starting MySQL .. ERROR! The server quit without updating PID file (/usr/local/var/mysql/xxxx.pid).PIDファイルがないとのお達し。
指定された場所に作成をする。$ touch /usr/local/var/mysql/xxxx.pidその上でサーバー起動を試みるも、、、
$ mysql.server start Starting MySQL .rm: /tmp/mysql.sock: Permission denied 2020-02-17T12:13:34.6NZ mysqld_safe Fatal error: Can't remove the socket file: /tmp/mysql.sock. Please remove the file manually (略)別のエラーが発生。
mysql.sockを削除しろと??
ないと言うから作ったのに。言われるがままに削除し、
どこか不本意な気持ちのまま再度サーバー起動。成功。$ mysql.server start Starting MySQL . SUCCESS! $ mysql -u root Welcome to the MySQL monitor. (略) mysql>MySQLへの接続も成功したようだ。釈然としない。
成功した理由を考えてみた
調べてみると、mysql.sockはMySQLサーバー起動時に自動的に作成されるファイルであり、
手動で作成する類のものではないらしい。
つまり、一番始めに発生した下記エラーは、mysql.sockを作成していないことが問題ではなく、
「Can't connect
:つなげない状態」であったことが問題であったと思われる。$ mysql -u root ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)よって、mysql.sockがない状態でも、
PIDファイルを作成してサーバー起動を成功させることによって(=ここでmysql.sockが自動作成され)
MySQLへの接続も成功した、、、という理解でいいのだろうか。では手動作成のmysql.sockは何が問題であったのか?
調べてみるとどうやら手動で作成したmysql.sockは権限に問題があるようだ。
検証のために再度手動でmysql.sockを作成し、
自動作成(サーバー起動時)されたmysql.sockと$ ls -l
の出力を比較してみた。#手動 -rw-r--r-- 1 root wheel 0 2 17 22:56 mysql.sock #自動作成 srwxrwxrwx 1 xxxx(ユーザー名) wheel 0 2 17 22:45 mysql.sockなるほど違う。
手動で作成された方はrootユーザーのみが書き込みの権限を持っている。
書き込みの権限がないとうまくいかないので、(参考:MySQL の設定上の考慮事項)
rootユーザー以外での実行ができない状態となっている??ならばと手動作成した上でrootユーザー権限でサーバー起動を試みてみる。
$ sudo mysql.server start Starting MySQL . ERROR! The server quit without updating PID file (/usr/local/var/mysql/xxxx.pid).だめかー。
では手動作成したものを自動作成と同じ権限に変えてみる。
これでダメな理由はないはず。$ sudo chmod 777 mysql.sock #権限を変更 $ sudo chown xxxx(ユーザー名) mysql.sock #所有者も変更 $ mysql.server start Starting MySQL . SUCCESS!成功した!
手動でmysql.sockを作成した場合でも
権限周りを調整することによりサーバー起動ができることの確認がとれました。まとめ
解決方法を色々とググりながら進めましたが、
「まずはじっくりとエラー分を解釈すること」の大切さを痛感しました。
またlinux等の知識が不足しており、後半の検証部分は気持ちとしてしこりが残っております。
(rootユーザー権限でサーバー起動できなかったあたり等)
今後の課題にするようにしたいと思います。はじめての記事投稿でしたが、思考を整理するとても良い機会となりました。
誤り・認識違い、アドバイス等ご指摘いただけましたらとてもありがたいです。
- 投稿日:2020-02-19T21:14:06+09:00
RSpecを導入した時、詰まったこと
エラー内容
Rspecを使ったテストを実行する際、以下のようなエラーが発生。
An error occurred while loading ./spec/models/board_spec.rb. Failure/Error: config.include FactoryBot::Syntax::Methods NameError: uninitialized constant FactoryBot行ったこと
参考
http://yurafuca.hatenablog.com/entry/2018/06/28/190842
https://qiita.com/Sa2Knight/items/90d32c9b8493d6bf94b3
・gemにrspec-railsを導入済み
・rspecの初期ファイルを作成済みエラー原因
spec/rails_helper.rbの一番最初の行にいきなり
config.include FactoryBot::Syntax::Methods
を記入してしまった。
下記が正しい書き方。RSpec.configure do |config| # 中略 config.include FactoryBot::Syntax::Methods end
- 投稿日:2020-02-19T21:14:06+09:00
RSpecを導入した時、詰まったこと(NameError: uninitialized constant FactoryBot)
エラー内容
Rspecを使ったテストを実行する際、以下のようなエラーが発生。
An error occurred while loading ./spec/models/board_spec.rb. Failure/Error: config.include FactoryBot::Syntax::Methods NameError: uninitialized constant FactoryBot行ったこと
参考
http://yurafuca.hatenablog.com/entry/2018/06/28/190842
https://qiita.com/Sa2Knight/items/90d32c9b8493d6bf94b3
・gemにrspec-railsを導入済み
・rspecの初期ファイルを作成済みエラー原因
spec/rails_helper.rbの一番最初の行にいきなり
config.include FactoryBot::Syntax::Methods
を記入してしまった。
下記が正しい書き方。RSpec.configure do |config| # 中略 config.include FactoryBot::Syntax::Methods end
- 投稿日:2020-02-19T18:21:31+09:00
これがあれば忘れても大丈夫。gem 'devise' 使い方
基本機能
gem "devise"のインストール
Gemfile# rails5系なら以下を記述 # For 5.0.x, 5.1.x and 5.2.x gem 'rails-i18n', '~> 5.1' gem 'devise' gem 'devise-i18n' gem 'devise-i18n-views' gem 'omniauth-twitter'deviseの初期設定
ターミナル# gemをインストール $ bundle install # deviseのインストール $ rails g devise:install # 日本語化するためのymlファイルを作成 > devise.views.ja.ymlが生成される $ rails g devise:views:locale ja # ログイン、新規登録などのviewを取得 $ rails g devise:views # deviseのコントローラーのカスタマイズ $ rails g devise:controllers users # userモデルの作成 $ rails g devise user日本語対応させる。
config/application.rbrequire_relative 'boot' require 'rails/all' # Require the gems listed in Gemfile, including any gems # you've limited to :test, :development, or :production. Bundler.require(*Rails.groups) module app-name class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. config.load_defaults 5.2 config.i18n.default_locale = :ja # 日本語対応 config.time_zone = 'Tokyo' # 日本時間 config.active_record.default_timezone = :local # 「データベースに保存されている時刻の値がlocalの時間にする」 # Settings in config/environments/* take precedence over those specified here. # Application configuration can go into files in config/initializers # -- all .rb files in that directory are automatically loaded after loading # the framework and any gems in your application. end end新規登録のカラム追加
application_controller.rbclass ApplicationController < ActionController::Base protect_from_forgery with: :exception before_action :configure_permitted_parameters, if: :devise_controller? protected def configure_permitted_parameters devise_parameter_sanitizer.permit(:sign_up, keys: [:username]) # ここにカラム名を追加する。paramsの定義は不要。 end endサインインしていない場合、ログイン画面表示
〇〇_controller.rbbefore_action :authenticate_user!ログイン時とログアウト時で表示を変える
html.haml%ul.float-right - if user_signed_in? %li = link_to "マイページ", user_path(current_user.id), class:"btn login" %li = link_to "ログアウト", destroy_user_session_path, class:"btn login" - else %li = link_to "ログイン", new_user_session_path, class:"btn login" %li = link_to "新規登録", registration_users_path, class:"btn registration"ユーザー情報を取得
html.haml%p current_user.name
current_userでユーザー情報を取得できます。
メール認証
のちほど追記予定
参考リンク
- 投稿日:2020-02-19T15:23:25+09:00
ActiveAdmin 画面遷移時にfilterのパラメーターをセットする
親要素から子要素に遷移する際, 親要素のidで絞りたい
これだけと何をいってるかわからないので
例) Company : Shop = 1 : N のRelationの時, Companyの画面から, Shopの一覧画面へ遷移する時, そのままではデータが大きすぎるので, 最初からShopを外部キーのCompany_Idで絞っておきたい# カスタム アクション # 一度変数に入れないと, エスケープされずエラーとなる query = "q[company_id_equals]" action_item :my_button1, only: :show do link_to "店舗の一覧に遷移する", active_admin_shops_path({query => company.id}) endこれだけで遷移と同時にfilterがかかります.
調べても載っておらず, 尚且つ需要があると思うので書きました.
- 投稿日:2020-02-19T13:00:51+09:00
Amazon Linux2でLet's EncryptするのをItamae化
はじめに
RailsアプリケーションのサーバーをItamaeで管理しているます。
環境構築時にELBを立てず、サーバー直接でアクセスさせる場合、サーバーへのSSL証明書の設定が必要になります。
サーバーはAmazon Linux2で、SSL証明書はLet's Encriptで取得するのをItamae化してみました。nginx, Itamae, Certbotのインストール、構築は既に済んでいるものとします。
環境
サーバー
EC2OS
Amazon Linux2バージョン
Rails: 5.x.x(複数プロジェクト)
Ruby: 2.x.x手動構築手順
簡単に説明すると、下記コマンドを打つ
$ sudo certbot --nginxすると、対話式でメールアドレス、対象ドメイン、規約への同意などなどの確認があったのち、SSL証明書が作成され、nginx.confに自動的に設定される.
その対話をコマンドオプション指定でなくすことができるかどうかが今回の争点!
結論
- cookbooks/certbot/default.rb
execute 'download EPEL7' do user 'root' command "wget -r --no-parent -A 'epel-release-*.rpm' http://dl.fedoraproject.org/pub/epel/7/x86_64/Packages/e/" end execute 'install EPEL7' do user 'root' command "rpm -Uvh dl.fedoraproject.org/pub/epel/7/x86_64/Packages/e/epel-release-*.rpm" end execute 'enable EPEL7' do user 'root' command 'yum-config-manager --enable epel*' end package 'certbot' package 'python2-certbot-nginx' execute 'SSL証明書を作成' do user 'root' command "certbot --nginx -d #{node[:dns][:server_name]} --agree-tos --register-unsafely-without-email -n" endやったこと
- Amazon Linux 2 でEPEL7を使用可能にする。
- certbotとpython2-certbot-nginxをインストール
- 証明書の作成
- オプション
- -d example.com # => DNSを指定。nginx.confのserver_nameと同じにする
- --agree-tos # => 規約に同意
- --register-unsafely-without-email # => メールを登録しない(非推奨)
- -n #=> 対話をなくす
certbot自体のオプションはそのまま流用可能なようなので、registerする場合は
--email test@example.comなどの指定も可能。
これでめっちゃ手軽にLet's Encript生活!!
事後作業
証明書更新のCronの設定は適宜参照してください。===>> 上記URL
参考にさせていただいたサイト
- 投稿日:2020-02-19T12:44:01+09:00
Rails6 のちょい足しな新機能を試す 121(PostgreSQL index_exists?編)
はじめに
Rails 6 に追加された新機能を試す第121段。 今回は、
PostgreSQL index_exists?
編です。
Rails 6 (と Rails 5.2.4.1) では、index_exists?
が正しく動作しないバグが fix されています。Ruby 2.6.5, Rails 6.0.2.1, Rails 5.2.4.1, Rails 5.2.3, PostgreSQL 12.0 で確認しました。 (Rails 6.0.0 でこの修正が入っています。)
$ rails --version Rails 6.0.2.1今回は、 name の属性を持つ User モデルを作り、インデックスを追加して確認してみます。
Rails プロジェクトを作る
Rails プロジェクトを新たに作成します。
$ rails new rails_sandbox $ cd rails_sandboxUser モデルを作る
name
属性を持つUser
モデルを作ります。$ bin/rails g model User name
インデックスを追加する
今回は2つのインデックスを作成します。
lower(name)
を指定したインデックスと、単純にname
カラムを指定したインデックスです。bin/rails g migration add_index_lower_name_to_usersdb/migrate/20200207213234_add_index_lower_name_to_users.rbclass AddIndexLowerNameToUsers < ActiveRecord::Migration[6.0] def change add_index :users, 'lower(name)', name: 'index_lower_name' add_index :users, 'name', name: 'index_name' end endマイグレーションを実行する
マイグレーションを実行します。
bin/rails db:create db:migraterails console で確認する
rails c
を実行します。$ bin/rails c Running via Spring preloader in process 344 Loading development environment (Rails 6.0.2.1)
indexes
で登録されているインデックスを調べてみましょう。
(わかりやすいように表示は折り返してます。)irb(main):001:0> User.connection.indexes(:users) => [ #<ActiveRecord::ConnectionAdapters::IndexDefinition:0x00005617bc6ef580 @table=:users, @name="index_lower_name", @unique=false, @columns="lower((name)::text)", # <= ここに注目 @lengths={}, @orders={}, @opclasses={}, @where=nil, @type=nil, @using=:btree, @comment=nil>, #<ActiveRecord::ConnectionAdapters::IndexDefinition:0x00005617bc8c3be0 @table=:users, @name="index_name", @unique=false, @columns=["name"], # <= ここに注目 @lengths={}, @orders={}, @opclasses={}, @where=nil, @type=nil, @using=:btree, @comment=nil> ]
index_lower_name
に対応する@columns
が'lower((name)::text)'
で String であるのに対して、index_name
に対応する@columns
が["name"]
とArray になっていることに注意してください。
index_exists?
を使ってindex_name
が存在することを確認します。irb(main):002:0> User.connection.index_exists?(:users, "name", name: :index_name) => true今度は、
index_lower_name
が存在することを確認します。irb(main):003:0> User.connection.index_exists?(:users, "lower((name)::text)", name: :index_lower_name) => trueRails 5 では
Rails 5.2.4.1 では、 Rails 6 と同じ動作ですが、 Rails 5.2.3 では、
index_lower_name
の存在を確認したときfalse
を返します。irb(main):001:0> User.connection.index_exists?(:users, "name", name: :index_name) => true irb(main):002:0> User.connection.index_exists?(:users, "lower((name)::text)", name: :index_lower_name) => false試したソース
https://github.com/suketa/rails_sandbox/tree/try121_index_exists_of_postgresql
参考情報
- 投稿日:2020-02-19T11:37:44+09:00
自作したrakeタスクをrailsが認識してないときに疑うこと
発生した問題
rake タスクを作成して実行しようとしたら、そんなタスク知らん(Don't know how to build task 'xxxxx')と突っぱねられてしまいました。
$ bundle exec rails my_awesome_task rails aborted! Don't know how to build task 'my_awesome_task' (See the list of available tasks with `rails --tasks`)確かに
rails --tasks
に挙がってない。$ bundle exec rails --tasks | grep my_awesome_task (該当なし)なんとなく
rake -T
も試したけどやっぱり見つからない。$ bundle exec rake -T | grep my_awesome_task (該当なし)以下がそのタスクです。
lib/my_awesome_task.rbdesc 'すごいタスク' task :my_awesome_task do puts 'すごいぞー \(^o^)/' endチェック1:配置場所は正しいか?
(Rails.root)/lib/tasks
配下に置かないとダメでした。修正前: lib/my_awesome_task.rb ↓ 修正後: lib/tasks/my_awesome_task.rbチェック2:拡張子は正しいか?
Rakeタスクの拡張子は
.rake
じゃないとダメでした。修正前: lib/tasks/my_awesome_task.rb ↓ 修正後: lib/tasks/my_awesome_task.rakeこの2つを直したら無事に動きました。
ちなみに
タスクを作るときに
rails generate task
コマンドを使っていれば、こんな変なハマり方しなかったと思います。反省。--
- 投稿日:2020-02-19T11:15:52+09:00
ActiveRecord::PendingMigrationErrorの解決方法
1.エラーメッセージの内容
2.エラーの原因
エラーの理由はmigrateし忘れてますよというものです。
考えられる理由は下記の3つです1.単純にrails db:createのあとrails db:migrateし忘れている
2.すでにmigrationが完了している(up)状態でマイグレーションファイルを更新しrails db:migrateしてしまった
3.マイグレーションファイルの中に入れた外部参照キーが参照するテーブルがない状態でrails db:creatしてしまった(マイグレーションファイルの記述に誤りがある)3.エラーの解決方法
1.単純にrails db:createのあとrails db:migrateし忘れている
マイグレーション実行の下記のコマンドを打ち込みましょう
$ rails db:migrate2.すでにmigrationが完了している(up)状態でマイグレーションファイルを更新しrails db:migrateしてしまった
方法1 既存のテーブルを全削除し、再度マイグレーションの状態をupにする下記のコマンドを打ち込みましょう
$ rails db:migrate:reset方法2 マイグレーションの最新のものだけ実行を取りやめて編集可能(down)にするコマンドrails db:rollbackののち、マイグレーションファイルの更新コマンドrails db:migrateを打ちましょう
$ rails db:rollback $ rails db:migrate※方法1と方法2の違いは処理速度(工程)の量の違いです。テーブルの数が多い場合は方法2としましょう。テーブルが数十程度なら方法1でも2でも大差はありません
※マイグレーションの状態を調べるコマンドは下記の通りです
$ rails db:migrate:status3.マイグレーションファイルの中に入れた外部参照キーが参照するテーブルがない状態でrails db:creatしてしまった
①-1外部参照されるマイグレーションファイルを作成し、app/modelの中のファイルにアソシエーションを追記(または修正)する
①-2マイグレーションファイルから不必要な外部参照キーを消す②上記①のどちらかの修正のあとに下記コマンドを打ち込みましょう
$ rails db:migrate:reset4.すでにデータベースにレコードを入れてしまい、それを残したまま修正する方法(補足)
新たに追加したい項目のテーブルを作成し、本来追加したかったテーブルのidを外部キーとする方法をとりましょう。
- 投稿日:2020-02-19T11:03:43+09:00
RubyのMysql2の各種情報(バージョン情報やオプション)を取得する方法
背景
Ruby on Rails 等で MySQLを利用している時、低レイヤーの根深い問題や、よくわからないエラーに遭遇したことはありますでしょうか?
RubyでMySQLを利用する際によく使われるライブラリである
Mysql2
では、C拡張を利用してlibmysqlclient
とリンクし、データベースサーバ上のmysqld
に対してアクセスしている都合上、複数の概念に対してのバージョン情報やオプションを扱う必要があります。これらのバージョン情報は、問題の原因究明に重要であるため、取得方法を知っておくことで、効率的な作業が可能になります。自分が調べる時は勿論、他の人に手伝ってもらう時にも重要なヒントになります。
TL; DR
以下のようなデータを記録しておくと、調査が捗ります。
# Railsの場合の Mysql2::Client のオブジェクトの取得方法の例 client = ActiveRecord::Base.connection.raw_connection # 自前の場合の Mysql2::Client のオブジェクトの作成方法の例 client = Mysql2::Client.new(host: 'localhost', username: 'root') puts JSON.pretty_generate( 'RUBY_DESCRIPTION' => RUBY_DESCRIPTION, # Rubyの詳細 'Mysql2::VERSION' => Mysql2::VERSION, # gemのバージョン 'Mysql2::Client#info' => client.info, # libmysqlclient のバージョン 'Mysql2::Client#server_info' => client.server_info, # 接続先の MySQL Server のバージョン ) # 接続に関するオプション (おまけ) puts JSON.pretty_generate(client.query_options.reject { |k, _v| k == :password }) # 他にも重要な情報はあるが、最低限、パスワードは取り除く出力例
{ "RUBY_DESCRIPTION": "ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-darwin18]", "Mysql2::VERSION": "0.4.10", "Mysql2::Client#info": { "id": 80016, "version": "8.0.16", "header_version": "8.0.16" }, "Mysql2::Client#server_info": { "id": 50637, "version": "5.6.37" } }各種バージョン
Rubyの詳細情報
ruby -v
の詳細が記述されます。https://docs.ruby-lang.org/ja/latest/method/Object/c/RUBY_DESCRIPTION.html
gem のバージョン
gem のバージョンは、以下の Mysql2 自体のバージョン
Mysql2::VERSION
になります。https://github.com/brianmario/mysql2
コードは以下のような形になっています。
module Mysql2 VERSION = "0.5.3".freeze endlibmysqlclient のバージョン
Mysql2 は、独自に MySQLサーバ との通信プロトコルを実装しているわけではなく、 MySQLの提供している、Cで書かれたクライアントライブラリを利用してアクセスしています。
この時のライブラリのバージョンによって、微妙な挙動の差異が発生する場合があるので、この情報も重要です。Mysql2 では、以下のようにC拡張で
Mysql2::Client#info
が実装されています。version = rb_str_new2(mysql_get_client_info());これが呼び出している
mysql_get_client_info()
が何を返すかは、MySQLのドキュメントに記述されています。https://dev.mysql.com/doc/refman/5.6/en/mysql-get-client-info.html
Returns a string that represents the MySQL client library version (for example, "5.6.48").
ということで、クライアントライブラリ
libmysqlclient
のバージョンが返却されます。接続先の MySQL Server のバージョン
問題が発生した時は、クライアントバージョンは勿論ですが、相手側のサーババージョンも気になるところです。
Mysql2 では、以下のようにC拡張で
Mysql2::Client#server_info
が実装されています。server_info = rb_str_new2(mysql_get_server_info(wrapper->client));これが呼び出している
mysql_get_server_info()
が何を返すかは、MySQLのドキュメントに記述されています。https://dev.mysql.com/doc/refman/5.6/en/mysql-get-server-info.html
Returns a string that represents the MySQL server version (for example, "5.6.48").
ということで、接続先の MySQL サーバのバージョンが返却されます。
接続に関するオプション
MySQLのサーバ側で設定されているオプションも勿論大切ですが、各クライアント(コネクション)毎に維持されているオプションも、細かい挙動を知る上では重要になってきます。
Mysql2 では、以下のようにインスタンス変数へのアクセッサーが生やされて、
Mysql2::Client#query_options
があるので、それを利用する形が良いと思われます。※ このアクセッサーにはパスワードを含む情報が格納されているので、情報共有の際には、それをしっかり取り除くことを留意しておいてください。
参考
https://github.com/brianmario/mysql2
https://dev.mysql.com/doc/refman/5.6/en/c-api-server-client-versions.html
- 投稿日:2020-02-19T09:53:25+09:00
rails 短縮系コマンドについて
完全なコマンド 短縮形
$ rails server →$ rails s
$ rails console →$ rails c
$ rails generate→ $ rails g
$ rails test →$ rails t
$ bundle install→ $ bundle
表 3.1: Railsで使える短縮形の例
- 投稿日:2020-02-19T02:47:48+09:00
【Rails】ActiveStorageを使わずにGoogle Cloud Storage(GCS)を使う
概要
RailsでGoogle Cloud Storage(GCS)を使うとなると、ActiveStorageを使う方法が挙がりますが、ActiveRecordを使わないケース(*1)や、そもそもActiveStorageを導入するのが手間だったりすることがあると思います。
ので、ActiveStorageを使わず比較的手軽にGCSを使う方法を紹介します。*1…2020年2月時点だと、ActiveRecordにしか対応してないみたいです。ActiveStorage and Mongo #31408
事前準備
- 入門ガイドを参考に、GCSのバケットを作成する。
- Google Cloud Platform のサービスアカウントキーを作成するを参考に、サービスアカウントキーのファイルを取得する。
- google-cloud-storageのライブラリを使うので、gemをインストールする。
サンプルの概要
以下のような処理を想定して、GCS使用部分のサンプルを書きます。
- クライアントからmultipart/form-dataでファイルを受け取る。(ファイルの受信部分はRailsでファイルをアップロードしてpublicディレクトリに保存したあとに表示するを参照のこと)
- GCSにファイルをアップロードする。
- アップロードしたファイルのURLを取得する。
実装サンプル
バケットの取得
Exampleを参考にして、バケットを取得します。また、事前準備で取得したkeyファイルは、configフォルダ配下に配置しているものとします。
google_cloud_storage_util.rbrequire "google/cloud/storage" module GoogleCloudStorageUtil def getBucket() storage = Google::Cloud::Storage.new( project_id: "GCPのプロジェクトIDを入力", credentials: "config/test_key.json" ) storage.bucket "事前準備で作成したバケット名を入力" end endファイルの確認・削除
アップロードするファイルはパス(フォルダ名+ファイル名)で一意にするので、受け取ったファイル名で既に存在する場合は削除します。
google_cloud_storage_util.rbdef deleteImageFile(fileName, bucket) file = bucket.file("test_folder/" + fileName) if !file.nil? file.delete end endファイルの追加
指定したパスにファイルを追加します。multipart/form-dataで受け取った場合は、tempfileで送信します。
google_cloud_storage_util.rbdef addImageFile(imageFile, fileName, bucket) # tempfileを送る bucket.create_file(imageFile.tempfile, "test_folder/" + fileName) end参照用URLの取得
アップロードしたファイルをパブリックで参照するためには、期限付きのURLを取得する必要があります。
google_cloud_storage_util.rbdef getImageUrl(fileName, bucket) file = bucket.file("test_folder/" + fileName) if !file.nil? file.signed_url(method: "GET", expires: 60 * 60 * 24) else nil end end参考記事など
google-cloud-storage API documentation
Google Cloud Storageのファイルを指定したファイル名でダウンロードしたい
- 投稿日:2020-02-19T01:40:52+09:00
画像アップロード機能実装について
目的
作成したアプリケーションに画像アップロード機能を実装するための手順や
考え方などを備忘録的に残していきます。画像アップロードとは
アップロードとはファイルやデータをPCやスマホからインターネット上のサーバーへ転送することを指します。
画像アップロードの仕組み
- ファイル選択ボタンを押して、画像を選択
- 送信ボタンをおす
- 画像ファイルを画像パスがリクエストして送信される
- 画像ファイルはアクセス先コンピューター内に、画像のパスはDBないにあるテーブルに保存される (画像の保存先には外部のストレージを使うことが多い。AWSサービスのS3など..)
実装の流れ
ライブラリのインストール
Gemfilegem 'carrierwave' gem 'mini_magick'bundle installアプリの雛形を作成
scaffoldで必要なモデルやコントローラーなど一式を作成します。
モデル名はFeedとし、画像を保存するためにimageカラムを作成します。$ rails g scaffold feed image:text $ rails db:migrateアップローダファイルを作成
アップローダファイルとは アップロードに関する設定 をするためのファイルです。
アップロードに関する設定とは以下が挙げられます。
- 外部ストレージを連携するかどうか
- 保存形式
- 画像ファイルの保存先の設定
- 画像サイズの調整
$ rails g uploader Imageapp/uploader/image_uploader.rbclass ImageUploader < CarrierWave::Uploader::Base include CarrierWave::MiniMagick # MiniMagickをincludeすると画像サイズ調整ができるようになる storage :file # 保存形式の設定。他に使うものとしてはfog形式などがある。 process :resize_to_limit => [50, 50] # 画像サイズの調整 # 画像ファイルの保存先の設定 # 保存先を指定するには `store_dir` というメソッドに定義します。 def store_dir "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" end end保存形式を指定しているのが storage :file という記述です。
file以外の保存形式として クラウドのストレージ が挙げられます。
クラウドのストレージとして、Amazonが提供している S3 というサービスが有名です。file形式は画像が実体として存在しますが、クラウドのストレージにおける画像は実体が存在しません。この場合は専用のgemを利用して storage :fog という記述をします。最後に該当のモデルにカラムとアップローダを指定します。
Feedモデル内に以下を記述app/model/feed.rb~省略~ #アップローダ定義 mount_uploader :image, ImageUploader ~省略~上記の記述をすることで、feedsテーブルの中にあるimageカラムにimageUploaderという名前のアップローダ機能を追加することができます。
まとめ
アップローダ定義の意味を総括すると以下のようになります。
- feedモデルが関係しているのでfeedsテーブルが関係している
- mount_uploaderは、画像アップロードの宣言をしている
- :imageはfeedsテーブル内の画像パスが入っているカラム名を指している
- ImageUploaderは、ImageUploaderファイル内の設定を元にアップロードすることを意味している
- 投稿日:2020-02-19T01:31:24+09:00
配列で便利なメソッドを紹介するぞpart1
whereメソッド基本形
User.where(admin: true)この場合、adminがtrueのユーザーを全て取得することができる。
whereメソッドの配列で指定
User.where(kind: [1,2])この場合、kindが1、または2のユーザーを全て取得することができる。
where.notメソッド
User.where.not(id: 2)この場合、idが2のユーザー以外を取得することができる。
whereメソッドで比較
User.where("kind" > "?", 1)これでkindが1より大きいユーザーを全て取得することができる。
whereメソッドでorを使う
User.where('kind = ? or name = ?', 0, 'yamada')この場合、kindが0かnameがyamadaのユーザーを全て取得することができる。
whereメソッドでandを使う
User.where('kind = ? and name = ?, 0, "yamada")この場合、kindが0かつ、nameがyamadaのユーザーを全て取得することができる。
whereメソッドでメソッドチェーンを使う
User.where(kind: 0).where(name: 'yamada')この場合、意味は先ほどのandと同じになる。
distinct uniqメソッド
これは配列の中で被っている要素をなくすメソッド。
Sample.select(:last_name,:first_name).distinct #レコード件数を数える場合 Sample.select(:last_name).distinct.size[1,1,2,2,3,3].distinct =>[1,2,3]こんな感じで使う。
uniqメソッドも使えるが、どうやら非推奨らしい。
sampleメソッド
sampleメソッドは配列の中からランダムで要素を取り出すメソッド。
配列.sample 配列.sample(2)引数がない場合は1つだけ要素を取り出す。
- 投稿日:2020-02-19T00:02:19+09:00
Rubyの配列で使えるメソッド
Railsアプリで配列データを分けて出力しようとした時に色々試したので記録しとこうと思います。
students = ["Tom","Mike"],["Sam","Eric"],["Billy"],["Jorge","Nancy","Rick"]適当に配列を用意しました。
flatten
入力p students.flatten出力["Tom", "Mike", "Sam", "Eric", "Billy", "Jorge", "Nancy", "Rick"]配列がくっつきます。
join
入力p students.join出力"TomMikeSamEricBillyJorgeNancyRick"
これもくっつきます。
flattenのクラスはArray、joinの場合はstringです。
ただ作ってたアプリでは複数の配列からランダムに一つずつ出力したかったため、これらでは上手くいかなくて(なぜかflattenでくっつかなかった)
sample
入力p students.sample(1)出力[["Jorge", "Nancy", "Rick"]]sampleは配列の要素を1個(引数を指定した場合は自身の要素数を越えない範囲で n 個) ランダムに選んで返します。
この場合はランダムに配列を1つ出力しています。入力students.each do |student| p student.sample(1) end出力["Mike"] ["Sam"] ["Billy"] ["Jorge"]この場合は一度ループ処理をしているので各配列から一つずつ要素が出力されています。
これを応用してアプリの機能が実装できました。配列面白いですよね。
参考
- 投稿日:2020-02-19T00:01:04+09:00
Rails6 シンプルなカレンダーにDBに格納されている予定を記載する
目的
- Rails6 シンプルなカレンダーを実装するにて成功したカレンダーにDBに格納されている予定を記載する方法をまとめる。
環境
- Rails version
- 6.0.2.1
- SQLite3
- 1.4
- OS
- macOS 10.13.6
目標
- http://localhost:3000/home/topにアクセスした時にカレンダーが表示される。
- 表示されたカレンダーにDBのデータが予定として記載されるようにする。
公式の手順
条件
- 下記の記事を参考に作業を行い、http://localhost:3000/home/topにアクセスした際にカレンダーが表示されるようになっていること。
実施方法
モデルの作成とテーブル作成
下記コマンドを実行してモデルを作成する。(string型のnameカラムとdatetime型のstart_timeカラムを保有したMeetingテーブル)
$ cd アプリ名フォルダ $ rails g scaffold Meeting name:string start_time:datetime下記コマンドを実行してテーブルを作成する。
$ rails db:migrate予定の格納
下記コマンドを実行してテスト用の予定を格納する。
$ rails c irb(main):001:0> meeting = Meeting.new(name: "test", start_time: "2020-02-18 08:50:42") irb(main):002:0> meeting.save => trueビューの設定
- 下記のファイルを開く
- アプリ名ディレクトリ/app/views/home
- top.html.erb
下記の内容をtop.html.erbに記載する。(すでに記載されている内容は削除してから記載する。)
<%= month_calendar events: @meetings do |date, meetings| %> <%= date.day %> <% meetings.each do |meeting| %> <div> <%= meeting.name %> </div> <% end %> <% end %>表示の確認
下記コマンドを実行してアプリケーションをスタートする。
$ cd アプリ名フォルダ $ rails sブラウザでhttp://localhost:3000/home/topにアクセスし下記の画面が表示されるか確認する。2020年2月18日のカレンダーのセルに「test」と記載されていることを確認する。