20190820のRailsに関する記事は9件です。

素人による "and return unless"

Railsチュートリアル11章リスト11.40にて

 以下のコードがあった。

  def show
    @user = User.find(params[:id])
    redirect_to root_url and return unless @user.activated?
  end

 このコードの中のand return unlessの挙動が分からなかったので、調べて考えたことをまとめておく。

and returnについて

 まずはand returnについて見てみよう。Railsガイドにて以下の解説と参考コードがあった。

Rails開発をやっていれば、一度は "Can only render or redirect once per action" エラーに遭遇したことがあるでしょう。いまいましいエラーですが、修正は比較的簡単です。このエラーはほとんどの場合、開発者がrenderメソッドの基本的な動作を誤って理解していることが原因です。

def show
  @book = Book.find(params[:id])
  if @book.special?
    render action: "special_show"
  end
  render action: "regular_show"
end

 上のコードでは、@book.special?trueの時、if文内のrenderとその外のrenderも実行されてしまい、二重レンダリングというエラーになる。そこで、and returnを使って明示的にメソッドを抜けることで二重レンダリングを避ける。

def show
  @book = Book.find(params[:id])
  if @book.special?
    render action: "special_show" and return
  end
  render action: "regular_show"
end

 挙動としては、renderredirect_toの戻り値がtrueなので、andの後ろのreturnが実行されるということだ。

 なお、&& returnを使うとこの場合正しく動作しない。というのも、&&は優先度が高いのでrender action: ("special_show" && return)ということになるからだろう。一方のandの優先度は超低い。and returnはこのandの優先度の低さを上手に利用している。

and return unlessについて

 and returnの働きとandの優先度について書いたので、あとはそれを組み合わせるだけだ。もう一度最初のコードを見てみよう。

  def show
    @user = User.find(params[:id])
    redirect_to root_url and return unless @user.activated?
  end

 andの優先順位は低いので、redirect_to root_urlが先に評価されるので、andが評価するのはredirect_to root_urlreturnになる。()でくくってやると以下のようになる。

(redirect_to root_url) and (return)

あとは、上のカタマリがunlessの後置修飾がついているだけだ。つまり、redirect_to root_url and return unless @user.activated?は以下と同じになる。

unless @user.activated?
  redirect_to root_url and return
end

おわり

 and return unlessというカタマリで見てしまったので挙動が見えず分からなくなってしまったが、ひとつずつ分解して見てみるとそこまで恐ろしいものでもなかった。「巨大で恐ろしい相手でも、ひとつひとつは取るに足らないものだぞ」と人生の教訓をプログラミングが教えてくれた。

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

Rails チュートリアル(3章、4章)をRSpecでテスト

はじめに

なんとなく、RSpecの書き方がわかってきたので、Rails チュートリアルのテストを書いて見ました。

Rails チュートリアル 3,4章

RSpecの導入

gemを入れます。

gemfile
group :development, :test do
  gem 'factory_bot_rails'
  gem 'rspec-rails', '~> 3.8'
  gem 'shoulda-matchers' #後の章で使うのでとりあえず入れてます。
end
$ bundle install
$ rails generate rspec:install

DBを作成していなければ、rails db:createで作成してください。作ってなく警告が出ました。

RSpecの設定

以下を参考にしました。↓
RailsでRSpecの初期設定を行う際のテンプレートを作ってみる-Qiita

.rspec
--require rails_helper
--format documentation
config/application.rb
module SampleApp
  class Application < Rails::Application
    config.load_defaults 5.2
#----------ここから下を追加---------------------------
    config.generators do |g|
      g.test_framework :rspec,
                       helper_specs: false,
                       routing_specs: false,
                       view_specs: false,
                       controller_specs: false
    end
#----------ここまで-----------------------------------
    config.generators.system_tests = nil
  end
end

RSpecを利用したコントローラの機能テストは、Rails5からはrequest specで記述することが推奨されてるみたいなので、controller_specsも省きました。

以下を参考にしました。↓
Rails5でコントローラのテストをController specからRequest specに移行する-Qiita
everydayrails
Project: RSpec Rails 3.8

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

テストを書く(3章、4章)

3章と4章のテストを書きます。
4章のテストを書いてます。元のテスト↓
4.1.2 カスタムヘルパー -Ruby on Rails チュートリアル

spec/requests/access_to_static_pages_spec.rb
require 'rails_helper'

describe 'Access to static_pages', type: :request do
  context 'GET #home' do
    before do
      get root_path
    end
    it 'response successfully' do
      expect(response).to have_http_status 200
    end
    it "title is 'Ruby on Rails Tutorial Sample App'" do
      expect(response.body).to include 'Ruby on Rails Tutorial Sample App'
      expect(response.body).to_not include '| Ruby on Rails Tutorial Sample App'
    end
  end

  context 'GET #help' do
    before do
      get help_path
    end
    it 'response successfully' do
      expect(response).to have_http_status 200
    end
    it "title is 'Home | Ruby on Rails Tutorial Sample App'" do
      expect(response.body).to include 'Help | Ruby on Rails Tutorial Sample App'
    end
  end

  context 'GET #about' do
    before do
      get about_path
    end
    it 'respose successfully' do
      expect(response).to have_http_status 200
    end
    it "title is 'Home | Ruby on Rails Tutorial Sample App'" do
      expect(response.body).to include 'About | Ruby on Rails Tutorial Sample App'
    end
  end
end

以上で3章と4章のテストが完了です。
5章で変更するルートはここで変更してしまってます。
また、contactアクションをつくることになってますが、省いてます。

request specのファイル名はなんて書けばいいかわからず、なんとなくで書いてしまいました。

Railsチュートリアル 5章

5章のルートのテストは4章でついで書いてしまったので、残りのレイアウトのテストを書きます。

system specの準備

gemfile
+ gem 'capybara'
+ gem 'webdrivers'
- #gem 'chromedriver-helper' #削除
$ bandle install
spec/spec_helper.rb
require 'capybara/rspec' #これも追加

RSpec.configure do |config|
  config.include FactoryBot::Syntax::Methods
#-------------ここから追加-----------------------------
  config.before(:each, type: :system) do
    driven_by :selenium_chrome_headless
  end
#-------------ここまで--------------------------------
end

最後にspecフォルダーにrequestsフォルダーを作り、その中にテストファイルを作ります。

テストを書く(5章)

ホームページのリンクのテストを書きます。
元のテスト↓
5.3.4 リンクのテスト Ruby on Railsチュートリアル

systems/site_layout_spec.rb
require 'rails_helper'

RSpec.describe 'site layout', type: :system do
  it 'has links sach as root_path, help_path and about_path' do
    visit root_path
    expect(page).to have_link nil, href: root_path, count: 2
    expect(page).to have_link 'Help', href: help_path
    expect(page).to have_link 'About', href: about_path
  end
end

一つのページにリンクがそろっているかのテストなので、itで分けませんでした。正しいかはわかりません。

次に以前書いたタイトルテストをリファクタリングします。テストでもfull_titleヘルパーを使います。

元のテスト↓
演習 Ruby on Railsチュートリアル

spec/spec_helper.rb
RSpec.configure do |config|
  config.include FactoryBot::Syntax::Methods
  config.before(:each, type: :system) do
    driven_by :selenium_chrome_headless
  end
  config.include ApplicationHelper #追加
end
spec/requests/access_to_static_pages_spec.rb
require 'rails_helper'

RSpec.describe 'Access to static_pages', type: :request do
  context 'GET #home' do
    before do
      get root_path
    end
    it 'response successfully' do
      expect(response).to have_http_status 200
    end
    it "title is 'Ruby on Rails Tutorial Sample App'" do
      expect(response.body).to include full_title('') #変更部分
      expect(response.body).to_not include '| Ruby on Rails Tutorial Sample App'
    end
  end

  context 'GET #help' do
    before do
      get help_path
    end
    it 'response successfully' do
      expect(response).to have_http_status 200
    end
    it "title is 'Home | Ruby on Rails Tutorial Sample App'" do
      expect(response.body).to include full_title('Help') #変更部分
    end
  end

  context 'GET #about' do
    before do
      get about_path
    end
    it 'respose successfully' do
      expect(response).to have_http_status 200
    end
    it "title is 'Home | Ruby on Rails Tutorial Sample App'" do
      expect(response.body).to include full_title('About') #変更部分
    end
  end
end

次にapplication_helperのテストを書きます。(full_titleヘルパーのテストです)
specフォルダーにhelpersフォルダーを作成し、その中にテストファイルを作ります。

helpers/application_helper_spec.rb
require 'rails_helper'

RSpec.describe ApplicationHelper, type: :helper do
  describe '#full_title' do
    it { expect(full_title('')).to eq 'Ruby on Rails Tutorial Sample App' }
    it { expect(full_title('Help')).to eq 'Help | Ruby on Rails Tutorial Sample App' }
  end
end

ひとまず、ここまでです。

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

Rails チュートリアル(3章、4章、5章)をRSpecでテスト

はじめに

なんとなく、RSpecの書き方がわかってきたので、Rails チュートリアルのテストを書いて見ました。

Rails チュートリアル 3,4章

RSpecの導入

gemを入れます。

gemfile
group :development, :test do
  gem 'rspec-rails', '~> 3.8'
end
$ bundle install
$ rails generate rspec:install

DBを作成していなければ、rails db:createで作成してください。作ってなく警告が出ました。

RSpecの設定

以下を参考にしました。↓
RailsでRSpecの初期設定を行う際のテンプレートを作ってみる-Qiita

.rspec
--require rails_helper
--format documentation
config/application.rb
module SampleApp
  class Application < Rails::Application
    config.load_defaults 5.2
#----------ここから下を追加---------------------------
    config.generators do |g|
      g.test_framework :rspec,
                       helper_specs: false,
                       routing_specs: false,
                       view_specs: false,
                       controller_specs: false
    end
#----------ここまで-----------------------------------
    config.generators.system_tests = nil
  end
end

RSpecを利用したコントローラの機能テストは、Rails5からはrequest specで記述することが推奨されてるみたいなので、controller_specsも省きました。

以下を参考にしました。↓
Rails5でコントローラのテストをController specからRequest specに移行する-Qiita
everydayrails
Project: RSpec Rails 3.8

テストを書く(3章、4章)

static_pagesコントローラーのテスト

4章のテストを書いてます。元のテスト↓
4.1.2 カスタムヘルパー -Ruby on Rails チュートリアル

spec/requests/access_to_static_pages_spec.rb
require 'rails_helper'

RSpec.describe 'Access to static_pages', type: :request do
  context 'GET #home' do
    before { get root_path }

    it 'responds successfully' do
      expect(response).to have_http_status 200
    end
    it "has title 'Ruby on Rails Tutorial Sample App'" do
      expect(response.body).to include 'Ruby on Rails Tutorial Sample App'
      expect(response.body).to_not include '| Ruby on Rails Tutorial Sample App'
    end
  end

  context 'GET #help' do
    before { get help_path }

    it 'responds successfully' do
      expect(response).to have_http_status 200
    end
    it "has title 'Home | Ruby on Rails Tutorial Sample App'" do
      expect(response.body).to include 'Help | Ruby on Rails Tutorial Sample App'
    end
  end

  context 'GET #about' do
    before { get about_path }

    it 'responds successfully' do
      expect(response).to have_http_status 200
    end
    it "has title 'Home | Ruby on Rails Tutorial Sample App'" do
      expect(response.body).to include 'About | Ruby on Rails Tutorial Sample App'
    end
  end
end

以上で3章と4章のテストが完了です。
5章で変更するルートはここで変更してしまってます。
また、contactアクションをつくることになってますが、省いてます。

request specのファイル名はなんて書けばいいかわからず、なんとなくで書いてしまいました。

Railsチュートリアル 5章

5章のルートのテストは4章でついで書いてしまったので、残りのレイアウトのテストを書きます。

system specの準備

gemfile
+ gem 'capybara'
+ gem 'webdrivers'
- #gem 'chromedriver-helper' #削除
$ bandle install
spec/spec_helper.rb
require 'capybara/rspec' #これも追加

RSpec.configure do |config|
  config.include FactoryBot::Syntax::Methods
#-------------ここから追加-----------------------------
  config.before(:each, type: :system) do
    driven_by :selenium_chrome_headless
  end
#-------------ここまで--------------------------------
end

最後にspecフォルダーにrequestsフォルダーを作り、その中にテストファイルを作ります。

テストを書く(5章)

site_layoutのテスト

ホームページのリンクのテストを書きます。

元のテスト↓
5.3.4 リンクのテスト -Ruby on Railsチュートリアル

systems/site_layout_spec.rb
require 'rails_helper'

RSpec.describe 'site layout', type: :system do
  context 'access to root_path' do
    before { visit root_path }
    subject { page }

    it 'has links sach as root_path, help_path and about_path' do
      is_expected.to have_link nil, href: root_path, count: 2
      is_expected.to have_link 'Help', href: help_path
      is_expected.to have_link 'About', href: about_path
    end
  end
end

一つのページにリンクがそろっているかのテストなので、itで分けませんでした。正しいかはわかりません。

application_helperのテスト

次に以前書いたタイトルテストをリファクタリングします。テストでもfull_titleヘルパーを使います。

元のテスト↓
演習 -Ruby on Railsチュートリアル

spec/spec_helper.rb
RSpec.configure do |config|
  config.include FactoryBot::Syntax::Methods
  config.before(:each, type: :system) do
    driven_by :selenium_chrome_headless
  end
  config.include ApplicationHelper #追加
end
spec/requests/access_to_static_pages_spec.rb
require 'rails_helper'

RSpec.describe 'Access to static_pages', type: :request do
  context 'GET #home' do
    before { get root_path }

    it 'responds successfully' do
      expect(response).to have_http_status 200
    end
    it "has title 'Ruby on Rails Tutorial Sample App'" do
      expect(response.body).to include full_title('') #変更部分
      expect(response.body).to_not include '| Ruby on Rails Tutorial Sample App'
    end
  end

  context 'GET #help' do
    before { get help_path }

    it 'responds successfully' do
      expect(response).to have_http_status 200
    end
    it "has title 'Home | Ruby on Rails Tutorial Sample App'" do
      expect(response.body).to include full_title('Help') #変更部分
    end
  end

  context 'GET #about' do
    before { get about_path }

    it 'responds successfully' do
      expect(response).to have_http_status 200
    end
    it "has title 'Home | Ruby on Rails Tutorial Sample App'" do
      expect(response.body).to include full_title('About') #変更部分
    end
  end
end

次にapplication_helperのテストを書きます。(full_titleヘルパーのテストです)
specフォルダーにhelpersフォルダーを作成し、その中にテストファイルを作ります。

helpers/application_helper_spec.rb
require 'rails_helper'

RSpec.describe ApplicationHelper, type: :helper do
  describe '#full_title' do
    it { expect(full_title('')).to eq 'Ruby on Rails Tutorial Sample App' }
    it { expect(full_title('Help')).to eq 'Help | Ruby on Rails Tutorial Sample App' }
  end
end

usersコントローラーのテスト

元のテスト↓
5.4.1 Usersコントローラ -Ruby on Railsチュートリアル

requests/access_to_users_spec.rb
require 'rails_helper'

RSpec.describe 'access to users', type: :request do 
  describe 'GET #new' do
    it 'responds successfully' do
      get signup_path
      expect(response).to have_http_status 200
    end
  end
end

site_layoutのテスト(signupページについて)

元のテスト↓
演習 -Usersコントローラ -Ruby on Railsチュートリアル

systems/site_layout_spec.rb
require 'rails_helper'

RSpec.describe 'site layout', type: :system do
  #上記省略

  context 'access to signup_path' do
    before { visit signup_path }
    subject { page }

    it "has 'Sign up' contens and includes 'Sign up' at title" do
      is_expected.to have_content 'Sign up'
      is_expected.to have_title full_title('Sign up')
    end
  end
end

ここまで5章が終わりです。

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

ガイドのための掲示板式マッチングサービスGuide Searchをつくった

はじめに

TechAcademyのWebアプリケーションコースを2か月間受講してオリジナルサービスを作りました。その過程で役に立った知識をまとめていきます。

Guide Search :https://guide-search.herokuapp.com/

TechAcademyのWebアプリケーションコースを受講する経緯などはこのページにまとめてあります。
https://yokubarilink.com/techacademy-learningdeliverable/

Guide Searchの説明

アプリの仕組みとしては、家庭教師の募集の掲示板のように掲示板の形式でマッチングを行います。ガイドを募集する側は募集の投稿を行います。一方ガイドをしたい側は、掲示板を見ながら自分にあったサービスに応募するという仕組みです。

主な機能は:
・userの作成、編集、退会
・投稿の作成、編集、削除
・ログイン機能
・投稿の検索
・フォロー機能

具体的な作成の流れ

基本はTechAcademyのWebアプリケーションコースでつくったTwitterクローンをもとにしています。
Ruby on Rails チュートリアルで学べることと基本は変わりません

追加で実装した機能と参考にしたサイトをまとめていきます。

・検索機能
https://qiita.com/yusuko/items/cff4e46aeafbc3beecf2
https://qiita.com/mochikichi321/items/5c9630c5d87b47130942

・投稿一覧に自分の投稿以外を並べる
https://teratail.com/questions/62493

・退会機能
https://qiita.com/kenzoukenzou104809/items/d52054000c16cb363707
https://teratail.com/questions/200344

難しかった点・課題・今後実装したい機能

・慣れないうちは、このコードをどこに書けばいいのかなどわからないことだらけです。機能の実装を繰り返すうちに感覚を身につけ、それから本質的な理解に移ればいいと思います。
・今後はDM(ダイレクトメール)機能・管理者の機能・ガイドする側とされる側でUserテーブルを分けるなど…

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

Amazon Linux + Rails + Nginx環境にLet's Encryptを導入する

テスト環境やステージング環境で、SSLを導入する際に、手軽にLet's Encryptを使うという場面が出てくると思う。今回は、Amaxon Linux + Rails + Nginxの環境にLet's Encryptを導入する際にいくつかハマったところがあったのでメモをする。
ちなみに、Amazon Linux2ではcertbotは正式にサポートされていないので、本番環境ではやめたほうがいいかもしれません。ただ、正常に動作しています。

以下の注意文言は、チュートリアル: Amazon Linux 2 に SSL/TLS を設定する - Amazon Elastic Compute Cloud より。

Certbot は Amazon Linux 2 で公式にサポートされていませんが、ダウンロードすることができ、
インストールすると正常に機能します。データを保護し、問題を回避するため、次のバックアップを作成しておくことをお勧めします。

環境情報

  • Amazon Linux AMI release 2018.03
  • Rails 5.2.1
  • Nginx 1.14.1

導入手順

certbotの導入

certbotをgitからcloneするだけです。作業用ディレクトリの/usr/local/に今回は落としました。

$ cd /usr/local
$ git clone https://github.com/certbot/certbot

このcertbotを使うことでSSLの導入を行うことができます。

$ cd certbot
$ ./certbot-auto --help

helpコマンドが動作していれば導入は成功です。

SSL証明書の発行をする前に、nginxを落としておきましょう。
なんか証明書の発行がうまくいかなかったので。。。

$ sudo nginx -s stop

SSLの証明書の発行

導入しようとしたら、Let's Encryptが正式にサポートされていないため、バックアップをとってから、--debugオプションをつけて実行してくださいとのエラーが出てきました。なので、念の為、AMIでバックアップをとりました。

debugオプションなし時のエラー内容
$ ./certbot-auto certonly --standalone -t

FATAL: Amazon Linux support is very experimental at present...
if you would like to work on improving it, please ensure you have backups
and then run this script again with the --debug flag!
Alternatively, you can install OS dependencies yourself and run this script
again with --no-bootstrap.

改めて、Amazon LinuxでLet's Encryptを入れる方はdebugオプションをつけて実行。

$ ./certbot-auto certonly --standalone -t --debug

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

今度は、pythonのファイルがない?のかエラーになりました。
どうやら、使用するpythonのバージョンが古かったぽいので、2.7を使うように設定。

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

再度、コマンドを実行すると以下のようになります。

./certbot-auto certonly --standalone -t --debug

Creating virtual environment...
Installing Python packages...
Installation succeeded.
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator standalone, Installer None
Enter email address (used for urgent renewal and security notices) (Enter 'c' 

メールアドレスを入力して、

-------------------------------------------------------------------------------
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf. You must agree
in order to register with the ACME server at
https://acme-v01.api.letsencrypt.org/directory
-------------------------------------------------------------------------------
(A)gree/(C)ancel: A
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing to share your email address with the Electronic Frontier
Foundation, a founding partner of the Let's Encrypt project and the non-profit
organization that develops Certbot? We'd like to send you email about our work
encrypting the web, EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

ドメインを聞かれるので、ドメインを入力します。

Please enter in your domain name(s) (comma and/or space separated)  (Enter 'c'
to cancel): test.hoge.jp

すると、以下のような文言が出てきました。これでどうやら証明書の発行は完了らしい。

MPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/test.hoge.jp/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/test.hoge.jp/privkey.pem
   Your cert will expire on 2019-11-18. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot-auto
   again. To non-interactively renew *all* of your certificates, run
   "certbot-auto renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

証明書が/etc/letsencrypt/live/の下に発行されるので、これを読み込むようにNginxであとは設定するだけ。

Nginxの設定

443ポートのリクエストを受け付けるように設定して、証明書のパスを記述。
また、Railsの場合は、proxy_set_header X-FORWARDED_PROTO https;
を忘れずに。詳しい解説は以下が参考になります。

Nginx のリバースプロキシ設定のメモ - Qiita

nginx.conf
server {
    listen 443 ssl default deferred;
    ssl_certificate     /etc/letsencrypt/live/test.hoge.jp/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/test.hoge.jp/privkey.pem;

    # <中略> # 
}
location /  {
   add_header  Access-Control-Allow-Origin *;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       # httpsの設定をしてあげないとRailsの方でSSL判定できずに無限ループに陥る
       proxy_set_header X-FORWARDED_PROTO https;
       proxy_set_header Host $http_host;
       proxy_redirect off;
       if (!-f $request_filename) {
         proxy_pass http://app;
         break;
       }
}

Nginxの設定ができたら、再起動しましょう。

$ sudo service nginx start

Rails側の設定

production環境はデフォルトでSSL設定されていると思いますが、今回はテスト環境だったので、以下を追記。
これにより、httpでアクセスされたものも、Rails側でリダイレクトさせることができます。

config/environments/test.rb
config.force_ssl = true

上述しましたが、この設定をする場合はnginxのconfniproxy_set_header X-FORWARDED_PROTO https;を記述して、
アプリケーション側にhttpsでのアクセスであることを伝えるようにしないと無限ループになりますので、注意です!

参考

チュートリアル: Amazon Linux 2 に SSL/TLS を設定する - Amazon Elastic Compute Cloud

alternatives で python を 2.7に切り替える - Qiita

Let's Encrypt で Nginx にSSLを設定する - Qiita

Nginx のリバースプロキシ設定のメモ - Qiita

railsアプリケーションをhttpsでアクセスできるようにするまでのこと。 - Qiita

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

Rails 6.0.0 のAction Textを使ってみた(Herokuにデプロイするまで)

Rails6がついに来た!

というわけで,主要機能の1つ,Action Textを早速試してみました。

開発環境

  • macOS Mojave 10.14.5
  • Ruby 2.6.3
  • Rails 6.0.0
  • Yern 1.17.3

参考

手順

1. アプリの準備

  • YarnWebpackが必要です。
  • MySQLを指定していますが,お好みで。
コンソール
$ brew install yarn
$ rails new action_text_sample -d mysql --webpack
  • Rails 6image_processingをインストールするためGemfileを編集します。
    • gem 'actiontext'Rails 6に標準実装されているので不要
    • coffee-railsを5.0.0にしないと警告が出るので一応
Gemfile
- gem 'rails'
- gem 'coffee-rails'
+ gem 'rails', '~> 6.0.0'
+ gem 'coffee-rails', '~> 5.0'
+ gem 'image_processing', '~> 1.9.3'
- gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
  • bundle installがエラーになるので,bundle updateを使用
  • Action Textをインストール
  • この記事ではscaffoldでサボりますが,お好みで。
コンソール
$ bundle update
$ rails db:create
$ rails g scaffold Post title:string
$ rails action_text:install
$ rails db:migrate

2. Action Textの導入

  • WebpackでJavaScriptを利用するためにタグを変更します。
    (この作業をとばすとActionTextが反映されません)
app/views/layouts/application.html.erb
- <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
+ <%= javascript_pack_tag 'application' %>
  • 上記作業でDELETEリクエストを送信できなくなる(削除ができなくなる)ので,rails-ujsを追加します。
コンソール
$ yarn add rails-ujs
app/javascript/packs/application.js
+ require("rails-ujs").start()
 require("trix")
 require("@rails/actiontext")
  • リッチテキストエディタ導入のため,ビューなどの編集をします
config/routes.rb
Rails.application.routes.draw do
  root 'posts#index'  # 追加
  resources :posts
end
app/models/posts.rb
class Article < ApplicationRecord
  has_rich_text :content  # 追加
end
app/controllers/posts_controller.rb
class PostsController < ApplicationController
  private
    ()
    def post_params
      params.require(:post).permit(:title, :content)  # :contentを追加
    end
end
app/views/posts/_form.html.erb
  <div class="field">
    <%= form.label :title %>
    <%= form.text_field :title %>
  </div>

  <!-- 以下を追加 -->
  <div class="field">
    <%= form.label :content %>
    <%= form.rich_text_area :content %>
  </div>
  <!-- ここまで -->

  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>
app/views/posts/index.html
      <td><%= link_to 'Destroy', post, method: :delete, data: { confirm: 'Are you sure?' } %></td>
    </tr>
  <!-- 以下を追加 -->
    <tr>
      <td colspan="4"><%= post.content %></td>
    </tr>
  <!-- ここまで -->
    <% end %>
  </tbody>
</table>
app/views/posts/show.html
<p>
  <strong>Title:</strong>
  <%= @post.title %>
  <%= @post.content %>  # 追加
</p>
  • http://localhost:3000/posts/newにアクセスすると……

スクリーンショット 2019-08-18 16.25.50.png

こんな感じの投稿ができます。もちろん投稿一覧にも反映されます!

3. Herokuにデプロイする際の注意点

  • 基本手順は以前の記事などを参照下さい。

  • 画像ファイルは時間経過やデプロイした際に消去されてしまうので,S3などを使用する必要があります。

  • Herokuにデプロイする際,Rails 6.0.0の不具合なのか次のエラーが発生します。

エラー内容
(略)
remote:        rake aborted!
remote:        ArgumentError: Missing `secret_key_base` for 'production' environment, set this string with `rails credentials:edit`
(略)
remote:  !
remote:  !     Precompiling assets failed.
remote:  !
(略)

次のコマンドで,Herokuに環境変数をあらかじめ追加することでデプロイできるようになります。

コンソール
$ heroku config:set SECRET_KEY_BASE=`ruby -rsecurerandom -e "puts SecureRandom.hex(64)"`

ところがもう一つ問題が……

jsやcssが404エラーとなり反映されない不具合が出ています。この問題は伊藤さんの記事に書かれているように,Herokuへの環境変数追加で解消できます。

コンソール
$ heroku config:set RAILS_SERVE_STATIC_FILES=1
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails6 のちょい足しな新機能を試す67(text size 編)

はじめに

Rails 6 に追加されそうな新機能を試す第67段。 今回は、 text size 編です。
Rails 6 では、 ActiveRecord のマイグレーションファイルの text:size オプションを指定できるようになりました。

Ruby 2.6.3, Rails 6.0.0.rc1, MySQL 8.0.16, PostgreSQL 10.7 で確認しました。Rails 6.0.0.rc1 は gem install rails --prerelease でインストールできます。

(Rails 6.0.0 がリリースされましたが、 確認当時は、 Rails 6.0.0.rc1 が最新でした。悪しからず :bow:

$ rails --version
Rails 6.0.0.rc1

なんとなく手抜きで、 モデルを1つ作って確認してみます。

プロジェクトを作る

rails new rails6_0_0rc1
cd rails6_0_0rc1

model を作る

User モデルを作ります。

bin/rails g model User name

マイグレーションファイルを編集する

users テーブルの マイグレーションファイルに text 型のカラムを追加します。

db/migrate/20190726231951_create_users.rb
class CreateUsers < ActiveRecord::Migration[6.0]
  def change
    create_table :users do |t|
      t.string :name
      t.text :profile0
      t.text :profile1, limit: 255
      t.text :profile2, limit: 16777215
      t.text :profile3, limit: 4294967295
      t.text :profile4, size: :tiny
      t.text :profile5, size: :medium
      t.text :profile6, size: :long

      t.timestamps
    end
  end
end

MySQLを使ってマイグレーションを実行する

データベースに MySQLを使い、マイグレーションを実行します。

$ bin/rails db:create db:migrate

schema.rb を確認する

schema.rb では、以下のようになります。

db/schema.rb
  create_table "users", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci", force: :cascade do |t|
    t.string "name"
    t.text "profile0"
    t.text "profile1", size: :tiny
    t.text "profile2", size: :medium
    t.text "profile3", size: :long
    t.text "profile4", size: :tiny
    t.text "profile5", size: :medium
    t.text "profile6", size: :long
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
  end

mysql で確認する

mysql で確認すると以下のようになっていました。

mysql> show create table users\G
*************************** 1. row ***************************
       Table: users
Create Table: CREATE TABLE `users` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `profile0` text,
  `profile1` tinytext,
  `profile2` mediumtext,
  `profile3` longtext,
  `profile4` tinytext,
  `profile5` mediumtext,
  `profile6` longtext,
  `created_at` datetime(6) NOT NULL,
  `updated_at` datetime(6) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |

PostgreSQL では

limit: 4294967295 を指定するとエラーになります。

ArgumentError: No text type has byte size 4294967295. The limit on text can be at most 1GB - 1byte.

ということで、以下のように修正して

db/migrate/20190726231951_create_users.rb
class CreateUsers < ActiveRecord::Migration[6.0]
  def change
    create_table :users do |t|
      t.string :name
      t.text :profile0
      t.text :profile1, limit: 255
      t.text :profile2, limit: 16777215
      t.text :profile3 # , limit: 4294967295
      t.text :profile4, size: :tiny
      t.text :profile5, size: :medium
      t.text :profile6, size: :long

      t.timestamps
    end
  end
end

試してみると schema.rb は以下のようになります。

db/schema.rb
  ...
  create_table "users", force: :cascade do |t|
    t.string "name"
    t.text "profile0"
    t.text "profile1"
    t.text "profile2"
    t.text "profile3"
    t.text "profile4"
    t.text "profile5"
    t.text "profile6"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
  end
  ...

試したソース

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

参考情報

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

初めてRails のサイトを Heroku でホスティングするときに躓いた,Precompiling assets failed. とrails credentials:edit

何があったか

RailsでHelloWorldを表示するサイトを作って,Herokuでホスティングしたい

git push heroku master

をすると,

$ Precompiling assets failed.

が出てくる.

結論

エラーの本体

ArgumentError: Missing `secret_key_base` for 'production'environment, set this string with `rails credentials:edit`

Precompiling assets failed. はエラーの本体ではない?

参考:Herokuにpushしたらprecompile assets faild.が。pushできたと思ったらApplication Errorが。解決するまで。- Qiita

対処法

以下のコマンドを打つ

$ heroku config:set RAILS_MASTER_KEY=<your-master-key>

your-master-keyはconfig\master.keyに書かれている文字列

$ heroku config:set RAILS_MASTER_KEY=123456789

参考:Rails 5.2 with master.key - Heroku deployment - stackoverflow

何故このエラーが生じるのか

復号鍵を渡さないといけない?

詳細は以下に詳しく書かれてます.

参考:Rails 5.2 で ActiveSupport::MessageEncryptor::InvalidMessage - Qiita

最後に

最初,Precompiling assets failed.で調べてたので,かなり時間をとってしまった.

ログはちゃんと見るべき

その他参考にしたところ

https://railstutorial.jp/chapters/beginning?version=5.1#sec-exercises_hello_world

https://qiita.com/fuku_tech/items/b21e49ff49cb19f04838

https://qiita.com/kazukimatsumoto/items/a0daa7281a3948701c39

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

初めてRails のサイトを Heroku でホスティングするときに躓いたPrecompiling assets failed. とrails credentials:edit

何があったか

RailsでHelloWorldを表示するサイトを作って,Herokuでホスティングしたい

git push heroku master

をすると,

$ Precompiling assets failed.

が出てくる.

結論

エラーの本体

ArgumentError: Missing `secret_key_base` for 'production'environment, set this string with `rails credentials:edit`

Precompiling assets failed. はエラーの本体ではない?

参考:Herokuにpushしたらprecompile assets faild.が。pushできたと思ったらApplication Errorが。解決するまで。- Qiita

対処法

以下のコマンドを打つ

$ heroku config:set RAILS_MASTER_KEY=<your-master-key>

your-master-keyはconfig\master.keyに書かれている文字列

$ heroku config:set RAILS_MASTER_KEY=123456789

参考:Rails 5.2 with master.key - Heroku deployment - stackoverflow

何故このエラーが生じるのか

復号鍵を渡さないといけない?

詳細は以下に詳しく書かれてます.

参考:Rails 5.2 で ActiveSupport::MessageEncryptor::InvalidMessage - Qiita

最後に

最初,Precompiling assets failed.で調べてたので,かなり時間をとってしまった.

ログはちゃんと見るべき

その他参考にしたところ

https://railstutorial.jp/chapters/beginning?version=5.1#sec-exercises_hello_world

https://qiita.com/fuku_tech/items/b21e49ff49cb19f04838

https://qiita.com/kazukimatsumoto/items/a0daa7281a3948701c39

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