20201126のRubyに関する記事は26件です。

Rails結合テスト ログイン処理まとめ

はじめに

Railsでオリジナルアプリ制作を終えました。モデルの単体テストは完了したものの、結合テストは未実施でした。ユーザーがログインしないと使えない機能テストにおいて、ログイン処理を繰り返しテストコードに記述するのは避けたいと思います。より簡素な記述をするため、書き記します。

開発環境
ruby 2.6.5
Rails 6.0.3.4
Gem : gem 'rspec-rails'

目次

1.ログイン処理
2.簡素なログイン処理の記述

1.ログイン処理

ログインするにあたり、email及びパスワードが必要だと仮定する。テストコードにおける記述は以下のようになる。問題は機能テストごとにログイン処理を書く必要がある。これを簡略化する方法を次の節で説明する。

spec/system/○○_spec.rb
visit root_path
fill_in 'user_email', with: user.email
fill_in 'user_password', with: user.password
click_on("Log in")
expect(current_path).to eq root_path
#以下ログインした状態での機能テストの記述を書く
visit new_desk_path

※なお、email入力フォームのidはuser_email、パスワードはuser_passwordとする。

2.簡素なログイン処理の記述

specディレクトリの直下にsupportディレクトリを作成する。さらにその直下にsign_in_support.rbファイルを作成し、下記ログイン処理のメソッドを作成する。

spec/supports/sign_in_support.rb
module SignInSupport
  def sign_in(user)
    visit new_user_session_path
    fill_in 'email', with: user.email
    fill_in 'password', with: user.password
    find('input[name="commit"]').click
    expect(current_path).to eq root_path
  end
end

ここで定義したsign_inメソッドをテストコードのファイルで使用できるように下記を設定する。

spec/rails_helper.rb
# コメントアウトを外す
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f }

# 中略

RSpec.configure do |config|
  # 追記
  config.include SignInSupport

以上によりsign_inメソッドを使用できるようになった。下記に使用例を示す。

spec/system/○○_spec.rb
before do
    #テスト用のユーザーダミーデータを生成する。
    @user = FactoryBot.create(:user)
  end
  context '画像投稿ができるとき'do
    it 'ログインしたユーザーは新規投稿できる' do
      # ログインする
      sign_in(@user)
#以下省略

以上

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

cloud9でrails sを終了せずに閉じてしまった時の対処法

はじめに

cloud9でrails sを終了せずにターミナルを閉じてしまいました...
再度rails sをするとこんなエラーが...

 A server is already running. Check /home/ubuntu/environment/[フォルダ名]/tmp/pids/server.pid.

pidファイルを開いてみるも5桁の数字が記載されているだけ...
下記の記事を見つけて再起動するも上手く行かず。

A server is already running 対処方法【Rails】

pidファイルを削除しようとするもファイルツリーから見つけられず...
上記エラー文から開いたpidファイルの数字を削除して再度rails sしました。
すると今度は違うエラー文...

Address already in use - bind(2)

解決法

下記の記事通り
Cloud9上でRails sをしてA server is already runningが出た時の対処法

$ kill -9 数字(pidファイルに記載)

で済むはずなんですが、今回は数字を消してしまったので...

$ killall -9 ruby

で解決しました?

参考:Address already in use - bind(2) when starting server in Cloud9 IDE

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

Ruby ハッシュとシンボルの記法 まとめ

Railsチュートリアル
ハッシュとシンボルの書き方

user = {} # {}は空のハッシュ
=> {}
user["first_name"] = "hurihata" # キーが "first_name" で値が "hurihata"
=> "hurihata"
user["last_name"] = "koyo" # キーが "last_name" で値が "koyo"
=> "koyo"
user["first_name"] # 要素へのアクセスは配列の場合と似ている
=> "hurihata"
user # ハッシュのリテラル表記
=> {"last_name"=>"koyo", "first_name"=>"hurihata"}

ハッシュのキーとしてシンボルを採用する場合、user のハッシュは次のように定義できる

一つめの記法

user = { :name => "koyo", :email => "kkkk@XXX.com" }
=> {:name=>"koyo", :email=>"kkkk@XXX.com"}
user[:name] # :name に対応する値にアクセスする
=> "koyo"
user[:password] # 未定義のキーに対応する値にアクセスする
=> nil

二つめの記法

{ name: "koyo", email: "kkkk@XXX.com" }

自分的にはハッシュロケット(=>)を使う一つ目の記法より二つ目のシンボルの:を後ろにつける記法の方が見やすく使いやすいと感じた。

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

コメント機能の実装要点メモ

はじめに

投稿に対して非同期通信でコメントできるようにする機能についてのメモ書きです。

前提

Ruby 2.6.5p114
Rails 6.0.3.4
macOS Catalina

ルーティングの修正

config/routes
  resources :items do
    resources :orders, only: [:index, :create]
    resources :comments, only: [:create]
  end

コメントの削除機能は実装しないため、destroyアクションは不要です。

チャネルの作成

ターミナル
% rails g channel comment

createアクションの設定

app/controllers/comments_controller
  def create
    @comment = Comment.new(comment_params)
    if @comment.save
      @user = @comment.user
      ActionCable.server.broadcast 'comment_channel', comment: [@comment, @user]
    end
  end

ActionCableの記述でbroadcastを通してcomment_channelに向けて@commentを送信しています。送信された情報はcomment_channel.jsで受け取り、テンプレートリテラルにする必要があります。

単体テストコード

contentが存在すれば保存できること、contentが存在しない場合保存できないこと、userと紐づいていない場合保存できないこと、itemと紐づいていない場合保存できないことをテストします。

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

アソシエーションを用いたデータ読み込み削減

はじめに

この投稿はRailsで開発しているフリーマーケット機能を持ったWEBアプリケーションで、データのやり取り回数を削減できることをメモしておくものです。

前提

Ruby 2.6.5p114
Rails 6.0.3.4
macOS Catalina

アソシエーション

app/models/item.rb
  belongs_to :user
  has_one :order
app/models/order.rb
  belongs_to :user
  belongs_to :item
app/models/user.rb
  has_many :items
  has_many :orders

itemと紐づけられたuserの情報を読み込む方法

商品詳細が表示される際に、ログインしているユーザーと出品しているユーザーが、同一人物の場合と同一人物ではない場合で条件分岐処理を行う必要がありました。前者の分岐処理の記述では余分なデータの読み込みが発生してしまいます。
後者の記述ではアソシエーションを活用した読み込みの手間の少ない可読性の高い記述となっています。

app/views/items/show.html.erb
   <% if Order.find_by(item_id: @item.id) == nil %>
      <% if user_signed_in? && current_user.id == @item.user.id %>
        <中略>
      <% elsif user_signed_in? %>
        <中略>
      <% end %>
    <% end %>
app/views/items/show.html.erb
    <% if @item.order == nil %>
      <% if user_signed_in? && current_user.id == @item.user.id %>
        <中略>
      <% elsif user_signed_in? %>
        <中略>
      <% end %>
    <% end %>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ancestryはawsにデプロイしただけでは使えない

 1.どんな状態だったか

ancestryを利用して、カテゴリー機能を実装、ローカルでは動くのに本番環境で反映されないという状態

2原因

ancestryを使うためには、本番環境でもローカルと同じ様に
db migrateし、seedを読み込まなくてはならない

3解決方法

まずdb migrateします

$ cd var/www/app名/current
$ rake db:migrate RAILS_ENV=production

上手くいかない時はdbをドロップしもう一度クリエイトし直す

$ RAILS_ENV=production DISABLE_DATABASE_ENVIRONMENT_CHECK=1 bundle exec rake db:drop

$ rake db:create RAILS_ENV=production

もう一度migrateします。

次にseedを反映させます。

$ rake db:seed RAILS_ENV=production

以上になります。

4最後に

自動デプロイをしている場合はcurrentディレクトリで操作を行う必要があるそうです
そうでない場合は~ディレクトリで大丈夫みたいです

参考にした記事
[aws,rails]ancestryをawsにデプロイした時に反映されない状況の解決方法
本番環境でrake db:seedを実行する際の注意点

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

「KeyError: Factory not registered:」に詰まった話

 RSpecについて勉強している者です。

 現在制作中のオリジナルアプリにフォロー機能を実装しており、そのフォロー機能のモデルの単体テストを実装していました。その時に、「KeyError: Factory not registered:」というエラーが発生して苦戦したため、解決方法を自分用にメモを残しておこうと思います。
(といっても、振り返れば非常に単純なことでした?)

 途中で見つけた解決策もご紹介していきます。参考になると幸いです。

エラーが発生した状況

エラーが発生した当時のコードを載せておきます。
(解決方法を手っ取り早く知りたい方は飛ばしてください)

app/models/relationship.rb
class Relationship < ApplicationRecord
  belongs_to :user
  belongs_to :follow, class_name: 'User'

  validates :user_id, presence: true
  validates :follow_id, presence: true
end
app/models/user.rb
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  # あるユーザーがフォローしている他ユーザーとのアソシエーション(フォロー)
  has_many :relationships, foreign_key: 'user_id', dependent: :destroy
  has_many :followings, through: :relationships, source: :follow

  # あるユーザーをフォローしている他ユーザーとのアソシエーション(フォロワー)
  has_many :reverse_of_relationships, class_name: 'Relationship', foreign_key: 'follow_id', dependent: :destroy
  has_many :followers, through: :reverse_of_relationships, source: :user
end
spec/factories/relationships.rb
FactoryBot.define do
  factory :relationship do
    association :user
    association :follow
  end
end
spec/factories/user_spec.rb
FactoryBot.define do
  factory :user do
    nickname { Faker::Lorem.characters(number: 10) }
    email { Faker::Internet.free_email }
    password = "a12345"
    password { password }
    password_confirmation { password }
  end
end
spec/models/relationship_spec.rb
require 'rails_helper'

RSpec.describe Relationship, type: :model do
  let!(:relationship) { FactoryBot.create(:relationship) }

  it "関係性が有効であること" do
    expect(relationship).to be_valid
  end

  it "user_idがnilの場合、関係性が無効であること" do
    relationship.user_id = nil
    expect(relationship).to_not be_valid
  end

  it "follow_idがnilの場合、関係性が無効であること" do
    relationship.follow_id = nil
    expect(relationship).to_not be_valid
  end
end

この状態で「bundle exec rspec」を実行すると……

ターミナル
Failures:

  1) Relationship 関係性が有効であること
     Failure/Error: let!(:relationship) { FactoryBot.create(:relationship) }

     KeyError:
       Factory not registered: "follow"
     # ./spec/models/relationship_spec.rb:4:in `block (2 levels) in <main>'
     # ------------------
     # --- Caused by: ---
     # KeyError:
     #   key not found: "follow"
     #   ./spec/models/relationship_spec.rb:4:in `block (2 levels) in <main>'

 このように
「KeyError: Factory not registered: "follow"」
というエラーが発生してしまいました。

噛み砕いて説明すると、
「spec/factories/relationships.rbに記述していた、"association :follow"の"follow"って何?」
と怒られているわけですね。

解決策

 3つほど解決方法があったので紹介していきます(自分の場合、以下の①と②は効果がありませんでした)。

① spec_helper.rbに記述を追加する

参考にさせていただいた記事:https://qiita.com/tmyn470/items/2bd1616cdb21f16916fb

 「KeyError: Factory not registered:」でGoogle検索をかけると結構記事が出てきました。
 自分がまずはじめに知った解決策は、spec_helper.rbに以下のような記述を追加するというものでした。

spec/spec_helper.rb
RSpec.configure do |config|
  config.before(:all) do
    FactoryBot.reload
  end
end

 自分はこちらの記述を追加しても解決しませんでしたが、ほとんどの記事でFactoryBot関係が原因だと結論づけられていました。
それから、
「どうやらFactoryBotに原因がありそうだな」
と予想して調べていきました。

②ターミナルで「spring stop」を実行する

 次に知った解決策は、「ターミナルで『spring stop』を実行する」というものです。
 これはプログラミングスクールのカリキュラムで紹介されていた方法です。

 この「spring stop」を実行する理由ですが、
 「Railsに標準で導入されている『Spring』というGemがバックグラウンドで作動していて、たまにロードエラーを起こしてしまう。その時は、『spring stop』を実行し、Springを一時停止する必要がある」
とのことです。
 早速実行してみました。しかし……

ターミナル
アプリケーションディレクトリ名 % spring stop

Spring is not running

 「Spring is not running」と出てしまい、「KeyError: Factory not registered:」のエラーは相変わらずです。

③ aliasで別名を命名する(今回の解決方法)

 こちらが、今回の解決策になります。
 aliasを用いて、「spec/factories/user_spec.rb」内のuserに「follow」という別名を命名したところ解決しました。

spec/factories/user_spec.rb
FactoryBot.define do
  # userに「follow」という別名を命名
  factory :user, aliases: [:follow] do
    nickname { Faker::Lorem.characters(number: 10) }
    email { Faker::Internet.free_email }
    password = "a12345"
    password { password }
    password_confirmation { password }
  end
end

 下記の「belongs_to :follow, class_name: 'User'」のように、アソシエーションに別名を名付けている場合は、ファクトリの方にも別名をつけてあげる必要があったという話でした。

app/models/relationship.rb
class Relationship < ApplicationRecord
  belongs_to :follow, class_name: 'User'
end

 思えば、非常に単純な話でした?
 
 もし、同じように「KeyError: Factory not registered:」に悩んでいる方がおられましたら、ご紹介した①や②の方法も試してみてください。実際、①②で解決した方もたくさんいるみたいです。

 もし間違っている点などありましたら、ご指摘いただけると幸いです。
 ここまで読んでいただき、ありがとうございました。

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

DockerでCGI: EPWING電子辞書サーバー「let me see...」 (2003年)

はじめに

Docker始めました

流行ってから既に数年、今更Docker始めました。
導入手法が明確になり、環境も汚さないのは便利ですね。

使える環境(自宅サーバー)を手に入れたのでSSHでつないでやってます。
正直これで良いのでは、というかそもそもDockerである必要性は…。別に環境汚れても良いし。
まぁ本格的な開発をするならローカルPCでやった方が楽なはず。あと配布は気楽。

Let me see...

今回Docker対応したのは、電子辞書オープンラボ・かずひこ様による「let me see...」。
2000年代くらいまでCD-ROM電子辞書形式として使われたEPWING形式などに対応しています。
最終更新は2003年で、それをDocker対応するのがちょっと面白いですね。

GitHubレポジトリはkurema/forkedLetMeSee、Dockerイメージはghcr.io/kurema/letmeseeです。

image.png
image.png

導入方法

対応手順を説明する前に導入方法は以下です。
あらかじめEPWing形式の辞書を適当な場所に配置しておいてください。

$ git clone https://github.com/kurema/forkedLetMeSee.git
$ cd forkedLetMeSee
$ nano docker-compose.yml
$ nano conf/letmesee.conf
$ sudo docker-compose up -d

辞書の場所に応じdocker-compose.ymlを編集し、各辞書や設定をconf/letmesee.confに記述します。
conf/letmesee.confから見える場所はdocker-compose.ymlでのマウント先以下になるのは注意です。

開発過程

Dockerを初めて二つ目なのでやはり手探りです。
いくつかベストプラクティスではかもしれません。

Docker対応

Dockerってめんどくさいと思ってましたけど、ベースイメージからのインストール手順をRUNに書いていくだけの簡単な作業です。
Dockerfileが導入方法の説明にもなるので便利ですね。

タイムゾーン設定

最初にDockerを試した時、以下のメッセージが出ました。

Please select the geographic area in which you live. Subsequent configuration
questions will narrow this down by presenting a list of cities, representing
the time zones in which they are located.

Ubuntu 18.04以降でgitインストール時に発生するらしいです。
httpdでは必要ないかもしれませんが、tzdataは大抵必要だと思うので以下の対処をしています。
ただし、ユーザーが日本在住でない場合は別のタイムゾーンに設定する必要があります。

Dockerfile
RUN apt-get update -y && \
    apt-get install -y --no-install-recommends tzdata

#Timezone is set to Japan assuming you are in Japan.
ENV TZ=Asia/Tokyo

参考記事

眠れない夜 (2018)「[Docker] build tzdata タイムゾーン選択回避方法(ubuntu)」エンジニアの眠れない夜 https://sleepless-se.net/2018/07/31/docker-build-tzdata-ubuntu/
@yagince (2018) 「Docker Ubuntu18.04でtzdataをinstallするときにtimezoneの選択をしないでinstallする」Qiita https://qiita.com/yagince/items/deba267f789604643bab

CGI有効化

ApacheでCGIの有効化はsedを使って設定ファイルを弄るような必要があるようです。スマートではないですね。将来壊れそうです。
できれば専用コマンドが欲しいところ。

Dockerfile
RUN sed -ri 's/#LoadModule cgid_module/LoadModule cgid_module/g; \ 
             s/DirectoryIndex index.html/DirectoryIndex index.rb index.cgi index.html/g; \ 
             s/Options Indexes FollowSymLinks/Options Indexes FollowSymLinks ExecCGI/g; \
             s/#Scriptsock cgisock/Scriptsock cgisock/g; \
             s/#AddHandler cgi-script .cgi/AddHandler cgi-script .pl .rb .cgi/g' /usr/local/apache2/conf/httpd.conf

ベースコンテナによってhttpd.confの場所が変わります。
扱っているCGIによってAddHandler cgi-scriptDirectoryIndexの拡張子が変わったりします。今回は.rb

Scriptsock cgisockをコメントインしないとService Unavailableのエラーが出るようです(参考)。出ました。
以前やった記憶がなかったですが、その時はubuntuでa2enmodが使えたのでそのときに導入されるようです。

mpm_prefork_moduleを使う可能性がある場合はs/#LoadModule cgi_module/LoadModule cgi_module/g;も追加した方が良いでしょう。cgidcgiになります。

参考記事

ワタナベ書店 (2015) 「Docker上でApacheコンテナを作成しCGIのコンテンツを走らせるまで」 https://senyoltw.hatenablog.jp/entry/2015/10/21/175847

配置

後はファイルを配置するだけ。
CGIでは実行ファイルにchmodで実行権限を付与すること忘れないようにしましょう。今回は777にしました。

個人的にはREADME.mdファイルをイメージに配置するのが良いと思います。
何かの理由でDockerイメージだけあるという状況には多少便利です。
レポジトリ全体を圧縮して配置するとかも良いですが、大きめの画像を配置したりすることもあるのでやめました。
容量を気にするなら辞めるなりgz圧縮なり。

Dockerfile
COPY edict-devel/letmesee/ /usr/local/apache2/htdocs/
RUN chmod 777 /usr/local/apache2/htdocs/*.rb

COPY README.md /

トラブル

当初、gem installをする段でSSLエラーが出るというトラブルがありました。
一時期証明書の追加で対処しましたが、CGI側の修正で不要になりました。
それについてはこちらの記事参照。

docker-compose

このCGIは設定ファイルがCGIと同じフォルダに配置されるタイプです。
Dockerイメージ内部のファイル自体を触るのは微妙なのでvolumesでマウントします。
辞書自体のマウントも必要です。
dockerコマンド一行にしては長いですし、docker-composeファイルにしました。

docker-compose.yml
version: '3'
services:

  letmesee:
    image: ghcr.io/kurema/letmesee:latest
    container_name: letmesee
    restart: always
    ports: 
      - 50002:80
    volumes:
      - ./conf/letmesee.conf:/usr/local/apache2/htdocs/letmesee.conf
      # /home/share/DictionaryをEPWing辞書が保存されている場所に変更してください。
      - /home/share/Dictionary:/usr/local/dict

公開

Docker HubがPull回数制限や利用されていないイメージの削除(後に保留)などを発表したので、イメージはGitHub Container Registryに保存することにしました。
6ヶ月どころか十年単位で放置する見込みなので、継続性が期待できるGitHubのサービスが確実だと判断しました。
マルチCPUアーキテクチャにも対応していて便利です。なにより無料。

GitHub Actions

GitHub Actionsで自動化をしたかったのでGitHubコミュニティーの例のマルチCPUアーキテクチャ対応のワークフローをほぼそのまま使いました。
以下の点を変更しています。

  • キャッシュはインラインで保存。GitHub Actions側に保存する方法もあるようです。
.github/workflows/docker.yml
          cache-from: type=registry,ref=${{ steps.prep.outputs.latest }}
          cache-to: type=inline
  • テスト用手動ディスパッチ。手動時のタグはtestになります。
.github/workflows/docker.yml
on:
  workflow_dispatch:
  • デイリービルドは頻度が高すぎるので月刊に。
  • プラットフォームは元イメージと同じ。無料だからってやりすぎですね。
.github/workflows/docker.yml
          platforms: linux/amd64,linux/arm64,linux/ppc64le,linux/s390x,linux/386,linux/arm/v7

最終的なyamlはこちら(記事時点)参照。

GitHub Container Registryはベータテスト中なのでGITHUB_TOKENが使えない点は注意が必要です。
自分でトークンを発行し、GHCR_PATをシークレットに登録してください。

時間

ビルド時間はキャッシュなしで11分。キャッシュありで2分といったところです(testタグはキャッシュ元として参照しません)。
image.png

タグを付けたら自動でイメージをビルドしプッシュしてくれるのは楽です。
マンスリービルドを参照すれば最新のベースコンテナにも追従できますし。
ただ実を言えば個人開発でCI/CDなんてのは建前で、以下みたいな目的が本音ですね。

  • 無料なので使いたい
  • 重い処理をオフロードしたい
  • ミスって個人情報が混入する事態を避けたい。

なので、テスト目的でもガンガンGitHub Actionsで実行して、GitHub Container Registryからイメージをpullして試してます。自前ビルドはしません。
幸いキャッシュが効いてるとCGIだけの修正では処理時間も短くサーバーの容量も新規では大して食いません。
合わせても100kb未満のCGIそれもダウンロード数が1-2桁(現時点では自分だけ)に数百MBを消費するのはどうなのかと最初は思いましたし、z/Architectureなんて環境でこれを使う人なんて絶対居ませんが、Dockerってのはそういう世界みたいです。怖いですね。

改修

流石に古いだけあってそのまますんなり動くわけではありませんでしたが、少しの修正で動きます。
コメントがなくrubyは滅多に書かなくても分かりやすかったです。
元作者さんとruby開発者は見事です。

  • Ruby側の更新に追従
    • 相対パスへのrequirerequire_relativeに。
      • 2003年当時はrequire 'letmesee.rb'で同一パスのrbファイルを参照してくれたようです。
      • 現時点ではrequire './letmesee.rb'にすれば動作します。
      • 実際にはrequire_relative './letmesee.rb'が正しいようです。これを書いている途中に気付いたので修正しました。
      • CGIならカレントディレクトリの問題とかは起きないはずですが、念のため。
    • File::open( path )File::open( path , "r:utf-8" )に修正。
      • 記憶にありませんが、文字化けでもしたんだと思います。
    • head['Content-Length'] = body.size.to_shead['Content-Length'] = body.bytesize.to_sに修正。
      • 2003年当時はstring.sizeでバイト数を取得できたようです。上の修正のせいかもしれません。
      • 出力が途中で途切れていたので不思議でした。
    • Iconv.iconvの利用をやめてEncoding::Converter#convertを利用するようにしました。
      • iconvの引数はiconv(to, from, *strs)なのに対し、Encodingsではnew(source_encoding, destination_encoding)と文字コードの順番が逆なので注意が必要です。
      • iconvのUTF-8はUTF8でも通るようですが、Encodingsでは通らないので注意が必要です(元々のバグかも)。
      • Encodingsでは変換元と変換後が同じ文字コードだとエラーが発生するようです。素通りしてくれれば良いのに。
  • HTML5対応
    • 音声には<audio>を使うようにしました。
      • 動画はMPEG-1なので<video>ではまず動きません。
        • JavaScriptで再生するjsmpegやwasm版のffmpegとかもありますが、十年単位で放置する予定なので辞めました。
    • ヘッダの変更。簡単なスマートフォン対応(cssで@mediaの追加・viewport)。
old
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
        "http://www.w3.org/TR/html4/strict.dtd">
<html lang="ja">
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
<%= css_tag %>
new
<!DOCTYPE html>

<html lang="ja">
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1.0" />
<%= css_tag %>
  • サーバーの性能向上に伴い、ちょっと富豪的に。
    • 辞書を絞って検索するメニューを削除。
      • 邪魔なので。<details>でもいいと思いますが、当時(2017年)は知りませんでした。
    • 外字をデフォルトで最大フォントサイズに。
      • 高解像度モニターも増えてますし。
      • 存在しない場合最小フォントサイズの外字にフォールバックします。
  • 高速化。
    • トップページの静的表示
      • letmesee.rb初期化時全辞書を読み込んでいたので、低性能マシンかつ大量辞書の環境では表示に時間が掛かっていました。
      • トップページでは辞書を読み込まず静的ファイルを表示するようにしたので表示が早くなりました。
    • 外字のキャッシュ
      • 外字が大量にある場合に遅かったので、ヘッダを変更し一日はキャッシュするようにしました。
      • 本来は一文字ずつ取得しに行く処理は避けるべきです(後述)。
  • XML対応
    • XMLでの取得に対応しました。ただし、常にwell-formedだとは期待できません。
    • Androidアプリでも作ろうかと思いましたが辞めました。
  • <b><i>
    • <b><i>が入れ子になっても正常動作するように修正しました。
      • 市販されている辞書では存在しないのか、入れ子に対応していないEPWINGソフトは結構あります。
      • 変換された辞書では普通にあって、検索候補の途中から盛大にレイアウトが崩れるので面倒です。
    • 対応しないタグを削除するようにしました。
  • その他
    • CSSや設定などを個人的な好みに合わせて変更。
    • 独自テーマを追加し、デフォルトをそちらに変更。
    • ロゴ画像を透過。

改修しなかった点は以下です。

  • 設定ファイルでの辞書記述
    • 大量の辞書を保存している場合、設定ファイルに一つずつ辞書のパスを追加するのは面倒です。
    • 自動追加するスクリプトを書くか、最上位パスの指定だけで済むように変更したかったですが面倒なので辞めました。
  • 外字表示の高速化
    • 現状では外字一文字ずつサーバーに問い合わせるようになっています。
    • 外字が多いと毎回CGIが起動して大量のIO処理が発生し時間が掛かります。
      • キャッシュはするようにしました。
    • 辞書ファイル側では各サイズ2ファイルで小容量なので一括で渡した方が良いかもしれません。
      • 普通は数kb程度ですが、大きいと2MB程度にはなります。
      • これはかなり大変そうでした。辞めました。
  • さらなるデザインの改良。
    • 自分で新しいデザインにしましたが、今見るとダサいです。
    • これは今後修正するかもしれません。

手間を掛けず、簡単にできる修正だけしたという感じです。
ruby自体まず書かないですが、読みやすく破壊的変更も大してないので楽でした。
またこのCGI自体テーマがあったり拡張しやすい設計です。素晴らしい
CGIは良いものですね。シンプルで分かりやすくて。

年表

日時 イベント
1987年 EPWINGの前身となるWINGフォーマット制定。
1988年 EPWING規約制定。
1993年 CGI登場
1995年 Ruby登場
1997年6月8日 EB Library 初版
2000年4月10日 ruby EB v1.0
2002年3月31日 ruby EB v1.7 (最新版)
2003年2月29日 let me see... v1.0
2003年11月9日 let me see... v1.1 (最新版)
2010年3月8日 EB Library v4.4.3 (最新版)
2013年3月13日 Docker 初版
2014年1月30日 ruby EB 久保健洋氏によるruby1.9対応非公式フォーク 初版
2014年1月30日 ruby EB 同フォーク 最終更新
2017年7月11日 let me see... kuremaによるフォーク v1.2 (微修正)
2020年11月10日 let me see... 同フォーク v1.3 (Docker対応)

しかしすごい歴史ですね。壮大。
まぁEPWINGの世界ってのはこんな感じです。Unicode対応以外は現在でもそれなりに「使える」フォーマットなのは感心します。
違う世代の辞書ファンたちがちょっとずつ色々何かやってるのがEPWINGの魅力です。
今でもずっと辞書アプリを開発してくださってる方もいらっしゃいます。感謝。

ちなみにこの記事では細かく触れませんでしたが、2017年にフォークし小改良、最近Docker対応のついでに中改良といった感じです。
さらに言えば記事の順番が前後しますが、これは私のDockerでCGI二つ目です。
一つ目はニコニコチャンネルキャッシュサーバー。そのうち記事にします。

その他、EPWING関係リンク:

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

Ruby: Google Cloud Translation API の使い方 (Advanced)

advanced01.rb
#! /usr/bin/ruby
# -*- encoding: utf-8 -*-
#
#   advanced01.rb
#
#                       Nov/26/2020
# ---------------------------------------------------------------------
require "google/cloud/translate"

project_id    = "project-translation"
text          = "Es war einmal ein kleines Mädchen."
target_language = "ja"
location_id = "global"

contents = [text]

client = Google::Cloud::Translate.translation_service

parent = client.location_path project: project_id, location: location_id

response = client.translate_text parent:               parent,
                                 contents:             contents,
                                 target_language_code: target_language

#
response.translations.each do |translation|
    puts "Translated text: #{translation.translated_text}"
end
#
# ---------------------------------------------------------------------

実行方法

export GOOGLE_APPLICATION_CREDENTIALS=./***.json
#
./advanced01.rb

実行結果

Translated text: 昔々、小さな女の子がいました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby: Google Cloud Translation API の使い方 (Basic)

basic01.rb
#! /usr/bin/ruby
# -*- encoding: utf-8 -*-
#
#   basic01.rb
#
#                       Nov/26/2020
# ---------------------------------------------------------------------
project_id    = "project-translation"
text          = "Es war einmal ein kleines Mädchen."
language_code = "ja"

require "google/cloud/translate"

translate   = Google::Cloud::Translate.translation_v2_service project_id: project_id
translation = translate.translate text, to: language_code

puts "Translated '#{text}' to '#{translation.text.inspect}'"
puts "Original language: #{translation.from} translated to: #{translation.to}"
#
# ---------------------------------------------------------------------

実行方法

export GOOGLE_APPLICATION_CREDENTIALS=./***.json
#
./basic01.rb

実行結果

Translated 'Es war einmal ein kleines Mädchen.' to '"昔々、小さな女の子がいました。"'
Original language: de translated to: ja
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails]Request Specでのログインの実施

はじめに

アプリ開発において、トップページ以外ログインをしていないと見れないという設定にしていたので、postsコントローラーのshowアクションのテストコードの際に利用しました。

目次

  • 1. deviseのヘルパー機能を呼び出す設定
  • 2. FactoryBotを利用したdevise認証

1. deviseのヘルパー機能を呼び出す設定

spec/rails_helper.rb
RSpec.configure do |config|
~~
  #下記を追記
  config.include Devise::Test::IntegrationHelpers, type: :request
~~
end

2. FactoryBotを利用したdevise認証

FactoryBotを利用できるように設定します。
spec配下にsupportディレクトリを作成しfactory_bot.rbファイルを作成します。

spec/support/factory_bot.rb
RSpec.configure do |config|
  config.include FactoryBot::Syntax::Methods
end

下記の一文のコメントアウトを外して有効にします。

spec/rails_helper.rb
~~
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f }
~~

FactoryBotを用いてテスト用のuserを作成します。

spec/factories/users.rb
FactoryBot.define do
  factory :user do
    nickname { Faker::Name.last_name }
    email { Faker::Internet.free_email }
    password = Faker::Internet.password(min_length: 6)
    password { password }
    password_confirmation { password }
    birthday { Faker::Date.in_date_period }
    gender { 2 }
  end
end

before do ~ endでユーザーログインまでの挙動を設定しています。

spec/requests/posts_request_spec.rb
require 'rails_helper'

RSpec.describe 'Posts', type: :request do
  before do
    # 登録しているuserを使うのでcreateとします。
    @user = FactoryBot.create(:user)
    # deviseのメソッドであるsign_inでログインしています。
    sign_in @user
    @post = FactoryBot.create(:post, image: fixture_file_upload('public/images/test_image.png'))
  end

  describe "GET #show" do
    it "showアクションにリクエストすると正常にレスポンスが返ってくる" do 
      get post_path(@post)
      expect(response.status).to eq 200
    end
    it "showアクションにリクエストするとレスポンスに投稿済みのクチコミの商品名が存在する" do 
      get post_path(@post)
      expect(response.body).to include @post.name
    end
    it "showアクションにリクエストするとレスポンスに投稿済みのクチコミのカテゴリーが存在する" do 
      get post_path(@post)
      expect(response.body).to include @post.category.name
    end
    it "showアクションにリクエストするとレスポンスに投稿済みのクチコミの更新日が存在する" do 
      get post_path(@post)
      expect(response.body).to include @post.created_at.strftime("%Y.%m.%d")
    end
    it "showアクションにリクエストするとレスポンスに投稿済みのクチコミの投稿者名が存在する" do 
      get post_path(@post)
      expect(response.body).to include @post.user.nickname
    end
    it "showアクションにリクエストするとレスポンスに投稿済みのクチコミの評価が存在する" do
      get post_path(@post)
      expect(response.body).to include "#{@post.evaluation}"
    end
    it "showアクションにリクエストするとレスポンスに投稿済みのクチコミ商品購入額が存在する" do
      get post_path(@post)
      expect(response.body).to include "#{@post.price}"
    end
    it "showアクションにリクエストするとレスポンスに投稿済みのクチコミ商品購入店が存在する" do
      get post_path(@post)
      expect(response.body).to include @post.shop_name
    end
    it "showアクションにリクエストするとレスポンスに投稿済みのクチコミレビュー文が存在する" do
      get post_path(@post)
      expect(response.body).to include @post.description
    end
    it "showアクションにリクエストするとレスポンスに投稿済みのクチコミの画像が存在する" do 
      get post_path(@post)
      expect(response.body).to include 'test_image.png'
    end
    it "showアクションにリクエストするとレスポンスに投稿済みのクチコミのお気に入り数が存在する" do 
      get post_path(@post)
      expect(response.body).to include "#{@post.likes.count}"
    end
    it "showアクションにリクエストするとレスポンスに関連商品のクチコミ表示部分が存在する" do 
      get post_path(@post)
      expect(response.body).to include '関連商品のクチコミ'
    end
  end 
end

参考リンク

https://qiita.com/Hyuga-Tsukui/items/57fa77df2b2942414307

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

[初心者向け]Railsでtodoアプリを作ってみよう

はじめに

プログラミングを初めてまず最初に作るアプリはtodoアプリだと思います。この基本の「き」とも言えるtodoアプリを一緒に作っていきましょう!

バージョン

Rails 6.0.3.4
ruby 2.6.3

プロジェクトの作成

それでは早速進めていきましょう。ターミナルに

ターミナル
$rails new todo-app

と打ってプロジェクトを作成させます。途中、passwordを求められますので忘れずに入力してください。その際、入力した文字が画面に表示されませんが構わずに続けてEnterを押して進んでください。

Webpacker successfully installed ? ?

と表示されればプロジェクト作成は完了です。ケーキ食べたい...(途中Warningがたくさん出てくるかもしれませんがErrorと出てこない限りは全部無視してしまって大丈夫です。)その後

ターミナル
$cd todo-app

と入力してtodo-appに移動しましょう。

モデルの作成

モデルを作成していきます。モデルは単数形で頭文字を大文字にするのがルールです。ここではtitleをstring型、bodyをtext型にして作っていきたいと思います。ターミナルで以下を実行してください。

ターミナル
$rails g model Task title:string body:text

できたらその後以下でマイグレートしましょう。(もし間違えて作成してしまった場合には、gをdに変えて実行すれば消すことができます。)

ターミナル
$rails db:migrate

コントローラの作成

コントローラを作ります。コントローラは複数形で全て小文字にするのがルールです。

ターミナル
rails g controller tasks

これで、大まかな構造を作ることができました。(もし間違えて作成してしまった場合には、モデルと同じくgをdに変えて実行すれば消すことができます。)次からコードを打ち込んでいきましょう!!

トップ画面 ~index~

それでは、まずはトップ画面を作成していきたいと思います。トップ画面にはやること一覧を表示させます。これにはindexアクションを用いましょう。ここではすべてのタスクをTask.allで取得します。

app/controllers/tasks_controller.rb
class TasksController < ApplicationController
  def index
    @tasks = Task.all
  end
end

次にviewを作成していきましょう。viewsフォルダのなかのtasksフォルダの中にindex.html.erbというファイルを作りましょう。(controlを押しながらクリックすれば作成できます。)ファイルを作ることができたら以下を記述しましょう。

app/views/tasks/index.html.erb
<h1>やること一覧</h1>

<table>
  <thead>
    <tr>
      <th>やること</th>
      <th>詳細</th>
    </tr>
  </thead>

  <tbody>
    <% @tasks.each do |task| %>
    <tr>
      <td><%= task.title %></td>
      <td><%= task.body %></td>
    </tr>
    <% end %>
  </tbody>
</table>

次に大事なルーティングを作成しましょう。以下のように記述してください。

config/routes.rb
resources :tasks

なんとなんとrailsだとこの1行でindex,new,create,edit,update,show,destroyの主要な7つのアクション一気に作ることができます。他の言語だと色々ごちゃごちゃと書かないといけないのですが、、、rails便利ですね。

これからは、localhost:3000/tasksと打てば今作成している画面を確認できるようになります。エラーが起きていないか常に確認しながら進めていきましょう。

新規作成機能 ~new,create~

ここからは新規作成機能を作っていきましょう。まずはコントローラに記述をしていきます。

app/controllers/tasks_controller.rb
class TasksController < ApplicationController
  def index
    @tasks = Task.all
  end

#ここから追加
  def new
    @task = Task.new
  end

  def create
    @task = Task.new(task_params
    if @task.save
      redirect_to tasks_path #セーブできたらindexページに行く
    else
      render 'new' #できなかったらnewページのまま
    end
  end

  private
  def task_params
  #モデル作成時に作ったやつ
    params.require(:task).permit(:title, :body)
  end
end

ここではストロングパラメータというものを使って、Taskモデルを作成した際にできたtaskテーブルににtitle(やること)とbody(詳細)を保存します。ストロングパラメータについて詳しく知りたいかたはこちらを参照してください。そして「redirect toとrenderの違いって何??」と思ったセンスの良いかたはこちらを参照してください。

viewを作成します。

app/views/tasks/new.html.erb
<h1>やること新規作成</h1>

<%= link_to '一覧へ', tasks_path %>

<%= form_with model: @task do |f| %>
<div class="field">
  <%= f.label :やること %><br>
  <%= f.textarea_field :title %>
</div>
<div class="field">
  <%= f.label :詳細 %><br>
  <%= f.text_field :body %>
</div>
<div class="actions">
  <%= f.submit %>
</div>
<% end %>

form_withを使ってデータを保存させます。form_withについて詳しく知りたいかたはこちら
これによって作られたデータは、createアクションへ運ばれます。

ここで、フォームが空欄だった場合に保存できないようにしておきましょう。この機能をバリデーションと呼びます。

app/model/task.rb
class Task < ApplicationRecord
    validates :title, presence: true
    validates :body, presence: true
end

詳しい説明はここでは省きますが、これで空欄のままsubmitを押しても保存されないようになります。バリデーションについて詳しくしれたい方はこちら

最後にindexのページ(やること一覧のページ)に新規作成ページへのリンクを貼り付けましょう。ターミナルで

ターミナル
$rails routes

と打ってみてください。すると、

ターミナル
     tasks  GET    /tasks(.:format)  tasks#index                                                              
         POST   /tasks(.:format)  tasks#create                                                              
   new_task GET    /tasks/new(.:format)  tasks#new                                                          
    edit_task GET    /tasks/:id/edit(.:format)   tasks#edit                                                   
         task GET    /tasks/:id(.:format)    tasks#show                                                       
              PATCH  /tasks/:id(.:format)    tasks#update                                                       
              PUT    /tasks/:id(.:format)     tasks#update                                                      
              DELETE /tasks/:id(.:format)      tasks#destroy 
  ...                                                    

と出てきたと思います。このtasks#newの左側にあるnew_taskにpathをくっつけたのがnewページに行くためのリンクになります。そのため、

app/views/tasks/index.html.erb
<h1>やること一覧</h1>

<%= link_to '新規作成', new_task_path %> #追加

<table>
  <thead>
    <tr>
      <th>やること</th>
      <th>詳細</th>
    </tr>
  </thead>

  <tbody>
    <% @tasks.each do |task| %>
    <tr>
      <td><%= task.title %></td>
      <td><%= task.body %></td>
    </tr>
    <% end %>
  </tbody>
</table>


これでtopページと新規作成機能は終わりです。

編集機能 ~edit,update~

続いて、編集機能を作成していきたいと思います。編集にはeditアクションとupdateアクションを使用します。コントローラーにこの2つのアクションを記述していきましょう。

app/controllers/tasks_controller.rb
class TasksController < ApplicationController
  def index
    @tasks = Task.all
  end

  def new
    @task = Task.new
  end

  def create
    @task = Task.new(task_params)
    if @task.save
      redirect_to tasks_path
    else
      render 'new'
    end
  end

 #ここから追加
  def edit
    @task = Task.find(params[:id])
  end

  def update
    @task = Task.find(params[:id])
    if @task.update(task_params) 
      redirect_to tasks_path #updateできたらindexページに行く
    else
      render 'edit' #できなかったらeditページのまま
    end
  end
 #ここまで

  private
    def task_params
      params.require(:task).permit(:title, :body)
    end
end

ここで新しく、find(params[:id])というコードが出てきましたね。これは投稿され情報に付けられたidを探し出すコードです。例えば、「ケーキを買う」という内容を編集したいのにボタン押したら隣に記述していた「部屋の掃除をする」という内容が画面に出てきたらもう訳わかんないですよね。ここではこのfind(params[:id])を使って編集したい内容を正しく呼び出せるようにしています。(ちなみにrailsというフレームワークを使っているからこの1行だけで情報を呼び出せるのであり、使はなければSQLという言語をゴリゴリ書く必要があります。railsすげえ。)

次にviewsファイルを作成していきましょう。

app/views/tasks/edit.html.erb
<h1>やること編集</h1>

<%= form_with model: @task do |f| %>
<div class="field">
  <%= f.label :やること %><br>
  <%= f.text_field :title %>
</div>
<div class="field">
  <%= f.label :詳細 %><br>
  <%= f.text_field :body %>
</div>
<div class="actions">
  <%= f.submit %>
</div>
<% end %>

<%= link_to '一覧へ', tasks_path %>

入力フォームなのでnew.html.erbと同じコードですね。最後に一覧画面に編集画面へのリンクを付け加えて終了です。

app/views/tasks/index.html.erb
<h1>やること一覧</h1>

<%= link_to '新規作成', new_task_path %>

<table>
  <thead>
    <tr>
      <th>やること</th>
      <th>詳細</th>
    </tr>
  </thead>

  <tbody>
    <% @tasks.each do |task| %>
    <tr>
      <td><%= task.title %></td>
      <td><%= task.body %></td>
      <td><%= link_to '編集', edit_task_path(task) %></td> #追加
    </tr>
    <% end %>
  </tbody>
</table>

pathはターミナルでrails routesと打って確認してみてください。(新規作成機能作る時に一回やったやつ。)edit画面へ遷移する時にはidが必要なので今この情報を持っているtaskを最後につけることを忘れずに。

これで編集機能は終わりです。

削除機能 ~destroy~

最後は削除機能を作成していきます。コントローラーにdestroyアクションを追加しましょう。

app/controllers/tasks_controller.rb
class TasksController < ApplicationController
  def index
    @tasks = Task.all
  end

  def new
    @task = Task.new
  end

  def create
    @task = Task.new(task_params)
    if @task.save
      redirect_to tasks_path
    else
      render 'new'
    end
  end

  def edit
    @task = Task.find(params[:id])
  end

  def update
    @task = Task.find(params[:id])
    if @task.update(task_params) 
      redirect_to tasks_path
    else
      render 'edit'
    end
  end

 #ここから追加
 def destroy
    @task = Task.find(params[:id])
    @task.destroy
    redirect_to tasks_path
  end
 #ここまで

  private
    def task_params
      params.require(:task).permit(:title, :body)
    end
end

ここではfind(params[:id])で削除する情報を見つけて、destroyで削除しています。
一覧画面に削除ボタンを付けましょう。

app/views/tasks/index.html.erb
<h1>やること一覧</h1>

<%= link_to '新規作成', new_task_path %>

<table>
  <thead>
    <tr>
      <th>やること</th>
      <th>詳細</th>
    </tr>
  </thead>

  <tbody>
    <% @tasks.each do |task| %>
    <tr>
      <td><%= task.title %></td>
      <td><%= task.body %></td>
      <td><%= link_to '編集', edit_task_path(task) %></td>
    <td><%= link_to '削除', task, method: :delete, data: { confirm: '本当に削除しますか?' } %></td>
    </tr>
    </tr>
    <% end %>
  </tbody>
</table>

ここではpath名ではなく、method: :deleteと記述することでdestroyアクションを呼びます。そして、data: { confirm: '本当に削除しますか?' }と記述することで確認のモーダルウィンドウを出すことができます。

最後に

お疲れ様です。以上でtodoアプリを作ることができました。たかがtodoアプリではありますが大事な要素が色々詰まっているので1つ1つ確認してみてください。

以上、最後まで読んでいただきありがとうございました!!!??

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

既存プロジェクトへのRidgepole導入

導入手順

Gemfile

gem 'ridgepole'

db/config.yml

development:
  adapter:  mysql2
  encoding: utf8
  database: xxxx_development
  pool:     5
  username: root
  timeout:  5000
  host:     127.0.0.1
  port:     3306

test:
  adapter:  mysql2
  encoding: utf8
  database: xxxx_test
  pool:     5
  username: root
  timeout:  5000
  host:     127.0.0.1
  port:     3306
  • スキーマファイル出力
bundle exec ridgepole -c db/config.yml --export -o db/Schemafile

マイグレーションの適用

  • diff/差分表示
bundle exec ridgepole --diff db/config.yml db/Schemafile
  • プレビュー
bundle exec ridgepole --config db/config.yml --file db/Schemafile --apply --dry-run
----------
Apply `db/Schemafile` (dry-run)
No change
  • 実適用
bundle exec ridgepole --config db/config.yml --file db/Schemafile --apply
----------
Apply `db/Schemafile`
No change
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

railsにSlimを導入する

Gemfile
gem 'slim-rails'
gem 'html2slim'
bundle

レイアウトファイルをSlimに変更する

bundle exec erb2slim app/views/layouts/ --delete
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Google Recruit

Mac OS X-10.15.7 ruby-2.7.1p83

Google Recruit

講義ページリンク

Google recruit problem, exp and prime

課題

ネイピア数(200桁)に出現する10桁の整数のうち一番初めに登場する素数を求めるついでに素数を求めるメソッドを実装する

方法

  • 先頭から順番に10文字ずつ切り取って素数判定する

解答例

"google_recruit.rb"
#!/usr/bin/env ruby
# frozen_string_literal: true

napier = File.read('napier.txt').delete('.')
digit_num = 10

def prime?(n)
  false if n == 1
  2.upto(Math.sqrt(n).to_i) do |i|
    return false if (n % i).zero?
  end
  true
end

(0..napier.length - digit_num).each do |i|
  n = napier.slice(i, digit_num).to_i
  if prime?(n)
    puts n
    break
  end
end
"napier.txt"
2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274274663919320030599218174135966290435729003342952605956307381323286279434907632338298807531952510190

出力

> ruby google_recruit.rb
7427466391

NOTE

  • prime?は(この問題では心配ないが)1はfalseになることを忘れないようにする
    • 中身はほとんど講義ページと同じ
  • 配列のスライスは .slice(pos, size) でposから長さsizeで切り出す事ができる

  • source ~/multiscalesim_toku/grad_members_20f/members/lynd2299/google_recruit.org
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

railsで7つのアクション以外のルーティングする場合(member,collection)

自分がcollection,memberを忘れていたので備忘録として。

railsで7つのアクション以外のルーティングをする場合

そもそも、、、7つのアクションとは

何か投稿するといった内容をイメージすると

index → 一覧表示
show  → 詳細表示
new  → 新規投稿
create → 新規投稿を保存
edit  → 投稿を編集
update → 投稿を更新
destroy  → 投稿を削除

これらは

resources :コントローラー名

でルーティングができるので便利です。
アクションを限定したいときはonly,で設定します。

7つのアクション以外のルーティングを設定したいときはどうするのか

方法としては2つあって
1つは

collection do
   get(アクションに応じたHTTPメソッド) 'アクション名'
end

もう1つは

member do
  get(アクションに応じたHTTPメソッド) 'アクション名'
end

この2つの違いはURIパターンに
:idが含まれるかどうか、です。

rails routes でURIパターンを確認し、

/tweets/search(.:format)  

であればcollectionを

 /tweets/:id/search(.:format) 

であればmember を使います。

HTTPメソッドもrails routes を実行すればわかりますが、
基本的にはgetが多いイメージです。。

get:何か出力を要求
post:データを送る という感覚です。

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

EC2で自動デプロイが反映されなくなったときの対処法

はじめに

現象

いつもどおり自動デプロイしたはずがまったく反映されない

やってみて

EC2インスタンスがおかしいのかなと思って再起動してみたら無事解決。
再起動に必要なコマンドを備忘します。

手順

EC2インスタンスを再起動

AWSコンソールからEC2インスタンスを再起動します。

DBを起動させる

EC2を再起動するとDBが停止状態になるので起動させます。
(私はMariaDBを使用しています)

確認コマンド

ターミナル(EC2)
$ sudo systemctl status mariadb

結果

ターミナル(EC2)
● mariadb.service - MariaDB database server
   Loaded: loaded (/usr/lib/systemd/system/mariadb.service; disabled; vendor preset: disabled)
   Active: inactive (dead)

死んじゃってるのが確認できます。


DB起動コマンド

ターミナル(EC2)
$ sudo systemctl start mariadb

これで確認するとActiveになっているはずです。

Nginxを起動させる

同じようにNginxも起動させます。

Nginx起動コマンド

ターミナル(EC2)
$ sudo systemctl start nginx

改めて自動デプロイを行う

これが本当に正解なのかわからないところがありますが(1度目の自動デプロイの内容をEC2が読み込めているなら、Unicornの起動だけでいいような気がします)

とりあえず自動デプロイを行えばEC2に反映されますし、Unicornも起動されるのでもう一度コマンドを打ちます。

ターミナル(ローカル)
% bundle exec cap production deploy

これにて一件落着です。

おわりに

スクリーンショット 2020-11-26 12.34.44.png

本当にこの画面が嫌いです。

✔︎

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

rubocopを導入してみた

始めに

rubocopはRubyで書いたコードが規則に従っているかを自動的にチェックしてくれるコーディングチェックツールです。Rubyはシンプルかつ多様な書き方が出来る言語なのでエンジニアによっては書き方にばらつきが生じます。そこで、rubocopを導入することで、複数人でコーディングをする場合にコードの可読性を保つことが出来るというメリットがあります。勿論一人で開発を進める時でも手軽にコード確認が行えますので、早速導入していきたいと思います。

rubocopのインストール

Gemfileに以下の二つを記述してからbundle installします。

Gemfile.
group :development do
  <snip>
  gem 'rubocop', require: false
  gem 'rubocop-rails'
end

これだけで導入が完了できました。

とりあえず使ってみる

このコマンドをアプリがあるディレクトリで実行するだけです。

rubocop

実行すると解析が始まり、ディレクトリ内のRubyで書かれたコードはチェックされます。

Inspecting 123 files
CCCCCCCCCCCCCCCWCCCCCCCCWCWCCCCCCCCCCCCCCCCCCCCCCCCCWCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCWCCCCCWCCCCCCCCCCCC

すごい数の警告が出てきました。

次はこの警告に対応してデバッグをしていきます。

rubocopの設定

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

rubocop --auto-gen-config

するとこのように2つの設定ファイルが生成されるはずです。

Added inheritance from `.rubocop_todo.yml` in `.rubocop.yml`.

.rubocop.ymlはコーディングの規則、.rubocop_todo.ymlは修正するべきコードの部分を記述したものであると考えていいでしょう。

.rubocop.ymlの中をいじっていきます。

rubocop.yml
inherit_from: .rubocop_todo.yml

require:
  - rubocop-rails

AllCops:
  TargetRubyVersion: 2.7.1

  Exclude:
    - 'config.ru'
    - 'bin/**'
    - 'lib/**'
    - 'db/**/*'
    - 'config/**/*'
    - 'script/**/*'
    - !ruby/regexp /old_and_unused\.rb$/

AsciiComments:
  Enabled: false

Documentation:
  Enabled: false

ClassAndModuleChildren:
  Enabled: false

Style/FrozenStringLiteralComment:
  Enabled: false

Style/GuardClause:
  Enabled: false

この辺の設定は個人やチームによって異なると思います。

修正

rubocopには自動修正機能があります。以下のコマンド実行で修正が始まります。

rubocop -a
123 files inspected, 605 offenses detected, 605 offenses corrected

かなりの部分が修正されましたが、これで全部ではありません。.rubocop.todo.ymlに書かれた違反部分を消す→rubocop実行→修正のサイクルで進めていくことになると思います。

終わりに

簡単な解説でしたが、無事にrubocopを導入してコードのチェックが出来るようになりました。

参考にさせていただいた記事

Rubocop導入+手順とコマンドの備忘録

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

Herokuを使ったデプロイ手順

はじめに

プログラミング初心者のメモ。
Herokuでデプロイしてみた覚書。

手順 ーはじめてデプロイをする場合

  1. Herokuにアカウント登録する
  2. Heroku CLIをインストールする
  3. 必要なGemを導入する
  4. masterブランチへcommitする
  5. Heroku上にアプリケーションを作成する
  6. MySQLを使用できるように設定する
  7. master.keyを環境変数として設定する
  8. Herokuへアプリケーションの情報をpushする
  9. Heroku上でマイグレーションを実行する

手順 ーデプロイ済みのアプリケーションに変更修正を加えた場合

  1. 変更修正をcommitする
  2. ブランチを作成していた場合は、masterブランチへマージする
  3. Heroku上にpushする
  4. (テーブルに変更を加えた場合は)Heroku上でマイグレーションを実行する

Basic認証を導入する

  1. アプリケーションコントローラーのprivateメソッドに以下のように記述
ruby.application_controller.rb
class ApplicationController < ActionController::Base
  before_action :basic_auth
(省略)

  private

  def basic_auth
    authenticate_or_request_with_http_basic do |username, password|
      username == 'admin' && password == '2222'
    end
  end
end
  1. 挙動確認後、ユーザー名、パスワードを環境変数につっこむ
% vim ~/.zshrc

# .zshrcの内部に次の記述を追加
export BASIC_AUTH_USER='admin'
export BASIC_AUTH_PASSWORD='2222'
# 記述を追加したら、escキーを押してインサートモードを抜け、「:wq」と入力して保存して終了する

# .zshrcを再読み込みし、定義した環境変数を有効にする
% source ~/.zshrc
  1. アプリケーションコントローラーの記述も環境変数に変更する
ruby.application_controller.rb
class ApplicationController < ActionController::Base
  before_action :basic_auth
 (省略)

  private

  def basic_auth
    authenticate_or_request_with_http_basic do |username, password|
     username == ENV["BASIC_AUTH_USER"] && password == ENV["BASIC_AUTH_PASSWORD"]  # 環境変数を読み込む記述に変更
   end
  end
end
  1. Heroku上に環境変数を設定する
% heroku config:set BASIC_AUTH_USER="admin" 
% heroku config:set BASIC_AUTH_PASSWORD="2222"

#ターミナル上で正しく設定されているか確認する
%heroku config

#以下のように表示されれば成功
=== stormy-journey-22625 Config Vars
BASIC_AUTH_PASSWORD:      2222
BASIC_AUTH_USER:          admin
  1. 変更したコードをgitにコミットし、Herokuへデプロイする
% git add .
% git commit -m “Basic認証を導入”
% git push heroku master
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】部分テンプレート(render)で別のコントローラーのビューを呼び出す方法

はじめに

違うファイルのビューを他のファイルのビューに表示さる際、部分的にそのビューをrenderで呼びだすことができます。
そんな、部分テンプレートの方法について紹介します。

目次

  1. 部分テンプレートファイルの名前について
  2. renderで呼び出す
  3. コントローラーへの定義

開発環境

ruby 2.6.5
rails 6.0.0

実装

それでは実装していきます〜

1. 部分テンプレートファイルの名前について

まず、部分テンプレートとしてビューファイルを作成する時は_index.html.erbのようにファイル名の前に_(アンダースコア)をつけます。

スクリーンショット 2020-11-23 5.40.44.png

今回はproductsコントローラーのビューを部分テンプレートとして使いたいので、products/_indexとなるようにファイル名を編集すます。

2. renderで呼び出す

次にテンプレートする側にrenderメッソドを記述します。
今回は以下の記述をします。

app/views/tops/index.html.erb
#省略
<%= render partial: "products/index" %>

構文はこちらです。

render partial: コントローラー名/ファイル名

partialオプションは部分テンプレートを呼び出す時に使います。ただ、強調しているだけ、つけなくても呼び出せます。

スクリーンショット 2020-11-23 5.48.40.png

これで完成!!と思ったのですが、今回@productsを定義してProductモデルからデータを取得してビューに表示してる為、topsコントローラーでも定義が必要です。

3. コントローラーへの定義

保存したデータを呼び出す場合コントローラーでインスタンス変数にデータを代入してビューで使用します。

productコントローラーで動かすのであればそちらに@productsを定義しますが、今回はtopsコントローラのアクションが動くのでそちらで定義する必要があります。

app/views/products/_index.html.erb
<h1>Products#index</h1>
<p>Find me in app/views/products/index.html.erb</p>

<div class="#">
  <% @products.each do |product|  %> #ここで@productsを定義してるので、コントローラーでも定義が必要です。
    <%= product.name %>
    <%= product.text %>
  <% end %>
</div>

このproducts/_index.html.erbが部分テンプレートとして呼び出されるので、呼び出された側のtops_contller.rbでも@products定義が必要です。

app/contollers/tops_contller.rb
class TopsController < ApplicationController
  def index
    @tops = Top.all
    @products = Product.all #部分テンプレートで_index.htmlを表示させる為の定義

  end

これで完成です!!!

まとめ

以上部分テンプレートの手順でした。
用途に応じて他にもやり方がありますが、今回はこの方法で実装してます。

最後に

私はプログラミング初学者ですが、自分と同じ様にエンジニアを目指す方々の助けになればと思い、記事を投稿しております。
それではまた次回お会いしましょう〜

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

Cloud9でRuby on Railsの環境構築 ~インストールから起動まで~

はじめに

備忘録としてタイトル通り、Cloud9を使用したRuby on Railsの環境構築の手順を記載します。

独学でPHP・Laravelを学習しており、現在就活中なのでプロのエンジニアではありません。
転職希望の企業がRubyとRailsを使用した開発をメインとしているので、改めて学習が必要となりアウトプットも兼ねてカキコします。

Cloud9を選択した理由は以下の通りです。

  • 使用PCがwindows10のため、ローカルに入れるよりもLinux環境の方がエラーの際情報が多い
  • ポートフォリオのインフラにAWSを使っている為アカウントを持っていた
  • 基本無料で使用できる

なおこの記事は環境設定のハウツー的な構成ではなく、私が行った手順とエラーを時系列そのままで記載します。
「環境設定の方法を知りてえんだ!」って方はプロの記事を参考にしてください。

目標

AWSのCloud9にRuby on Railsをインストールし、アプリケーションを起動して「Yay! You’re on Rails!」を表示させる

環境

Amazon linux
ruby 2.6.3
Rails 6.0.3.4
MySQL 5.5.62(後々5.7にバージョン上げてエラーになる)
MySQL 5.5から5.7へのバージョンアップと、libmysqlclient.so.18: cannot open shared object file: No such file or directoryの解消

やってきましょう

バージョン確認

とりあえずRubyのバージョン確認。もともとインストールはされている模様。

$ ruby -v
ruby 2.6.3p62 (2019-04-16 revision 67580) [x86_64-linux]

続いてRailsのバージョンも確認しておきましょう。

$ rails -v
Rails 5.0.0

Railsも入っているんですね。
でもバージョン5.0.0って、beta1が2015年12月18日にリリースされたらしくかなり古い様子。
バージョンアップしたいなあ。

$ gem install rails
$ rails -v
Rails 6.0.3.4

取り合えず最新版にアップデートできました。

そうしたらプロジェクトを作成するディレクトリを作ります。

名前は何でもいいので、ホームディレクトリに移動して"rails-training"を作成します。
そのあとcdコマンドでrails-trainingディレクトリに入り込みましょう。

$ cd
$ mkdir rails-training
$ cd rails-training

ここでMySQLのバージョン確認を思い出す。

$ mysql -v
ERROR 2002 (HY000): Can't connect to local MySQL server through socket'/var/lib/mysql/mysql.sock' (2)

エラーが出ました。
どうやらsocketファイルが無いのでMySQLに接続できていないらしい。

MySQLを再起動すると自動でsocketファイルが作成されるので、一度停止してもう一度起動してみる。
(restartでもいいけど、何となく気持ち悪いのでしっかり停止と起動を実行)

$ /etc/init.d/mysqld stop
$ /etc/init.d/mysqld start
touch: cannot touch ‘/var/log/mysqld.log’: Permission denied
chown: changing ownership of ‘/var/log/mysqld.log’: Operation not permitted
~略~
chown: changing ownership of ‘/var/lib/mysql’: Operation not permitted

パーミッションエラーですね、私には起動させる権限がないようです。

$ sudo /etc/init.d/mysqld start

ってことでsuduコマンドで強制実行。うまく再起動できました。

引き続き以下のコマンドで最低限のセキュリティ設定をします。MySQLの初期設定についてメモしておく
その後に忘れずMySQLの再起動。

$ mysql_secure_installation
~略(対話形式でパスワード等を設定)~
$ sudo /etc/init.d/mysqld restart

プロジェクト作成

ここまでやってやっとRaylsプロジェクトを作成。
カレントディレクトリが先ほど作ったrails-trainingであることを確認します。

RailsはデフォルトのデータベースがSQLiteに設定されているので、オプションで"-d mysql"を指定してあげます。

$ rails new training_app -d mysql
~略~
An error occurred while installing mysql2 (0.5.3), and Bundler cannot continue.
Make sure that `gem install mysql2 -v '0.5.3' --source 'https://rubygems.org/'` succeeds before bundling.
~略~

こんなエラーが発生しました。

「rails new」コマンドを実行すると、アプリ生成時に必要なパッケージを「RubyGems」で自動的にインストールする仕組みになっています。

さきほど、「-d mysql」オプションを指定したことにより、「gem install mysql2」コマンドが内部で実行されました。

ところが、「mysql2」というgemパッケージをインストールするには、「mysql-devel」というrpmパッケージがCentOSにインストールされていることが前提となっていたため、「mysql2」のインストールに失敗してしまったようです。
つまり、この問題を解決するには

yumで「mysql-devel」をインストール
gemで「mysql2」をインストール

という手順を踏む必要があります。
【Ruby on Rails環境構築】インストールから起動までの手順【MySQL】

という事なので、私はyumで「mysql-devel」をインストールしました。

加えて引用サイトに記載もありますが、先ほどの"rails new"コマンドは生きているので、プロジェクト自体はすでに作成されています。
ですので新しく"rails new"コマンドを実行する必要はありません。

$ sudo yum install -y mysql-devel
$ ls
app  bin  config  config.ru  db  Gemfile  lib  log  package.json  public  Rakefile  README.md storage  test  tmp  vendor

サーバー起動

プロジェクトディレクトリに移動してから実行します。

$ cd training_app
$ rails s
=> Booting Puma
=> Rails 6.0.3.4 application starting in development 
=> Run `rails server --help` for more startup options
Exiting
Traceback (most recent call last):
~略~
/home/ec2-user/.rvm/gems/ruby-2.6.3/gems/webpacker-4.3.0/lib/webpacker/configuration.rb:95:in `rescue in load': Webpacker configuration file not found /home/ec2-user/rails-training/training_app/config/webpacker.yml. Please run rails webpacker:install Error: No such file or directory @ rb_sysopen - /home/ec2-user/rails-training/training_app/config/webpacker.yml (RuntimeError)

rails webpacker:installを実行してくださいエラー:そのようなファイルまたはディレクトリはありません

ひとまず言われた通りに"rails webpacker:install"を実行。

$ rails webpacker:install
Yarn not installed. Please download and install Yarn from https://yarnpkg.com/lang/en/docs/install/

yarnがインストールされていないようなので、インストールしてから再度実行し、サーバーも起動。

$ brew install yarn
$ rails webpacker:install
$ rails s

ページにアクセスすると、以下のエラーが出て正常に表示されない。

To allow requests to **********.vfs.cloud9.ap-northeast-1.amazonaws.com, add the following to your environment configuration:

なにやらRails6からDNS再バインド攻撃対策として、自身からしかアクセスができない使用になっているらしい。

config/application.rbのApplicationクラスにアクセスを許可する設定を記載すれば解決される様子。

<config/application.rb>

require_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 TrainingApp
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 6.0

    #以下一文を追加。末尾が"amazonaws.com"のドメインは許可する。
    config.hosts << ".amazonaws.com" 

    # 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

これで表示されることを信じてサーバーを起動。

$ rails s

Mysql2::Error::ConnectionError
Access denied for user 'root'@'localhost' (using password: NO)

今度はMySQLのrootユーザーのパスワードが一致しないので、データベースにアクセスできないときた。
これはLaravelでも経験があるエラーなので落ち着いて対処。

Raylsではtraning_app/config/detabase.ymlにデータベース周りの設定を記載すればいいみたい。
私の環境だと17行にさっき対話形式で設定したMySQLのパスワードを書いていく。

<traning_app/config/detabase.yml>

~略~
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: ここにパスワードを記載
  socket: /var/lib/mysql/mysql.sock

development:
  <<: *default
  database: training_app_development
~略~

これでどうでしょうか、そろそろ勘弁してください。

$ rails s

ActiveRecord::NoDatabaseError
Unknown database 'training_app_development'

また出ました。
"training_app_development"なんてデータベース知りませんっておっしゃってます。

あれ?そもそもデータベース作ってないな。
ってことでデータベースを作ります。

$ mysql -u root -p
Enter password: **********

> CREATE DATABASE test_table;
> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test_table         |
+--------------------+

よしよし、データベースはできました。
後から知りましたが、Railsはdbコマンドでデータベースを作成した方がいいようです。

$ rake db:create

この作った"test_table"を使用するように設定します。

ひとつ前でパスワードを設定した"traning_app/config/detabase.yml"ファイルを眺めていると、エラー内容と同じ名前のデータベース名を発見。
多分ここに書けば反映されそう。

<traning_app/config/detabase.yml>

~略~
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: ここにパスワードを記載
  socket: /var/lib/mysql/mysql.sock

development:
  <<: *default
  database: ここにデータベース名を記載
~略~

これで完璧なはず。

$ rails s

**********.vfs.cloud9.ap-northeast-1.amazonaws.com で接続が拒否されました。

調べてみると画像の部分を押して別タブで開けば表示されるとの情報を発見。

名称未設定のデザイン (12).jpg

スクリーンショット 2020-11-26 184833.png

出来ました。
Yay! You’re on Rails!を表示できたので、とりあえず一件落着です。

MySQLのバージョンアップは以下の記事を参照。
MySQL 5.5から5.7へのバージョンアップと、libmysqlclient.so.18: cannot open shared object file: No such file or directoryの解消

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

[Rails]ユーザー新規登録時にメールを自動配信する機能を実装する[備忘録]

はじめに

先日、Ruby on Railsでアプリケーションを作成しました。
その中で、ユーザーに新規登録をしてもらうと同時に、ユーザーのメールアドレス宛にメールを送る機能を作りました。
ネットで調べつつ、試行錯誤しながら実装したのですが、色々な情報が入り乱れていて、少しだけ分かりにくかった印象があったので、備忘録も兼ねて、ここでまとめたいと思います。
それでは参りましょう!

メール送信機能を記述

config/environment/development.rb
#以下を追記
config.action_mailer.raise_delivery_errors = true
config.action_mailer.default_url_options = { :host => 'localhost:3000'}
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
  :address => 'smtp.gmail.com',
  :port => 587,
  :domain => 'gmail.com',
  :user_name => "hoge@gmail.com",  # user_name, passwordはご自身のものに変更して下さい。
  :password => "hogehoge",
  :authentication => :plain,
  :enable_starttls_auto => true
}

メーラーを作成

メール送信におけるコントローラー的役割を果たすMailerを作成します。
rails g mailer <メーラー名> <メソッド名>

ターミナル
$ rails g mailer ThanxMailer complete_registration

このコマンドを打つことにより、app/mailers/application_mailer.rbapp/mailers/thanx_mailer.rbが生成されます。
次に、それらのテンプレートファイルを編集していきましょう!!

メーラーを編集

app/mailers/application_mailer.rb
class ApplicationMailer < ActionMailer::Base
  default from: '管理者'
  layout 'mailer'
end
app/mailers/thanx_mailer.rb
class ThanksMailer < ApplicationMailer
  def complete_registration(user)
    @user = user
    mail(:subject => "登録ありがとう!!!!", to: user.email)
  end
end

メール本文の作成

views/thanx_mailer/complete_registration.text.erb
<%= @user.name %> 様

会員登録ありがとう!!!!

コントローラへの記述

app/controllers/users_controller.rb
def create
  @user = User.new(user_params)
  if @user.save
    ThanxMailer.complete_registration(@user).deliver
  end
end

メーラーは、メーラー名.メソッド名と記述することで、クラスメソッドを呼び出すように実行できます。
実際の送信はdeliverメソッドが行います。

おわりに

メール送信機能自体は、記述する量も比較的少ないため、理解がしやすいと思います。
ただただコピペするだけでなく、一つ一つの意味をしっかり理解していきたいですね。

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

Mysql2::Error: Table '○○_production.users' doesn't existを解消した話

表題が発生し、解消するまでの顛末をまとめました。原因は2つありました。

開発環境

ruby 2.6.5
Rails 6.0.3.2
capistrano 3.14.1
AWS EC2
webサーバーNginx
アプリケーションサーバーUnicorn

事の発端

データベース関連の修正を行ったため、本番環境(EC2)で一度テーブルを落としてから再作成しました。
そしてマイグレーションを行った際、表題のエラーが発生しました。結論、原因は2つありました。

原因その1 userを参照するreferencesメソッドが、userテーブルが作成される前に読み込まれていた

こちらの方がわかりやすくまとめられてます。
https://obel.hatenablog.jp/entry/20170719/1500456452

rails db:migrate:statusで確認すると、確かにテーブルのステータスがdownになっていました。
タイトルの通り、エラーメッセージの指摘は何ら矛盾がありませんでしたね。
ただ、開発環境ではエラーにはならず?アプリも正常に動いていたので、気づくのにかなり時間を費やしました。

こちらの記事の通り、マイグレーションファイルの日付を修正して、読み込まれる順序を変更しました。
そして、statusはupになりましたが、それでもエラー自体は解消されませんでした。

原因その2 本番環境でgit pull origin masterをしていなかった

結論、これによって上の作業がEC2上に反映され、ようやく解消に至りました。

いやもう思い違いをしていたというか、今なお十分な理解に至っていないのですが、githubへpush(作業ブランチで開発していた場合はmergeしてmasterへpullまで)したら、このコマンドは必要ないと思っていました。
実際、それで自動デプロイのコマンドを打てば、本番環境に機能を実装させることはできていました。

git pull origin masterは毎回必要なのだろうか?この辺りは宿題になっています。
git,githubは大分慣れたように思っていましたが、まだまだ知識が不足しているようです。

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

【Public】マルチスケールシミュレーション特論公開記事リスト

はじめに

マルチスケールシミュレーション特論の講義メモです.授業内で 学習メモがpublicになっていて,LGTMをもらえている という指示があったので,拙い内容ですが投稿しています.

公開記事リスト

  1. 【Week 5】bash, ruby_first

  2. 【Week 6】my_help, ruby_second

  3. 【Week 7】gem, ruby_third

  4. 【Week 8】rake, ruby_fourth

  5. 【Week 9】rubular, ruby_fifth

  6. 【Week 10】Coming soon…

  7. 【Week 11】Coming soon…

  8. 【Week 12】Coming soon…


  • source ~/grad_members_20f/members/e79a93e5b7b1/public_list.org
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails 6.0~ DEPRECATION WARNINGが出力されないようにした。

rails6.0~から定数の読み込みにzeitwerkモードというものが使われるようになりました。
https://railsguides.jp/autoloading_and_reloading_constants.html
それに起因して、サーバーを起動した際に以下のようなwarningがログに出力されるようになりました。
このwarning邪魔なので消したいなあと思っていたところ、無事解決することができたので、同じことで困っている方たちのお役に立てれば良いなと思い、雑記します。

DEPRECATION WARNING: Initialization autoloaded the constants MyClass.

結論から述べると、このwarningが出る原因は、initializersディレクトリ内で自分で定義した定数(MyClass)を読み込んでいたことでした。
initializersディレクトリ内での定数の読み込みはリロード時には行われない。そして、自分で定義した定数はリロード時に変更を反映できる方が開発の便宜上良いので、initializersで読み込むべきではない、といったところでしょうか。

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

マルチスケールシミュレーション特論: google recruit

ruby-2.5.5p157

はじめに

今回はマルチスケールシミュレーション特論という大学院の授業で ruby を使った課題があったのでプログラムを作成してみた

  • 課題{e(自然対数の底)の値で連続する 10 桁の数のうち,最初の素数}を求めよ

手法

e は以下のように定義されている

e = 2.71828182845904523536028747135266249775
    7247093699959574966967627724076630353547
    5945713821785251664274274663919320030599
    2181741359662904357290033429526059563073
    81323286279434907632338298807531952510190

以下のような 手順 で今回は進めていこうと思う

手順

  • e.txt というテキストファイルに e の値を保存しておく
  • e.txt から値を読み込む
  • 2.7 の部分の "." を除去して 10 桁毎に値を区切る
  • 区切った値が素数かを判定する

プログラム

 1  #!/usr/bin/env ruby
 2  require 'prime'
 3  
 4  def divide_per_ten
 5    f = File.open("e.txt")
 6    s = f.read.delete(".")
 7    start_index, goal_index = 0, 10
 8    while true do
 9      if prime_decision(s[start_index, goal_index].to_i) == true then
10        puts s[start_index, goal_index]
11        break
12      end
13      start_index = start_index + 1
14    end
15  end
16  
17  def prime_decision(num)
18    return Prime.prime?(num)
19  end
20  
21  divide_per_ten

各関数の説明

  • divide_per_ten 関数:ファイルから e の値を読み込み、10 桁毎に区切ってprime_decision 関数に渡す

  • prime_decision 関数:素数の判定を行って、true or false を返り値として渡す

GitHub

コードは以下の URL から閲覧できます

結果

実行すると以下のような答えがでてきます

7427466391

さいごに

是非、おもしろいなと思ったら LGTM してくれると今後の励みになるのでお願いします!!

(LGTM されると嬉しくて踊りだします)


  • source ~/Downloads/git/grad_members_20f/members/taiseiyo/memos/google.org
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む