20201017のRailsに関する記事は17件です。

本日の学習まとめ ユーザー管理機能実装にて

はじめに

 今回は完全に自分用で覚えておきたいことを雑多に書き連ねている。

正規表現

 

PASSWORD_REGEX = /\A(?=.*?[A-z])(?=.*?[\d])[A-z\d]+\z/i.freeze # 半角英数混合1字以上
ZENKAKU_REGEX = /\A[ぁ-んァ-ン一-龥]+\z/.freeze # 全角ひらカタ漢字
KANA_REGEX = /\A[ァ-ヶー-]+\z/.freeze # 全角カナ

freezeは変数が変わらないようにするため。

バリデーションのオプションをまとめる

with_options presence: true do
 validates #オプションをつける 
end

エラーメッセージを表示させる

foem_withの中でrenderメソッドでファイルを呼び出す。そのとき、devise配下のファイルであるように記述をする。

<%= form_with model: @user, url: user_registration_path', local: true do |f| %>
  <%= render 'devise/shared/error_messages', model: f.object %>
_error_messages.html.erb
<% if model.errors.any? %>
  <div id="error_explanation">
    <h2>
      <%= I18n.t("errors.messages.not_saved",
                 count: model.errors.count,
                 resource: model.class.model_name.human.downcase)
       %>
    </h2>
    <ul>
      <%= model.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
    </ul>
  </div>
<% end %>

modelを呼び出すように記述する。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails ブラウザ上で、ルートを確認する

はじめに

今回は、ブラウザ上でルートの確認の仕方について学習します。

普段は、ターミナルにrails routesをたたき、確認していました。

$ rails routes
      Prefix Verb   URI Pattern               Controller#Action
sessions_new GET    /sessions/new(.:format)   sessions#new
        root GET    /                         static_pages#home
        help GET    /help(.:format)           static_pages#help
       about GET    /about(.:format)          static_pages#about
     contact GET    /contact(.:format)        static_pages#contact
      signup GET    /signup(.:format)         users#new
             POST   /signup(.:format)         users#create
       login GET    /login(.:format)          sessions#new
             POST   /login(.:format)          sessions#create
      logout DELETE /logout(.:format)         sessions#destroy
       users GET    /users(.:format)          users#index
             POST   /users(.:format)          users#create
    new_user GET    /users/new(.:format)      users#new
   edit_user GET    /users/:id/edit(.:format) users#edit
        user GET    /users/:id(.:format)      users#show
             PATCH  /users/:id(.:format)      users#update
             PUT    /users/:id(.:format)      users#update
             DELETE /users/:id(.:format)      users#destroy

ブラウザ上で確認する方法

(http://localhost:3000/rails/info/routes)

こちらにアクセスするだけです!

左の列から
-Helper
-HTTP Verb
-Path
-Controller#Action

となっていて、構成はターミナルと変わりません。

こちらの方が見やすいですね!

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

EC2にRAILSをデプロイ

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

Rails if文とunlessの混合条件式の作成

最終課題に向けて調整を行いました。
その際に、条件式をifとunlessの両方を使用するという特殊なパターンに
チャレンジしてみました。備忘録として投稿させて頂きます。

今回はhamlにて記述しています。

sample.rb
#viewファイルにて

.item-show-page__link-btn
        -if @item.buyers.present?
          %p SOLD OUT
        -else
          - unless user_signed_in? && @item.user_id == current_user.id
            = link_to purchase_item_path(@item.id), class: "item-show-page__link" do
              購入画面へ
          - else
            %p 出品者は購入できません

メソッドの中身
@item 出品情報が入っています。
buyers 購入した履歴のメソッドになります。

解説

if〜else
もし購入した履歴のIDが存在したらSOLD OUTを表示

unless~else
if文のelseの中に入れ子として格納しています。そこからunlessの条件式を入れています。
もし出品した商品とユーザーIDが一致しない場合は購入画面に遷移するリンクを出現。
そうでない場合は「出品者は購入できません」と出現させる。

以上となります。

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

Javascriptで日付を扱う(moment.js)

はじめに

Qiita初投稿です。
間違っていることがありましたら、ご指摘いただけると幸いです。

開発環境

ruby 2.6.5
Rails 6.0.3.3

概要

moment.jsとはjavascriptで日付を扱うときに便利なライブラリです。
パッケージ管理面での欠点があるとも言われていますが、まだ主流な技術なので使用してみました。 

使用方法

作業中のディレクトリでmoment.jsをインストールします

npm install moment

使用したいjsファイルでmomentを読み込みます

〇〇.js
var moment = require(moment);

↓このような書き方で生成できます

〇〇.js
const dt = new moment();

しかし、これだけだとrails sで引っかかります。
↓おそらく、yarnの再インストールが必要になります。

error Lockfile does not contain pattern: "moment@^2.29.1"                                                                                                              
error Found 1 errors.                                                                                                                                                  


========================================
  Your Yarn packages are out of date!
  Please run `yarn install --check-files` to update.
========================================


To disable this check, please change `check_yarn_integrity`
to `false` in your webpacker config file (config/webpacker.yml).

check_yarn_integrityはデフォルトでFalseとなっているので
yarn install --check-filesだけを実行してみます

yarn install --check-files

問題なく使うことができました

最後に

moment.jsはレガシーな技術で今後はあまり使われなくなるかも知れません。
day.jsの方が軽量で管理面でも上位互換だとも言われていますが,
現役で活躍していることもあるので試験的に使用してみました。

移行する際は、この方の記事が参考になります。(勝手に掲載してすいません)
https://qiita.com/oika/items/2d15aea7809ab358ba25

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

Spree::Productのカラムを解説

solidus使っていると初心者にとっては「。。。ん?」みたいな状態ですよね。
この記事を読まれていると言うことは少し全体像が掴めて、「Spree::Productにはどう言ったカラムが存在するんだ?」と言うところなのかなと思います。:point_up:
そこで今回は「Spree::Product」内のカラムについて簡潔に紹介と説明をしていきます。

Solidusのバージョン

solidus 2.0.9

カラムの紹介と説明

Spree::Productのid=1をのぞいてみましょう。
スクリーンショット 2020-10-17 15.41.43.png
それではここにあるカラムについて説明します。

id

idです。笑

name

商品名。

description(description:説明する)

商品紹介文。

available_on(available:利用可能な)

ストアで買うことができるようになる日付。
未設定の場合、表示されない。

deleted_at(delete:削除)

available_onの逆で、ストアで買えなくなる日付。

slug(IT用語:位置を示すコード)

「位置を示すコード」等の意味がある(IT用語)。URL(パーマリンク)の末尾の部分を任意の文字列に指定できる機能があり、SEOにも関係がある。

meta_description(meta:高次〜)

SEO用で、サーチエンジン向けの説明。

meta_keywords

SEO用で、サーチエンジン向けのキーワード。

tax_category_id

商品の税区分

shipping_category_id(shipping:運送)

配送料の指定。

created_at

商品が作られた日時。

updated_at

商品が更新された日時。

promotionable

Promotionルールに基づく金額を生成する。

meta_title

HTMLのtitleタグ用。空欄の場合はnameが代用される。

駆け出しsolidus開発者にとってSpree::Productモデルを理解する糧になれば幸いです!

もし間違っていたらご指摘をお願いします。。

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

Ruby on Rails で特定のViewにCSS を適用する

Ruby on Rails で作ったWebアプリケーションのあるページで、Tableタグで作った表中の文字が上揃えになっていました。
このままでは見た目が悪いので、上下中央揃えとなるよう、CSSを適用する方法を調べましたので自分用メモとして残します。

1.何を修正すれば良いのか?

/marketpurser/app/assets/stylesheets 内のファイルです。
デフォルトで存在するapplication.scss に追記すると、すべてのViewに適用されます。
また、Viewの名前に対応した.scssファイルに追記すると、特定のViewのみに適用されます。

2.どう記述すれば良いのか?

CSSと同じ文法で良いようです。
今回はtableクラスを持ったtableタグ内の、tdタグに適用したいので、以下のように記述しました。

/marketpurser/app/assets/stylesheetssample.scss
table.table td {
 vertical-align:middle;
}
sample.html.erb
<table class="table">
  <thead>
    <tr>
      <th>#</th>
      <th>Info</th>
    </tr>
   </thead>
   <tbody id="myTable">
    <tr>
      <td>1</td>
      <td>data1</td>
    </td>
   </tbody>
</table>

解決しました。
なお、単にブラウザを再読み込みするのではなく、もう一度修正したViewのページにアクセスしないとCSSが反映されませんでした。(初歩的なミス)

以上、個人的なメモでした。

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

certbot停止からの再インストール

はじめに

certbotが死にました。。
というよりかは本番環境で運用していたhttps通信の証明証がいきなり破棄されて、戻すのに大変だったので備忘録。

開発環境

ruby 2.5.7
Rails 5.2.3
AWS ec2
nginx
puma

手順

cd ~
rm -r -f certbot
git clone https://github.com/certbot/certbot.git
cd certbot/
chmod a+x certbot-auto
sudo ./certbot-auto --nginx --debug 
※あとはyesに答えるだけ

エラー集

エラー①

エラーコード

Traceback (most recent call last):
  File "<stdin>", line 27, in <module>
  File "<stdin>", line 19, in create_venv
  File "/usr/lib64/python2.7/subprocess.py", line 185, in check_call
    retcode = call(*popenargs, **kwargs)
  File "/usr/lib64/python2.7/subprocess.py", line 172, in call
    return Popen(*popenargs, **kwargs).wait()
  File "/usr/lib64/python2.7/subprocess.py", line 394, in __init__
    errread, errwrite)
  File "/usr/lib64/python2.7/subprocess.py", line 1047, in _execute_child
    raise child_exception
OSError: [Errno 2] No such file or directory

原因

  • pythonのバージョンの不一致

改善コード

alternatives --set python /usr/bin/python2.7

エラー②

エラーコード

pkg_resources.DistributionNotFound: The 'virtualenv==15.1.0' distribution was not found and is required by the application

原因

  • virtualenvのバージョンの不一致

改善コード

sudo pip uninstall virtualenv
pip install virtualenv==15.1.0

エラー③

エラーコード

pkg_resources.DistributionNotFound: The 'pip==9.0.3' distribution was not found and is required by the application

原因

  • pipのバージョンの不一致

改善コード

sudo easy_install pip == 9.0.3

参考サイト

https://yoshinorin.net/2018/09/10/letsencrypt-cannot-update/

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

"~"で任意の文字を囲む方法

【概要】

1.結論

2.どのようにコーディングするか

3.開発環境

1.結論

gets.chomp、lengthメソッドを使用する!!


2.どのようにコーディングするか

str = gets.chomp #---❶
str_length = str.length
puts('~' * (str_length + 2)) #---❷
puts('~'+str+'~') #---❸
puts('~' * (str_length + 2)) #---❷

このようにすると、下記のようになります。
スクリーンショット 2020-10-17 15.41.09.png

❶:.chompを入れないと下記のようになります。改行をして2行目の最後の"~"をくっつけています。
スクリーンショット 2020-10-17 15.42.50.png
❷:lengthメソッドで入力したの文字の長さに +2しています。+2する理由は左上の"~"と右上の"~"の角っこを加えています。
❸:入力した文字の両端に"~”を加えています。

3.開発環境

Mac catalina 10.15.4
Vscode
Ruby 2.6.5
Rails 6.0.3.3

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

curl: (77) error setting certificate verify locations: CAfile: ~/anaconda3/ssl/cacert.pem CApath: none の対処法

概要

RVMをインストールする際に \curl -sSL https://get.rvm.io | bash -s stableを実行したところ、
次のようなエラーが出た。

curl: (77) error setting certificate verify locations: 
CAfile: ~/anaconda3/ssl/cacert.pem 
CApath: none

対処法

以下の処理を実行する。

conda update curl
conda install ca-certificates

以上です。

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

[rails] devise導入中のエラー

devise導入中に下記のエラーが出ました。
gemをbundle installしたのち、rails g devise:installを実行。
その後、rails g devise userを実行したのち、rake db:migrateを実行した時に発現したエラーです。

エラー

Mysql2::Error: Table 'development.users' doesn't exist
/Users/projects/db/migrate/20201016082907_add_devise_to_users.rb:7:in `block in up'
/Users/projects/db/migrate/20201016082907_add_devise_to_users.rb:5:in `up'
/Users/projects/bin/rails:9:in `<top (required)>'
/Users/projects/bin/spring:15:in `<top (required)>'
bin/rails:3:in `load'
bin/rails:3:in `<main>'
Caused by:
ActiveRecord::StatementInvalid: Mysql2::Error: Table 'development.users' doesn't exist
/Users/projects/db/migrate/20201016082907_add_devise_to_users.rb:7:in `block in up'
/Users/projects/db/migrate/20201016082907_add_devise_to_users.rb:5:in `up'
/Users/projects/bin/rails:9:in `<top (required)>'
/Users/projects/bin/spring:15:in `<top (required)>'
bin/rails:3:in `load'
bin/rails:3:in `<main>'
Caused by:
Mysql2::Error: Table 'development.users' doesn't exist
/Users/projects/db/migrate/20201016082907_add_devise_to_users.rb:7:in `block in up'
/Users/projects/db/migrate/20201016082907_add_devise_to_users.rb:5:in `up'
/Users/projects/bin/rails:9:in `<top (required)>'
/Users/projects/bin/spring:15:in `<top (required)>'
bin/rails:3:in `load'
bin/rails:3:in `<main>'
Tasks: TOP => db:migrate
(See full trace by running task with --trace)
=================================

解決方法
初学者でまず何が起こっているのかわからなかったので、
現状のテーブルがどれが動いているのか確認しました。

rails db:migrate status

結果

〇〇-no-MacBook% rake db:migrate:status
database: development
 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20201013135213  Create items
   up    20201014013111  Create users
  down    20201016082907  Add devise to users

ここでdeviseをbundle installする前に、
試しに作っていた、userテーブルができてしまっていることに気がつきました。

必要ないかもしれないですが一度テーブルを元に戻すために下記を実行

rails db:rollback

全てdownの状態にしました。
その後、不必要な、20201014013111 Create usersを削除

rm -rf db/migrate/20201014013111_create_users.rb

テーブルを削除した後、

〇〇-no-MacBook% rake db:migrate:status                          
database: NF_development
 Status   Migration ID    Migration Name
--------------------------------------------------
  down    20201013135213  Create items
  down    20201016082907  Add devise to users

そして

〇〇-no-MacBook% rails db:migrate                                   
== 20201013135213 CreateItems: migrating ======================================
-- create_table(:items)
   -> 0.0173s
== 20201013135213 CreateItems: migrated (0.0174s) =============================

== 20201016082907 AddDeviseToUsers: migrating =================================
-- change_table(:users)
rails aborted!
StandardError: An error has occurred, all later migrations canceled:

さらにエラーが出てしまいました。
原因は、deviseをinstallした際に本来、createでできるものがchangeになっておりエラーが発生
下記に修正しました。

class CreateItems < ActiveRecord::Migration[6.0]
  def change→create
    change→create_table :items do |t|
      t.string :name
      t.string :text
      t.text :image
      t.integer :category_id
      t.integer :item_id
      t.timestamps
    end
  end
end

その後、deviseをアンインストールするために削除

〇〇-no-MacBook% rails d devise user             
Running via Spring preloader in process 73770
Deprecation warning: Expected boolean default value for '--orm'; got :active_record (string).
This will be rejected in the future unless you explicitly pass the options `check_default_type: false` or call `allow_incompatible_default_type!` in your code
You can silence deprecations warning by setting the environment variable THOR_SILENCE_DEPRECATION.
      invoke  active_record
      remove    db/migrate/20201016082907_add_devise_to_users.rb
      remove    app/models/user.rb
      invoke    test_unit
      remove      test/models/user_test.rb
      remove      test/fixtures/users.yml
       route  devise_for :users

そして最後に、再度deviseをinstallし正常に動くようになりました。

〇〇-no-MacBook%rails g devise user 
Running via Spring preloader in process 73899
Deprecation warning: Expected boolean default value for '--orm'; got :active_record (string).
This will be rejected in the future unless you explicitly pass the options `check_default_type: false` or call `allow_incompatible_default_type!` in your code
You can silence deprecations warning by setting the environment variable THOR_SILENCE_DEPRECATION.
      invoke  active_record
      create    db/migrate/20201016152820_devise_create_users.rb
      create    app/models/user.rb
      invoke    test_unit
      create      test/models/user_test.rb
      create      test/fixtures/users.yml
      insert    app/models/user.rb
       route  devise_for :users

初学者なので2,3時間かかってしまいました。
誰かのお役に立てれば嬉しいです。

参考
Qitta:【Rails】マイグレーションファイルの削除
https://qiita.com/ISSO33/items/33a935cb3255c269bef2

Qitta:Rails 本番環境 ActiveRecord::StatementInvalid (Mysql2::Error: Table 'テーブル名' doesn't exist):
https://qiita.com/ashketcham/items/a0d0a2ac788779895fb4

Qiita:Mysql2::Error::ConnectionError: Access denied for user
'root'@'localhost' (using password: YES)の解決法
https://qiita.com/naota7118/items/b62d71484e21d6739d68

Qiita:deviseのアンインストール
https://qiita.com/NT90957869/items/8c5285775a67a51f03e1

teratall:[rails] devise導入中のエラー
https://teratail.com/questions/214948

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

Rails zshを使った環境変数 設定の仕方と記述方法

Google Map API を使用中自分で取得したAPIをそのまま記述してGit Hubのpushしてしまいました。
するとGit Hubからこんなメールが…
GitGuardian has detected the following Google Key exposed within your GitHub account.
GitGuardian は、あなたの GitHub アカウント内で公開されている以下の Google キーを検出しました。
素晴らしい!GitHubはこんなことまでしてくれるのだと感動しました。
感動している場合ではないのですぐ環境変数に入れて記述を変えようといろいろ調べたので共有させてください

環境変数とは何か

見せたくないものを隠す変数…といったイメージで良いと思います

そして環境変数を設定できるものはたくさんあるのでご自身で良いものを探してみてください!
私の場合はzshを使って環境変数をし設定していきます

zshは自称「最強」のシェルらしいです

Zshのインストール方法

初心者向け:Zshの導入
こちらの記事がとてもわかりやすかったです!
こちらの記事からZshをインストールしてきてください

Zshを使った環境変数の設定の仕方

% vim ~/.zshrc

で.zsherを開きます
すると
スクリーンショット 2020-10-17 12.13.25.png
こんな画面になっていると思います
自分はすでにいろいろ設定しているので記述されている内容が多いですが無視してください
この画面が開いたらとりあえず「i」を入力してください
左下に

-- INSERT--

と出ていると思いますこれをインサートモードと言います
入力ができるようになるので

export 使いたい変数名='隠したい値' # イコールにはスペースを入れないように気をつけてください

export GOOGLE_MAP_API='hoge'

このように記述すれば設定完了です

インサートモードを抜けるコマンドはescキー抜けれます抜けた後
設定を保存する際は「:wq」
保存しないときは「:q!」
で終了してください

その後
.zshrcを再読み込みし、定義した環境変数を有効にします

source ~/.zshrc

で環境変数の設定は終わりです。

設定した環境変数の使い方

基本的には

ENV['設定した環境変数']

と使います
APIを使用したりしてAPI KEYをviewに記述するときは

<%= ENV['設置した環境変数'] %>

と記述します
以上になります!

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

Rails Tutorial 拡張機能の返信機能を作ってみた(その1)

Rails Tutorialの第14章にある拡張機能について

Rails Tutorialをの第14章には、Tutorialを完了した人向けに、自分で機能を拡張するお題がいくつかあります。
最初のお題である、返信機能に挑戦しています。まだ作成途中ですが、できたところまで投稿します。

作る要件を確認し、仕様を作る

要件は以下のように書かれています。

Twitterには、マイクロポスト入力中に@記号に続けてユーザーのログイン名を入力するとそのユーザーに返信できる機能があります。このポストは、宛先のユーザーのフィードと、自分をフォローしているユーザーにのみ表示されます。この返信機能の簡単なバージョンを実装してみましょう。具体的には、@replyは受信者のフィードと送信者のフィードにのみ表示されるようにします。

仕様のヒントも書かれています。

これを実装するには、micropostsテーブルのin_reply_toカラムと、追加のincluding_repliesスコープをMicropostモデルに追加する必要があると思います。

要件を具体的にブレークダウンします。

@replyが表示されるのは、以下の3者
replyの受信者
replyの送信者(自分)
replyの送信者のフォロワー

上記以外のユーザーには表示されない

・マイクロポストの先頭に「@reply ユーザーのログイン名」を入力したときに、このポストをreplyと判定

仕様を深堀する、例示されているtwitterを参考にするため調べる

Tutorialの「6.2.5 メールアドレスの一意性」を読み返したところ、大文字と小文字の区分けをするか書いてありました。
ユーザー名に大文字と小文字で区分けをすべきなのか、TaroとTAROを違うものとするかどうかです。
twitterはどうなのかネットで調べます。

内部では同じだが、入力時に区分けはするという記事が多かったです。ズバリ書いている記事が見つからなかったです。
メアドと同じ仕様で作ることにします。

この大文字小文字の機能は、最初からではなく後で追加することにしました。後から追加するのが簡単そうに見えたためです。

どういう機能を作るか、以前に追加した機能に似ているので読み返す

以前に追加した機能に似ているので、どの機能と似ているか読み返します。

13章のマイクロポストの機能に似ている
6.7章のユーザー登録の機能に似ている
6.2.5 一意性を検証する 
  メールアドレスの一意性

その結果をもとに、以下のような機能を考えました。

・replyで表示する/しないの判定ができる機能をmodelに追加
 このpostはreplyかどうか
@replyの入力を判別する機能をviewまたはcontrollerに追加
・ユーザー名がユニークになるように、modelとviewに追加

最後の「ユーザー名がユニーク」の機能は、最初からではなく後で追加することにしました。まずはユニークなテストデータだけで動くものを作ってみて、後からユニークにする制約の機能を付け加えればよいと考えたためです。

機能を詳しく設計する モデル

14章の14.1.1を再度読みます。id間のrelatoinのことでした。

micropostsテーブルのin_reply_toカラムと、追加のincluding_repliesスコープをMicropostモデルに追加する必要があると思います。

をヒントに、modelをどう変更するか考えます。

microposts

列名 属性
id integer
content text
user_id integer
in_reply_to integer
created_at datetime
updated_at datetime

in_reply_to の列を追加するとして、型は何になるか?どのユーザーか特定するのだから、idと同じでintegerと考えました。

機能を詳しく設計する メソッド

micropostのメソッドを追加するか、既存のメソッドを変更するか。
表13.1を参考にします。
user.micrposts   Userのマイクロポストの集合をかえす 既存の変更
user.microposts.build(arg) userに紐付いた新しいMicropostオブジェクトを返す 既存の変更
user.microposts.find_by(id: 1) userに紐付いていて、idが1であるマイクロポストを検索する 既存の変更

replyのメソッドを追加するか、考えます。
user.microposts.create(arg,reply:user2) user2へのreplyのマイクロポストを作成する
既存のcreateメソッドを変更することにします。

機能を詳しく設計する ビュー

画面は主に2つ修正、replyを入力するところと、replyを表示するところです。

入力項目は増やす必要がない、なぜなら、contentの先頭に@replyと記入するからと考えました。

出力でreply専用の画面が必要か? 
Twitterを調べます。replyは元Tweetをクリックすると別画面に移ってreplyの一覧を表示しています。replyの親子のTweetを一覧で表示しています。

ちょっと複雑なので今回はそこまではやらず、元Tweetと同じ画面に表示することにします。

画面のイメージは、モックを作るのは面倒なのでテキストだけです。
comment box : @reply michael Cum aspermatur ..

Feedの表示イメージ
@reply michael Cum aspermatur ..

機能を詳しく設計する ビューの入力エラーチェック

user_idが見つからないときは、親切な設計なら入力時にエラーを表示します。createするときにチェックするはずなのでエラーを表示することにします。

postをした後で、user_idが削除されたケースはどうするか?
このmicropostを削除するべきか。もういない人にreplyしたmicropostだけが残っているほうがよいと考え、micropostは削除しないと考えます。

所要時間

9/27から10/1までの3.0時間です。

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

【CircleCI】CircleCIの自動テストでハマった(rails + mysql)【メモ】

はじめに

CircleCIを使ってRailsアプリの自動テストをやろうとしてハマったのでメモ。
特にmysqlコンテナとの接続が上手くいかず、ロクに考えずconfigをいじりまくっていたらCircleCIの無料枠を食いつぶすことになりました。
各種設定ファイルの内容や、エラーへの対策を備忘録として残すことに。

環境

CircleCI  2.1
Bundler  2.1.4
Rails 6.0.3.4
ruby 2.6.5
MySQL 5.7

開発環境はDocker-composeで構築。
サービス名とコンテナ名の関係は以下のよう。

サービス名 コンテナ名
web webapp_web_1
db webapp_db_1
app webapp_app_1

設定ファイル

アプリ名はwebappとする。

database.ymlとdb.env

データベースの設定ファイル。
この設定がCircleCI側で上手く使えなかったので、今回は以下の記事を参考にCircleCI用のデータベース設定ファイルを作成することにしました。
よって、ここの設定はCircleCIとは関係ないです。
CircleCI 2.0の設定メモ

config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: <%= ENV.fetch('MYSQL_USER') { 'root' } %>
  password: <%= ENV.fetch('MYSQL_PASSWORD') { 'rootpass' } %>
  port: 3306
  host: db

development:
  <<: *default
  database: webapp_development

test:
  <<: *default
  database: webapp_test
environments/db.env
MYSQL_ROOT_USER=root
MYSQL_ROOT_PASSWORD=rootpass
MYSQL_USER=kagamiya
MYSQL_PASSWORD=kagamiya

ポートの設定は要らないかも。
host: dbはDocker-composeのサービス名です。
ENV.fetchの{ 'root' }とかも要らないと思います。

database.yml.ci

CI用のデータベース設定ファイル。
CirclCIでの自動テストではこちらを使います。

config/database.yml.ci
test:
  adapter: mysql2
  encoding: utf8
  pool: 5
  username: 'root'
  port: 3306
  host: '127.0.0.1'
  database: webapp_test

config.yml

肝心のCircleCIの設定ファイル。
参考はこちら。
CircleCIでテストを自動化

circleci/config.yml
version: 2.1 # バージョン指定  

executors:  
  default:  
    working_directory: ~/webapp  
    docker:  
      - image: circleci/ruby:2.6.5-node
        environment:  
          BUNDLER_VERSION: 2.1.4
          RAILS_ENV: test
          DB_HOST: 127.0.0.1
          DB_USERNAME: 'root'
          DB_PASSWORD: ''
      - image: circleci/mysql:5.7 
        environment:
          MYSQL_ROOT_HOST: '%'
          MYSQL_ALLOW_EMPTY_PASSWORD: 'true'

commands:  
  setup:  
    steps:  
      - checkout  
      - run:  
          name: Update bundler # bundlerのバージョン2へのアップデート  
          command: gem update bundler  

      - run:  
          name: Which bundler? # バージョン確認  
          command: bundle -v  

      - restore_cache: # キャッシュを読み込む  
          keys:  
            - gem-cache-v1-{{ checksum "Gemfile.lock" }}  
            - gem-cache-v1-  

      - run:  
          name: Bundle Install  
          command: bundle check --path vendor/bundle || bundle install --deployment  

      - save_cache: # キャッシュを保存する  
          key: gem-cache-v1-{{ checksum "Gemfile.lock" }}  
          paths:  
            - vendor/bundle  

      # 以下はRails6でWebpackerを使う場合は必須   
      - restore_cache:  
          keys:  
            - yarn-cache-v1-{{ checksum "yarn.lock" }}  
            - yarn-cache-v1-  

      - run:  
          name: Yarn Install  
          command: yarn install --cache-folder ~/.cache/yarn  

      - save_cache:  
          key: yarn-cache-v1-{{ checksum "yarn.lock" }}  
          paths:  
            - ~/.cache/yarn  

jobs:  
  test:  
    executor: default  
    environment:  
      RAILS_ENV: test  
    steps:  
      - checkout  
      - setup  
      - run:  
          name: Wait for DB  
          command: dockerize -wait tcp://127.0.0.1:3306 -timeout 90s  

      - run:
          name: Use specific database.yml # CircleCI用のデータベース設定を使う
          command: mv config/database.yml.ci config/database.yml

      - run:  
          name: Database setup  
          command: |
            bin/rails db:create
            bin/rails db:schema:load --trace  

      - run: # 普通のテストとシステムテストを実行する  
          name: Rails Test  
          command: |  
            bin/rails test  
            bin/rails test:system  

workflows:  
  build_and_test:  
    jobs:  
      - test  

(MySQLの8系を使う場合は記述の追加が必要なようで、5.7を使うことにしました。
また、rubyのイメージはnodeがついていないとyarnコマンドが使えませんでした。)

特にデータベース周りの設定でハマりました。
というのも、私がMySQLの仕様をあまり理解できていなかった(というか今も理解できていない)からで…
当初は参考記事にならって、

DB_USER: 'kagamiya'
DB_PASSWORD: 'kagamiya'

MYSQL_USER: 'kagamiya'
MYSQL_PASSWORD: 'kagamiya'

としていました。
しかし、そもそもkagamiyaなんていうユーザーはCircleCIのMySQLイメージには登録されていません。(開発環境のdbコンテナにはもちろんありますが)
そこで必然的にrootを使うことになるので、以下のようにしました。

DB_USER: 'root'
DB_PASSWORD: 'rootpass'

MYSQL_USER: 'root'
MYSQL_PASSWORD: 'rootpass'

しかし、上手くいきませんでした。
というのは、rootユーザーのデフォルトのパスワードは設定されていないからです(多分)。
そういうわけで、パスワードを空にしても上手くいきません。

DB_USER: 'root'
DB_PASSWORD: ''

MYSQL_USER: 'root'
MYSQL_PASSWORD: ''

というわけで、ユーザーはroot、パスワードはMYSQL_ALLOW_EMPTY_PASSWORD: 'true'として(空を許可?)で接続しなければならないようです。

      - image: circleci/ruby:2.6.5-node
        environment:  
          BUNDLER_VERSION: 2.1.4
          RAILS_ENV: test
          DB_HOST: 127.0.0.1
          DB_USERNAME: 'root'
          DB_PASSWORD: ''
      - image: circleci/mysql:5.7 
        environment:
          MYSQL_ALLOW_EMPTY_PASSWORD: 'true'

ここでまたまたエラーを吐きました。

Access denied for user 'root'@'127.0.0.1'

ここの理解に苦しんだのですが、どうやら'root'@'127.0.0.1'というユーザーはいないということのようです。
mysqlのユーザー一覧を見てみると、'root'@'%'やら'root'@'localhost'はいますが、'root'@'127.0.0.1'はいません。
mysqlのホスト名(DB_HOST)にlocalhostを使うか127.0.0.1を使うかは、また別の問題として色々あるようです。
しかしながら、今は接続することが最優先なので、rootのホストとして%を指定してやります。
(%は「全てのホスト」という意味だそうですが、よく分かりません)

MYSQL_ROOT_HOST: '%'
MYSQL_ALLOW_EMPTY_PASSWORD: 'true'

理由はどうあれ、これでやっと接続できました。

次に、CircleCIのイメージでは独自のデータベース設定を使うため、database.ymlをdatabase.yml.ciで上書きします。
データベースのセットアップ前に処理を追加します。

      - run:
          name: Use specific database.yml # CircleCI用のデータベース設定を使う
          command: mv config/database.yml.ci config/database.yml

私の環境では、指定したデータベース(webapp_test)が無いと怒られたので、データベースの作成を行いました。

      - run:  
          name: Database setup  
          command: |
            bin/rails db:create
            bin/rails db:schema:load --trace  

(ここは次回以降の実行でエラーの原因になるかも…?)

まとめ

MySQLの仕様とconfigの内容は理解しきれていません。
configのサンプルは多くの方がアップしておられますが、詳細まで解説されているものが少ない印象です。
よって、自分が理解できていない部分でエラーとなればまたハマる可能性が大ですね…

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

javascriptを使用して、音声や音楽を流す方法

前置き

私は独学でプログラミング学習を始めて3か月の初学者です。
何度も壁にぶつかりながら、学習を進めていく中で、先駆者の方々の記事に助けられてきました。
私も悩んでいる方の助けになればと思い、記事を投稿することにしました。

この記事はWebアプリの制作過程で、Javascript(以後JSと略称を使用します)のイベント時や特定の処理を実施した際に、音声を再生したいという思いから調べた内容がもとになっています。
もともとHTMLにはaudio要素があり、audio要素のsrc属性にファイルの場所を指定して利用することで音声を再生できます。
しかし、Railsの環境下だとファイル場所の指定がうまくいかず、つまずいた結果、『audiojs-rails』というGemを使用することにしました。

目的

この記事では、『再生プレイヤーを非表示にして、HTMLのInputボタンを押した際に音声を再生する』ということを目的として記載していきます。アレンジを行えば、特定の処理が終わった後に再生をするということが可能になります。

使用環境

OS:Win10
Rails 5.2.4.4
Ruby 2.6.6
現在はローカル環境で開発中

目次

◆Gemのインストールと使用方法
◆特定のイベントによって再生ができるようにアレンジ
◆再生プレイヤーを非表示に!

◆使用するGemのインストールと使用方法

1.Gemfileに下記の内容を追加してbundle installを行います。

※rails serverを起動している場合は再起動してください。

gem 'audiojs-rails'
2.audiojsの初期化と再生プレイヤー設置

音声データを再生したいViewに下記の内容を記載します。
audiojs.createAll()によって再生プレイヤーが作成されます。
※再生プレイヤーはいらないよ!って方でも、再生できるか確かめるために下記の内容をViewへ記載することをお勧めします
※sample.mp3は、ご自分が用意した音源ファイルの名前に変更してください。

<!-- 再生プレイヤー -->
<%= audio_tag 'sample.mp3' %>

<!-- audiojsの初期化 -->
<script>
    const audioPlayer = audiojs.createAll();
</script>
3.assetsパスの追加

上記で設置した再生プレイヤーで読み込んでいる『sample.mp3』は音声ファイルの名前です。
お好きなファイルを用意していただければよいのですが、保存場所には注意が必要です。
必ず、app/assets/audios/に配置するようにしましょう。(私はaudiosのフォルダがなかったので作成しましたが正常に動作しました。)

しかし、保存しただけでは使用できませんので、アセットパイプラインで配信するために、assetsパスを追加します。
config/initializers/assets.rb に下記を追加します。

config/initializers/assets.rb
Rails.application.config.assets.paths << Rails.root.join("app", "assets", "audios")
4.assetsパスが追加されたか確認する。

皆さんが使用しているコマンドラインで、Rails consoleを起動して下記の内容を打ち込んでください。

Rails.application.config.assets.paths

結果として、末尾にaudiosと書かれたフォルダパスが読み込まれていれば問題なさそうです。
※下記のフォルダパスは一例なので、皆さんがWebアプリを保存している場所によって変わります。

"C:/Users/sample/ruby/webapp/app/assets/audios"

パスが追加されたことを確認したら、再生できるか試してみましょう。
再生ができたら、準備満タンです。

◆特定のイベントによって再生ができるようにアレンジをする。

1、ViewにInputタグを追加してIDを設定し、それをScriptで読み込む。

今回は、operationというIDを振って変数に代入しています。

<input type="submit" id="operation">
<script>
    const operation = document.getElementById("operation");
    const audioPlayer = audiojs.createAll();
</script>
2.再生プレイヤーの情報をaudio変数に代入して、inputをクリックしたときに、音声の再生を行う。

※必ず、audioPlayerのインデックス番号 [0] を入れた変数を用意してください。
audioPlayer.play();と入力しても動作しません。

<input type="submit" id="operation">
<script>
    const operation = document.getElementById("operation");
    const audioPlayer = audiojs.createAll();
# ここから追加した内容
    const audio = audioPlayer[0];

    operation.addEventListener("click", () => {
        audio.play();
    });
# ここまで
</script>

なぜ audio に対して audioPlayer[0] を入れなければいけないのかは厳密には理解できていませんが、
audioPlayerの中身をConsole.logで覗いてみると下記のようになっていることがわかりました。
キャプチャ.PNG
再生プレイヤーを生成したときの情報がaudioPlayerに入っています。
故にインデックス番号0の中身に音声ファイルの情報や、再生や停止といった操作にかかわる情報が入っているため、それを指定しないと動作しないのではないかと推測しています。

◆再生プレイヤーを非表示に!

あとは簡単、Audio_tagをDivタグで囲ってあげて、CSSのDisplayをnoneにしてあげるだけです。

<div class="none">
    <%= audio_tag 'decision48.mp3' %>
</div>    

最後に

今回いろんな記事の情報を自分なりに操作した内容をまとめてみました。
何かお気づきな点ございましたら、お教えていただけると助かります。
参考にさせていただいた記事もまとめておきますので、ご興味のある方は是非!

【Rails】audiojs-railsの導入からオーディオファイル再生までの手順
↑再生プレイヤーのオプションもまとめられています。再生プレイヤーをいじりたい人は是非。
MP3を再生するjavascript(audio.js)のメモ
↑jQueryを使用して、再生ボタンや停止ボタンを作っています。応用すればJSだけでも同じことができるかもしれません。

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

どうやら本番サーバー上でsidekiqをサービスで動かすと環境変数が別物のようだ

概要

AWSのEC2上でsidekiqをsystemdでサービス化して起動していたところ、通したはずのPythonコマンド用の環境変数のPATHが効かない現象が起きたので調査した。

調査

コード中のいろんな箇所にwhoamiや環境変数を確かめるコマンドを差し込んだりした結果、
sidekiqのジョブとPOSTリクエストを受けているcontrollerで実行しているユーザが違うことからsidekiqをサービス起動する設定が怪しいことに気がついた。

ちなみにRspecやローカル環境は実行ユーザーに環境変数が効いていたからなのかsidekiqで失敗するジョブもオールグリーンだった。

ところでSystemdってなに?
ってぐぐってみたらこの記事が参考になった。

これからSystemd入門する
https://qiita.com/bluesDD/items/eaf14408d635ffd55a18

対処法

systemdのsidekiq.serviceファイルの設定を書き換えてはサービスやOSの再起動を繰り返して微調整し、OS起動直後やサービス再起動しても差し込んだコードに環境変数が効く状態になった。

systemdのsidekiq.serviceファイル

環境変数を読みこむシェルスクリプトを実行するようにExecStartPreを追記。

/etc/systemd/system/sidekiq.service
[Unit]
Description=sidekiq
After=syslog.target network.target

[Service]
WorkingDirectory=/var/www/hoge-app
ExecStartPre=/bin/sh /var/www/hoge-app/aws/service/sidekiq_exec_start.sh
ExecStart=/root/.rbenv/bin/rbenv exec bundle exec sidekiq -e production

・・・(中略)・・・

[Install]
WantedBy=multi-user.target

ExecStartPreで実行するシェルスクリプト

sourceで.bash_profile読んだり、exportでなど何らかの形で環境変数を設定(※)した後、systemctlのset-environmentでsystemdでも同じ環境変数を使えるようにする。
※環境によってはどちらか一方かもしくは無くても動くかもしれない。

/var/www/hoge-app/aws/service/sidekiq_exec_start.sh
source /home/ec2-user/.bash_profile
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"

# systemdにも環境変数を適用
/bin/systemctl set-environment PYENV_ROOT="$PYENV_ROOT"
/bin/systemctl set-environment PATH="$PATH"

# Python関連の設定処理
pyenv global 3.8.3
eval "$(pyenv init -)"

# この時点で設定されている環境変数を任意のログファイルに書き出す。(デバッグ用)
LOGFILE=/var/www/hoge-app/log/production.log
echo "Sidekiq Service Exec Start Pre --------" >> $LOGFILE
echo "$PYENV_ROOT" >> $LOGFILE
echo "$PATH" >> $LOGFILE
python -V >> $LOGFILE
whoami >> $LOGFILE
echo "-------------------------------------" >> $LOGFILE

サービス再起動

systemctl daemon-reload 
systemctl restart sidekiq.service

サービスのステータスがactiveかつ、ProcessのExecStartPreの記載が設定と一致していれば設定は成功。
後は実際にアプリケーションを動作させて確認。

[root@ip-*-*-*-* hoge-app]# systemctl status sidekiq.service
● sidekiq.service - sidekiq
   Loaded: loaded (/etc/systemd/system/sidekiq.service; enabled; vendor preset: disabled)
   Active: active (running) since Sat 2020-10-31 18:28:39 JST; 3s ago
  Process: 7130 ExecStartPre=/bin/sh /var/www/hoge-app/aws/service/sidekiq_exec_start.sh (code=exited, status=0/SUCCESS)
 Main PID: 7731 (bundle)
   CGroup: /system.slice/sidekiq.service
           └─7731 sidekiq 6.1.1 hoge-app [0 of 1 busy]
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RailsにBootstrapを導入する方法

RubyにBootstrapを導入する方法

手順

  • Bootstrapのインストール
  • SCSSファイルの作成
  • JSファイルの修正
  • Rails(Puma)の再起動 ## Bootstrapをgemでインストール
Gemfile
gem 'bootstrap', '~> 4.3.1'
gem 'jquery-rails'
ターミナル
bundle install

SCSSファイルを作成

ターミナル
mv app/assets/stylesheets/application.css app/assets/stylesheets/application.scss
app/assets/stylesheets/application.scss
/*
 * This is a manifest file that'll be compiled into application.css, which will include all the files
 * listed below.
 *
 * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
 * vendor/assets/stylesheets directory can be referenced here using a relative path.
 *
 * You're free to add application-wide styles to this file and they'll appear at the bottom of the
 * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
 * files in this directory. Styles in this file should be added after the last require_* statement.
 * It is generally better to create a new file per style scope.
 *
 *= require_tree .    <(削除)
 *= require_self      <(削除)
 */
@import "bootstrap";  <(追加

JSファイルを修正

app/assets/javascripts/application.js
# 以下の3つを追記
//= require jquery3
//= require popper
//= require bootstrap

# 元々のコード
//= require rails-ujs
//= require activestorage
//= require turbolinks

Rails(Puma)を再起動

Dockerfile
# Railsに必要なパッケージをインストール
RUN apt-get update -qq && apt-get install -y nodejs
RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - \
    && apt-get install -y nodejs

# 以下の公式サイトの記述ではnode.jsのバージョンが低くてbootstrapが使えない
# RUN apt-get update -qq && apt-get install -y nodejs

Bootstrapの使い方(テンプレート)

app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>App</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <div class="d-flex flex-column flex-md-row align-items-center p-3 px-md-4 mb-3 bg-white border-bottom shadow-sm">
      <h5 class="my-0 mr-md-auto font-weight-normal">Company name</h5>
      <nav class="my-2 my-md-0 mr-md-3">
        <a class="p-2 text-dark" href="#">Features</a>
        <a class="p-2 text-dark" href="#">Enterprise</a>
        <a class="p-2 text-dark" href="#">Support</a>
        <a class="p-2 text-dark" href="#">Pricing</a>
      </nav>
      <a class="btn btn-outline-primary" href="#">Sign up</a>
    </div>
    <p class="notice"><%= notice %></p>
    <p class="alert"><%= alert %></p>
    <%= yield %>
  </body>
</html>

こうなる!

e8cf55d4ebff169216236d8d3dfac518.png

現場からは以上です!

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