- 投稿日:2020-01-04T23:15:00+09:00
form_withでデフォルトのデータ送信先を変更する[Rails]
ポートフォリオアプリを作っています。
作品の一覧と各作品の詳細は誰でも見られるようにしようと思いますが、作品の投稿と編集は管理者だけができるようにしたいと思います。管理者ユーザーの作成は、過去の自分のこちらの記事を読んで実装できたのですが、
【初心者向け】管理者ユーザーと管理者用controllerの追加方法[Ruby, Rails]
その後、管理者ユーザーの投稿機能をつけ、submitボタンを押したときに、以下のようなエラーが出ました。
何、
/works
にPOSTメソッドでつながるルーティングがないそうです。
確かに、rake routes
で確認してみると、管理者ユーザーが画像を投稿するときのルーティングはadmin_works_path
で、URLも/admin/works
です。works GET /works(.:format) works#index work GET /works/:id(.:format) works#show admin_works GET /admin/works(.:format) admin/works#index POST /admin/works(.:format) admin/works#createところが、form_withの記述を見直してみても、以下の通り。
= form_with model: @work, local: true do |f| # 中略 =f.submitそうでした、form_withは投稿先のメソッドに応じて、よしなにURLを変更してくれるのでした。ちなみに、これで
POST(create)
にもPATCH(edit)
にも対応してくれます。わー、便利。ですが、今回はこちらのデフォルトのURLを変更しなければいけません。
form_withのAPIドキュメントを翻訳してくれた方がいたので、こちらの記事を参照しました。Rails 5.1〜: ‘form_with’ APIドキュメント完全翻訳
こちらの記事によると、「ルーティングをadmin_post_urlのように名前空間化する場合は以下のようにします。」とのこと。
<%= form_with(model: [ :admin, @post ]) do |form| %> ... <% end %>こちらを参考に、hamlに合わせて、以下のように記述を変更しました。
第二引数にurlを追記しています。= form_with model: [ :admin, @work ], local: true do |f|・・・そしたら、、、動いた!!
以上、簡単ですが、form_withのデフォルトの送信先を変更する方法でした^^
- 投稿日:2020-01-04T22:43:37+09:00
Ruby on Rails にdeviseを使ってログイン機能を導入する
書きつくされているRuby on Railsにdeviseを導入する記事ですが、ひとそれぞれ目的が微妙に違うのか躓いてしまいます。
そこで僕の無知から来るミスも含めて共有し、同じ過ちを皆様に犯さないでいただけるのなら記事を書いたかいがあります。
また、よりよい方法があると思いますが、ご参考にしていただければと思います。それではいきましょう!
環境
・macOS
・Ruby 2.7.0
・Ruby on Rails 6.0.2もくじ
1.Railsのプロジェクトを作成する
2.簡単な画面遷移を作る
3.ログイン機能を実装する(ここでdeviseが登場)1.Railsのプロジェクトを作成する
まずはアプリを開発するディレクトリを作成する。
$ mkdir app_name $ cd app_nameその後のプロジェクトの作成方法は以下を参照してください。
https://qiita.com/tom-ohiro/items/0030999b838bfe05006dak2.簡単な画面遷移を作る(トップページの作成)
この工程があったために勝手に混乱することに。
まずはユーザーコントローラを作って、トップページを作成。
以下のコマンドでusers_controller.rbなどのファイル、ディレクトリが作成される。$ rails g controller usersapp/controllers/users_controller.rbdef index endルートを設定する。
config/routes.rbget '/' => 'users#index'表示ページを作成する。inde.html.erbは新規ファイルを自分で作成する。
app/view/users/index.html.erbHello world! とプログラマっぽく書く以下を実行してサーバーを起動する。
$ rails shttp://localhost:3000/
にアクセスするとトップページが表示される。3.deviseを用いてログイン機能を実装する
ここからが本番。
コマンドの順番を間違えると初学者には非常に厄介に感じられるので、よく注意して進んでください。1.Gemfileに以下を記入
gem 'devise'2.以下のコマンドをターミナルで実行
順番を間違えないようにゆっくりやりましょう。$ bundle install僕は以下のコマンドを忘れていて非常に困った。。。皆様ご注意ください。
$ rails g devise:installこちらの設定は1,2だけ別途やっておけば大丈夫。
1.はメールを送るときの設定の話。以下の記述を追記してください。
まぁ書いてあるとおりにやるだけなんですが、英語で表示されているだけでうわってなってしまいますよね。
これからこんな画面の連続なので、頑張って読みに行くようにしてみましょう。
読んで見ればこんなこと解説するまでもねーじゃねえかって思うようなことなんです。
でも、はじめのとっつきにくさは半端ないので少しでもハードルが下がればと思い解説させていただきました。config/environments/development.rbconfig.action_mailer.default_url_options = { host: 'localhost', port: 3000 }2.はトップページの表示の話。
以下の記述は上の方で書いた内容と同じことなので、以下の内容を上書きしていただければ大丈夫です。config/routes.rbroot to: "home#index"次に以下のコマンドをターミナルで実行します。
これでログイン画面や新規登録画面などを用意してくれます。$ rails g devise:views続いてUserモデルの作成です。
migrationファイルなどが作成されます。
初めての場合は特にmigrationファイルの編集なしで連続して以下のコマンドを入力しても大丈夫でしょう。
あとから保存内容を変えることもできますし、今のうちに編集していただいてももちろん大丈夫です。$ rails g devise User $ rake db:migrate続いて以下の画面。
僕はここで非常に困ってしまいました。
すでにusers_controllersを作ってしまっているので、名前がかぶってしまうのではないか?
ということでコントローラを消すという作業をしてしまいました。
deviceでよく使うusers_controllerと混同してしまいますが、実行しても問題ありません。今後は先を見越して先にdeviceの導入からしたほうがいいでしょう。$ rails g devise:controllers users以下の記述はログインする前にページにアクセスしようとすると、ログイン画面に遷移させるというものです。
app/controllers/application_controller.rbbefore_action :authenticate_user!これでdeviceの導入は完了です。
トップページにアクセスしようとするとログイン画面に遷移すると思います。おわりに
deviceはとっても便利な機能である一方でわけわからなくても使えてしまうgemでもあります。
便利さと引き換えに使いこなしまでのレベルになるにはもう何段階かレベルアップする必要がありますが、まずは使える技を少しずつ増やして自信をつけることが大切だと思います。
共に頑張っていきましょう。
もし、この方法でうまくいかないとか、このやり方はおかしい。このやり方の方が適当ではないかと言う場合はコメントいただけると大変うれしく思います。
最後までお読みいただきありがとうございました。
- 投稿日:2020-01-04T22:21:31+09:00
【Rails】Rspec何言ってるか解読してみた件。コントローラー#index編
今回は、写真とタイトルを投稿するアプリケーションのtweetsコントローラーのindexアクション(トップページを表示する)が問題なく動くかどうか、Rspecという言語を使ってテスト。
テストする内容は2つ。
tweets_controller.rb内でindexアクションの定義文で生成した@tweetsに、意図したものが入っているかな?
tweets_controller.rbdef index @tweets = Tweet.includes(:user).page(params[:page]).per(5).order("created_at DESC") endテスト環境上で、indexアクションを起こすリクエストを飛ばして、indexアクションに対応したビューが返ってくるかな?
コントローラーのテストの際は、2つの点に注意。
①tweets_controller.rbにおいて、テストしたいアクションに対し、before_actionが定義されていないこと。
②gem rails-controller-testingをインストールしよう。テストで使うダミーデータの生成
また、トップページはこれまで投稿されたツイートが一覧表示される仕様。テスト環境上でのindexアクションで持ってくる、これまでに投稿されたツイートデータを、ダミーでテスト用に生成。gemのfactory_botを利用しよう。ツイート投稿の際、そのツイートは誰が作ったのかという情報も含まれるため、ダミーユーザーも作成しダミーツイートにその情報を含ませよう。
spec/factories/users.rbFactoryBot.define do factory :user do nickname {"mamama"} email {Faker::Internet.email} password {"00000000"} password_confirmation {"00000000"} end endspec/factories/tweets.rbFactoryBot.define do factory :tweet do text {"I love animals"} image {"animals.png"} created_at { Faker::Time.between(from: DateTime.now - 1, to: DateTime.now) } user end end
email{Faker::Internet.email}
tweets_controller.rb内indexアクション定義文のインスタンス変数には、複数のツイートデータが入る。テストで、インスタンス変数に意図したデータが入っているかを調べる際、factory_bot :tweetで生成したツイートデータを複数個一旦登録しておく。そして、テスト環境上で起こすindexアクションで、登録したデータ達を持って来て、インスタンス変数にそれらが入っているか確かめる。しかしemail {mmmm@e.mail}
などでは、テスト上で登録するツイート達の投稿者(user)のemailが全て被ってしまう。今回アプリの仕様上、同じメールアドレスは登録できないようにしてあるので、Fakerというgemをインストールしてemailを自動でランダムに設定させよう。
created_at { Faker::Time.between(from: DateTime.now - 1, to: DateTime.now) }
tweets_controller.rb内indexアクション定義文に、order("created_at DESC”)
とある。ツイートが投稿された日時(created_at)を大きい方から小さい方へ(DESC)、つまり新しいツイート順に並べる(order)という意味。何も指定しないと、ダミーツイートデータのcreated_atは全て同じになるので、意図した順番になっているかテストできない。バラバラな日時を設定する必要があるので、Fakerというgemをインストールし、現在の日時の1日前(DateTime.now - 1)から現在の日時(DateTime.now)の間で、created_atを自動でランダムに設定させよう。
user
factory_botを利用して作った :userのこと。それでは、見ていきましょう。
テストコードを解読。
tweets_controller_spec.rbrequire 'rails_helper' describe TweetsController, type: :controller do describe 'GET #new' do #「【Rails】Rspec何言ってるか解読してみた件。コントローラー#new編」を参照。 end describe 'GET #edit' do #「【Rails】Rspec何言ってるか解読してみた件。コントローラー#edit編」を参照。 end describe 'GET #index' do # 1. tweets_controller.rb内でindexアクションの定義文で生成した@tweetsに、意図したものが入っているかな? it "populates an array of tweets ordered by created_at DESC" do dummyTweets = create_list(:tweet, 3) get :index expect(assigns(:tweets)).to match(dummyTweets.sort{|a, b| b.created_at <=> a.created_at }) end # 2. テスト環境上で、indexアクションを起こすリクエストを飛ばして、indexアクションに対応したビューが返ってくるかな? it "renders the :index template" do get :index expect(response).to render_template :index end end end1. tweets_controller.rb内でindexアクションの定義文で生成した@tweetsに、意図したものが入っているかな?
require 'rails_helper'
RailsでRspecを利用する時の共通の設定が記載されているrails_helper.rbを読み込む。これがなきゃ始まらない。
describe TweetsController, type: :controller do end
tweetsコントローラーのテストをするよ。 type: :controllerこれは書かなきゃいけないみたいですね。
describe 'GET #index' do end
GETメソッドのindexアクションに関するテストだよ。
it "populates an array of tweets ordered by created_at DESC" do end
do - endの間に書かれている、実際に動くテストコードの説明。投稿日時で降順(created_at DESC)となっているtweetsの配列(an array of)があるか(populates)と言っている。日本語でも良いらしい。ちなみに、it do endのセット1つで、1exampleと呼ぶ。
dummyTweets = create_list(:tweet, 3)
factory_botで生成したダミーツイートを3つ登録するという意味。それをdummyTweetに入れる。ちなみにこれら3つのダミーツイートの作成者はemailだけが異なっている。
get :index
テスト環境上でリクエストを起こすコード。get :index
でアクション名indexをそのリクエストに情報として渡す。
expect(assigns(:tweets)).to match(dummyTweets.sort{|a, b| b.created_at <=> a.created_at })
インスタンス変数に意図したものが入っているかな?というテストコード。assignsは、インスタンス変数の中身をチェックしてくれるやつ。今回は、tweets_controller.rb内で定義した@tweetsが対象なので、(:tweets)と書こう。コードの意味は、@tweetsの中身は、一旦登録させてindexアクションで持ってこさせたdummyTweetsと一緒でかつ並びもcreated_atの降順(.sort{|a, b| b.created_at <=> a.created_at })である(.to match)と期待する(expect)。tweets_controller_spec.rb#省略 describe 'GET #index' do # 1. tweets_controller.rb内でindexアクションの定義文で生成した@tweetsに、意図したものが入っているかな? it "populates an array of tweets ordered by created_at DESC" do dummyTweets = create_list(:tweet, 3) get :index expect(assigns(:tweets)).to match(dummyTweets.sort{|a, b| b.created_at <=> a.created_at }) end # 2. テスト環境上で、indexアクションを起こすリクエストを飛ばして、indexアクションに対応したビューが返ってくるかな? it "renders the :index template" do get :index expect(response).to render_template :index end end #省略2. テスト環境上で、indexアクションを起こすリクエストを飛ばして、indexアクションに対応したビューが返ってくるかな?
it "renders the :index template" do end
do - endの間に書かれている、実際に動くテストコードの説明。indexアクションに対応したビューファイル(template)が呼び出される(renders)ことをテストしますと言っている。
get :index
テスト環境上でリクエストを起こすコード。get :index
でアクション名indexをそのリクエストに情報として渡す。
expect(response).to render_template :index
ちゃんと期待するビューが返ってくるかな?というテストコード。resposeが、indexが起きた時に呼ばれるrender_template(ビューである)と期待する(expect)。テストを実施。
ターミナルにて
% bundle exec rspec spec/controllers/tweets_controller_spec.rb
を実行しよう。
初学者の視点からRailsアプリケーションのRspecを使ったテストについてまとめてみました。指摘やご意見お待ちしてます。モデルや、コントローラーのその他アクションについても、まとめていきたいと思います。
最後までご覧いただきありがとうございました!
- 投稿日:2020-01-04T21:49:33+09:00
Ruby on railsとDjangoの違いまとめ~基礎編~
1. はじめに
プログラミングを始めて4ヶ月の初心者です!
Ruby on railsとDjangoを勉強中なので、
アウトプット(備忘録)として、その基礎的なコードの違いを書いていきたいと思います!!
railsから学習を始めていることから、
基本rails目線で、Djangoの場合はどうか?という目線で書いております
少しでも、ご参考になりましたら幸いです。
(勉強中なので、随時追記・修正していく予定です!)2. MVCモデル(Rails)とMTVモデル(Django)
"View"の名前が被っているので、ややこしい感じがしますが、大まかな流れは同じです。
自分のイメージを以下に示します。
3. ルーティング編
(Railsの場合)
routes.rbに記載していきます。
ターミナル上で"rake routes"を叩けば、URLパターンやprefixを確認できます!config/routes.rbroot 'products#index' get 'index', to: 'products#index'(Djangoの場合)
urls.pyに記載していきます。
path()関数を使用し、これは引数にroute,view,name,kwargsの4つの引数を取ります。
ここでは、ルートURL('')に、viewのindex関数を対応させ、indexという名称で他のファイル(templateなど)から呼び出せるようにしています。
viewにおいて汎用クラスを呼び出す場合は、"as_view"を使用します。app/urls.pyfrom django.urls import path from . import views app_name = "アプリ名" urlpatterns = [ path("", views.index, name="index"), path("products/", views.ProductListView.as_view(), name="products_list"), ]4. コントローラー/ビュー編
4-1. htmlファイルの指定方法
(Railsの場合)
controllerのアクション名と同じ名前のviewが呼び出されるというルールがありますので、
特にコードは必要なく、アクション名と同名のviewファイルを準備することで、そのview(html)ファイルが呼び出されます。controllers/products_controller.rbdef index endviews/index.html.erb.title haml等でhtmlを記載していきます(Djangoの場合)
関数を使用するか、クラスを使用するかによって、
それぞれ、renderメソッドかtemplate_nameメソッドを使用します(他にもいっぱいあるようです)app/views.py# 関数を使用する場合 def index(request): return render(request, "index.html") # クラスを使用する場合 class ModelListView(ListView): model = Model template_name = "index.html"4-2.インスタンス変数のhtmlファイルへの渡し方
(Railsの場合)
htmlファイルにおいて、変数を使用するために、@をつけて、インスタンス変数を定義します。products_controller.rbdef index @product = Product.where(id: 1..10) end(Djangoの場合)
変数がないのにhtmlファイルでデータが扱える、というのが衝撃的です!views.rbclass XxxListView(LoginRequiredMixin, ListView): model = Xxx template_name = "xxx.html" # templateにおいて、xxx_listで配列としてデータが使用できる(とはいっても、get_context_dataやget_querysetで変数の定義やデータの選択が可能です)
5. ビュー/テンプレート編
・部分テンプレートの書き方
(Railsの場合)
renderメソッドを使用します。index.html.erb<%= render '(フォルダ名/)yyy.html.erb' %> -# render先は'_yyy.html.erb'という名称とします(Djangoの場合)
base.html{% block content %} # ここに他のhtmlファイルを差し込みます {% endblock %}index.html{% extends "base.html" %} {% block content %} # この部分をbase.htmlに差し込みます(逆かもしれません) {% endblock %}ここはrailsの方が自由度が高いかと思います。
6. モデル編
・マイグレーション
(Railsの場合)
モデルの作成 (rails g model Xxx) or マイグレーションファイルの作成 (rails g migration)
->マイグレーションファイルの記入
->マイグレーションの実行(rake db:migrate)Migrationファイル##一例です t.string :name, null: false(Djangoの場合)
models.pyへの記入
->マイグレーションファイルの作成(python manage.py makemigrations)
->マイグレーションの実行(python manage.py migrate)models.pyclass Xxx(models.Model): xxx = models.CharField(max_length=200) user = models.ForeignKey(User, on_delete=models.CASCADE) def __str__(self): return self.title7. 感想
触っている時間が長いせいもあるかと思いますが、
railsの方がファイルの関係性も簡潔であり、
erbファイルにロジックが書けたりと、コードの自由度が高く、狙い通りのアプリを作成しやすい気がします。
一方で、Djangoは、やや構成に癖があるような気がします。
ただ、記述量が少なく、慣れたら速そうです。
さらに、pythonのメリットは豊富なライブラリにあると考えているので、
その豊富なライブラリをアプリで活かせるかどうか、が、ポイントのような気がしています。
結局はどんなものを作りたいか、によるのではないでしょうか。
(もっと勉強して、随時修正予定です!)
読んでいただきありがとうございました
- 投稿日:2020-01-04T21:45:35+09:00
RailsでiOSアプリのURI スキームに対応する
一瞬「あれっ...」ってなったので備忘録
TL; DR
routes.rb
内でダイレクトルーティングで定義すればOKバージョン
- Ruby:2.6.1
- Rails:5.2.3
タイトルにiOSと書いてますがAndroidも対応できます。ただのRoutingの話なので。
やりたいこと
- RailsがWebとモバイルアプリの両方のサーバサイドの役割を担っている
- モバイルアプリ内で、特定の画面に遷移させるURIスキームを使いたい
- メニューなどで表示されていないページへの遷移など
- 上記の例としてInstagramに「運営からのコメント」があり、チャットで操作説明を受ける画面に遷移させたいような目的があったとする
- ヘルパーリンク:
qa_chat
- URIスキーム:
instagram://qa_chat
解決策
routes.rb
routes.rb
で、以下のようなダイレクトルーティングを設定してあげれば良いです。routes.rbdirect :qa_chat do "instagram://qa_chat" endヘルパーリンク
Railsと同一のViewでヘルパーリンクを利用する場合は、以下のように記述します。
sample.erb<%= link_to qa_chat_url %>ちなみにダイレクトルーティングについて、Railsガイドでは以下の部分に記載があります。
(このURIスキームについての記載はありませんが、あくまで参考までに)
小ネタ
外部URLもroutes.rbで変数として定義できる
ダイレクトルーティングといえば、こちらの使い方のほうが一般的です。
よく使う外部URLを変数定義して、Railsアプリケーション内で使うことができます。
サービスLPのURLを記述する時は、個別にではなく、routes.rb
にまとめて記述するほうが管理しやすいです。example.rbdirect :homepage do "http://www.rubyonrails.org" end
- 投稿日:2020-01-04T21:00:42+09:00
FizzBuzzの問題を外部入力した数値から数えてアプリケーションを作ってみた
通常FizzBuzzの問題は、1~100までを数えるものが多いみたいですが、今回はgets.to_iを使用し、入力した数を(含めて)から30数えるアプリケーションを作ってみる
目的
・学習のため
・入力した数値からFizzBuzzできたら面白そうだと思ったから下記条件を満たすように作る
・外部入力させる
・入力させた数値を含めて、そこから30数える
・3の倍数の場合はFizzと表示させる
・5の倍数の場合はBuzzと表示させる
・15の倍数の場合はFizzBuzzと表示させる
・「数値を入力してください」と表示させた後に、入力させる
・数値を入力させた後は、改行させるか、文字をいれる(ターミナル上で見栄え良くするため)擬似コードを書く
puts "数え始める開始の数値を入力してください" x = 数字を入力させる puts "下記に入力した数値を含めて30数えます" y = 30数えるため、外部入力させた数値に30を足す xから(30数える=y)each do|i| ※ここから先はいつものFizzBuzzと一緒 if ○○なら puts ○○と表示する elsif ○○なら puts ○○と表示する elsif ○○なら puts ○○と表示する else それ以外なら puts ○○と表示するできたアプリケーションがこちら
puts "数え始める開始の数値を入力してください" x = gets.to_i puts "下記に入力した数値を含めて30数えます" y = x + 30 (x..y).each do|i| if i%15==0 puts "FizzBuzz" elsif i%3==0 puts "Fizz" elsif i%5==0 puts "Buzz" else puts i end end動作確認しよう。今回は、100から数えてみる。
数え始める開始の数値を入力してください 100 下記に入力した数値を含めて30数えます Buzz 101 Fizz 103 104 FizzBuzz 106 107 Fizz 109 Buzz Fizz 112 113 Fizz Buzz 116 Fizz 118 119 FizzBuzz 121 122 Fizz 124 Buzz Fizz 127 128 Fizz Buzzあっさり出来た。
感覚的にできるもんすね・・・・・。たぶん間違っていないかと思われる。
他に良い方法ありそうでしたら、ご指摘いただけますと幸いです。参考:FizzBuzz基本問題
https://qiita.com/pontarou194/items/6cf17868a8346613fddf
- 投稿日:2020-01-04T21:00:42+09:00
FizzBuzzの問題を外部入力した数値から数えるアプリケーションを作ってみた
通常FizzBuzzの問題は、1~100までを数えるものが多いみたいですが、今回はgets.to_iを使用し、入力した数を(含めて)から30数えるアプリケーションを作ってみる
目的
・学習のため
・入力した数値からFizzBuzzできたら面白そうだと思ったから下記条件を満たすように作る
・外部入力させる
・入力させた数値を含めて、そこから30数える
・3の倍数の場合はFizzと表示させる
・5の倍数の場合はBuzzと表示させる
・15の倍数の場合はFizzBuzzと表示させる
・「数値を入力してください」と表示させた後に、入力させる
・数値を入力させた後は、改行させるか、文字をいれる(ターミナル上で見栄え良くするため)擬似コードを書く
puts "数え始める開始の数値を入力してください" x = 数字を入力させる puts "下記に入力した数値を含めて30数えます" y = 30数えるため、外部入力させた数値に30を足す xから(30数える=y)each do|i| ※ここから先はいつものFizzBuzzと一緒 if ○○なら puts ○○と表示する elsif ○○なら puts ○○と表示する elsif ○○なら puts ○○と表示する else それ以外なら puts ○○と表示するできたアプリケーションがこちら
puts "数え始める開始の数値を入力してください" x = gets.to_i puts "下記に入力した数値を含めて30数えます" y = x + 30 (x..y).each do|i| if i%15==0 puts "FizzBuzz" elsif i%3==0 puts "Fizz" elsif i%5==0 puts "Buzz" else puts i end end動作確認しよう。今回は、100から数えてみる。
数え始める開始の数値を入力してください 100 下記に入力した数値を含めて30数えます Buzz 101 Fizz 103 104 FizzBuzz 106 107 Fizz 109 Buzz Fizz 112 113 Fizz Buzz 116 Fizz 118 119 FizzBuzz 121 122 Fizz 124 Buzz Fizz 127 128 Fizz Buzzあっさり出来た。
感覚的にできるもんすね・・・・・。たぶん間違っていないかと思われる。
他に良い方法ありそうでしたら、ご指摘いただけますと幸いです。参考:FizzBuzz基本問題
https://qiita.com/pontarou194/items/6cf17868a8346613fddf
- 投稿日:2020-01-04T20:35:50+09:00
「文言」ruby出力に挑戦
はじめに
漢文風プログラミング言語「文言/wenyan-lang」は、初期commitが2019年12月という新しい言語で、現在進行形で開発が進んでいます。その美しいレンダリングは漢字圏に住む我々日本人としても目の離せない言語です。
初期時はハードルが高めでしたが、現在はnpmからインストールし簡単に使い始められます。まだの方はこちらの記事を参考に今すぐインストールしてみて下さい
この記事では「文言/wenyan-lang」で書かれたプログラムからrubyソースに変換し、実行してみます
動作確認
こちらの記事の確認環境は以下の通りです
npm v6.13.4
wenyan v0.2.0実行
公式を見ると
ruby出力に対応しているとの事、
usageを確認します$ wenyan ,_ ,_ \/ == /\ [] WENYAN LANG 文言 Compiler v0.2.0 Usage: wenyan [options] [files...] Options: -v, --version Output the version -l, --lang <lang> Target language, can be "js", "py" or "rb" (default: "js") -c, --compile Output the compiled code instead of executing it -e, --eval <code> Evaluate script -i, --interactive Interactive REPL -o, --output [file] Output compiled code or executing result to file -r, --render Outputs renderings --roman [method] Romanize identifiers. The method can be "pinyin", "baxter" or "unicode" --outputHanzi Convert output to hanzi (default: true) --log <file> Save log to file --title <title> Override title in rendering -h, --help Display help--lang rb で行けそうです。
実行してみると$ wenyan -l rb examples/helloworld+.wy Target language "rb" is not supported for direct executing. Please use --compile option instead.替わりに--compileオプションを使えとの事、実行してみます
$ wenyan --compile rb examples/helloworld+.wy ENOENT: no such file or directory, open '/xxxxxxx/wenyan-lang/rb'--compileのオプションの指定方法がいまいちのようです
言語指定してみましょう$ wenyan --compile -l rb examples/helloworld+.wy # encoding: UTF-8 require 'forwardable' <略 45行> ##### 甲=3 甲.times do |_rand1| _ans1="問天地好在。" p([_ans1].join) endなんか50行を超える行が出力されましたが、最後の5行は公式にあった出力です。やった
ruby出力方法がわかったので、公式にある「エラトステネスの篩」を実行してみます
また、その実行結果を保存し、rubyで実行してみます
$ wenyan --compile -l rb -o sieve.rb examples/sieve.wy $ tail -n 42 sieve.rbdef 埃氏篩(甲) 掩=Ctnr.new 甲.times do |_rand1| 掩.push(true) end _ans1=甲/2; 甲半=_ans1; 戊=2 while true do if 戊==甲半 break end 戌=2 while true do if 戌==甲半 break end _ans2=戊*戌; 合=_ans2; if 合<=甲 掩[合-1]=false else break end _ans3=1+戌; 戌=_ans3 end _ans4=1+戊; 戊=_ans4 end 諸素=Ctnr.new 戊=2 while true do if 戊==掩.length break end _ans5=掩[戊-1]; 素耶=_ans5; if 素耶 諸素.push(戊) end _ans6=1+戊; 戊=_ans6 end return 諸素 end _ans7=埃氏篩(100);p([_ans7].join)$ ruby sieve.rb "[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]"rubyで100までの素数が求められました
おわりに
美しいレンダリングとruby出力がしたくて、「文言」言語の存在を知った12月19日その日に「文言」アドベントカレンダーを作成しました。
はじめは環境も作れず参加者も増えず、無謀なのかと思いましたが、開発が進み簡単に実行できるようになりました。みなさんも是非美しいレンダリング、漢字でプログラム出来る新感覚、体験してみて下さい
- 投稿日:2020-01-04T19:57:21+09:00
Ruby 2.4.4 から 2.7.0 までの主要な変更点をざっくりと知る
はじめに
- rubyのバージョン
2.4.4
から2.7.0
までの、 比較的ビギナー層にも影響のある変更のまとめ です。細かな変更点や、変更内容の詳細などは割愛しています。2.4.4
からスタートなのは、私が使っているrubyが2.4.3
で長らく止まっているため、それ以降の変更を一気にキャッチアップしたいがためです。- 各マイナーバージョンは 2020/01/02 時点の最新版まで
2.4.4
2.4.5
2.4.6
2.4.7
2.4.8
2.4.9
2.5.0
rescue/else/ensure
がdo/end
ブロック内にも直接書けるようにdef f [1].each do 2 / 0 rescue StandardError p '例外だよ!!' end end fこれまで$ ruby 2_5_0.rb 2_5_0.rb:6: syntax error, unexpected keyword_rescue, expecting keyword_end rescue StandardError ^ 2_5_0.rb:9: syntax error, unexpected keyword_end, expecting end-of-input
これから$ ruby 2_5_0.rb "例外だよ!!"
Kernel#yield_self
の追加自身を受け渡すブロックを実行し、ブロック全体の評価値を戻り値にします。
p 1.yield_self { |n| n + 1 }これから$ ruby 2_5_0.rb 2
※ このメソッドには2.6.0で
then
というエイリアスが追加されます
Hash#slice
の追加Railsではお馴染みなので新機能感ないですが、Ruby標準サポートされました。
p ({ a: :Hoge, b: :Fuga, c: :Foo, d: :Bar }.slice(:b, :c))これまで$ ruby 2_5_0.rb 2_5_0.rb:3:in `<main>': undefined method `slice' for {:a=>:Hoge, :b=>:Fuga, :c=>:Foo, :d=>:Bar}:Hash (NoMethodError)これから$ ruby 2_5_0.rb {:b=>:Fuga, :c=>:Foo}
Hash#transform_keys
の追加Hashのキーをブロックに渡して任意の変換を行う。
hash = { hoge: 1, fuga: 2, foo: 3, bar: 4 } p hash.transform_keys { |key| key.upcase } # または p hash.transform_keys(&:upcase)これから$ ruby 2_5_0.rb {:HOGE=>1, :FUGA=>2, :FOO=>3, :BAR=>4}
transform_keys!
もあるよ!トップレベルに定義した定数の参照ルールの変更
以下のコードのように、任意の名前空間(
Hoge
)を経由してトップレベルの定数(Fuga
)を参照した場合、これまでは警告付きではあるものの参照できていたのが参照不可になります。class Hoge end class Fuga end p Hoge::Fugaこれまで$ ruby 2_5_0.rb 2_5_0.rb:6: warning: toplevel constant Fuga referenced by Hoge::Fuga Fuga
これから$ ruby 2_5_0.rb Traceback (most recent call last): 2_5_0.rb:6:in `<main>': uninitialized constant Hoge::Fuga (NameError) Did you mean? Fugaみんな大好き
pp
が自動ロードされるうれピーピー
obj = { hoge: [1, 2, 3, 4, 5], fuga: { a: '1', b: '2' } } pp objこれまで$ ruby 2_5_0.rb 2_5_0.rb:11:in `<main>': undefined method `pp' for main:Object (NoMethodError)これから$ ruby 2_5_0.rb {:hoge=>[1, 2, 3, 4, 5], :fuga=>{:a=>"1", :b=>"2"}}バックトレース、エラーメッセージの表示順の変更
def f2 hoge end def f1 f2 end f1これまで(下から上に読んでいく)$ ruby 2_5_0.rb 2_5_0.rb:12:in `f3': undefined local variable or method `hoge' for main:Object (NameError) from 2_5_0.rb:8:in `f2' from 2_5_0.rb:4:in `f1' from 2_5_0.rb:15:in `<main>'これから(上から下に読んでいく)$ ruby 2_5_0.rb Traceback (most recent call last): 3: from 2_5_0.rb:15:in `<main>' 2: from 2_5_0.rb:4:in `f1' 1: from 2_5_0.rb:8:in `f2' 2_5_0.rb:12:in `f3': undefined local variable or method `hoge' for main:Object (NameError)トレースバックがむっちゃ長いとき、直近の原因が末尾に表示されるのでわかりやすい(?)
String#delete_prefix
String#delete_suffix
の追加先頭あるいは末尾の任意文字列を削除できる
str = 'hogefuga' p str.delete_prefix('hoge') p str.delete_suffix('fuga')これから$ ruby 2_5_0.rb "fuga" "hoge"参考
その他の変更内容や詳細については以下ご参照ください。
2.5.1
2.5.2
2.5.3
2.5.4
2.5.5
2.5.6
2.5.7
2.6.0
Kernel#yield_self
の別名then
の追加2.5.0で追加されたメソッドを呼びやすい感じに。こっちのほうが値をどんどん加工してる感じがして使いやすい。
puts 1.then { |n| n + 1 } .then { |n| n * 2 } .then(&:to_s)これから$ ruby 2_6_0.rb 4終端のない
Range
を扱えるようにp '123456789'[2..]これまで$ ruby 2_6_0.rb 2_6_0.rb:3: syntax error, unexpected ']' p '123456789'[2..]これから$ ruby 2_6_0.rb "3456789"無限リストとしても扱えるように
(2..).each do |i| break if i > 10 p i endこれから$ ruby 2_6_0.rb 2 3 4 5 6 7 8 9 10
合成関数を作る
Proc#<<
Proc#>>
の追加f = proc { |x| x**2 } g = proc { |x| x * 10 } fg = f << g # ≒ f(g(2)) gf = f >> g # ≒ g(f(2)) p fg.call(2) p gf.call(2)これまで$ ruby 2_6_0.rb Traceback (most recent call last): 2_6_0.rb:6:in `<main>': undefined method `<<' for #<Proc:0x0000557816119660@2_6_0.rb:3> (NoMethodError)これから$ ruby 2_6_0.rb 400 40
binding.source_location
の追加現在行のファイル名と行番号を教えてくれる
# frozen_string_literal: true hoge = 1 p binding.source_location fuga = 2これから$ ruby 2_6_0.rb ["2_6_0.rb", 4]
Array#to_h
でブロックを渡せるようにブロックでは
Array
内の値を受け取れるので、[key, val]
の形式になるArrayを戻すことで、それを元に新たなHashを生成します。hash = %w[hoge fuga foo bar].to_h do |val| [val, val.upcase] end pp hashこれから$ ruby 2_6_0.rb {"hoge"=>"HOGE", "fuga"=>"FUGA", "foo"=>"FOO", "bar"=>"BAR"}
Enumerable#chain
で繰り返し可能オブジェクトを連鎖できるように
Array
など、Enumerable
なオブジェクトを連鎖させたEnumerator::Chain
オブジェクトを生成できます。chained = [1, 2, 3].chain([4, 5, 6], [7, 8, 9]) p chained.class p chained.to_aこれから$ ruby 2_6_0.rb Enumerator::Chain [1, 2, 3, 4, 5, 6, 7, 8, 9]
Enumerable
であればRange
とかでももちろん可能chained = (1..3).chain((90..)) chained.each do |i| break if i > 100 p i endこれから$ ruby 2_6_0.rb 1 2 3 90 91 92 93 94 95 96 97 98 99 100
Enumerator#+
でEnumerator
同士を連結前項と同じようなものだけど、前項は
Enumerable
で、本項はEnumerator
なので注意。chained = [1, 2, 3].each + [4, 5, 6].each p chained.reduce(&:+)これから$ ruby 2_6_0.rb 21
和集合を取る
Array#union
の追加p [1, 2, 3, 4, 5].union [4, 5, 6, 7, 8]これから$ ruby 2_6_0.rb [1, 2, 3, 4, 5, 6, 7, 8]実は
|
でも同じことが以前からできてたけど、 「||
の間違いじゃないんですか〜??」 というコードレビューでもコメントを何度も頂いた実績があるのでこっちのほうが助かる。差集合を取る
Array#difference
の追加基本は
union
と一緒p [1, 2, 3, 4, 5].difference [4, 5, 6, 7, 8]これから$ ruby 2_6_0.rb [1, 2, 3]
Hash#merge
で複数のハッシュを渡せるように機能としては今まで通りだけど、今までは引数を複数指定できなくて、mergeメソッドをチェインしていたのが、1回で済むようになった。
hash = { hoge: 'HOGE' }.merge({ fuga: 'FUGA' }, foo: 'FOO') p hashいままで$ ruby 2_6_0.rb Traceback (most recent call last): 1: from 2_6_0.rb:3:in `<main>' 2_6_0.rb:3:in `merge': wrong number of arguments (given 2, expected 1) (ArgumentError)これから$ ruby 2_6_0.rb {:hoge=>"HOGE", :fuga=>"FUGA", :foo=>"FOO"}もちろん
merge!
も同様参考
その他の変更内容や詳細については以下ご参照ください。
2.6.1
2.6.2
2.6.3
2.6.4
2.6.5
2.7.0
パターンマッチの導入(実験版)
渡されたオブジェクトの構造がパターンと一致するかどうかを調べ、一致した場合にその値を評価する仕組み
case [0, 1, 2, { hoge: 'HOGE', fuga: 'FUGA' }] in [0, 1, n, { hoge: 'HOGE', fuga: fuga }] puts "n = #{n}" puts "fuga = #{fuga}" else puts 'no match' endこれから$ ruby 2_7_0.rb 2_7_0.rb:3: warning: Pattern matching is experimental, and the behavior may change in future versions of Ruby! n = 2 fuga = FUGAパターンにマッチした部分の変数にその値が代入されていることがわかります。
また、実行結果に警告が出ている通り、パターンマッチは2.7では実験段階で、将来的に挙動が変わる可能性もあるため、プロダクトコードでの私用は控えたほうが良いように思えます。
パターンマッチの機能は非常に強力で柔軟なので、ここでは割愛しますが詳細が気になる方は参考記事を見てみてください。
irbの強化
標準REPLであるirbが強化され、複数行コードを記述する時にインデントが自動で挿入されたり、シンタックスハイライトがされたりと改善されています。pryを使ってたら関係ないですが。
キーワード引数を通常の引数から分離
こちらは非推奨で警告が出るようになりますが、ruby3では廃止される予定なので、警告を見つけ次第修正していくべきです。
ハッシュオブジェクトを用いてキーワード引数を指定することが非推奨になります。
def f(x: 10) x * 2 end hash = { x: 20 } p f(hash)これから$ ruby 2_7_0.rb 2_7_0.rb:8: warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call 2_7_0.rb:3: warning: The called method `f' is defined here 40def f(**params) pp params end hash = { x: 20 } f(hash)これから$ ruby 2_7_0.rb 2_7_0.rb:8: warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call 2_7_0.rb:3: warning: The called method `f' is defined here {:x=>20}
**
をつけて、明示的にキーワード引数とすることで、これを回避できます。このコードはRuby3でも動くそうです。def f(**params) pp params end hash = { x: 20 } f(**hash)これから$ ruby 2_7_0.rb {:x=>20}他、キーワード引数と通常引数を組み合わせた場合に警告が出るバターンが増えているのでご注意を。
(リリースノート引用)def foo(h, **kw); end; foo(key: 42) # warned def foo(h, key: 42); end; foo(key: 42) # warned def foo(h, **kw); end; foo({key: 42}) # OK def foo(h, key: 42); end; foo({key: 42}) # OK def foo(h={}, key: 42); end; foo("key" => 43, key: 42) # warned def foo(h={}, key: 42); end; foo({"key" => 43, key: 42}) # warned def foo(h={}, key: 42); end; foo({"key" => 43}, key: 42) # OK def foo(opt={}); end; foo( key: 42 ) # OKブロックの仮引数を番号指定で参照できるように
%w[hoge fuga foo bar].each_with_index do puts "str = #{_1}" puts "index = #{_2}" endこれから$ ruby 2_7_0.rb str = hoge index = 0 str = fuga index = 1 str = foo index = 2 str = bar index = 3ブロック引数を定義せずとも、何番目に渡される引数かだけで参照できるようになりました。
全ての引数を別のメソッドに渡す構文の追加
def f1(...) f2(...) end def f2(x, y, z, hoge:) puts x, y, z puts hoge end f1(1, 2, 3, hoge: 'HOGE')これから$ ruby 2_7_0.rb 1 2 3 HOGE
なんだろ、デリゲーションしたりかな。
積集合を取る
Array#intersection
の追加p [1, 2, 3].intersection([2, 3, 4], [3, 4, 5])これから$ ruby 2_7_0.rb [3]
- これまでも
&
を使って同じことはできました- 「
&&
の間違いじゃないんですか〜??」 という誤解のレビューを受けずに済みます- 和集合(union)と差集合(difference)は2.6.0のほうで追加されてます。
selectとfilterを同時に行う
Enumerable#filter_map
の追加使い方は概ね
map
と同じですが、ブロックの戻り値が真の値だけが取り出されます。p [-2, -1, 0, 1, 2].filter_map { |n| n * 2 if n.positive? }これから$ ruby 2_7_0.rb [2, 4]もう
compact
とかチェインする必要は無い。要素ごとの個数をカウントする
Enumerable#tally
の追加p %w[HOGE FUGA HOGE HOGE FUGA HOGE FOO FUGA FUGA FUAG].tallyこれから$ ruby 2_7_0.rb {"HOGE"=>4, "FUGA"=>4, "FOO"=>1, "FUAG"=>1}実にかゆいところに手が届くメソッド。
任意のシーケンスを生成する
Enumerator.produce
の追加数列の規則のようにブロックを定義することで、無限リストになるシーケンスを簡易的に生成できるように。
enum = Enumerator.produce(2) { |n| n * 2 } p enum.take(10)これから$ ruby 2_7_0.rb [2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]工夫次第でこんなことも
require 'date' enum = Enumerator.produce(Date.today, &:next_day) pp enum.take(10)これから$ ruby 2_7_0.rb [#<Date: 2020-01-02 ((2458851j,0s,0n),+0s,2299161j)>, #<Date: 2020-01-03 ((2458852j,0s,0n),+0s,2299161j)>, #<Date: 2020-01-04 ((2458853j,0s,0n),+0s,2299161j)>, #<Date: 2020-01-05 ((2458854j,0s,0n),+0s,2299161j)>, #<Date: 2020-01-06 ((2458855j,0s,0n),+0s,2299161j)>, #<Date: 2020-01-07 ((2458856j,0s,0n),+0s,2299161j)>, #<Date: 2020-01-08 ((2458857j,0s,0n),+0s,2299161j)>, #<Date: 2020-01-09 ((2458858j,0s,0n),+0s,2299161j)>, #<Date: 2020-01-10 ((2458859j,0s,0n),+0s,2299161j)>, #<Date: 2020-01-11 ((2458860j,0s,0n),+0s,2299161j)>]
Method#inspect
がより詳細にメソッドオブジェクトの情報を取得する
Method#inspect
メソッドにて、引数情報や定義元が出るようになってデバッグしやすい感じにdef f(x, y, z, hoge:) pp [x, y, z, hoge] end p method(:f).inspectこれまで$ ruby 2_7_0.rb "#<Method: main.f>"これから$ ruby 2_7_0.rb "#<Method: main.f(x, y, z, hoge:) 2_7_0.rb:3>"参考
その他の変更内容や詳細については以下ご参照ください。
- サンプルコードでわかる!Ruby 2.7の新機能・パターンマッチ(前編)
- サンプルコードでわかる!Ruby 2.7の新機能・パターンマッチ(後編)
- サンプルコードでわかる!Ruby 2.7の主な新機能と変更点 Part 1 - 番号指定パラメータ(numbered parameter)
- サンプルコードでわかる!Ruby 2.7の主な新機能と変更点 Part 2 - キーワード引数に関する仕様変更
- サンプルコードでわかる!Ruby 2.7の主な新機能と変更点 Part 3 - 新機能と変更点の総まとめ
- Ruby 2.7のここがすごい! パターンマッチ、コンパクションGCなどをリリースマネージャーに聞いた
- Ruby 2.7 adds Enumerator#produce
- 投稿日:2020-01-04T19:45:25+09:00
FizzBuzzの問題で3の時はFizzと表示し、5の時Buzzと表示、15の時FizzBuzzと表示する
RubyのFizzBuzz練習問題を解く(今回はeach doを使用)
・1から30まで数える
・3の時はFizzと表示する
・5の時はBuzzと表示する
・15の時はFizzBuzzと表示するまず、擬似コードを考える前に、情報を整理
どのようなコードが必要そうかを並べてみる。①1から30まで数える
②もし3だったらFizzと表示する
③もし5だったらBuzzと表示する
④もし15だったらFizzBuzzと表示する以上。
では、擬似コードっぽいやつ書いていく。
1から30まで数える(今回は、each do を使って) if ○○なら puts ○○と表示する elsif ○○なら puts ○○と表示する elsif ○○なら puts ○○と表示する else それ以外なら puts ○○と表示するここにコードをあてていくと、考えがまとまりやすくなり、コードがすっきりしそう。
もし、仮説と違ったら擬似コードの考え方を実際の答えと比べてみる。(1..30).each do|i| if i%15==0 puts "FizzBuzz" elsif i%3==0 puts "Fizz" elsif i%5==0 puts "Buzz" else puts i end end1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz 16 17 Fizz 19 Buzz Fizz 22 23 Fizz Buzz 26 Fizz 28 29 FizzBuzzこのように表示されていればOKです。
応用編:数字の横にFizzとBuzzをそれぞれつけてみる。
考え方はほとんど一緒
表示の仕方だけ変えればいいかな?っと仮説を立ててみる。
合ってたら自分を褒める。(1..30).each do|i| if i%15==0 puts "#{i} FizzBuzz" elsif i%3==0 puts "#{i} Fizz" elsif i%5==0 puts "#{i} Buzz" else puts i end end見やすくするため、一応数字と文字の間にスペースいれてます。
うまくいくと、以下のようになります。
1 2 3 Fizz 4 5 Buzz 6 Fizz 7 8 9 Fizz 10 Buzz 11 12 Fizz 13 14 15 FizzBuzz 16 17 18 Fizz 19 20 Buzz 21 Fizz 22 23 24 Fizz 25 Buzz 26 27 Fizz 28 29 30 FizzBuzz以上となります。
ご参考いただけますと幸いです。
- 投稿日:2020-01-04T16:37:43+09:00
技術ブログはじめました
みなさん、はじめまして!
音楽とアニメとハイボールが大好きな Web エンジニアの yasu と申します!このたび、超個人的嗜好で厳選したお気に入りの音楽を Apple Music のプレイリスト形式で紹介していく音楽ブログ「Fav Music」の構築・運用過程で得た技術的知見を qiita にアウトプットさせていただくことにしました。
僕がここでアウトプットした技術情報がいつか誰かの助けになったら嬉しいです :)
今回はご挨拶がわりに僕が Fav Music を構築・運用するために使用している技術や製品をご紹介させていただきます。
なお、Fav Music の全てのソースコードは GitHub でも公開してますので興味のある方は合わせてご参照ください。
<(*_ _)>Fav Music を構築するために使用している技術や製品
- MacBook Early 2015
- macOS Catalina 10.15.2
- Git 2.21.0 (Apple Git-122.2)
- Homebrew 2.2.2
- Rbenv 1.1.2
- Ruby 2.6.5
- Jekyll 3.8.6
- Adobe XD 25.1.12.7
- Visual Studio Code 1.41
- Google Chrome 79.0.3945.88
- GitHub
使用した技術や製品をいろいろ列挙しましたけど、重要なのは Jekyll だけですね笑
今流行りの静的サイトジェネレーターってやつですw
最初は WordPress でサイトを構築したんですけど、静的サイトジェネレーターをいろいろ試してみて最終的に Jekyll にしました。
Jekyll の他にも
を試してみましたが、Jekyll を採用した決め手は、タグの一覧ページのページング機能が割と簡単に実現できたことです(各静的サイトジェネレーターのデフォルトの機能では意外と実現するのが難しい部分です)。
静的サイトジェネレーターで生成した静的サイトは WordPress で構築した動的サイトと比較してページングと検索の機能が弱い(というか自分で実装しないといけない)ので、これから静的サイトジェネレーターを使おうと思っている方はまず最初にその辺の使い勝手を徹底的に調査しておいた方がいいかもしれません。
ちなみに、Fav Music ではまだ検索機能は実装してません?
Adobe XD はキャッチアイ画像を作成するのに使ってるだけです。僕はデザインツールには詳しくないのでアレですが、Adobe XD はサクサク動いて使ってて気持ちいいですv
Visual Studio Code はコード(
HTML
,CSS
,JavaScript
,YAML
,Ruby
,Liquid
)と記事(Markdown
)を編集するのに使ってるのと、Git
とかShell
コマンドも内臓ターミナルから叩いてるので、ぶっちゃけほとんどこの中にいますwGoogle Chrome は、もちろん表示の確認とデバッグ(スタイルの調整)に使ってます。
Fav Music を運用するために使用している技術や製品
最初に WordPress でサイトを構築したときは EC2 と RDS と ALB を使ってガチで半年ほど運用してましたが、そもそも静的なコンテンツしかないんだから S3 で十分じゃね?ということに気付き、先日 S3 に切り替えました (笑)
これで万が一 Yahoo 砲が来ても耐えれますw
WordPress から S3 の静的 Web サイトホスティングに切り替える時にちょっと困ったことは、S3 ではページ URL の拡張子(
.html
)を省略できないっていうことでした(ディレクトリ URL のindex.html
は省略できます)。対策はいくつかあるみたいですが、僕は単純に内部リンクは拡張子(
.html
)付きで書いて、WordPress の時に使われていた拡張子なしの URL は新しい URL に Rewrite (S3 側にRedirection rules
として登録) するようにしました。このやり方が一番良いやり方だったとは思えないので、もう少し調べて別の記事にまとめたいと思ってます。
S3 + CloudFront でブログを運用した場合の実際のコスパについてもみなさん気になるところだと思うので近々公開したいと思ってますが、幸か不幸か全くアクセスがないサイトなので (恥)、参考になる数字が出せる日が来るかどうかは怪しいものです (笑)
まとめ
以上、僕が Fav Music を構築・運用するために使用している技術や製品をご紹介させていただきましたがいかがだったでしょうか。
今回は技術情報としてはほとんど価値のない記事だったと思うので、次回はもう少し役に立つ情報をアウトプットしたいと思います?
ではまた ( ⸝⸝•ᴗ•⸝⸝ )੭⁾⁾
- 投稿日:2020-01-04T15:04:57+09:00
【第7章】Railsチュートリアル 5.1(第4版) ユーザー登録
大まかな流れの自己整理が目的のため、不足・誤り等あれば追記&訂正していきますのでご指摘頂けますと幸いです
なお、筆者はYassLabさんの動画版で学んでいるため、本記事は「チュートリアル sample_app」+「他補足」個人的に「電子ページ以上に分かりやすい!」と感じた解説部分+参考記事を整理してみようと試みた劣化の内容寄りになってます。7.1 ユーザーを表示する
params
Railsで送られてきた値を受け取るためのメソッド(その後Railsが保存を行う)。中身はハッシュ。
主に、以下の2つ
・投稿フォームなどPOSTで送信されたデータ
・検索フォームなどGETで送信されURLにクエリとして入るデータex.params[:id] → ユーザなどのid
<参考>
【Rails】paramsについて徹底解説!
【Rails入門】params使い方まとめdebug(メソッド)
paramsの中身(表示画面)を出力してくれる。putsのような扱い。
本番環境に展開したアプリケーションではデバッグ情報を表示したくないので、後置if文でデベロッパー確認を追加する。
(後置if文は1行で済むときによく使用される)app/views/layouts/application.html.erb 内に下記追加
<%= debug(params) if Rails.env.development? %>補足
Railsにはテスト環境 (test)、開発環境 (development)、そして本番環境 (production) の3つの環境がデフォルトで装備されている。Rails consoleのデフォルトの環境はdevelopment。
app/assets/stylesheets/custom.scssに
デバッグ表示を整形するための追加と、Sassのミックスインを追加する(ここでは省略)
/users/1 のURLを有効にするため、routes(るーつ、らうつ)ファイルsignup下に追加resources :users
確認(今回注目するのはnewアクションとshowアクション)$ rails routes Prefix Verb URI Pattern Controller#Action root GET / static_pages#home static_pages_home GET /static_pages/home(.:format) static_pages#home help GET /help(.:format) static_pages#help about GET /about(.:format) static_pages#about contact GET /contact(.:format) static_pages#contact sighup GET /sighup(.:format) users#new 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#destroyputリクエスト → 全部(旧残り)
patchリクエスト → 欲しい情報の一部(現在主流)
Usersコントローラにshowアクションを追加する(showアクションはGET /users/:id と連動)。挿入場所(順番)は可読性を考慮し出来ればRESTfulなルート順(表)が望ましい。
@user
はインスタンス変数とされ、showアクション外(例えばviewであるshowテンプレート: => app/views/users/show.html.erb)からも呼び出すことが出来るため、「paramsで持ってきたユーザid(リクエスト値)を@user
に格納する」ような流れ。def show @user = User.find(params[:id]) end
HTTPリクエスト URL アクション 名前付きルート 用途 GET /users index users_path すべてのユーザーを一覧するページ GET /users/1 show user_path(user) 特定のユーザーを表示するページ GET /users/new new new_user_path ユーザーを新規作成するページ (ユーザー登録) POST /users create users_path ユーザーを作成するアクション GET /users/1/edit edit edit_user_path(user) id=1のユーザーを編集するページ PATCH /users/1 update user_path(user) ユーザーを更新するアクション DELETE /users/1 destroy user_path(user) ユーザーを削除するアクション
サンプルアプリケーションを既にHeroku上にデプロイしている場合は、heroku run rails consoleというコマンドを打つことで、本番環境を確認することができます。$ heroku run rails console >> Rails.env => "production" >> Rails.env.production? => trueデバッガー(debugger)
追記して稼働させるとゆっくり読み込み中になる
def show @user = User.find(params[:id]) # => app/views/users/show.html.erb debugger endrails サーバを立ち上げると、止まってる場所がわかる
def show 4: @user = User.find(params[:id]) 5: # => app/views/users/show.html.erb 6: debugger => 7: end 8: 9: def new 10: end 11: end (byebug)コマンドはlist,nextなど。exit、ctrl+cで終了。
使い終わったらコメントアウト。
show.html.erbにgravatar_forヘルパーメソッドを使い、WordPress系アバター画像のGravatarの画像を利用できるようにする。<% provide(:title, @user.name) %> <h1> <%= gravatar_for @user %> <%= @user.name %> </h1>ヘルパーメソッドとしてusers_helper.rbに追加する。
最後の行のimage_tag(url、alt&class属性付与)がgravatar_forに返される。
なお、gravatar_forメソッドでのemailは(has_secure_passwordのように)Digest::MD5によってハッシュ化されている。module UsersHelper # 引数で与えられたユーザーのGravatar画像を返す def gravatar_for(user) gravatar_id = Digest::MD5::hexdigest(user.email.downcase) gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}" image_tag(gravatar_url, alt: user.name, class: "gravatar") end endこの時点でデフォルト画像のまま表示されるが、show.html.erbにasideタグ(サイドバーなど補足として付け加えたいときに便利なもの)を付け加える。
<% provide(:title, @user.name) %> <div class="row"> <aside class="col-md-4"> <section class="user_info"> <h1> <%= gravatar_for @user %> <%= @user.name %> </h1> </section> </aside> </div>saasに追記してフォーマット等調整。
/* sidebar */ aside { section.user_info { margin-top: 20px; } section { padding: 10px 0; margin-top: 20px; &:first-child { border: 0; padding-top: 0; } span { display: block; margin-bottom: 3px; line-height: 1; } h1 { font-size: 1.4em; text-align: left; letter-spacing: -1px; margin-bottom: 3px; margin-top: 0px; } } } .gravatar { float: left; margin-right: 10px; } .gravatar_edit { margin-top: 15px; }7.2 ユーザー登録フォーム
コントローラのnewアクションに空のオブジェクトを作成して@user変数を追加する
def new @user = User.new end
view画面のnewに追記。
form_forはブロック付き引数で、ブロック内部では例として「email」というキーの中にユーザのバリューが入るイメージ。
「f.label」はラベルのなので削っても問題ないが、あるとユーザ視点で何を入力していいか分かりやすい。(変更イメージの参考:[rails]ActiveModelを使ったフォームのラベル名を変更する)
「f.submit」は"Create my account"というボタンからこれらのデータをnewアクション→createアクションへ送る(次のアクションへ)。<h1>Users#new</h1> <div class="row"> <div class="col-md-6 col-md-offset-3"> <%= form_for(@user) do |f| %> <%= f.label :name %> <%= f.text_field :name %> <%= f.label :email %> <%= f.email_field :email %> <%= f.label :password %> <%= f.password_field :password %> <%= f.label :password_confirmation, "Confirmation" %> <%= f.password_field :password_confirmation %> <%= f.submit "Create my account", class: "btn btn-primary" %> <% end %> </div> </div>formのscss追記
/* forms */ input, textarea, select, .uneditable-input { border: 1px solid #bbb; width: 100%; margin-bottom: 15px; @include box_sizing; } input { height: auto !important; }そのまま作るとエラーが起きるが、「newアクション移行→createアクションがないよ」という表示なので正常。
createアクション追加&renderでビュー画面newに戻り、登録情報確認(試験的にfoobar入れてます)
def create @user = User.new render 'new' end7.3 ユーザー登録失敗
ユーザー登録の失敗に対応できるcreateアクション
オプション引数について
ハッシュのハッシュなので、userの中に[:name],[:email],[:password]があるので:userで省略。
def create # オプション引数はキーワードにシンボルが入ってバリューに値が入ってる集合体 # → User.new(name: ..., email:, ...) # @user.name = params[:user][:name] # @user.user = params[:user][:email] # @user.password = params[:user][:password] # 1行で完結 @user = User.new(params[:user]) if @user.save #=> Validation # Sucess else #Failure render 'new' end endエラー登場。createの直後のparamsはユーザが送る情報なのでいろいろな情報を送る(いじる)ことができるので、今後adminなどを入れていく過程で悪意あるユーザからDB書き換えたれるなどのマスアサインメント脆弱性を回避するRails4.0移行実装の機能。paramsハッシュでは:user属性を必須とし、名前、メールアドレス、パスワード、パスワードの確認の属性をそれぞれ許可し、それ以外を許可しないようにしたいので、requireなどを追加したuser_paramsメソッドをコントローラに追加してメソッドで対応する。
users_controller.rbdef create @user = User.new(user_params) if @user.save #=> Validation # Sucess else #Failure render 'new' end end def user_params params.require(:user).permit(:name, :email, :password, :password_confirmation) endRails consoleからメソッド「.errors.full_messages」でエラー詳細表示
空のユーザ作成後save失敗から.full_messagesメソッドでエラーの詳細表示ができる。
(今回はいろいろ空だったことが原因)2.6.3 :002 > @user = User.new => #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, password_digest: nil> 2.6.3 :003 > @user.valid? User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE "users"."email" IS NULL LIMIT ? [["LIMIT", 1]] => false 2.6.3 :004 > @user.save (0.1ms) begin transaction User Exists (0.4ms) SELECT 1 AS one FROM "users" WHERE "users"."email" IS NULL LIMIT ? [["LIMIT", 1]] (0.1ms) rollback transaction => false 2.6.3 :005 > @user.errors.full_messages => ["Name can't be blank", "Email can't be blank", "Email is invalid", "Password can't be blank", "Password can't be blank", "Password is too short (minimum is 6 characters)"]ユーザ登録時にエラーメッセージが出るよう追記する。sharedディレクトリもviewディレクトリ下に作る。
<h1>Users#new</h1> <div class="row"> <div class="col-md-6 col-md-offset-3"> <%= form_for(@user) do |f| %> <%= render 'shared/error_messages' %> <%= f.label :name %> <%= f.text_field :name, class: 'form-control' %> <%= f.label :email %> <%= f.email_field :email, class: 'form-control' %> <%= f.label :password %> <%= f.password_field :password, class: 'form-control' %> <%= f.label :password_confirmation, "Confirmation" %> <%= f.password_field :password_confirmation, class: 'form-control' %> <%= f.submit "Create my account", class: "btn btn-primary" %> <% end %> </div> </div>
パーシャル(Viewでの似たようなコードを一つでまとめてるもの)を作るがアンダーバーなので注意$ cd app/views/ $ mkdir shared $ c9 open _error_messages.html.erb
「.errors.eny?」 → save,validなど何か実行されてエラーがなければfalse(何も表示しない)、「.count」あるので1個以上あればtrueを返す。pluralizeは"error"を個数に応じて単数・複数形で判断してくれる。_error_messages.html.erb<% if @user.errors.any? %> <div id="error_explanation"> <div class="alert alert-danger"> The form contains <%= pluralize(@user.errors.count, "error") %>. </div> <ul> <% @user.errors.full_messages.each do |msg| %> <li><%= msg %></li> <% end %> </ul> </div> <% end %>「Password can't be blank」が2つ出る理由は、「has_secure_password」と「validates presence」で引っかかっているためのバグ。
応急処置として、has_secure_password内に下記を追記するなどがある。allow_nil: true
エラー表示のSCSS追加#error_explanation { color: red; ul { color: red; margin: 0 0 30px 0; } } .field_with_errors { @extend .has-error; .form-control { color: $state-danger-text; } }<form class="new_user" id="new_user" action="/users" accept-charset="UTF-8" method="post">とあり、
アクションが「/users」、メソッドが「post」から、「postリクエストを/usersに送りつける」ことが分かる。
ポストリクエストの流れは下記から確認でき、
「POST」リクエストが「/users」に送られると、「users」コントローラの「create」アクションが反応する。$ rails routes Prefix Verb URI Pattern Controller#Action root GET / static_pages#home static_pages_home GET /static_pages/home(.:format) 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 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「assert_no_difference」を使った、失敗時のテスト
インテグレーションテスト(結合テスト)から
$ rails generate integration_test users_signup Running via Spring preloader in process 4226 invoke test_unit create test/integration/users_signup_test.rb
自動生成されたものに追記。「signup_path」にgetリクエストを送りつける。
postリクエストをusers_pathに送り、その時にパラメータ:{ user: { name:,email:,password:,password_confirmation}}(オプション引数)を送りつける。
assert_no_differenceは呼び出す前後で値に違いがないことを主張するテストで、引数に(User.count)が入っていることから、「ユーザ数を覚えた後にデータを投稿してみて、ユーザ数が変わらないかどうかを検証するテスト」になる(公式より)。users_signup_test.rbrequire 'test_helper' class UsersSignupTest < ActionDispatch::IntegrationTest test "invalid signup information" do get signup_path assert_no_difference 'User.count' do post users_path, params: { user: { name: "", email: "user@invalid", password: "foo", password_confirmation: "bar" } } end assert_template 'users/new' end endこの時点でテスト(通過)
$ rails t補足(エラー 「undefined local variable or method `signup_path'」)
筆者の場合、この時点で下記のようなエラーが出ました。
$ rails t Running via Spring preloader in process 4176 Run options: --seed 61612 # Running: .E.......... Finished in 0.618448s, 19.4034 runs/s, 30.7221 assertions/s. 1) Error: UsersSignupTest#test_invalid_signup_information: NameError: undefined local variable or method `signup_path' for #<UsersSignupTest:0x00000000065b4838> test/integration/users_signup_test.rb:6:in `block in <class:UsersSignupTest>' 12 runs, 19 assertions, 0 failures, 1 errors, 0 skips
「自分でアカウント追加して遊んだから講義とユーザ数ずれちゃったせいかな?」と考えたりしてましたが(このテストでは前後数のみで関係ない)
ルート(routes.rb)、ビュー(home.html.erb)でsignup_pathがsighup_pathにタイプミスしてました
7.4 ユーザー登録成功
createアクションにリダイレクトを追加する(省略過程あり)。
def create @user = User.new(user_params) # Sucess # redirect_to user_path(@user.id) # user_pathの引数デフォルトがidなので「.id」省略可、 # redirect_to user_path(@user) # さらにredirect_toのデフォルト挙動としてユーザオブジェクトを渡すとuser_pathになるので redirect_to @user #GETリクエスト(が右にいく) => "/users/#{@user.id}" => showアクションが動く else #Failure render 'new' end endflash
登録完了後に表示されるページにメッセージを表示する (この場合は新規ユーザーへのウェルカムメッセージ)。
createアクション(if文直下)と、ビュー(yield直前)に追加users_controller.rbflash[:success] = "Welcome to the Sample App!"application.html.erb<% flash.each do |message_type, message| %> <div class="alert alert-<%= message_type %>"><%= message %></div> <% end %>↑(ビュー側のerb埋め込みruby)の補足
ハッシュはキー+バリューの仕組みになっていて、
eachメソッドで呼び出すと、message_type(キー:success)とmessage(バリュー:"Welcome to the Sample App!")の関係になっている。
また、classの中にmessageを埋め込んでいる。
登録動作を確認してみると、5番目のユーザで作成できてる(成功!)。
flashは一度だけなのでリロードすればメッセージ(緑色)は消える。成功時のテスト
成功時、ユーザのカウントが1増えてればokという内容。
基本的にはshowテンプレートが表示されていれば?♂️users_signup_test.rbtest "valid signup information" do get signup_path assert_difference 'User.count', 1 do post users_path, params: { user: { name: "Example User", email: "user@example.com", password: "password", password_confirmation: "password" } } end follow_redirect! assert_template 'users/show' endURLを確認すると「https://〇〇.herokuapp.com/
users/1
」となっており、
本番環境(heroku)では1人目のユーザであることが分かる。7.5 プロのデプロイ
本番環境でのSSL
herokuのサブドメイン「https://〇〇
.herokuapp.com(2番目)
/users/1」を使っている内はサービス上SSL化(?Secure)されている。(Googleなどではhttpより検索順位が上位になったりするので重要であり、将来的に独自ドメインを使っていく際は自分で証明書の発行が必要になる。)https(SSL)通信を本番環境で強制するやり方として、production(本番環境).rbに下記を追記(コメントアウト解除してtrueに)する。
これにより、もしhttpでアクセスしても問答無用でhttpsに切り替わる。config/environments/production.rb# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. config.force_ssl = true
本番環境に適したWebサーバーを構築する
heroku推奨の設定ファイルをpumaに書き換える。
config/environments/production.rbworkers Integer(ENV['WEB_CONCURRENCY'] || 2) threads_count = Integer(ENV['RAILS_MAX_THREADS'] || 5) threads threads_count, threads_count preload_app! rackup DefaultRackup port ENV['PORT'] || 3000 environment ENV['RACK_ENV'] || 'development' on_worker_boot do # Worker specific setup for Rails 4.1+ # See: https://devcenter.heroku.com/articles/ # deploying-rails-applications-with-the-puma-web-server#on-worker-boot ActiveRecord::Base.establish_connection end
Pumaがheroku上で使うようにプロックファイル(./Procfile)(はデフォルトでないので)作成し、定義する。/sample_app $ c9 open Procfileweb: bundle exec puma -C config/puma.rb一応テスト走らせた後、
再度herokuへデプロイ(コミットメッセージが分かるように)して終了。$ git add -A $ git commit -m "Use SSL and the Puma webserver in production"感想ほか
講義が非常に分かりやすく全く挫折することなく終えました(講師:安川さん、ありがとうございました!!)。
教材模写(受け身)が中心だったので、忘れた部分含め2周目自力で進めて公式ドキュメント漁って読み込むなどもっと頭を悩ませる必要はあるかなと。
最後までお読み頂きありがとうございました!!
- 投稿日:2020-01-04T14:38:38+09:00
openssl1.0x から openssl1.1x @ruby
この記事は
opensslのバージョンアップにより、各種アプリケーションが起動できなくなるエラーが起きているようです。
ssl関係は結構googleを始めプラットフォーマーが敏感で、バージョンアップをサボりにくいです。他のアプリケーションのバージョンアップでopenssl1.1xが要求されるケースも多いです。
っという事情か、'18年後半から現在まで「phpが動かないよー」とか「rubyが動かないよー」という記事がたくさん出ているみたいです。ぶっちゃけ対処法はそれらにも載っているのですが、如何せんスマートな方法を書いている記事がなく。
・他により良い対処法はないのか?
・なぜスマートな方法が見つからないのか?ということで調べてみました。(phpの名前を出しておいてアレですが、rubyだけです悪しからず。)
この記事の対象
○Macユーザー
△その他Unix系ユーザー
×windowsユーザー検証環境
Mac OS Mojave 10.14.6 (アップデートをサボっています)
rbenv 1.1.2
ruby 2.6.3
Rails 5.2.3rubyが動かない現象
事の発端は久々にrailsでバックエンドを作ろうとした時のこと。とりあえずrails -vを打ったところ、やたら長いエラーが発生。もしかしてrails --versionじゃないとダメだったか?と思い、ロングオプションを打つも同じエラー。
仕方がないのでエラーをちゃんと読むとopenssl関係だと分かりました。
運がいいことに、前日postgresqlのバージョンアップでopenssl1.1.0を入れていたので、"openssl1.0.0"の文字からバージョン関係のエラーだと切り分ける事ができました。ググる
rubyを再インストールして見たら動いたというパターンと、rubyを再インストールすればいいよという記事を見て再インストールしているケースが多数。なるほど最悪rubyを再インストールすればいいと分かりました。
でも明らかに参照先のopensslが違うだけのエラーなので、もうすこし簡単な方法があるはずでは?間違ったopensslを探しに行っている犯人を探してみる
ruby2.6.3のなかに設定ファイルはないか?
結論→ない
grep -r "(opensslのパス)" .rbenv/versions/2.6.3 してもそれらしい設定ファイルは見つからず。その代わり、
.rbenv/versions/2.6.3/lib/ruby/2.6.0/x86_64-darwin18/digest/md5.bundle
.rbenv/versions/2.6.3/lib/ruby/2.6.0/x86_64-darwin18/digest/sha2.bundle matches
.rbenv/versions/2.6.3/lib/ruby/2.6.0/x86_64-darwin18/digest/rmd160.bundle matches
.rbenv/versions/2.6.3/lib/ruby/2.6.0/x86_64-darwin18/digest/sha1.bundle matches
.rbenv/versions/2.6.3/lib/ruby/2.6.0/x86_64-darwin18/openssl.bundle matches
.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/extensions/x86_64-darwin-18/2.6.0-static/puma-3.12.1/puma/puma_http11.bundle
.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/puma-3.12.1/ext/puma_http11/puma_http11.bundle
.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/puma-3.12.1/lib/puma/puma_http11.bundleがヒット。pumaはgemだけど、後のはどう見てもruby本体のライブラリ、嫌な感じしかしないですね。
もしかして:環境変数
結論→ない
printenvしても一切見つからず。
大抵こういうパターンでも新たに特定の変数名で環境変数を作ってやると解決するパターンがある可能性は高いですが、とりあえず「なくても動いている」=「他の参照元が有効である」ことは確実です。ということは
rubyをビルドする時にインストール済みのopensslを探しに行ってライブラリに直書きするパターン?
だから再インストールで直るのかー。rubyが正常に動く状態にする
シンボリックリンクを張る
ln -s libssl.1.1.dylib libssl.1.0.0.dylib
ln -s libcrypto.1.1.dylib libcrypto.1.0.0.dylib私の環境ではopenssl絡みで参照されるライブラリはlibsslとlibcryptoだけでした。(grepすると分かります。)
おそらく一般的にそうなのではないかと思います。
コマンドの数字の部分は左側が実在のファイルと同じ、右側が最初のエラーで出たopensslのバージョンです。動いた
まあそうですよね。動くに決まっています。
どのような対応がベストか?
シンボリックリンクを張るだけでうまいこと動いてくれました。
おそらく以降でopensslのバージョンを参照する場合は1.1で記憶してくれると期待しています。なので急に動かなくなるのはあまり心配していません。ですが、opensslのバージョンをもう一度上げた場合はどうなるのでしょうか?おそらくシンボリックリンクのリンク切れが起きるか、もう一度シンボリックリンクを張り直すことになる気がします。
結局、今後opensslのバージョンアップで同じようなことが起こると予想されますので、ruby自体を再インストールしても問題が起きないように、bundler + GemfileでGemを管理して、グローバルインストールはしないのがベストかもしれませんね。
- 投稿日:2020-01-04T14:38:38+09:00
opensslバージョンアップ @ruby
この記事は
opensslのバージョンアップにより、各種アプリケーションが起動できなくなるエラーが起きているようです。
ssl関係はgoogleはじめプラットフォーマーが敏感なせいかサボりにくい部分です…。
'18年後半から現在まで「phpが動かないよー」とか「rubyが動かないよー」という記事がたくさん出ていて、ぶっちゃけ対処法はそれらにも載っているのですが、如何せんスマートな方法を書いている記事がなく。
・他により良い対処法はないのか?
・なぜスマートな方法が見つからないのか?ということで調べてみました。(phpの名前を出しておいてアレですが、rubyだけです悪しからず。)
この記事の対象
○Macユーザー
△その他Unix系ユーザー
×windowsユーザー検証環境
Mac OS Mojave 10.14.6 (アップデートをサボっています)
rbenv 1.1.2
ruby 2.6.3
Rails 5.2.3rubyが動かない現象
事の発端は久々にrailsでバックエンドを作ろうとした時のこと。とりあえずrails -vを打ったところ、やたら長いエラーが発生。もしかしてrails --versionじゃないとダメだったか?と思い、ロングオプションを打つも同じエラー。
仕方がないのでエラーをちゃんと読むとopenssl関係だと分かりました。
運がいいことに、前日postgresqlのバージョンアップでopenssl1.1.0を入れていたので、"openssl1.0.0"の文字からバージョン関係のエラーだと切り分ける事ができました。ググる
rubyを再インストールして見たら動いたというパターンと、rubyを再インストールすればいいよという記事を見て再インストールしているケースが多数。なるほど最悪rubyを再インストールすればいいと分かりました。
でも明らかに参照先のopensslが違うだけのエラーなので、もうすこし簡単な方法があるはずでは?間違ったopensslを探しに行っている犯人を探してみる
ruby2.6.3のなかに設定ファイルはないか?
結論→ない
grep -r "(opensslのパス)" .rbenv/versions/2.6.3 してもそれらしい設定ファイルは見つからず。その代わり、
.rbenv/versions/2.6.3/lib/ruby/2.6.0/x86_64-darwin18/digest/md5.bundle
.rbenv/versions/2.6.3/lib/ruby/2.6.0/x86_64-darwin18/digest/sha2.bundle
.rbenv/versions/2.6.3/lib/ruby/2.6.0/x86_64-darwin18/digest/rmd160.bundle
.rbenv/versions/2.6.3/lib/ruby/2.6.0/x86_64-darwin18/digest/sha1.bundle
.rbenv/versions/2.6.3/lib/ruby/2.6.0/x86_64-darwin18/openssl.bundle
.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/extensions/x86_64-darwin-18/2.6.0-static/puma-3.12.1/puma/puma_http11.bundle
.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/puma-3.12.1/ext/puma_http11/puma_http11.bundle
.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/puma-3.12.1/lib/puma/puma_http11.bundleがヒット。pumaはgemだけど、後のはどう見てもruby本体のライブラリ、嫌な感じしかしないですね。
もしかして:環境変数
結論→ない
printenvしても一切見つからず。
大抵こういうパターンでも新たに特定の変数名で環境変数を作ってやると解決するパターンがある可能性は高いですが、とりあえず「なくても動いている」=「他の参照元が有効である」ことは確実です。ということは
rubyをビルドする時にインストール済みのopensslを探しに行ってライブラリに直書きするパターン?
だから再インストールで直るのかー。rubyが正常に動く状態にする
シンボリックリンクを張る
ln -s libssl.1.1.dylib libssl.1.0.0.dylib
ln -s libcrypto.1.1.dylib libcrypto.1.0.0.dylib私の環境ではopenssl絡みで参照されるライブラリはlibsslとlibcryptoだけでした。(grepすると分かります。)
おそらく一般的にそうなのではないかと思います。
コマンドの数字の部分は左側が実在のファイルと同じ、右側が最初のエラーで出たopensslのバージョンです。動いた
まあそうですよね。動くに決まっています。
どのような対応がベストか?
シンボリックリンクを張るだけでうまいこと動いてくれました。
ですが、またopensslのバージョンを変えた場合は同じことの繰り返しです。それを考えると、どうしても今のrubyを維持したい場合はこの方法でも良いのですが、そうでなければ再インストールでもいいような気がしました。
(追記)そんな甘い話ではなかった
openssl1.0x以下とopenssl1.1xでは起動時にライブラリをロードする方法が違うとのことで、1.0xからバージョンアップした際、openssl.bundleがエラーを吐くことがわかりました。
1.0x以下の環境下でビルドされたrubyはopenssl1.1xの実行に必要なOPENSSL_init_sslを起動できず、
逆にopenssl1.1xに存在しない_SSL_library_initを呼び出そうとするためエラーになる模様。検証内容
grep -r SSL_library_init /(path to 2.6.3's)/openssl.bundle
-> match
grep -r OPENSSLinit_ssl /(path to 2.6.3's)/openssl.bundle
-> no matchopenssl1.1.0が存在する状態で
rbenv install 2.6.0
rbenv local 2.6.0
元が2.6.3なので、rubyのバージョンは下がっています。ですのでrubyのバージョンが左右する訳ではないはず。
grep -r SSL_library_init /(path to 2.6.0's)/openssl.bundle
-> no match
grep -r OPENSSLinit_ssl /(path to 2.6.0's)/openssl.bundle
-> match呼び出し関数名が変わっているのがわかります。
gem install rails
rails new test-app
cd test-app
rails s
-> OK今度は正常に動いてますね…。
つまり
やっぱり再インストールした方が無難です。
- 投稿日:2020-01-04T14:12:58+09:00
【Rails】Rspec何言ってるか解読してみた件。コントローラー#edit編
今回は、写真とタイトルを投稿するアプリケーションのtweetsコントローラーのeditアクション(投稿したツイートの編集画面を呼ぶ)が問題なく動くかどうか、Rspecという言語を使ってテスト。
テストする内容は以下の2つ。
tweets_controller.rb内でeditアクションを定義した際に生成したインスタンス変数に期待する値が入っているかな?
tweets_controller.rbdef edit @tweet = Tweet.find(params[:id]) end擬似的にeditアクションを起こすリクエストを飛ばして、ちゃんとeditアクションに対応したビューが返ってくるかな?
コントローラーのテストをする際は、2つの点に注意。
①tweets_controller.rbに、テストしたいアクションに対して、before_actionが定義されていないこと。
②gem rails-controller-testingをインストールしよう。また、factory_botを利用して、テストにおいてeditアクションで編集するダミーのツイートデータを作成しよう。
spec/factories/users.rbFactoryBot.define do factory :user do nickname {"mamama"} email {"mamama@mail.com"} password {"00000000"} password_confirmation {"00000000"} end endspec/factories/tweets.rbFactoryBot.define do factory :tweet do text {" I love animals"} image {"animals.png"} user #←factory_botを利用して作った :userのこと。ツイートを投稿した際、そのツイートは誰が作ったのかも情報に含まれるため、ダミーのユーザー情報も作成しダミーのツイートを作成する際に利用している。 end endでは、見ていきましょう。
tweets_controller_spec.rbrequire 'rails_helper' describe TweetsController, type: :controller do describe 'GET #new' do #「【Rails】Rspec何言ってるか解読してみた件。コントローラー#new編」を参照。 end describe 'GET #edit' do # 1. tweets_controller.rb内でeditアクションを定義した際に生成したインスタンス変数に期待する値が入っているかな? it "assigns the requested tweet to @tweet" do dummyTweet = create(:tweet) get :edit, params: { id: dummyTweet } expect(assigns(:tweet)).to eq dummyTweet end # 2. 擬似的にeditアクションを起こすリクエストを飛ばして、ちゃんとnewアクションに対応したビューが返ってくるかな? it "renders the :edit template" do dummyTweet = create(:tweet) get :edit, params: { id: dummyTweet } expect(responce).to render_template :edit end end end1. tweets_controller.rb内でeditアクションを定義した際に生成したインスタンス変数に期待する値が入っているかな?
require 'rails_helper'
RailsでRspecを利用する時の共通の設定が記載されているrails_helper.rbを読み込む。これがなきゃ始まらない。
describe TweetsController, type: :controller do end
tweetsコントローラーのテストをするよ。 type: :controllerこれは書かなきゃいけないみたいですね。
describe 'GET #edit' do end
GETメソッドのeditアクションに関するテストだよ。
it "assigns the requested tweet to @tweet" do end
do - endの間に書かれている、実際に動くテストコードの説明。呼ばれたtweet(the requested tweet)が@tweetにアサインされているかをテストしますと言っている。日本語でも良いらしい。ちなみに、it do endのセット1つで、1exampleと呼ぶ。
dummyTweet = create(:tweet)
factory_botで生成したtweetをcreateアクションを起こさせて、一旦登録。それをdummyTweetに入れる。
get :edit, params: { id: dummyTweet }
擬似的なリクエストを起こすコード。get :edit
でアクション名editを、params: { id: dummyTweet }
でdummyTweetがTweetsテーブルの何番目のカラムにあるのかを示すidを、そのリクエストに情報として渡す。
expect(assigns(:tweet)).to eq dummyTweet
インスタンス変数に意図したものが入っているかな?というテストコード。assignsは、インスタンス変数の中身をチェックしてくれるやつ。今回は、tweets_controller.rb内で定義した@tweetが対象なので、(:tweet)と書こう。@tweetの中身は、一旦登録させてeditアクションで持ってこさせたdummyTweetと一緒だと(.to eq)と期待する(expect)。tweets_controller_spec.rb#省略 describe 'GET #edit' do # 1. tweets_controller.rb内でeditアクションを定義した際に生成したインスタンス変数に期待する値が入っているかな? it "assigns the requested tweet to @tweet" do dummyTweet = create(:tweet) get :edit, params: { id: dummyTweet } expect(assigns(:tweet)).to eq dummyTweet end # 2. 擬似的にeditアクションを起こすリクエストを飛ばして、ちゃんとnewアクションに対応したビューが返ってくるかな? it "renders the :edit template" do dummyTweet = create(:tweet) get :edit, params: { id: dummyTweet } expect(responce).to render_template :edit end end #省略2. 擬似的にeditアクションを起こすリクエストを飛ばして、ちゃんとnewアクションに対応したビューが返ってくるかな?
it "renders the :edit template" do end
do - endの間に書かれている、実際に動くテストコードの説明。editアクションに対応したビューファイル(template)が呼び出される(renders)ことをテストしますと言っている。
get :edit, params: { id: dummyTweet }
擬似的なリクエストを起こすコード。get :edit
でアクション名editを、params: { id: dummyTweet }
でdummyTweetがTweetsテーブルの何番目のカラムにあるのかを示すidを、そのリクエストに情報として渡す。
expect(response).to render_template :edit
ちゃんと期待するビューが返ってくるかな?というテストコード。resposeが、editが起きた時に呼ばれるrender_template(ビューである)と期待する(expect)。
ターミナルにて
% bundle exec rspec spec/controllers/tweets_controller_spec.rb
を実行してテストを実施しよう。
初学者の視点からRailsアプリケーションのRspecを使ったテストについてまとめてみました。指摘やご意見お待ちしてます。モデルや、コントローラーのその他アクションについても、まとめていきたいと思います。
最後までご覧いただきありがとうございました!
- 投稿日:2020-01-04T11:52:59+09:00
rails: datetime_selectをカスタマイズする方法
やりたいこと
デフォルトで
datetime_select
を使うとデザイン的にあまり美しく無いので下記のようにカスタマイズしてみた。
デフォルトだと下記のような殺風景なデザインでUX的に美しくない。どのようにしたらできるのか?
結論から言うと、
datetime_separator
を弄ることでafter後のデザインに出来る。
初めは、文字しか書けないんだろうなと思ったらhtml
も書き込むことができた。= f.datetime_select :date, {use_month_numbers: true, start_year: Date.today.year, datetime_separator: '<h4 class="fb-txt font-weight-bold my-2">時間</h4>'},{class: "form-control", id: 'ymd-date'}ちなみに
datetime_separator
以外にdate_separator
とtime_separator
もあるので暇なときにそっちについても記事にしていきたいと思う。
コメントで要望があればすぐに対応しますが、多分ググればそれっぽい記事があると思うのでまずはググってみてください。
- 投稿日:2020-01-04T11:50:47+09:00
【jQuery】RailsでValidation Pluginを使った動的なバリデーションチェックの実装その1
はじめに
本記事がQiitaでの初投稿となります。
プログラミングスクールで開発中のECサイトアプリでjQueryのプラグインを使って
動的なバリデーションチェック機能を実装しました。
実装手順とRailsで使用する場合の注意点をシェアします。開発環境
Ruby 2.5.1
Rails 5.0.7.2
jQuery 3.4.1
jQuery Validation Plugin 1.19.1
Haml 5.1.2
Sass 3.7.4jQuery Validation Pluginとは
jQuery Validation Pluginはバリデーションチェックが実装できるjQueryのプラグインです。
公式サイト:https://jqueryvalidation.org/
やりたいこと
- 入力フォームにユーザー情報を入力する際にリアルタイムにバリデーションをチェック
- バリデーションエラーがある場合はエラーをリアルタイムに表示
- バリデーションがNGの場合は入力欄が赤色、OKの場合は緑色に変更
なぜjQuery Validation Pluginを選んだのか?
バリデーションチェックを実装するにあたり、実装方法を検討しました。
他にも以下の方法があります。
①RailsのActive Record バリデーション
②HTMLのフォーム検証機能
③HTML5 + JavaScriptによるFormバリデーションプラグインなどを有効活用でき、動的にバリデーションチェックできることを主軸に検討し、
jQueryプラグインでフロントエンドでの第1チェックを行い、Railsのバリデーションでバックエンド側の最終チェックを行う方法を選びました。完成イメージ
実装手順
1. プラグインの導入
CDNでも導入できるそうですが、上手くいかなかったため、下記手順で導入しました。
1.1 公式サイトにアクセス
1.2 ダウンロードページへ
1.3 最下段からzipファイルをダウンロード
1.4 下記のJSファイルをアプリのディレクトリに保存
- jquery-validation-1.19.1/dist/jquery.validate.min.js (※1)
- jquery-validation-1.19.1/src/localization/messages_ja.js (※2)
※1 : 必須
※2 : 標準メッセージを日本語化したい場合のみ2. HTMLファイルの作成
下記のように入力フォームのform_forとf.text_filedなどの各入力欄にidを割り振ります。
(例: id: "signup-form", id: "name" etc.)
BEMが長くて読みにくいですが、ご容赦ください。Railsでの注意点:HTMLではname属性値を付けないようにしましょう。(理由は後述します。)
私は最初、name属性値を指定していてバリデーションチェックが動作しませんでした。
registration.html.haml= form_for(@user, url: phone_signup_index_path, method: :get, html: {class: "registration__main__form", id: "signup-form"}) do |f| %div.registration__main__form__content %div.registration__main__form__content__group = f.label :name, "ニックネーム", class: "registration__main__form__content__group__label" %span.registration__main__form__content__group__require 必須 = f.text_field :name, class: "registration__main__form__content__group__input", placeholder:"例)テスト太郎", id: "name" %div.registration__main__form__content__group = f.label :email, "メールアドレス", class: "registration__main__form__content__group__label" %span.registration__main__form__content__group__require 必須 = f.email_field :email, class:"registration__main__form__content__group__input", placeholder:"PC・携帯どちらでも可", id: "email" %div.registration__main__form__content__group = f.label :password, "パスワード", class: "registration__main__form__content__group__label" %span.registration__main__form__content__group__require 必須 = f.password_field :password, class:"registration__main__form__content__group__input", placeholder:"7文字以上の半角英数字", id: "password" %p.registration__main__form__content__group__input__info ※ 英字と数字の両方を含めて設定してください。 %div.registration__main__form__content__group = f.label :password_confirmation, "パスワード(確認)", class: "registration__main__form__content__group__label" %span.registration__main__form__content__group__require 必須 = f.password_field :password_confirmation, class:"registration__main__form__content__group__input", placeholder:"7文字以上の半角英数字", id: "password_confirmation"3. Javascriptファイルの作成
次に下記のようにJavascriptファイルを作成します。
ファイル名は任意です。jquery.validate.handler.user.js$(function () { // メソッドの定義 var methods = { email: function (value, element) { // メールアドレスの正規表現 return this.optional(element) || /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/i.test(value); }, password: function (value, element) { // パスワードの正規表現 return this.optional(element) || /^(?=.*?[a-z])(?=.*?\d)[a-z\d]{8,100}$/i.test(value); }, } // メソッドの追加 $.each(methods, function (key) { $.validator.addMethod(key, this); }); // バリデーションの実行 $("#signup-form").validate({ // ルール設定 rules: { "user[name]": { required: true // ニックネームの入力有無チェック }, "user[email]": { required: true, // メールアドレスの入力有無チェック email: true // メールアドレスの正規表現チェック }, "user[password]": { required: true, // パスワードの入力有無チェック password: true // メールアドレスの正規表現チェック }, }, // エラーメッセージの定義 messages: { "user[name]": { required: "ニックネームを入力してください" }, "user[email]": { required: "メールアドレスを入力してください", email: "フォーマットが不適切です" }, "user[password]": { required: "パスワードを入力してください", password: "英字と数字両方を含むパスワードを入力してください" }, }, errorClass: "invalid", // バリデーションNGの場合に追加するクラス名の指定 errorElement: "p", // エラーメッセージの要素種類の指定 validClass: "valid", // バリデーションOKの場合に追加するクラス名の指定 } }); // 入力欄をフォーカスアウトしたときにバリデーションを実行 $("#name, #email, #password").blur(function () { $(this).valid(); }); });基本的な記述方法は下記の記事を参考にさせていただきました。
【jQuery入門】validate()の使い方と独自ルールの設定方法!
jQuery Validation 簡単にフォームをチェック バリデーション
フォームの入力値を検証するjQuery Validation Pluginの使い方メールアドレスとパスワードの正規表現はデフォルトのルールでも実装可能です。
Railsでの注意点
通常の使い方だとrules:の中にname属性値を指定しますが、下記の記事の通り、Railsの場合は少し通常と異なります。
[Rails]「jQueryValidationプラグイン」を使用してフォームのバリデーションを実装ページのソースを確認するとname属性値は"user[name]"となっています。
このname属性値をrules:の中で指定するとバリデーションチェックが動作します。<input class="クラス名" placeholder="例)メルカリ太郎" id="name" type="text" name="user[name]" /> <input class="クラス名" placeholder="PC・携帯どちらでも可" id="email" type="email" name="user[email]" /> <input class="クラス名" placeholder="7文字以上の半角英数字" id="password" type="password" name="user[password]" />このRails特有のname属性値の指定の仕方についての記事が少なく途中で手詰まりました。
いろいろ調べたところ以下記事で明確な記載がありました。
JQuery validate in Rails applicationsPlease note that in rails, name of an element is created as form[name] instead of name only. If you are creating a form for creating a new user and fields in this form are Email first_name, last_name etc then name of these fields is being created as user[emal], user[first_name], user[last_name] resp. While using these name of an elements as key you have to keep in mind to use them in qoutes i.e
“user[email]” or your jquery will be unable to understand what this name belongs to.'user[name]': {required : true}一部を訳すとRailsではname属性値がuser[email]となっているため、"user[email]"としないとjQueryがそのname属性が何に属しているかを認識しないと記述がありました。
入力欄をフォーカスアウトした時に動作させる
通常の使い方ですとsubmitボタンが押されたタイミングでバリデーションチェックが動作します。
入力欄をフォーカスアウトした時などに動作させたい場合は、下記のように実行のタイミングを指定します。// 入力欄をフォーカスアウトしたときにバリデーションを実行 $("#name, #email, #password").blur(function () { $(this).valid(); });下記の記事を参考させていただきました。
jquery.validate.jsでvalidateチェックタイミングを指定する4. CSSファイル作成
バリデーションNGもしくはOKの時に追加されるクラス名を独自に指定できるので、
CSSで枠線を指定します。errorClass: "invalid", // バリデーションNGの場合に追加するクラス名の指定 validClass: "valid", // バリデーションOKの場合に追加するクラス名の指定registration.scss.registration { &__main { // 〜省略〜 &__form { // 〜省略〜 &__content { // 〜省略〜 &__group { // 〜省略〜 &__input.invalid { // バリデーションNGの場合に枠線を赤色に変更 border: #ea352d 1px solid; } &__input.valid { border: seagreen 1px solid; // バリデーションNGの場合に枠線を緑色に変更 } } } } } } // エラーメッセージ #name-error, #email-error, #password-error { color: #ea352d; line-height: 1.5; font-size: 14px; margin-top: 8px; } // 入力欄をクリック時に枠線を水色に変更 input[type=text]:focus, input[type=email]:focus, input[type=password]:focus { outline: none; border-color: #0098E8; }まとめ
jQuery Validation Pluginを用いて実行タイミングを指定すると動的なバリデーションチェックが実装可能です。
他にもselectタグのバリデーションなども実装しましたので別記事でまとめたいと思います。
記載内容に誤りなどございましたら、ご指摘いただけますと幸いです。参考URL
https://jqueryvalidation.org/
https://www.sejuku.net/blog/44470
https://sys-guard.com/post-14579/
https://into-the-program.com/jquery-validation-plugin/
[Rails]「jQueryValidationプラグイン」を使用してフォームのバリデーションを実装
jquery.validate.jsでvalidateチェックタイミングを指定する
- 投稿日:2020-01-04T11:28:30+09:00
【Rails】Rspec何言ってるか解読してみた件。コントローラー#new編
今回は、写真とタイトルを投稿するアプリケーションのtweetsコントローラーのnewアクション(新規ツイート投稿画面を呼ぶ)が問題なく動くかどうか、Rspecという言語を使ってテスト。
spec/controllers/tweets_controller_spec.rbに、擬似的にnewアクションを起こすリクエストを飛ばして、ちゃんとnewアクションに対応したビューが返ってくるかな?というテストコードを記述。
コントローラーのテストをする際は、2つの点に注意。
①tweets_controller.rbに、テストしたいアクションに対して、before_actionが定義されていないこと。
②gem 'rails-controller-testing'をインストールしよう。では、見ていきましょう。
tweets_controller_spec.rbrequire ‘rails_helper' describe TweetsController, type: :controller do describe 'GET #new' do it "renders the :new template" do get :new expect(response).to render_template :new end end end
require 'rails_helper'
RailsでRspecを利用する時の共通の設定が記載されているrails_helper.rbを読み込む。
これがなきゃ始まらない。
describe TweetsController, type: :controller do end
tweetsコントローラーのテストをするよ。 type: :controllerこれは書かなきゃいけないみたいですね。
describe 'GET #new' do end
GETメソッドのnewアクションに関するテストだよ。
it "renders the :new template" do end
do - endの間に書かれている、実際に動くテストコードの説明。
newアクションに対応したビューファイル(template)が呼び出される(renders)ことをテストしますと言っている。日本語でも良いらしい。ちなみに、it do endのセット1つで、1exampleと呼ぶ。
get :new
擬似的なリクエストを起こすテストコード。そのリクエストに、アクション名newを情報として渡す。
expect(response).to render_template :new
ちゃんと期待するビューが返ってくるかな?というテストコード。
resposeが、newが起きた時に呼ばれるrender_template(ビューである)と期待する(expect)。ターミナルにて
% bundle exec rspec spec/controllers/tweets_controller_spec.rb
実行すると以下の表示が。TweetsController GET #new renders the :new template Finished in 0.13692 seconds (files took 3.21 seconds to load) 1 example, 0 failures
TweetsController
GET #new
describeに書いたテストの概要説明。
renders the :new template
itに書いた、実際に動くテストコードの説明。
1 example, 0 failures
1exampleあって、0個の失敗。つまりテストは成功し、問題なかったということ。
初学者の視点からRailsアプリケーションのRspecを使ったテストについてまとめてみました。指摘やご意見お待ちしてます。モデルや、コントローラーのその他アクションについても、まとめていきたいと思います。
最後までご覧いただきありがとうございました!
- 投稿日:2020-01-04T08:55:01+09:00
github actions rspec
成果物
.github/workflows/ruby.ymlname: Ruby on: [push] jobs: build: runs-on: ubuntu-latest services: postgres: image: postgres:10.3 ports: ["5432:5432"] options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 steps: - uses: actions/checkout@v1 - name: Set up Ruby 2.5 uses: actions/setup-ruby@v1 with: ruby-version: 2.5 - name: Install PostgreSQL client run: | sudo apt-get -yqq install libpq-dev dialog apt-utils - name: Build App env: RAILS_ENV: test DATABASE_URL: postgresql://postgres@localhost:5432/postgres?encoding=utf8&pool=5&timeout=5000 run: | gem install bundler:1.16.1 cd docker/api/api bundle install --quiet --jobs 4 --retry 3 bin/rails db:migrate:reset RAILS_ENV=test - name: Build and test with Rspc env: RAILS_ENV: test DATABASE_URL: postgresql://postgres@localhost:5432/postgres?encoding=utf8&pool=5&timeout=5000 run: | cd docker/api/api bundle exec rspecconfig/database.ymldefault: &default adapter: postgresql encoding: unicode host: db username: postgres password: pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> development: <<: *default database: myApi_development test: <<: *default database: postgres_test url: <%= ENV['DATABASE_URL'].gsub('?', '_test?' ) %> production: <<: *default database: myApi_production username: myApi password: <%= ENV['MYAPI_DATABASE_PASSWORD'] %> url: <%= ENV['DATABASE_URL'] %>
はまった
エラー1
PG::ConnectionBad: could not translate host name "postgres" to address: Temporary failure in name resolution
役に立った
https://stackoverflow.com/a/20722229
postgresql://[user[:password]@][netloc][:port][/dbname][?param1=value1&...]
stackoverflowを見る限り、localhostにしておけばいいっぽい。
てことで、これでなおったbefore env: RAILS_ENV: test DATABASE_URL: postgresql://postgres@postgres:5432/postgres?encoding=utf8&pool=5&timeout=5000 ---------- after env: RAILS_ENV: test DATABASE_URL: postgresql://postgres@localhost:5432/postgres?encoding=utf8&pool=5&timeout=5000
エラー2
Could not locate Gemfile
解決策
Gemfileが存在するdirectoryに移動する
cd docker/api/apiエラ-3
戦闘
エラーですぎ。うれしい。エラーでないと死ぬ
OSが本番環境と違うと思った。とりあえずOK
https://rocky-plateau-44026.herokuapp.com/
https://github.com/kajirikajiri/rails-api