20200529のRailsに関する記事は30件です。

ActiveModel::Serializers::JSONのfrom_jsonの使い方を3分で理解。

Railsの標準機能で、JSONをrubyオブジェクトへとシリアライズする。
Rails製APIでよく使われるのに情報が少ないのでメモ

from_jsonとは?

from_json(json, include_root = include_root_in_json)
modelのattributesは、JSON文字列からセットする。
selfを返す。

使用例

class Person
  include ActiveModel::Serializers::JSON
  attr_accessor :name, :age, :awesome

  def attributes=(hash)
    hash.each do |key, value|
      send("#{key}=", value)
    end
  end

  def attributes
    instance_values
  end
end

json = { name: 'bob', age: 22, awesome: true }.to_json
person = Person.new
person.from_json(json)
person.name // bob
person.age // 22

もし与えられたJSON文字列が、root nodeを持っていた場合。
第二引数にtrueを渡すことで、root nodeを排除してシリアライズ可能

json = { person: { name: 'bob', age: 22, awesome: true } }
person = Person.new
person.from_json(json, true)
person.name // bob
person.age // 22

参考
https://api.rubyonrails.org/classes/ActiveModel/Serializers/JSON.html

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

【Rails6+Bootstrap4】コピペだけ!Bootstrap4をRails6で使うための手順完全版

環境

ruby 2.6.4

Rails 6.0.2.2

rbenv 1.1.2

bootstrap 4.3.1

mysql2 0.5.3

やりたいこと

コピペだけでBootstrap4をRails6で使える手順を共有します

手順通りに進めれば魔法のように導入できちゃいますよ

完全手順

1. bootstrap 4.3.1を追加

$ yarn add bootstrap@4.3.1 jquery popper.js

2. application.jsに下記コード追加

app/javascript/packs/application.js
import "bootstrap"

3. webpack/environment.jsを修正

config/webpack/environment.js
const { environment } = require('@rails/webpacker')
const webpack = require("webpack")
environment.plugins.append("Provide", new webpack.ProvidePlugin({
    $: 'jquery',
    jQuery: 'jquery',
    Popper: ['popper.js', 'default']
}))

module.exports = environment

4. application.cssを修正

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

5. custom.css.scssを作成&下記コード追加

app/assets/stylesheets/custom.css.scss
@import 'bootstrap/dist/css/bootstrap';

あとはあなた好みのカスタマイズをするだけです!

参考文献

【Rails6/Bootstrap4】Bootstrap4をRails6で使うための手順完全版
https://www.twinzlabo.com/rails6_bootstrap4_install/

【Vue/BootstrapVueコピペだけ】シンプルなチャットアプリ(掲示板) の作成方法を徹底解説
https://www.twinzlabo.com/vue-chatapp-create/

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

【Rails6+Bootstrap4】コピペだけでBootstrap4をRails6で使うための手順完全版

環境

ruby 2.6.4

Rails 6.0.2.2

rbenv 1.1.2

bootstrap 4.3.1

mysql2 0.5.3

やりたいこと

コピペだけでBootstrap4をRails6で使える手順を共有します

手順通りに進めれば魔法のように導入できちゃいますよ

完全手順

1. bootstrap 4.3.1を追加

$ yarn add bootstrap@4.3.1 jquery popper.js

2. application.jsに下記コード追加

app/javascript/packs/application.js
import "bootstrap"

3. webpack/environment.jsを修正

config/webpack/environment.js
const { environment } = require('@rails/webpacker')
const webpack = require("webpack")
environment.plugins.append("Provide", new webpack.ProvidePlugin({
    $: 'jquery',
    jQuery: 'jquery',
    Popper: ['popper.js', 'default']
}))

module.exports = environment

4. application.cssを修正

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

5. custom.css.scssを作成&下記コード追加

app/assets/stylesheets/custom.css.scss
@import 'bootstrap/dist/css/bootstrap';

あとはあなた好みのカスタマイズをするだけです!

参考文献

【Rails6/Bootstrap4】Bootstrap4をRails6で使うための手順完全版
https://www.twinzlabo.com/rails6_bootstrap4_install/

【Vue/BootstrapVueコピペだけ】シンプルなチャットアプリ(掲示板) の作成方法を徹底解説
https://www.twinzlabo.com/vue-chatapp-create/

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

EC2関連で使用するターミナルコマンド(順次追加予定)

ターミナル
chmod 600 ダウンロードした鍵の名前.pem

chmodは権限の変更。
chmod 600で所有者のみに読み込み権限と書き込み権限を付与してそれ以外は全て不許可

ターミナル
mkdir ~/ファイル名

ホームディレクトリに新規ディレクトリを作成するコマンド。

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

マイグレーション入門

マイグレーション入門

マイグレーションとは

text
マイグレーションは、データベーススキーマの継続的な変更を、簡単に行なうための便利な手法です。マイグレーションではRubyのDSLを使っているので、生のSQLを作成する必要がなく、スキーマへの変更をデータベースの種類に依存せずに済みます。

なるほど本来であればテーブルを追加したときや、テーブルに対して属性を追加した時などは
SQLを作成する必要がありますよね。

CREATE TABLE HOGE

こんな感じで生のSQLを書いてデータベースへの変更をするがそれをする必要がなくなります。
またデータベースの種類に依存しません。
なんとなく使ってたけどすごいよねー。

マイグレーションの例

productsというテーブルを追加する例です。

nameというstringカラムと、descriptionというtextカラムが含まれています。主キーはidという名前で暗黙に追加されます。idはActive Recordモデルにおけるデフォルトの主キーです。

ruby.rb
class CreateProducts < ActiveRecord::Migration[5.0]
  def change
    create_table :products do |t|
      t.string :name
      t.text :description

      t.timestamps
    end
  end
end

このマイグレーションを実行することでテーブルが生成されます。
またロールバックをすることでこのテーブルを削除することもできます。

マイグレーションを作成

rails generate migration AddPartNumberToProducts part_number:string

上記のコードを実行すると以下のようなマイグレーションファイルが生成されます。
productsに対してカラムを追加するという内容になっています。

ruby.rb
class AddPartNumberToProducts < ActiveRecord::Migration[5.0]
  def change
    add_column :products, :part_number, :string
  end
end

DBに反映される

これまでのマイグレーションファイルをDBに反映させます。

#実行
rails db:migrate
#ロールバック
rails db:rollback

以上のようにしてマイグレーションを実行、またはロールバックができるというわけですね。

ざっくりとですがマイグレーションについてまとめてみました。
今までなんとなく使っていた私ですが、
どういったものなのか少しずつ理解できるようになってきました。

本日は以上です
1人前のエンジニアになるまであと92日

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

【Rails】TwitterのOGPを設定する

Gemなしです。

TwitterのOGPを表示させるために必要なmetaタグについては以下の記事を参考にしました。
【2020年版】Twitterカードとは?使い方と設定方法まとめ

実装

app/helper/application_helper.rb
def full_title(page_title = '')
  base_title = 'MC BATTLE CHANNEL'
  if page_title.empty?
    base_title
  else
    "#{page_title} | #{base_title}"
  end
end

def full_url(path)
  domain = if Rails.env.development?
             'http://0.0.0.0:3000'
           else
             'https://mcbattle-ch.jp'
           end
  "#{domain}#{path}"
end
app/views/layouts/application.html.erb
<head>
  <!-- ogp -->
  <meta name="twitter:card" content="summary_large_image" />
  <meta name="twitter:site" content="@McBattleChannel" />
  <meta property="og:title" content="<%= full_title(yield(:title)) %>" />
  <meta property="og:url" content="<%= request.url %>" />
  <meta property="og:description"
    content="<%= content_for?(:description) ? yield(:description) : 'MCバトルの総合サイトです。' %>" />
  <meta property="og:image"
    content="<%= content_for?(:image_url) ? yield(:image_url) : full_url('/assets/other/ogp_default.png') %>" />
app/views/hoge/fuga.html.erb
<%= content_for(:title, "この個別ページのタイトル!") %>
<%= content_for(:description, "この個別ページの説明文!") %>
<%= content_for(:image_url, full_url("assets/mc/hoge.img")) %>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RailsのViewでの微妙に異なる繰り返しの書き方をいくつか

概要

以下みたいなコードを見ると思う。4件だからいいが10件とかあったり、ネストが深いと悲しくなってくる。
どうにか簡単に、繰り返しを少なく書きたい。ついいろいろ試してしまう。

<ul>
  <li>
    <div>ユーザ名</div>
    <div><%= user.name %></div>
  </li>
  <li>
    <div>メールアドレス</div>
    <div><%= user.email %></div>
  </li>
  <li>
    <div>性別</div>
    <div><%= user.sex == 1 ? '男性' : '女性' %></div>
  </li>
  <li>
    <div>役割</div>
    <div><%= user.role %></div>
  </li>
</ul>

1. 単純な繰り返しの場合

DraperActive Recordモデルの翻訳を使うと以下のようにかける。
単純な繰り返しで良ければこれで大丈夫

<!-- sex_textメソッドをUserDecoratorに追加すること。 -->
<ul>
  <% %i[name email sex_text role].each do |key| %>
    <li>
      <div><%= User.human_attribute_name(key) %></div>
      <div><%= user.send(key) %></div>
    </li>
  <% end %>
</ul>

2. 部分的な繰り返しの場合

途中にモデル外のものが混ざってしまう場合、単純なループではだめになる。3回以上同じ記述が現れてしまうが、以下のようにすれば少しは減らせる

<ul>
  <% %i[name email].each do |key| %>
    <li>
      <div><%= User.human_attribute_name(key) %></div>
      <div><%= user.send(key) %></div>
    </li>
  <% end %>
  <!-- 途中に今日の天気を入れる指示が来た -->
  <li>
    <div>今日の天気</div>
    <div><%= Wheather.today %></div>
  </li>
  <% %i[sex_text role].each do |key| %>
    <li>
      <div><%= User.human_attribute_name(key) %></div>
      <div><%= user.send(key) %></div>
    </li>
  <% end %>
</ul>

3. Helperを使う

htmlの記述を3回繰り返すのは嫌なので、せめてメソッドにする。

class UsersHelper
  def user_param_li(label, value)
    tag.li do
      tag.div(label) +
      tag.div(value)
    end
  end
end
<ul>
  <% %i[name email].each do |key| %>
    <%= user_param_li(User.human_attribute_name(key), user.send(key)) %>
  <% end %>
  <!-- 途中に今日の天気を入れる -->
  <%= user_param_li('今日の天気', Wheather.today) %>
  <% %i[sex_text role].each do |key| %>
    <%= user_param_li(User.human_attribute_name(key), user.send(key)) %>
  <% end %>
</ul>

4. クラスを用意してしまう

やっぱり読みづらいし、繰り返し構造が見えないので悲しい。オブジェクトを用意してしまう。

# このオブジェクトは、「サービスオブジェクト」「Presenter」「view_object」「PORO」など様々な呼ばれ方をされます。
# この役割なら、僕はプレゼンターという名前をつけると思います。
class UserParamsPresenter
  attr_reader :user
  def initialize(user)
    @user = user
  end

  def params
    [
      user_param(:name),
      user_param(:email),
      wheather_param,
      user_param(:sex_text),
      user_param(:role),
    ]
  end

  private 

  def wheather_param
    ['今日の天気', Wheather.today]
  end

  def user_param(key)
    [User.human_attribute_name(key), user.send(key)]
  end
end
<ul>
  <!-- このPresenterはcontrollerからも渡せます。僕はどっちがいいのかわかりません -->
  <% UserParamsPresenter.new(user).params.each do |label, value| %>
    <%= user_param_li(label, value) %>
  <% end %>
</ul>

5. やりすぎたので反省してViewだけで見てもわかりやすく書く

このケースではこんなに複雑にする必要はなかったかもしれない。デザイナーが困る。
ちょっとならrubyのコードをerbに書いちゃってもいいよね?Presenterは消せる。

<%
  user_params = [
    [User.human_attribute_name(:name), user.name)],
    [User.human_attribute_name(:email), user.email)],
    ['今日の天気', Wheather.today],
    [User.human_attribute_name(:sex_text), user.sex_text)],
    [User.human_attribute_name(:role), user.role)],
  ]
%>
<ul>
  <% user_params.each do |label, value| %>
    <%= user_param_li(label, value) %>
  <% end %>
</ul>

6. ここだけであればそもそももっと簡単にかけそうだ

HelperやらDraper,I18nなんてついやってしまったが、別にそれもなくてもそこそこきれいに書けるのでは?
急ぎのプロジェクトだしなあ。

<%
  user_params = [
    ['ユーザ名', user.name],
    ['メールアドレス', user.email],
    ['今日の天気', Wheather.today],
    ['性別', user.sex == 1 ? '男性' : '女性'],
    ['役割', user.role],
  ]
%>
<ul>
  <% user_params.each do |label, value| %>
    <li>
      <div><%= label %></div>
      <div><%= value %></div>
    </li>
  <% end %>
</ul>

まとめ

という感じで、いくつも書き方は思い浮かんでしまい、逡巡することになります。
この内、どれがいいかは場況を見るしかありません。
自分ではあまり書いたことのない書き方があれば、まずはぜひ手を動かして書いてみてください。
とりあえず書いてみて、数週間後の仕様変更や、同僚からのコメントで書き方が適切だったかどうかが試されます。

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

【Rails】whenever による定時バッチ処理

【Rails】whenever による定時バッチ処理

Wheneverを使ってRailsでのバッチ処理を実装したのでまとめます。

目次


動作環境

OS : macOS Mojave 10.14.6
ruby : 2.6.3p62
rails : 5.2.4

やりたいこと

決まった時間に定期的に実行するタスクを作成したい

手順

wheneverのインストール

Gemfile
gem 'whenever', require: false

インストールの実行

Bundle install

railsにlibを加える

Railsがlibフォルダを読み込めるように設定します
libフォルダにバッチ処理をするファイルを置くためです.

class Application < Rails::Application
  config.autoload_paths += Dir["#{config.root}/lib"]
end

バッチ処理の記載

libにbatchというフォルダを作成し、その中に定期実行するファイルを作成します。
Batch::以降は任意の名前で良いです。


batch/deadline_cleaner.rb

deadline_cleaner
class Batch::DeadlineClear
  def self.deadline_clear
    puts DateTime.now
    puts 'Test'
  end
end

確認

$ bundle exec rails runner Batch::DeadlineClear.deadline_clear

Running via Spring preloader in process 77676
test

schedule.rbの作成・編集

アプリケーションのルートフォルダに移動し、以下のコマンドを実行

$ cd blog-app
$ bundle exec wheneverize .

実行すると config/schedule.rbが作成されます。

その後、以下のようにschedule.rbにスケジュールと実行したいタスクを記載します。

set :output, 'log/crontab.log'
set :environment, :development

every 1.day, at: '00:00 am' do
  runner 'Batch::DeadlineClear.deadline_clear'
end

以下のコマンドでCRONへ反映します.

$ bundle exec whenever --update-crontab 

実行結果

実際に1分ごとにバッチ処理がされていることがわかります.

$ cat log/crontab.log 
Running via Spring preloader in process 78244
2020-05-29T19:50:01+09:00
test
Running via Spring preloader in process 78534
2020-05-29T19:51:01+09:00
test
Running via Spring preloader in process 78598
2020-05-29T19:52:00+09:00
test
Running via Spring preloader in process 78652
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

画像アップロードにS3を使用メモ

herokuでデプロイした際にS3を画像アップローダー先として指定する場合メモ

Rails5.2.3
carrierwave (2.1.0)

carrierwaveで画像をアップロードできる様になっている
またS3という前提で進めます。

外部のストレージを選択しアップロードするのを補助してくれる
fog-awsというgemを追加してbundle installする。

Gemfile
gem 'fog-aws'

アップロードにfogを使用するための設定を行う。
storage :fileをコメントアウトし
storage :fogのコメントアウトを外す。

app/uploaders/image_uploader.rb
# storage :file
  storage :fog

fogのアップロード先の設定をする
/config/initializers直下に、carrierwave.rbというファイルを作成し、
下記のコードをそのままコピペする。

/config/initializers/carrierwave.rb
require 'carrierwave/storage/abstract'
require 'carrierwave/storage/file'
require 'carrierwave/storage/fog'

CarrierWave.configure do |config|
  config.storage = :fog
  config.fog_provider = 'fog/aws'
  config.fog_credentials = {
    provider: 'AWS',
    aws_access_key_id: Rails.application.credentials.aws[:access_key_id],
    aws_secret_access_key: Rails.application.credentials.aws[:secret_access_key],
    region: 'ap-northeast-1' #アジアパシフィック(東京)を表している
  }

  config.fog_directory  = 'ここにバケット名を入れる'
  config.asset_host = 'https://s3-ap-northeast-1.amazonaws.com/ここにバケット名を入れる'
end

credentials.yml.encの内容は暗号化されてるため、エディタなどで直接ファイルを開いて編集することはできません。

そこでviを利用して環境変数:EDITORにviを指定してrails credentials:editコマンドを実行します。

ターミナル
$ EDITOR="vi" bin/rails credentials:edit

上記のコマンドで出てきたcredentials.yml.encの内容に対して、
上3行のコメントアウトを外しインデントを整え、
access_key_idと、
secret_access_keyをそれぞれ入力します。
そしてescでインザートモードを終えて:wqで保存します。

credentials.yml.enc
aws:
  access_key_id: 123
  secret_access_key: 345

# Used as the base secret for all MessageVerifiers in Rails, including the one protecting cookies.
secret_key_base: 8be8e637d755f79c799048bed8be0c...

本番環境ではmaster keyの指定漏れを防ぐためにconfig/environments/production.rbでconfig.require_master_key = trueを有効化することが推奨されてるようですのでコメントアウトを外す。

config/environments/production.rb
config.require_master_key = true

credentials.yml.enc を使っている場合は、以下のコマンドで master.key を heroku の環境変数としてセット

ターミナル
$ heroku config:set RAILS_MASTER_KEY=`cat config/master.key`

タイムゾーンを変更するため、
config/application.rb に以下を追記

application.rb
config.time_zone = "Tokyo"
config.active_record.default_timezone = :local

以上で設定は完了し、あとはherokuでの作業となります。

ターミナル
$ heroku login
$ git push heroku master
$ heroku open
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

インターネットの仕組みを復習

ルーターとインターネットプロトコル

通信とは相手に、共通認識を与えること
多くの相手と通信ができるようにした仕組みがインターネット

ネットワークでは、物理的な接続と、論理的な道(データリンク)が必要。
データリンクの中の交通ルールがプロトコル

ネットワーク同士を繋げたのが、インターネット

しかし、このままではデータリンクが異なる
それを合わせるために機器などを全て統一するのは不可能、、、

そこで、データリンクは異なったまま、その通信を専用通信機器を通すようにしました

それがルーター

そして、今までのデータリンクも残しながら
インターネットプロトコル(IP)という全く新しいルールを追加

ルーターはIP以下(IP、データリンク)を層をみる機械

IPアドレスを割り振れば、データリンクによらずに共通で使える

データリンクではMACアドレス
IPではIPアドレスを使う
※1つのMACアドレスに対して1つ付与される

IPアドレスは管理が繁雑にならないよう、同じ管理者のネットワークごと(LAN)で
連続した末尾になっている

図解付きの解説はこちら
https://www.youtube.com/watch?v=BGfhIR4599I

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

[rails]AWS 課金にならないように各機能を削除する方法

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

rails dbして�WebサーバーからMySQLのCLIに繋ぐときのメモ

この記事について

自分用メモです。

メモ

# RAILS_ENVには環境名を入れる
# dbはdbconsoleでも可。
RAILS_ENV=production bundle exec rails db
> passwordを入力

# デフォルトの出力だと見にくいのでlessで結果を見る
mysql> pager less -n -i -S

# 見たいdatabaseに切り替える
mysql> use `hoge-database`;

# 見たい結果を得るためのクエリ
mysql> select * from hoge_table;
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

rails dbして�Webサーバー等からMySQLのCLIに繋ぐ

この記事について

自分用メモです。

メモ

# RAILS_ENVには環境名を入れる
# dbはdbconsoleでも可。
RAILS_ENV=production bundle exec rails db
> passwordを入力

# デフォルトの出力だと見にくいのでlessで結果を見る
mysql> pager less -n -i -S

# 見たいdatabaseに切り替える
mysql> use `hoge-database`;

# 見たい結果を得るためのクエリ
mysql> select * from hoge_table;
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

rails dbしてWebサーバー等からMySQLのCLIに繋ぐ

この記事について

自分用メモです。

メモ

# RAILS_ENVには環境名を入れる
# dbはdbconsoleでも可。
RAILS_ENV=production bundle exec rails db
> passwordを入力

# デフォルトの出力だと見にくいのでlessで結果を見る
mysql> pager less -n -i -S

# 見たいdatabaseに切り替える
mysql> use `hoge-database`;

# 見たい結果を得るためのクエリ
mysql> select * from hoge_table;
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RSpecでsession not created: This version of ChromeDriver only supports Chrome version 81

どのようなエラーか

systemspecで使用しているブラウザであるchromeと、クロームでテストする際に必要なchromedriverのバージョンが合ってない。

現在使用しているchromedriverはバージョン81のchromeしかサポートしていないと言われている。

chromedriverのバージョンをchromeに合わせるか、chromeのバージョンをdriverに合わせるかをすればいい。

解決法

chromedriverをchromeに合わせる

chromeのバージョンを調べたら83になってた。

なのでdriverも83に合わせる。

chromedriverのインストール

https://chromedriver.storage.googleapis.com/index.html?path=83.0.4103.39/

mac windows linuxいずれかによって適切な物をダウンロードする。

chromedriverを置き換える

chromedriverは自分の環境の場合、webdriversの中にある

$ ~/.webdrivers/chromedriver -v

=> 81.0.4044.138

このchromedriverを消して、先ほどダウンロードしたchromedriverをこの中に置いたらエラーが出なくなった。

もしもっと適切なやり方がある場合、コメントしていただけたら嬉しいです。

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

【NoMethodError】newアクションで発生した際の解決法

概要

登録画面に遷移したいのに、エラーになって全然表示できない:sob:
状況に陥り、何時間も悪戦苦闘した結果、解決しましたので備忘録として残します。

事象

下記のようなエラーが発生:zap:
スクリーンショット 2020-05-29 11.45.21.png

routes.rb
Rails.application.routes.draw do
  devise_for :users
  root "groups#index"

  resources :users, only: [:edit, :update]

  resources :groups, only: [:index, :new, :create, :edit, :update] do
    resources :tasks, only: [:index, :new, :create, :edit, :update, :destroy]
  end
end
controller.html.haml
  def new
    @task = Task.new
  end
main_view.html.haml
#省略
.new_display
  = form_for @task do |f|
#省略

エラーを見た感想

おかしなとこない:disappointed_relieved:
何言ってんねん:persevere:
newアクションだからデータないやんかーーー
と一人で悶々としてました。。。

原因

原因は【form_forが自動的に生成してくれるパスは複数形のみ】ということ!!
エラー文にも記載ありました!

undefind method 'tasks_path' for ~

私は、その箇所を読んでも何言ってんの??そんなパスないよ:triumph:
と思ってましたが:sweat:

解決策

viewを下記のように変更しました!

main_view.html.haml
#省略
.new_display
  = form_for @task, url: group_tasks_path do |f|
#省略

画面

スクリーンショット 2020-05-29 13.40.42.png

似たようなことでお悩みの方の足掛かりになれば幸いです:relaxed:

参考

https://qiita.com/annaaida/items/ae38de82526bf5b4aa73

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

Rails + MySQLで作ったアプリをherokuにデプロイする

※rails初心者向けの記事です。

herokuのデータベース

herokuはデフォルトのデータベース(以下DB)はPostgreSQLです。
なのでMySQLで作ったアプリをherokuにデプロイするときは次の2つがあります。

① DBをPostgreSQLに変更してherokuにデプロイ
こちらのサイトに大変お世話になりました。本記事では取り扱いません。
【初心者向け】railsアプリをherokuを使って確実にデプロイする方法【決定版】

② DBをMySQLのままherokuにデプロイ
本記事ではこちらの方法についての備忘録です。

この記事でやること

  • ClearDBアドオンを追加
  • Gemとデータベースをチェック
  • MySQLからMySQL2に変更

ClearDBアドオンを追加

ClearDB はクラウド上で提供されている MySQL データベースです。
クレジットカード必須。
データ容量5MBの最小構成であれば無料で使えます。(2020年5月現在)
詳しくは公式で。

参考 : HerokuでMySqlの設定をする

ターミナル
$ heroku addons:add cleardb

Gemとデータベースをチェック

まずはGemの確認

Gemfile
# Use mysql as the database for Active Record
  gem 'mysql2', '0.5.3'

mysql2を使っていることがわかりました。
そして以下を実行。

ターミナル
$ heroku config | grep CLEARDB_DATABASE_URL

CLEARDB_DATABASE_URL:  mysql://ユーザー名:パスワード@ホスト/データベース名?reconnect=true

このコマンドにより、自分のmysqlの情報を知ることができました。

ちなみにこのデータをSequelProに紐付けることでデータベースをGUI操作できます。
201862herokuでMySQL環境作ってやんよ!!!

MySQLからMySQL2に変更

Gemと合わせるためにmysqlからmysql2に変えましょう。

ターミナル
$ heroku config:set  DATABASE_URL='mysql2://ユーザー名:パスワード@ホスト/データベース名?reconnect=true'

詰まった方はこちらを参考に
HerokuでMySQLを使おうとして詰まったところ

参考

お世話になりました。
HerokuでMySqlの設定をする
HerokuでMySQLを使おうとして詰まったところ

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

[Rails6]webpacker-dev-serverがheap out of memory(OOM)エラーで落ちる時の対処方法

RailsでWebpackerを用いフロント開発していたところ、
webpacker-dev-serverがやたらとメモリを食い「heap out of memory」エラーが頻出していました。

Docker環境だからか、VM上でDockerを立てていたからか、仕様かわかりませんが、
最大メモリサイズを指定することでエラーがほぼ出なくなったので、同様の現象が起きている方は参考にしてみてください。

rails 6.0.3.1
ruby 2.6.6
webpacker 5.1.1

フロント:React(bin/webpack-dev-server利用)
サーバー:Rails

結論

bin/webpack-dev-serverに最大のメモリサイズを渡すと、最大メモリに近づいた時にメモリ解放を行ってくれました。

NODE_OPTIONSの環境変数に--max-old-space-size=3072を加えると最大メモリサイズを設定することができます。

bin/webpack-dev-server
#...
ENV["NODE_OPTIONS"]  ||= "--max-old-space-size=3072"
#...

参考: Rails5.1のbin/webpacker-dev-serverでJavaScript heap out of memoryが起きた時の対処方

解説

開発はDockerを用いています。
Rails ServerとWebpackerを分けて、composeで管理をしています。

docker-compose.yml
version: '3'
services:
  db:
    image: postgres:11.6-alpine
    volumes:
      - db:/var/lib/postgresql/data:cached
    networks:
      - web
    environment:
      TZ: Asia/Tokyo
  webpacker:
    build: .
    command: ./bin/webpack-dev-server
    volumes:
      - .:/app:cached
      - bundle:/usr/local/bundle:cached
      - yarn:/node_modules:cached
    ports:
      - '3035:3035'
    networks:
      - web
    environment:
      NODE_ENV: development
      RAILS_ENV: development
      WEBPACKER_DEV_SERVER_HOST: 0.0.0.0
  web:
    build: .
    command: sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/app:cached
      - bundle:/usr/local/bundle:cached
      - yarn:/node_modules:cached
    ports:
      - '3000:3000'
    depends_on:
      - db
      - webpacker
    networks:
      - web
    tty: true
    stdin_open: true
    environment:
      WEBPACKER_DEV_SERVER_HOST: webpacker
volumes:
  db:
  bundle:
  yarn:
networks:
  web:

webpack-dev-serverを立てている状態でフロント部分を開発していると、JSを更新すると自動コンパイルされます。
コンパイル内容をメモリに格納していくようで、開発を進めていると更新の度にどんどんメモリが圧迫されます。

LIMITを超えたタイミングで「heap out of memory」エラーが発生しDockerを再起動する必要があります。(メモリを開放する)

Dockerのメモリ使用量はdocker statsで確認することができます。

docker stats
=>
CONTAINER ID        NAME                CPU %               MEM USAGE / LIMIT     MEM %               NET I/O             BLOCK I/O           PIDS
f697683f3b6e        app_web_1           0.01%               116.4MiB / 3.859GiB   2.95%               84.5kB / 39.1kB     0B / 0B             19
c66e3f0371b1        app_db_1            0.00%               2.633MiB / 3.859GiB   0.07%               11.1kB / 60kB       0B / 0B             7
8bcd63949c32        app_webpacker_1     0.00%               859.9MiB / 3.859GiB   21.76%              92.6kB / 63kB       0B / 0B             11

MEM USAGELIMITPIDSを超えるとOOMエラーとなります。

MEM USAGE / LIMITPIDS
859.9MiB / 3.859GiB 

WebpackerのDockerでは./bin/webpack-dev-serverコマンドを実行してます。

./bin/webpack-dev-serverでは最終的にnode_modules/.bin/web-packer-devを実行しているようです。

参考: Webpacker使うなら最低限これだけは知っておいてほしいこと

./bin/webpack-dev-server上ではnodeに環境変数を渡すことができます。
NODE_OPTIONSに--max-old-space-size=3072を渡すと最大メモリサイズを指定してweb-packer-devを実行するようになります。

ご自身の環境に合わせて、任意のメモリサイズを指定してください。

bin/webpack-dev-server
#!/usr/bin/env ruby

ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
ENV["NODE_ENV"]  ||= "development"
ENV["NODE_OPTIONS"]  ||= "--max-old-space-size=3072"

require "pathname"
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
  Pathname.new(__FILE__).realpath)

require "bundler/setup"

require "webpacker"
require "webpacker/dev_server_runner"

APP_ROOT = File.expand_path("..", __dir__)
Dir.chdir(APP_ROOT) do
  Webpacker::DevServerRunner.run(ARGV)
end

これでwebpack-dev-serverが最大メモリサイズに達したらメモリ解放されるようになりました。

メモリサイズが小さいため、頻繁にコンパイルするとメモリ解放が間に合わずOOMが出る時もありますが、かなり頻度が下がりました。

ご自身のスペックにあったメモリサイズを指定し、快適な開発に用いてください!

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

【Rails】deviseのバリデーションをカスタマイズ

最初に

deviseを使用して、ユーザーの新規登録機能を実装している際に、
バリデーションを付与しているのにバリデーションが適用されず、実装に苦戦したため備忘録として残します。

deviseのデフォルトのバリデーション

deviseは認証機能を簡単に実装できる様にするためのgemですが、勝手にgemが動いてくれるがゆえに見えないところで何をしているかが、初学者の私には理解が難しかったです。これがバリデーションを付与しているのに適応されない原因でした。

new.html.haml
= form_for(@user, url: user_registration_path) do |f|  
  = f.password_field :password, class: "main__box__bottom__content__group2__form", placeholder: "7文字以上の半角英数字", 

結論はフォームでpassword_fieldを使用していたため、Railsはこの入力フォームをpasswordと認識して、簡単なバリデーションを自動でかけるようになっているようです。

deviseのカスタマイズ手順

1.フォームを修正(適切なフォームに)

password_fileldからtext_fieldに修正。

new.html.haml
= form_for(@user, url: user_user_registration_path) do |f|  
  = f.text_field :password
end

これでpasswordカラムと認識。

2.deviseのバリデーションの設定

ただモデルのpasswordカラムを追加に対してバリデーションをかけると2重でバリデーションがかかってしまうので、
deviseのバリデーションを追加している:validatableを削除する。

user.rb
class User < ApplicationRecord
 devise :database_authenticatable, :registerable,
  :recoverable, :rememberable, :validatable 
                                  #↑削除する。
end

これでdeviseのバリデーションは掛からなくなり、passwordに自分でカスタマイズしたバリデーションが付与されるようになりました。

まとめ

・バリデーションには参照する優先順位があり、
テキストフィールドに与えられているバリデーション>devise>自作のバリデーション
となっている。
・カスタムバリデーションのみ適用させる場合は、text_fieldを使い、deviseの:validatableを削除する。

参考文献

https://qiita.com/kouheiszk/items/215afa01eeaadbd99340

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

【Rails】超簡単TODOアプリを開発【CRUD & ユーザーログイン & Bootstrap】

はじめに

Railsで簡単なTODOアプリを作りました。大まかな内容は下の通りです。

  • CRUD機能が付いている(validationはやってません)
  • ユーザーがログインできて、ログアウトできる
  • ユーザーに画像アップロード機能がついている
  • ユーザーの詳細ページがついている
  • Bootstrapで多少デザインは整えている

完成形はこんな感じです。
スクリーンショット 2020-05-29 12.04.16.png

投稿意図

「Railsで何か作りたいな」となったとき、簡単に作成できるサービスなりアプリがあれば役に立つかなという考えに至ったからです。僕自身Rails学習当初そういった気持ちになったことがあります。

❶:CRUD機能

タスクをMySQLに格納(Create)し、読み出し(Read)、更新し(Update)、削除する(Delete)ところまでを実装しました。

データを格納する際のバリデーションはやっていないので、ググって自分好みに実装してもらえればなと思います。

❷:Bootstrapでデザイン整備

申し分ない程度にデザインを整えました。僕はCSSが壊滅的に書けないのでBootstrapを採用。

ちなみにタスク内容編集ページ、ユーザー新規登録、ユーザーログイン画面はデザインが初期状態なので、気になる場合自分なりにデザインを整備してみてください。

❸:ユーザーログイン機能実装

ユーザーログインには「devise」というgemを使用しました。deviseはロジックがガチガチなのでオリジナルサービスを開発する際は不採用にしたりするのですが、簡単にユーザーログインを実現できるので今回は採用。

ユーザーには名前情報とプロフィール情報を追加していますが、CRUD同様バリデーションはしていないので気になれば実装してみてください。プロフィールはJavaScriptで文字数カウントとかすると面白いかもしれません。。。

ユーザー詳細ページとトプ画情報も追加しました。

最後に

何かしらの役に立てれば嬉しいです!

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

【Rails】ヘルパーメソッド、confimartionの使い方

 最初に

パスワード入力時に確認用で2回パスワードを打ち込む仕様になっているサービスをよく見かける。
同じことを実装しようとした際にconfimartionというRailsにおけるバリデーションのヘルパーメソッドを使用すれば簡単に実装できたため、備忘録として残します。

connfimartionとは

2つのテキストフィールドで受け取る内容が完全に一致する必要がある場合に使います。たとえば、メールアドレスやパスワードで、確認フィールドを使うとします。このバリデーションヘルパーは仮想の属性を作成します。属性の名前は、確認したい属性名に「confirmation」を追加したものになります。
https://railsguides.jp/active
record_validations.html
上記より引用。

要は2つのフォームで同じデータでなければ登録できないバリデーションをかけるメソッドという認識で問題ないかと思います。

実装手順

1.モデルの修正

user.rb
class User < ApplicationRecord
  validates :password, confirmation: true
end

モデルにconfimartionメソッドを適用したいカラムに対して、上記の様な記述を追加。
これでバリデーション完了。

2.ビューに確認用のフォームを追加

new.html.haml
= form_for(@user, url: user_registration_path) do |f|  
  = f.text_field :password 
  = f.text_field :password_confirmation
end

テキストフィールドの第二引数の属性名は、confimartionで確認したい属性名に_confimartionを追加します。
実際に記述したモデルとビューについては下記の様な感じになります。
スクリーンショット 2020-05-29 12.05.37.png

スクリーンショット 2020-05-29 12.03.40.png

以上で2つのフォームに入力された値が同じでなければバリデートされる様になります!
バリデーションを追加したい場合は、確認したい属性にバリデーションを付与すれば良いだけです。

最初実装する際に、
・確認用の属性を作成して、
・二つのフォームに入力がされた値が同じかどうかを確認する様な条件分岐の作成
・同じであれば保存
の様なコードを書かないといけないと思っていたので、confirmationを使うことにより非常に簡単に実装が完了しました。

参考文献

https://railsguides.jp/active_record_validations.html

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

【EC2・Rails】デプロイのエラーIs the server running on host "3.114.69.77" and accepting TCP/IP connections on port 5432? (PG::ConnectionBad)の解決法

unicorn.logの結果は下記の通り。

Is the server running on host "3.114.69.77" and accepting
    TCP/IP connections on port 5432?
 (PG::ConnectionBad)

原因はいくつかある。

Ec2内のデータベースにアクセスできる権限がない。

アプリディレクトリでpsql -lと打って下記のように表示されれば、権限がない可能性があります。

スクリーンショット 2020-05-26 12.10.1610.png

[uploading-0]()

$  su - postgres  #管理者権限でDBに入る。

$  psql postgres

$  psql -U postgres -d postgres #postgresユーザで入る。

$  su postgres

$  psql -l

$  GRANT ALL PRIVILEGE<img width="732" alt="スクリーンショット 2020-05-26 18.42.0242.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/568461/741f8925-1698-3c57-8245-6af5adeffebf.png">
S ON DATABASE portfolio to postgres;  #これで権限を追加できる。

スクリーンショット 2020-05-26 18.51.4451.png

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

【EC2・Rails】unicorn.logのエラーIs the server running on host "3.114.69.77" and accepting TCP/IP connections on port 5432? (PG::ConnectionBad)の解決法

デプロイをしている最中のエラー。
Postgresqlを使っています。

unicorn.logの結果は下記の通り。

Is the server running on host "3.114.69.77" and accepting
    TCP/IP connections on port 5432?
 (PG::ConnectionBad)

原因はいくつかある。

Ec2内のデータベースにアクセスできる権限がない。

アプリディレクトリでpsql -lと打って下記のように表示されれば、権限がない可能性があります。

スクリーンショット 2020-05-26 12.10.1610.png

\lで確認しても権限がない。
portfolioの部分にアクセス権が書いていない。

スクリーンショット 2020-05-26 12.34.5234.png

したがって下記のコマンドで権限を追加します。

$  su - postgres  #管理者権限でDBに入る。

$  psql postgres

$  psql -U postgres -d postgres #postgresユーザで入る。

$  su postgres

$  psql -l

$  GRANT ALL PRIVILEGES ON DATABASE portfolio to postgres;  #これで権限を追加できる。

スクリーンショット 2020-05-26 18.51.4451.png

しかしunicorn.logのエラー文は変わらず。

database.ymlの本番環境のhost名はlocalhostかIPを指定する。

database.ymlの本番環境のhost名でlocalhostかIPを指定することによって解決。

以下のようなルールがあるとのこと。

production環境の host名をdbにするのは、dockerを使って内部ネットワークを利用するときに使用する。

そうでない場合は、host名は、dbのホスト名かIPを指定する。

同じサーバー内で動かすのであれば、localhostでも良い。

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

EC2内で本番環境のコンソールに入れない際のエラーinvalid base64 (ArgumentError)の解決法

EC2内でコンソールに入ろうとbundle exec rails c -e productionをしたところ次のエラーが表示されました。

[shogo@ip-10-0-0-221 Portfolio]$ bundle exec rails c -e production
/home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/bootstrap-4.4.1/lib/bootstrap/version.rb:4: warning: already initialized constant Bootstrap::VERSION
/home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/bootstrap-sass-3.4.1/lib/bootstrap-sass/version.rb:2: warning: previous definition of VERSION was here
/home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/bootstrap-4.4.1/lib/bootstrap/version.rb:5: warning: already initialized constant Bootstrap::BOOTSTRAP_SHA
/home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/bootstrap-sass-3.4.1/lib/bootstrap-sass/version.rb:3: warning: previous definition of BOOTSTRAP_SHA was here
Traceback (most recent call last):
    58: from bin/rails:4:in `<main>'
    57: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325:in `require'
    56: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:291:in `load_dependency'
    55: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325:in `block in require'
    54: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
    53: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require_with_bootsnap_lfi'
    52: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
    51: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `block in require_with_bootsnap_lfi'
    50: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require'
    49: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/commands.rb:18:in `<main>'
    48: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/command.rb:46:in `invoke'
    47: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/command/base.rb:65:in `perform'
    46: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/thor-1.0.1/lib/thor.rb:392:in `dispatch'
    45: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/thor-1.0.1/lib/thor/invocation.rb:127:in `invoke_command'
    44: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/thor-1.0.1/lib/thor/command.rb:27:in `run'
    43: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/commands/console/console_command.rb:101:in `perform'
    42: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/command/actions.rb:15:in `require_application_and_environment!'
    41: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/command/actions.rb:28:in `require_environment!'
    40: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/application.rb:339:in `require_environment!'
    39: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325:in `require'
    38: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:291:in `load_dependency'
    37: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325:in `block in require'
    36: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/zeitwerk-2.3.0/lib/zeitwerk/kernel.rb:23:in `require'
    35: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
    34: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require_with_bootsnap_lfi'
    33: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
    32: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `block in require_with_bootsnap_lfi'
    31: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require'
    30: from /var/www/rails/Portfolio/config/environment.rb:5:in `<main>'
    29: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/application.rb:363:in `initialize!'
    28: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/initializable.rb:60:in `run_initializers'
    27: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/2.6.0/tsort.rb:205:in `tsort_each'
    26: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/2.6.0/tsort.rb:226:in `tsort_each'
    25: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/2.6.0/tsort.rb:347:in `each_strongly_connected_component'
    24: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/2.6.0/tsort.rb:347:in `call'
    23: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/2.6.0/tsort.rb:347:in `each'
    22: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/2.6.0/tsort.rb:349:in `block in each_strongly_connected_component'
    21: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/2.6.0/tsort.rb:431:in `each_strongly_connected_component_from'
    20: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/2.6.0/tsort.rb:350:in `block (2 levels) in each_strongly_connected_component'
    19: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/2.6.0/tsort.rb:228:in `block in tsort_each'
    18: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/initializable.rb:61:in `block in run_initializers'
    17: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/initializable.rb:32:in `run'
    16: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/initializable.rb:32:in `instance_exec'
    15: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/devise-4.7.1/lib/devise/rails.rb:37:in `block in <class:Engine>'
    14: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/devise-4.7.1/lib/devise/secret_key_finder.rb:10:in `find'
    13: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/devise-4.7.1/lib/devise/secret_key_finder.rb:24:in `key_exists?'
    12: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/core_ext/module/delegation.rb:297:in `method_missing'
    11: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/encrypted_configuration.rb:38:in `options'
    10: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/encrypted_configuration.rb:33:in `config'
     9: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/encrypted_configuration.rb:21:in `read'
     8: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/encrypted_file.rb:43:in `read'
     7: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/encrypted_file.rb:80:in `decrypt'
     6: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/messages/rotator.rb:21:in `decrypt_and_verify'
     5: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/message_encryptor.rb:157:in `decrypt_and_verify'
     4: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/message_encryptor.rb:185:in `_decrypt'
     3: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/message_encryptor.rb:185:in `map'
     2: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/message_encryptor.rb:185:in `block in _decrypt'
     1: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/2.6.0/base64.rb:74:in `strict_decode64'
/home/shogo/.rbenv/versions/2.6.3/lib/ruby/2.6.0/base64.rb:74:in `unpack1': invalid base64 (ArgumentError)
    55: from bin/rails:4:in `<main>'
    54: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325:in `require'
    53: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:291:in `load_dependency'
    52: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325:in `block in require'
    51: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
    50: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require_with_bootsnap_lfi'
    49: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
    48: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `block in require_with_bootsnap_lfi'
    47: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require'
    46: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/commands.rb:18:in `<main>'
    45: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/command.rb:46:in `invoke'
    44: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/command/base.rb:65:in `perform'
    43: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/thor-1.0.1/lib/thor.rb:392:in `dispatch'
    42: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/thor-1.0.1/lib/thor/invocation.rb:127:in `invoke_command'
    41: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/thor-1.0.1/lib/thor/command.rb:27:in `run'
    40: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/commands/console/console_command.rb:101:in `perform'
    39: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/command/actions.rb:15:in `require_application_and_environment!'
    38: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/command/actions.rb:28:in `require_environment!'
    37: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/application.rb:339:in `require_environment!'
    36: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325:in `require'
    35: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:291:in `load_dependency'
    34: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/dependencies.rb:325:in `block in require'
    33: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/zeitwerk-2.3.0/lib/zeitwerk/kernel.rb:23:in `require'
    32: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
    31: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:21:in `require_with_bootsnap_lfi'
    30: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/loaded_features_index.rb:92:in `register'
    29: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `block in require_with_bootsnap_lfi'
    28: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/bootsnap-1.4.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:22:in `require'
    27: from /var/www/rails/Portfolio/config/environment.rb:5:in `<main>'
    26: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/application.rb:363:in `initialize!'
    25: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/initializable.rb:60:in `run_initializers'
    24: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/2.6.0/tsort.rb:205:in `tsort_each'
    23: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/2.6.0/tsort.rb:226:in `tsort_each'
    22: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/2.6.0/tsort.rb:347:in `each_strongly_connected_component'
    21: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/2.6.0/tsort.rb:347:in `call'
    20: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/2.6.0/tsort.rb:347:in `each'
    19: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/2.6.0/tsort.rb:349:in `block in each_strongly_connected_component'
    18: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/2.6.0/tsort.rb:431:in `each_strongly_connected_component_from'
    17: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/2.6.0/tsort.rb:350:in `block (2 levels) in each_strongly_connected_component'
    16: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/2.6.0/tsort.rb:228:in `block in tsort_each'
    15: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/initializable.rb:61:in `block in run_initializers'
    14: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/initializable.rb:32:in `run'
    13: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/railties-6.0.0/lib/rails/initializable.rb:32:in `instance_exec'
    12: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/devise-4.7.1/lib/devise/rails.rb:37:in `block in <class:Engine>'
    11: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/devise-4.7.1/lib/devise/secret_key_finder.rb:10:in `find'
    10: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/devise-4.7.1/lib/devise/secret_key_finder.rb:24:in `key_exists?'
     9: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/core_ext/module/delegation.rb:297:in `method_missing'
     8: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/encrypted_configuration.rb:38:in `options'
     7: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/encrypted_configuration.rb:33:in `config'
     6: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/encrypted_configuration.rb:21:in `read'
     5: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/encrypted_file.rb:43:in `read'
     4: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/encrypted_file.rb:80:in `decrypt'
     3: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/messages/rotator.rb:21:in `decrypt_and_verify'
     2: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/message_encryptor.rb:157:in `decrypt_and_verify'
     1: from /home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/message_encryptor.rb:183:in `_decrypt'
/home/shogo/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-6.0.0/lib/active_support/message_encryptor.rb:206:in `rescue in _decrypt': ActiveSupport::MessageEncryptor::InvalidMessage (ActiveSupport::MessageEncryptor::InvalidMessage)

master.key、crefidentials.keyが間違っているから。

タイミング的にあまり遭遇することのないエラーだと思うので、とりあえずEC2サーバー内のmaster.key、crefidentials.key周りをローカル環境と合わせましょう。

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

【】本番環境でgit pull origin masterをしたのにCSSの変更が適用されない際の対処法

本番環境でアプリのディレクトリまでいき、下記を実行する。

bundle exec rake assets:precompile RAILS_ENV=production

で、アプリを再起動する。

$  sudo service nginx restart
$  sudo systemctl restart  postgresql
$  ps -ef | grep unicorn | grep -v grep
$  bundle exec unicorn_rails -c /var/www/rails/Portfolio/config/unicorn.conf.rb -D -E production

終了です。

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

【EC2】本番環境でgit pull origin masterをしたのにCSSの変更が適用されない際の対処法

本番環境でアプリのディレクトリまでいき、下記を実行する。

bundle exec rake assets:precompile RAILS_ENV=production

で、アプリを再起動する。

$  sudo service nginx restart
$  sudo systemctl restart  postgresql
$  ps -ef | grep unicorn | grep -v grep
$  bundle exec unicorn_rails -c /var/www/rails/Portfolio/config/unicorn.conf.rb -D -E production

終了です。

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

【Rails】Devise、ActiveStorage、S3でユーザーアバターの実装

概要

タイトルの通りです。
事前にActionTextを使用していた関係で一部手順が抜けている部分もあるかもしれませんがご了承ください。
CarrierWaveを使用した記事も書いたのですが、ActiveStorageの方が何かと便利そうです。
【Rails】Devise、CarrierWave、S3でユーザーアバターの実装

環境

Ruby: 2.7.1
Rails: 6.0.2.2
Devise導入済み
(gem 'devise', '~> 4.7', '>= 4.7.1')

手順

今回は「avatar」という名称で実装してますが好みでimageなどに変更してください。

ActiveStorageのインストール

以下の手順で「active_storage_attachments」と「active_storage_blobs」の二つのテーブルが作成されます。

$ rake active_storage:install

# DBマイグレーション
$ rake db:migrate

モデルの設定

これで画像が「active_storage_attachments」テーブルの「record_type」カラムに「User」で保存されるようになります。
今回は1枚の画像のみ保存できればいいので「has_one_attached」としています。
複数枚保存する方法もありますがそちらは別記事に譲ります。

app/models/user.rb
class Comment < ApplicationRecord
  has_one_attached :avatar
end

Deviseのstrong parametersを追加

今回は編集画面でのみアバターを設定できるようにします。

app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected
    # deviseのpermitted_parameterを追加する
    def configure_permitted_parameters
      devise_parameter_sanitizer.permit(:account_update, keys: [:avatar] )
      # 登録時も必要であればsign_upを追加
      # devise_parameter_sanitizer.permit(:sign_up, keys: [:avatar] )
    end
end

S3の設定

こちらの記事を参考にしてください。
Railsでaction text(active storage)の画像保存先をaws s3に変更した

アバターの保存と表示

アバター保存画面

app/views/users/registrations/edit.html.erb
<%= form_with model: @user, url: user_registration_path, local: true do |f| %>
  <div class="field">
    <%= f.label :avatar %>
    <%= f.file_field :avatar %>
  </div>

  <div class="actions">
    <%= f.submit "保存" %>
  </div>
<% end %>

アバター表示画面

<% if @user.avatar.attached? %>
   <%= image_tag @user.avatar %>
<% end %>

画像が表示されない場合

image_processingをインストールしてみてください。

Gemfile
# rails6であればすでにあるとおもうのでコメントアウトを外してください。
gem 'image_processing', '~> 1.2'
$ bundle

後書き

こちらの記事を参考にすれば保存した画像の整形なども簡単にできます。
Active StorageのVariantの指定方法いろいろ

冒頭に書いたように最初はCarrierWaveを使用していたのですが、それだとS3のパブリックアクセスブロックをオフにしてURLからアクセスできるようにしなければならなかったのでActiveStorageの使用に切り替えました。
設定もこちらの方が楽でした。

参考

Active Storage の概要
【Rails 5.2】 Active Storageの使い方

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

シンプルにRailsでStripeを動かす(コンソールで決済してみる)

RailsでStripe gemをinstall

gem 'stripe'

RailsでStripe設定ファイルを手動で作る

config/initializers/stripe.rb

RailsでStripeを鍵をセット

stripe.rb
Rails.configuration.stripe = {
    :publishable_key => "あなたのPublishable key",
    :secret_key => "あなたのSecret key"
 }

 Stripe.api_key = Rails.configuration.stripe[:secret_key]

RailsでStripe決済する

% rails c

> amount = 500
> token = 'tok_jp'
> order_id = 'sample_order_id'
> charge = Stripe::Charge.create(
    amount: amount,
    currency: 'jpy',
    source: token,
    metadata: { order_id: order_id },
  )
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

type: :mailer以外のrspecだとActionMailer::Base.deliveriesが空っぽ

困った

request specなどでも
ActionMailer::Base.deliveries を使ってテストがしたいのに
type: :mailer 以外のrspecだと ActionMailer::Base.deliveriesが []のままで困った

きっとtype: :mailerの時は何かが裏で勝手にincludeとかしてるんだろうなーと思って

調べてみる

rspec の type: :model とかについて
という記事を見つけた
どうやらそういうことらしい

typeに応じてここにあるものが読み込まれるのかな?
https://github.com/rspec/rspec-rails/blob/master/lib/rspec/rails/example/

ってことで試してみる

解決

rails_helper.rb
RSpec.configure do |config|
.
.
.
  config.include RSpec::Rails::MailerExampleGroup
.
.
.

ってやると
お、 ActionMailer::Base.deliveries に積まれるようになった〜〜
よかったよかった

常に読み込ませたくないなら

ActionMailer::Base.deliveries を使いたいrspecの中でのみ

include RSpec::Rails::MailerExampleGroup`

でおk

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

Docker for Mac の Mutagen-based cachingを使ったらホスト側のファイルの変更が反映されなくなった

何が起きたか

Docker for Mac の Mutagen-based caching で Volume のパフォーマンスが劇的に改善した
こちらの記事を見て試してみたらrspecとかrubocopとか爆速になってうおおおおおおってなったけど
swagger.ymlのホスト側での変更がredocのコンテナ内に反映されなくなってしまった
しかし、railsプロジェクトの方は問題なく反映されていてなんでだろうと思ったら

原因

docker-compose.yml
version: '3'
services:
  redoc:
    image: redocly/redoc:latest
    volumes:
      - ./swagger.yml:/usr/share/nginx/html/swagger.yml
    environment:
      SPEC_URL: swagger.yml
    ports:
      - 8081:80

volumesで
- ./swagger.yml:/usr/share/nginx/html/swagger.yml と書いていたこと
どうやらファイル単位での指定をすると反映がされなくなるようだ
なんでかはわからん、暇な時に気が向いたら調べる

解決策

ディレクトリ単位でマウントする

docker-compose.yml
version: '3'
services:
  redoc:
    image: redocly/redoc:latest
    volumes:
      - ./swagger:/usr/share/nginx/html/swagger
    environment:
      SPEC_URL: swagger/swagger.yml
    ports:
      - 8081:80

ちなみに

Mutagen-based caching使ったらrspecとか4倍ぐらい早くなるので
railsをdocker使って開発してて遅いなぁって困ってる人にはとてもおすすめ
もうdocker for mac遅いなんて言わせない!!!!!

edge版なので何があるかわからんけど

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