20190417のRailsに関する記事は27件です。

ハッシュ関数とは

ハッシュ関数とは

プログラミング初心者なりに『ハッシュ関数とは』何かをまとめてみた。

ハッシュ関数とは

一言でいうと『入力されたデータに対して適当な値を返してくれる関数。』

そしてその返ってきた値をハッシュと呼ぶ。

ちなみに関数にいれるものは『引数』呼ぶ。

ハッシュは引数として関数にいれた値をぐちゃぐちゃにしてハッシュとして返してくれる特性があるため、第三者にばれてはいけないパスワードなどの設定になどに使われる。

ちょっと汚い話になるけれど、

ラーメン(引数)を食べたら
それが体(関数)に入って
うんち(ハッシュ)としてでてくる。

うんちを見た人は一体何を食べたのか分からない。

つまりハッシュは、入力されたデータに対して適当な値を返してくれる関数。だと思えばOKだと思う。

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

RailsプロジェクトのGitHubリポジトリ主要言語判定がHTMLになってしまうのをRubyにする

経緯

  • ずっと気になっていて、ググってはわからん、ググっては諦めるを繰り返していたのですが、ついに解決方法を見つけました。

解決法

  • ルートディレクトリ直下に .gitattributes を作成し、以下のように記述してコミット&プッシュします。
  • ただ、erbファイルをRubyとみなさせているだけなので、それで良いという方のみ行ってみてください。
.gitattributes
*.html.erb linguist-language=Ruby

参考

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

Railsでテーブルのカラムを確認したい時

Railsにてカラムを確認したい時は、コンソールからモデル名を入力すれば確認できる様子

2.4.1 :017 > User
 => User(id: integer, organization_id: integer, login_id: string, password_digest: string, first_logged_in_at: datetime, last_logged_in_at: datetime, created_at: datetime, updated_at: datetime, deleted_at: datetime) 

補足:Hoge (call 'Hoge.connection' to establish a connection)が出た時

=> Hoge (call 'Hoge.connection' to establish a connection)

上記のように表示されたときは
ActiveRecord::Base.clear_cache!をコンソールに入力すれば良いらしい。

http://nyaahara.hatenablog.com/entry/2015/02/19/234513

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

アソシエーションって? 初心者メモ

アソシエーションとは

モデル(テーブル)間の紐付けをする機能のこと。

アソシエーションを使うとデータの呼び出しが楽になる!:point_up::sparkles:

どんなときに使うの?

例)userが複数の画像を追加するとき

id user image1 image2 image3
1 A photo1 photo4 photo7
2 B photo2 photo5 photo8
3 C photo3 photo6 photo9

↑これはダメなテーブルの作り方
 画像を追加するたびにカラムを増やさなきゃいけない
 いちいちコンソルで$rails g modelするのなんてめんどくさすぎ:weary:

テーブルを分けるしかない:helmet_with_cross:

userテーブル

id user
1 A
2 B
3 C

imageテーブル

id image article_id
1 photo1 1
2 photo2 2
3 photo3 3
4 photo4 1
5 photo5 2
6 photo6 3
7 photo7 1

バラバラになっちゃったのでuserテーブルとimageテーブルは
関係のあるテーブルだとわからせたい

:angel_tone2:アソシエーションを使おう

アソシエーションを定義する

アソシエーションを使う条件
①モデルクラスにhas_manyやbelong_toなどの定義がされている。
②所属する側のテーブルに「所属するカラム名_id」というカラムがある。

例)ツイートとユーザーを関連づける
全てのツイートはいずれかのユーザーが作成したもので、
ユーザーは自分の作成したツイートを複数もっているということになる。

:imp:userから見るとtweetを複数持っている→has_manyの関係

app/models/user.rb
class User < ApplicationRecord
    has_many :tweets
end

:scroll:tweetから見るといずれかのuserに属している→beong_toの関係

app/models/tweet.rb
class Tweet < ApplicationRecord
    belongs_to :user
end

アソシエーションを実装する

:frowning2:アソシエーションを使用しない場合

ターミナルでrails cコマンド実行
[1] pry(main)> user = User.find(1)
[2] pry(main)> Tweet.where(user_id: user.id)

:umbrella2:tweetsテーブルに対してuser_idがuserのidと等しいコードを取得している。

:relaxed:アソシエーションを使用した場合

ターミナルでrails cコマンド実行
[1] pry(main)> user = User.find(1)
[2] pry(main)> user.tweets

:star:Userモデルに「user has many tweets」の記述をしたので
userモデルのインスタンス.tweetsでそのインスタンスが持つツイートを取得できる。
→短くて楽!:sparkles:

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

【Rails】ローカル開発環境で他の端末からrails serverに接続する方法

IPアドレス確認

ターミナルでifconfig コマンドを入力して、wi-fiで接続しているインターフェイスのIPアドレスを確認する。

$ ifconfig
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
    options=1203<RXCSUM,TXCSUM,TXSTATUS,SW_TIMESTAMP>
    inet 127.0.0.1 netmask 0xff000000 
    inet6 ::1 prefixlen 128 
    inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1 
    nd6 options=201<PERFORMNUD,DAD>
gif0: flags=8010<POINTOPOINT,MULTICAST> mtu 1280
stf0: flags=0<> mtu 1280
XHC0: flags=0<> mtu 0
XHC20: flags=0<> mtu 0
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
    ether xxxxxxxxxxxxxxxxxxx
    inet6 fe80::a5:5017:3c48:df62%en0 prefixlen 64 secured scopeid 0x6 
    inet 192.168.11.10 netmask 0xffffff00 broadcast 192.168.11.255
    nd6 options=201<PERFORMNUD,DAD>
    media: autoselect
    status: active

en0: を見ると 192.168.11.10 であるのが分かる。

serverを立ち上げる。

serverのPCはrails serverを立ち上げます。この時-b オプションが必要。

rails s -b 0.0.0.0

外部端末から接続

rails s したPCと同じWi-Fi(正確には同一のSSID)に接続し、
ブラウザのアドレスバーにserverのIPアドレスと3000番ポート番号を指定して入力する。
今回の場合、サーバーのPCのIPアドレスが192.168.11.10なので、192.168.11.:3000
と入力する。

スクリーンショット 2019-04-17 22.00.18.png

これでherokuなどにデプロイしなくても、スマホから画面確認などが出来ます。
また、httpなのでwiresharkなどでパケットキャプチャーすれば中身が見れます。

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

【Rails】development環境で外部端末からserverに接続する方法

IPアドレス確認

ターミナルでifconfig コマンドを入力して、wi-fiで接続しているインターフェイスのIPアドレスを確認する。

$ ifconfig
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
    options=1203<RXCSUM,TXCSUM,TXSTATUS,SW_TIMESTAMP>
    inet 127.0.0.1 netmask 0xff000000 
    inet6 ::1 prefixlen 128 
    inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1 
    nd6 options=201<PERFORMNUD,DAD>
gif0: flags=8010<POINTOPOINT,MULTICAST> mtu 1280
stf0: flags=0<> mtu 1280
XHC0: flags=0<> mtu 0
XHC20: flags=0<> mtu 0
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
    ether xxxxxxxxxxxxxxxxxxx
    inet6 fe80::a5:5017:3c48:df62%en0 prefixlen 64 secured scopeid 0x6 
    inet 192.168.11.10 netmask 0xffffff00 broadcast 192.168.11.255
    nd6 options=201<PERFORMNUD,DAD>
    media: autoselect
    status: active

en0: を見ると 192.168.11.10 であるのが分かる。

serverを立ち上げる。

serverのPCはrails serverを立ち上げます。この時-b オプションが必要。

rails s -b 0.0.0.0

外部端末から接続

rails s したPCと同じWi-Fi(正確には同一のSSID)に接続し、
ブラウザのアドレスバーにserverのIPアドレスと3000番ポート番号を指定して入力する。
今回の場合、サーバーのPCのIPアドレスが192.168.11.10なので、192.168.11.:3000
と入力する。

スクリーンショット 2019-04-17 22.00.18.png

これでherokuなどにデプロイしなくても、スマホから画面確認などが出来ます。
また、httpなのでwiresharkなどでパケットキャプチャーすれば中身が見れます。

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

Railsの部分テンプレ(partial)をラッピングして、collection変数を渡す

TL;DR

_item.html.slim
h3 Item Name: #{item.name}
p Item Index: #{item_counter}
_wrapped_item.html.slim
h2 Item Wrapper
.item-area
  = render partial: 'item',\
    locals: { item: wrapped_item, item_counter: wrapped_item_counter }
index.html.slim
h1 Naked Items
.naked-items = render partial: 'item', collection: @items

h1 Wrapped Items
.wrapped-items = render partial: 'wrapped_item', collection: @items

はじめに

パーシャルをrenderする際、<%= render partial: 'item', collection: @items %>を使うと、.each文より見通しが良くなるだけでなく、性能も向上されるとされています。
しかし、パーシャルにそれぞれラッピングやデコレーションをしたい場合、どうすれば良いのでしょう。

発見

_item.html.slim
h3 Item Name: #{item.name}
p Item Index: #{item_counter}
_wrapped_item.html.slim
h2 Item Wrapper
.item-area = render partial: 'item'
index.html.slim
h1 Naked Items
.naked-items = render partial: 'item', collection: @items

h1 Wrapped Items
.wrapped-items = render partial: 'wrapped_item', collection: @items

上記の構文のように、そのまま_item.html.slimにラッピングを当てて、renderingしようとする時、Template::Errorが発生し、変数itemがないと言われました。

ActionView::Template::Error (undefined local variable or method `item' for #<#<Class:0x00007f8d8fa105d0>:0x00007f8da6f657a8>:
    1: h3 Item Name: #{item.name}
    2: p Item Index: #{item_counter}

だったら変数itemを手動で渡せば良いのでは?と思って、変数wrapped_itemitemとして渡しました。もちろん、Indexも必要な時は、#{variable_name}_countも伝播しなければいけません。

_wrapped_item.html.slim
h2 Item Wrapper
.item-area
  = render partial: 'item',\
    locals: { item: wrapped_item, item_counter: wrapped_item_counter }

参考

https://qiita.com/otakumesi/items/74a75cd6ebff7eba5c63

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

【大反省】素人がAWSS3をいじっていると「Your AWS Account is compromised!」とメールが来た

Railsでポートフォリオを作成しておりまして、Herokuへのデプロイ後の画像保存先をAWSS3に指定しました。

すると後日AWS様からメールで「Your AWS Account is compromised!」とご連絡頂き、結果的にバケットとIAMを削除して作り直したのですが、そもそもなぜそんなことになったのかを反省しつつ書いておきます。

原因:AccessKeyをベタ書きしてcommitしてしまっていた

AWSS3を使う場合Active Storageを使って、保存先をconfig/storage.ymlで以下のように書くかと思います。

storage.yml
amazon:
  service: S3
  access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
  secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
  region: ap-northeast-1 #東京
  bucket: #bucketname

ただ僕は以前の記事でも書いた通り、#string does not have #dig methodというエラー解決に苦しみ、結果的にaccess_key_idsecret_access_keyをベタ書きしてした状態でgit commitして全世界に僕のアクセスキーを大公開してしまっていたわけです。

まあ、僕のリポジトリのコードなど詳しく見る人はいないだろうという甘い想定でしたが、実際はBotによって攻撃される危険性などがあるそうで、その辺りの想定が甘すぎました、、、

とりあえずポートフォリオとして完成させることを急ぐあまり、セキュリティの意識が大幅に欠落していて、まだ個人でポートフォリオを実装している段階なのでマシですが、これが実際の業務だったら死んでいたな、、、と猛省しました

対処法

  • AWS ルートアカウントのユーザーパスワードを変更する。
  • すべてのルートおよび AWS Identity and Access Management (IAM) アクセスキーを削除するか、交換する。
  • 危険にさらされている IAM ユーザーを削除し、他のすべての IAM ユーザーのパスワードを変更する。
  • EC2 インスタンスおよび AMI、EBS ボリュームおよびスナップショット、および IAM ユーザーなどの作成していないアカウントのリソースを削除する。
  • AWS サポートから受け取った通知には、AWS サポートセンター経由で返信してください。

参照元:自分の AWS アカウントが危険にさらされているようです

上記を実行した上で、再度バケット、IAMを作り直して実装し直しました。

以上、大反省の記録でした。

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

Rails6 のちょい足しな新機能を試す4 (Date#before? Date#after? 編)

はじめに

Rails 6 に追加されそうな新機能を試す第3段。 Date#before? Date#after? 編です。
記載時点では、Rails は 6.0.0.beta3 です。 gem install rails --prerelease でインストールできます。

試してみる

今回は、rails の projectを作らなくても試せるので、直接、ruby (irb) から試してみましょう。

$ irb -ractive_support/core_ext

# 今日は昨日より後?
irb(main):001:0> Date.today.after?(Date.today.yesterday)
=> true

# 今日は明日より後?
irb(main):002:0> Date.today.after?(Date.today.tomorrow)
=> false

# 今日は昨日より前?
irb(main):003:0> Date.today.before?(Date.today.yesterday)
=> false

# 今日は明日より前?
irb(main):004:0> Date.today.before?(Date.today.tomorrow)
=> true

# 今日は今日より後?
irb(main):005:0> Date.today.after?(Date.today)
=> false

# 今日は今日より前?
irb(main):006:0> Date.today.before?(Date.today)
=> false

DateTime, Time, TimeWithZone にも同様に before? と after? が追加されています。

これ、わかりやすいんですかね。英語ペラペラの人にとっては自然なのかもですが、そうでない人には、ちょっと微妙かもと思ったり思わなかったり。以下みたいな読み違いをしそうな気がしないでもない...

# 今日の後は昨日? => この解釈が間違い。
irb(main):001:0> Date.today.after?(Date.today.yesterday)
=> true

このメソッドは、 :>after? の <: が before? の aliasとして定義されています。と書こうとしたのですが、どうやらそうではなかったようです。

irb(main):015:0> Date.today.method(:before?).original_name
=> :before?
irb(main):016:0> Date.today.method(:after?).original_name
=> :after?

アレッと思ってソースを調べてみました。

irb(main):018:0> Date.today.method(:before?).source_location
=> ["/usr/local/bundle/gems/activesupport-6.0.0.beta3/lib/active_support/core_ext/date_and_time/calculations.rb", 64]
irb(main):019:0> Date.today.method(:after?).source_location
=> ["/usr/local/bundle/gems/activesupport-6.0.0.beta3/lib/active_support/core_ext/date_and_time/calculations.rb", 69]

実際のコードはこんな感じです。

calclulation.rb
    # Returns true if the date/time falls before <tt>date_or_time</tt>.
    def before?(date_or_time)
      self < date_or_time
    end

    # Returns true if the date/time falls after <tt>date_or_time</tt>.
    def after?(date_or_time)
      self > date_or_time
    end

調べてみたら、alias で定義していたものを refactoring してました。

元のPRが Add before? and after? methods to date and time classes で、
refactoring の PR が Move implementation of before? and after? to DateAndTime::Calculations です。

参考情報

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

【Rails】 jQueryが動作しない時の対処法 (読み込む順番)

いつも忘れてしまうので備忘録。

ダメなパターン

_head.html.erb
<%= stylesheet_link_tag    'style', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'selectordie' %>

<!-- JQuery -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

javascript_include_tagjQuery CDN の順番では期待通りになりませんでした。

正のパターン

_head.html.erb
<!-- JQuery -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

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

jQuery CDNjavascript_include_tag の順番だと期待値通りの動作!

まとめ

先にjQueryロードしないとスクリプト読めないって話。(Railsに限った話じゃない・・・)

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

【Rails】 jQueryが動作しない時の対処法 (読み込む順番に気をつけて)

いつも忘れてしまうので備忘録。

ダメなパターン

_head.html.erb
<%= stylesheet_link_tag    'style', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'selectordie' %>

<!-- JQuery -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

javascript_include_tagjQuery CDN の順番では期待通りになりませんでした。

正のパターン

_head.html.erb
<!-- JQuery -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

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

jQuery CDNjavascript_include_tag の順番だと期待値通りの動作!

まとめ

先にjQueryロードしないとスクリプト読めないって話。(Railsに限った話じゃない・・・)

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

【Rails】 jQuery/jsファイル 読み込む順番

いつも忘れてしまうので備忘録。

ダメなパターン

_head.html.erb
<%= stylesheet_link_tag    'style', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'selectordie' %>

<!-- JQuery -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

javascript_include_tagjQuery CDN の順番では期待通りになりませんでした。

正のパターン

_head.html.erb
<!-- JQuery -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>

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

jQuery CDNjavascript_include_tag の順番だと期待値通りの動作!

まとめ

先にjQueryロードしないとスクリプト読めないって話。(Railsに限った話じゃない・・・)

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

本番API server に graphql を段階導入

@_nishisuke です!

フリーランスやってます!

ある案件で本番iosのAPI serverとして既に動いてる rails にgraphqlを導入しました。

(この案件では実装の全権限をもらってます。)

いきなりclient側の実装を変えるのは変更が大きすぎると判断しました。

第一段階としてサーバーのシリアライザーレイヤーだけをgraphqlに置き換えようとしました。

api serverはrequest specが書いてあり、json-schemaによりresponse jsonが担保されています。

https://github.com/ruby-json-schema/json-schema

一部の読み込みqueryだけをターゲットにし書き込み処理は最初のスコープに入れませんでした。

rails で graphql

https://qiita.com/nishisuke/items/c4f6065b069b2c1f3083

install

gem 'graphql'

before

app/controllers/users_controller.rb
class UsersController < ApplicationController
  def index
    user = User.where(適当なコンディション).includes(適当なアソシエーション)
    render json: UserSerializer(user)
  end
end

after

app/controllers/users_controller.rb
class UsersController < ApplicationController
  USER_SCHEMA = <<~USER_SCHEMA
    {
      users { name }
    }
  USER_SCHEMA

  def index
    gql_res = MyApplicationSchema.execute(USER_SCHEMA).to_h

    raise SomeError unless gql_res['errors'].nil?

    render json: gql_res.to_json
  end
end

結果

serializer layerだけ変えたかったが、controllerも変更を余儀なくされました。
MVC -> M + graphql
のイメージです。

gemの注意点

  • graphql-rubyのqueryはdefaultでcamelcase
  • graphql-rubyは200 statusでerror jsonを返そうとする

所感

思ったより簡単にできた。
実態と実装の構造が近くなって、変更を加えるのが容易になった。

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

Stripe ConnectのCustomアカウントで、子アカウントへの入金情報などを取得する方法(アカウントヘッダー)

Stripe Connectでの子アカウントに関する情報をAPIで取得したい

ドキュメントが少しわかりづらかったので記事を書きました。
プラットフォーム上で子アカウントの情報(例:決済情報、入金情報)を取得し、マイページなどで表示する方法です。
Stripe APIにはアカウントヘッダーという機能があり、APIを呼び出す上で、どのAccountに紐づいた情報を取得するのかを指定できます。このアカウントヘッダーを使用しない場合は、デフォルトで親アカウントが指定されるようです。

  # 例) 子アカウント(ID: acct_xxxxxxxxxx)に対して行われた最新の入金を3件取得する
    Stripe::Payout.list(
      {limit: 3},
      {stripe_account: "acct_xxxxxxxxxx"}
    )

このように、第一引数にパラメータ、第二引数にacct_idを指定することで、特定のアカウントに基づいた情報を取得できるようになります。

例) ある月の売上の入金額を取得する

私が開発しているCtoCサービスでは、子アカウントの売上の入金スケジュールを月末締め、翌月末払いにしています。そこで欲しい情報は、毎月の入金情報です。
例えば2019年3月に作成された入金情報を取得したい場合は、以下のようにします。

    beginning_of_month = Date.new(2019, 3).to_time.to_i
    end_of_month = Date.new(2019, 3).end_of_month.to_time.to_i

    payout = Stripe::Payout.list(
      {created: {gte: beginning_of_month, lte: end_of_month}}, #gteが以上、lteが以下。日時の範囲指定が独特w
      {stripe_account: "acct_xxxxxxxxxx"}
    )

    # 入金額
    payout.data[0].amount
    # 入金予定日
    Time.at(payout.data[0].arrival_date).strftime("%Y/%m/%d")

間違いなどあればご指摘頂けると嬉しいです。

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

メルカリでハマったところ3

capistranoでデプロイ時にエラー

unicornが起動できないみたい
00:17 unicorn:start
      01 $HOME/.rbenv/bin/rbenv exec bundle exec unicorn -c /var/www/freemarket_47nagoya/current/config/unicorn.rb -E production -D 
      01 master failed to start, check stderr log for details

ログを確認しても何も書かれていなかった
Caused by:
SSHKit::Command::Failed: bundle exit status: 1
bundle stdout: Nothing written
bundle stderr: master failed to start, check stderr log for details

ec2のcurrentディレクトリで実行してもダメ
current]$ unicorn_rails -c config/unicorn.rb -E production

/home/ec2-user/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/unicorn-5.4.1/lib/unicorn/configurator.rb:592:in 
`working_directory': config_file=config/unicorn.rb would not be accessible in working_directory=/var/www/freemarket_47nagoya/releases/current (ArgumentError)

psコマンドって何よ

詳しい情報を見たい時は -efオプションをつけるみたい
参考:https://www.ibm.com/support/knowledgecenter/ja/ssw_aix_71/com.ibm.aix.osdevice/cmd_check_proc_stat.htm

grepコマンド

簡単に言うと検索するコマンド
参考:
https://eng-entrance.com/linux-command-grep#grep

catコマンド

concatnate:連結するの意

環境変数

定義は/etc/environmentに保存することで、サーバ全体に適用される。
環境変数の書き込みはvimコマンドを使用して行う。
環境変数を定義する場所はいくつかある。
左から順に優先される。
本番環境なら、/etc/environment ~/.bash_profile
ローカル環境なら、~/.bash_profile .env.development(gem'dotenv')

gitignore関連の問題

<理由>
一度コミットしたファイルについては、その後.gitignoreに追加したとしてもGitの管理下から外されず、pushされてしまう。

<対処方法>
(例)
・ターミナルで
 > git rm --cached secrets.yml
 を実行しGitで管理されないようにする。

・secrets.ymlには直接キーを記述せず、環境変数を参照するようにする。

各5点

(補足)
環境変数とは、その端末のみからアクセスできる変数です。パスの指定や、今回のようにキーを保存するのに使われます。

Linuxでは.bash_profileに記述をすることで、毎回環境変数を設定しなくても起動時にセットすることができます。

よく使う機能のため、ネット記事等を参考に整理しておくことをお勧めします。

本番環境で出品できなくなった

#current/log/production.rb
ActionView::Template::Error (undefined method `category_id' for #<Item:0x00005623a4362ab8>):

ローカルと本番環境のコードは同じに見える。
itemsテーブルにcategory_idがあることは確認。
悩むこと半日ぐらい。
最終的にインスタンスの再起動で治りました。
デプロイでハマったらインスタンス再起動しましょう。

本番環境でrails c した時にエラー

Can't connect to local MySQL server through socket '/tmp/mysql.sock' (13)

本番環境でコンソールを使うときは

rails c production

らしい。

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

Railsチュートリアルで抑えておくべきポイント

minitestの書き方

なぜコントローラーのテストを実装するのか
- ルーティング通りにアクセスし、期待するページを表示出来ているかどうか
- 表示されたページの文言が期待するものであるかどうか

require 'test_helper'

class StaticPagesControllerTest < ActionDispatch::IntegrationTest

  def setup
    @base_title = "Ruby on Rails Tutorial Sample App"
  end

  test "should get home" do
    get static_pages_home_url
    assert_response :success
   #特定のHTMLタグが存在するかどうかをテストします 
   #(この種のアサーションメソッドはその名から「セレクタ」と呼ばれることもある。
    assert_select "title", "Home | #{@base_title}"
  end
end

setupメソッドは、テストが実行される直前で呼ばれる。
→リファクタリングで使用。

# この書き方は、application.html.rbが無い場合。railsを使うならこの方法は一般的では無い。
<% provide(:title, "Home") %>
<!DOCTYPE html>
<html>
  <head>
    <title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
  </head>
  <body>
    <h1>Sample App</h1>

↓railsで実装するなら↓

app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
    <%= csrf_meta_tags %>
    <%= stylesheet_link_tag    'application', media: 'all',
                               'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application',
                               'data-turbolinks-track': 'reload' %>
  </head>
app/views/static_pages/home.html.erb
<% provide(:title, "Home") %>
<h1>Sample App</h1>
<p>
  This is the home page for the
  <a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a>
  sample application.
</p>

provideの:titleが空の場合、無駄な「|」が入ってします。これを防ぐために、カスタムヘルパーを定義する。

app/helpers/application_helper.rb
module ApplicationHelper

  # ページごとの完全なタイトルを返します。
# メソッド定義とオプション引数。
#引数にデフォルト値を含めている。 (この例のデフォルト値は空の文字列です)。このように指定すると、page_title変数に引数を渡すことも渡さないこともできます。引数を渡さない場合は、指定のデフォルト値(この場合は空の文字列)を渡すことができる。
  def full_title(page_title = '') 
    base_title = "Ruby on Rails Tutorial Sample App"
    if page_title.empty?
      base_title
    else
      page_title + " | " + base_title
    end
  end
end

カスタムヘルパーを定義し、以下のように修正をする。

application.html.erb
<title><%= full_title(yield(:title)) %></title>

Unixのプロセス

プロセスを確認できる。

$ ps aux

プロセスの種類を指定してフィルタするには、psの結果をUnixの「パイプ」|でつないで、パターンマッチャーであるgrepに渡す。
※Springは「rails server」「rails console」「rake」コマンドが速くなる、Railsの新しいプリローダー

$ ps aux | grep spring

$ ps aux | grep server

プロセスid、略してpidを使い。不要なプロセスを排除するには、killコマンドでpidを指定し、Unixのkillコードを発行。

# 9はシグナル番号。
$ kill -9 [PID]

開発中に動作がおかしくなったりプロセスがフリーズしていると思えたら、すぐにps auxで状態を確認し、kill -15 やpkill -15 -f <プロセス名>で整理してみましょう。

$ spring stop

# spring stopが効かなかったら、下記で一気にspringプロセスをkillする。
$ pkill -9 -f spring

盲点

シングルクォートは、入力した文字をエスケープせずに「そのまま」保持するときに便利。

>> '\n'       # 'バックスラッシュ n' をそのまま扱う
=> "\\n"

# ”\n”になると改行を意味してしまう。"\\n"をシングルクォートを使えば、実装が楽。

オブジェクトとは (いついかなる場合にも) メッセージに応答するものです。
Ex,文字列のようなオブジェクトは、例えばlengthというメッセージに応答する

# if文の違う書き方
puts "x is not empty" if !x.empty?

#「!!」(「バンバン (bang bang)」と読みます) という演算子を使うと、そのオブジェクトを2回否定することになるので、どんなオブジェクトも強制的に論理値に変換できる
>> !!nil
=> false
>> !!0
=> true

Rubyのメソッドには「暗黙の戻り値がある」ことにご注意。これは、メソッド内で最後に評価された式の値が自動的に返されることを意味します (訳注: メソッドで戻り値を明示的に指定しなかった場合の動作です)
なので、以下のような場合は、returnが必要。

def string_message(str = '')
  return "It's an empty string!" if str.empty?
  "The string is nonempty."
end

splitメソッド(文字列を処理して配列を返す)

>>  "foo bar     baz".split     # 文字列を3つの要素を持つ配列に分割する
=> ["foo", "bar", "baz"]

>> "name".split('')
=> ["n", "a", "m", "e"]
>> "name".split
=> ["name"]

>> "fooxbarxbaz".split('x')
=> ["foo", "bar", "baz"]

joinメソッド(splitの逆の処理。配列を処置して文字列を出力)

>> a
=> [42, 8, 17, 6, 7, "foo", "bar"]
>> a.join                       # 単純に連結する
=> "4281767foobar"
>> a.join(', ')                 # カンマ+スペースを使って連結する
=> "42, 8, 17, 6, 7, foo, bar"
>> a = %w[foo bar baz quux]         # %wを使って文字列の配列に変換
=> ["foo", "bar", "baz", "quux"]
>> a = (0..9).to_a
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>> ('a'..'e').to_a
=> ["a", "b", "c", "d", "e"]

# 範囲(レンジ)と配列は蜜に関係している。
 (1..5).each { |i| puts 2 * i }

>> (1..5).map { |i| i**2 }          # 「**」記法は冪乗 (べき乗) 
=> [1, 4, 9, 16, 25]

# mapとjoinは繋げられる
def yeller(s)
  s.map(&:upcase).join
end
=> :yeller

yeller(['o','l','d'])
=> "OLD"

# 以上ことを把握できれば、以下が理解できる。
('a'..'z').to_a.shuffle[0..7].join

>> p :name             # 'puts :name.inspect' と同じ
:name
>> params = {}        # 'params' というハッシュを定義する ('parameters' の略)。
=> {}
>> params[:user] = { name: "Michael Hartl", email: "mhartl@example.com" }
=> {:name=>"Michael Hartl", :email=>"mhartl@example.com"}
>> params
=> {:user=>{:name=>"Michael Hartl", :email=>"mhartl@example.com"}}
>>  params[:user][:email]
=> "mhartl@example.com"
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsチュートリアルで押さえておくべきポイント

minitestの書き方

なぜコントローラーのテストを実装するのか
- ルーティング通りにアクセスし、期待するページを表示出来ているかどうか
- 表示されたページの文言が期待するものであるかどうか

require 'test_helper'

class StaticPagesControllerTest < ActionDispatch::IntegrationTest

  def setup
    @base_title = "Ruby on Rails Tutorial Sample App"
  end

  test "should get home" do
    get static_pages_home_url
    assert_response :success
   #特定のHTMLタグが存在するかどうかをテストします 
   #(この種のアサーションメソッドはその名から「セレクタ」と呼ばれることもある。
    assert_select "title", "Home | #{@base_title}"
  end
end

setupメソッドは、テストが実行される直前で呼ばれる。
→リファクタリングで使用。

# この書き方は、application.html.rbが無い場合。railsを使うならこの方法は一般的では無い。
<% provide(:title, "Home") %>
<!DOCTYPE html>
<html>
  <head>
    <title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
  </head>
  <body>
    <h1>Sample App</h1>

↓railsで実装するなら↓

app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
    <%= csrf_meta_tags %>
    <%= stylesheet_link_tag    'application', media: 'all',
                               'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application',
                               'data-turbolinks-track': 'reload' %>
  </head>
app/views/static_pages/home.html.erb
<% provide(:title, "Home") %>
<h1>Sample App</h1>
<p>
  This is the home page for the
  <a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a>
  sample application.
</p>

provideの:titleが空の場合、無駄な「|」が入ってします。これを防ぐために、カスタムヘルパーを定義する。

app/helpers/application_helper.rb
module ApplicationHelper

  # ページごとの完全なタイトルを返します。
# メソッド定義とオプション引数。
#引数にデフォルト値を含めている。 (この例のデフォルト値は空の文字列です)。このように指定すると、page_title変数に引数を渡すことも渡さないこともできます。引数を渡さない場合は、指定のデフォルト値(この場合は空の文字列)を渡すことができる。
  def full_title(page_title = '') 
    base_title = "Ruby on Rails Tutorial Sample App"
    if page_title.empty?
      base_title
    else
      page_title + " | " + base_title
    end
  end
end

カスタムヘルパーを定義し、以下のように修正をする。

application.html.erb
<title><%= full_title(yield(:title)) %></title>

Unixのプロセス

プロセスを確認できる。

$ ps aux

プロセスの種類を指定してフィルタするには、psの結果をUnixの「パイプ」|でつないで、パターンマッチャーであるgrepに渡す。
※Springは「rails server」「rails console」「rake」コマンドが速くなる、Railsの新しいプリローダー

$ ps aux | grep spring

$ ps aux | grep server

プロセスid、略してpidを使い。不要なプロセスを排除するには、killコマンドでpidを指定し、Unixのkillコードを発行。

# 9はシグナル番号。
$ kill -9 [PID]

開発中に動作がおかしくなったりプロセスがフリーズしていると思えたら、すぐにps auxで状態を確認し、kill -15 やpkill -15 -f <プロセス名>で整理してみましょう。

$ spring stop

# spring stopが効かなかったら、下記で一気にspringプロセスをkillする。
$ pkill -9 -f spring

文法における盲点

シングルクォートは、入力した文字をエスケープせずに「そのまま」保持するときに便利。

>> '\n'       # 'バックスラッシュ n' をそのまま扱う
=> "\\n"

# ”\n”になると改行を意味してしまう。"\\n"をシングルクォートを使えば、実装が楽。

オブジェクトとは (いついかなる場合にも) メッセージに応答するものです。
Ex,文字列のようなオブジェクトは、例えばlengthというメッセージに応答する

# if文の違う書き方
puts "x is not empty" if !x.empty?

#「!!」(「バンバン (bang bang)」と読みます) という演算子を使うと、そのオブジェクトを2回否定することになるので、どんなオブジェクトも強制的に論理値に変換できる
>> !!nil
=> false
>> !!0
=> true

Rubyのメソッドには「暗黙の戻り値がある」ことにご注意。これは、メソッド内で最後に評価された式の値が自動的に返されることを意味します (訳注: メソッドで戻り値を明示的に指定しなかった場合の動作です)
なので、以下のような場合は、returnが必要。

def string_message(str = '')
  return "It's an empty string!" if str.empty?
  "The string is nonempty."
end

splitメソッド(文字列を処理して配列を返す)

>>  "foo bar     baz".split     # 文字列を3つの要素を持つ配列に分割する
=> ["foo", "bar", "baz"]

>> "name".split('')
=> ["n", "a", "m", "e"]
>> "name".split
=> ["name"]

>> "fooxbarxbaz".split('x')
=> ["foo", "bar", "baz"]

joinメソッド(splitの逆の処理。配列を処置して文字列を出力)

>> a
=> [42, 8, 17, 6, 7, "foo", "bar"]
>> a.join                       # 単純に連結する
=> "4281767foobar"
>> a.join(', ')                 # カンマ+スペースを使って連結する
=> "42, 8, 17, 6, 7, foo, bar"
>> a = %w[foo bar baz quux]         # %wを使って文字列の配列に変換
=> ["foo", "bar", "baz", "quux"]
>> a = (0..9).to_a
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>> ('a'..'e').to_a
=> ["a", "b", "c", "d", "e"]

# 範囲(レンジ)と配列は蜜に関係している。
 (1..5).each { |i| puts 2 * i }

>> (1..5).map { |i| i**2 }          # 「**」記法は冪乗 (べき乗) 
=> [1, 4, 9, 16, 25]

# mapとjoinは繋げられる
def yeller(s)
  s.map(&:upcase).join
end
=> :yeller

yeller(['o','l','d'])
=> "OLD"

# 以上ことを把握できれば、以下が理解できる。
('a'..'z').to_a.shuffle[0..7].join

>> p :name             # 'puts :name.inspect' と同じ
:name
>> params = {}        # 'params' というハッシュを定義する ('parameters' の略)。
=> {}
>> params[:user] = { name: "Michael Hartl", email: "mhartl@example.com" }
=> {:name=>"Michael Hartl", :email=>"mhartl@example.com"}
>> params
=> {:user=>{:name=>"Michael Hartl", :email=>"mhartl@example.com"}}
>>  params[:user][:email]
=> "mhartl@example.com"
>> class String             # WordクラスはStringクラスを継承する
>>   # 文字列が回文であればtrueを返す
>>   def palindrome?
>>     self == self.reverse        # selfは文字列自身を表します
>>   end
>> end
=> :palindrome?

selfはオブジェクト(インスタンス)をさす。
self == reverseと、selfの省略も可能。

"aaa"はStringクラスのインスタンス

IE9への対応

念のため、以下のタグを

タグに入れた方が良い
<!--[if lt IE 9]>
  <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/r29/html5.min.js">
 </script>
<![endif]-->

 画像の格納場所

assetのコンパイル対象にしたいならassets配下。
ブラウザのキャッシュコントロールのためのバージョン管理化に置かれなくていいならpublic配下に置く。基本的にはシステム側で作る画像はassets以下、ユーザー側のアップロードする画像はpublic配下に置いておく。

ただ、表示速度を重視したい背景画像などは、public配下に置くと良い。
↓先頭に/(スラッシュ)をつけると、public配下になる。

<%= image_tag '/images/hoge.png' %>

yarnを使わず、gemでbootstrapを導入する方法

https://github.com/twbs/bootstrap-rubygem

# できるだけ、カスタムCSSは、一つのファイルで編集する
$ touch app/assets/stylesheets/custom.scss
app/assets/stylesheets/custom.scss
# 以下をimport
@import "bootstrap";
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【解決】ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock’

ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock’ が出た時の対処法

開発実務1年目のボクがハマった勉強中には見なかったエラーの一つ

ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)

とかいうエラー

初めてこれにでくわした時は解決までに使った時間は3時間くらいだったと思います
なんせボクの開発現場ではみんなイヤホンをしているし、新人なのでエラーで相談は迷惑かなーーーと感じていたからです

いま思えば新人だからこそエラーとか質問しやすいですよねw
ホントばかだったわ泣

ボクの場合はdb:migrate後に//localhost:3000に接続できなくなりMysql2::Error::ConnectionError: Can't connect to MySQL server on '127.0.0.1' (111)エラーが吐かれました
調べてみるとmysqlを起動できれば解決しそうだという事まで突き詰めました

ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)の【解決コピペコード】

/var/run/mysqld/mysqld.sockの削除

$ sudo rm -f /var/run/mysqld/mysqld.sock

/tmp/mysql.sockの削除

$ sudo rm -f /tmp/mysql.sock

mysqlサーバーの再起動

$ sudo /etc/init.d/mysql start

mysqlサーバー接続

$ mysql -u root -p

以上です
接続できたらcontrol+Zでmysqlから脱出してrails db:migrateなりrails s -b 0.0.0.0なりお好きにどうぞ

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

gem install mysql2のエラー対応

macでローカル環境を作るときに出やすいエラー

An error occurred while installing mysql2 (0.5.2), and Bundler cannot
continue.
Make sure that `gem install mysql2 -v '0.5.2' --source 'https://rubygems.org/'`
succeeds before bundling.

ERROR: While executing gem ... (Errno::EACCES)
Permission denied @ rb_sysopen

対応

$ sudo chown -R (ユーザ名):staff /Users/(ユーザ名)/.rbenv
$ bin/bundle config --local build.mysql2 "--with-cppflags=-I/usr/local/opt/openssl/include"
$ bin/bundle install --path vendor/bundle
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

コールバックの種類

コールバック:登録や削除イベントの前後に挟む任意の処理のこと

コールバックの種類 代表的な用途
before_validation 検証前の値の正規化
after_validation 検証結果(エラーメッセージの正規化)
before_save

before_create

before_update
saveのために裏側で行いたいデータ準備を行う。

検証エラーを出してもユーザー側からどうしようもない状態異常を防ぐために例外を出す。

after_save

after_create

after_update
モデルの状態に応じて他のモデルの状態を変えるなどの、モデルの状態に連動した挙動を行わせる。

検証エラーを出してもユーザー側からどうしようもない状態異常を防ぐために例外を出す。

before_destroy 削除してOKかをチェックし、ダメなら例外を出すなどして防ぐ。
after_destroy そのモデルの削除に応じて他のモデルの状態を変えるといった連動した挙動を実現する。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

devise NoMethodError (undefined method `utc'

こんなエラーが出てしまった場合

I, [2019-04-17T02:04:34.636864 #7612]  INFO -- : [18ca5a07-0693-4dd5-8be1-ac3c7c5ea47d] Started GET "/users/sign_in" for 133.218.55.173 at 2019-04-17 02:04:34 +0000
I, [2019-04-17T02:04:34.637545 #7612]  INFO -- : [18ca5a07-0693-4dd5-8be1-ac3c7c5ea47d] Processing by Users::SessionsController#new as HTML
D, [2019-04-17T02:04:34.639131 #7612] DEBUG -- : [18ca5a07-0693-4dd5-8be1-ac3c7c5ea47d]    (0.2ms)  SET NAMES utf8mb4 COLLATE utf8mb4_bin,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
D, [2019-04-17T02:04:34.639915 #7612] DEBUG -- : [18ca5a07-0693-4dd5-8be1-ac3c7c5ea47d]   User Load (0.3ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 1 ORDER BY `users`.`id` ASC LIMIT 1
I, [2019-04-17T02:04:34.641703 #7612]  INFO -- : [18ca5a07-0693-4dd5-8be1-ac3c7c5ea47d] Completed 500 Internal Server Error in 4ms (ActiveRecord: 1.0ms)
F, [2019-04-17T02:04:34.642646 #7612] FATAL -- : [18ca5a07-0693-4dd5-8be1-ac3c7c5ea47d]
F, [2019-04-17T02:04:34.642770 #7612] FATAL -- : [18ca5a07-0693-4dd5-8be1-ac3c7c5ea47d] NoMethodError (undefined method `utc' for Sat, 06 Apr 2019:Date):
F, [2019-04-17T02:04:34.642858 #7612] FATAL -- : [18ca5a07-0693-4dd5-8be1-ac3c7c5ea47d]
F, [2019-04-17T02:04:34.642973 #7612] FATAL -- : [18ca5a07-0693-4dd5-8be1-ac3c7c5ea47d] devise (4.5.0) lib/devise/models/rememberable.rb:118:in `remember_me?'
[18ca5a07-0693-4dd5-8be1-ac3c7c5ea47d] devise (4.5.0) lib/devise/models/rememberable.rb:143:in `serialize_from_cookie'
[18ca5a07-0693-4dd5-8be1-ac3c7c5ea47d] devise (4.5.0) lib/devise/strategies/rememberable.rb:22:in `authenticate!'
[18ca5a07-0693-4dd5-8be1-ac3c7c5ea47d] warden (1.2.8) lib/warden/strategies/base.rb:54:in `_run!'
[18ca5a07-0693-4dd5-8be1-ac3c7c5ea47d] warden (1.2.8) lib/warden/proxy.rb:369:in `block in _run_strategies_for'
[18ca5a07-0693-4dd5-8be1-ac3c7c5ea47d] warden (1.2.8) lib/warden/proxy.rb:365:in `each'
[18ca5a07-0693-4dd5-8be1-ac3c7c5ea47d] warden (1.2.8) lib/warden/proxy.rb:365:in `_run_strategies_for'
[18ca5a07-0693-4dd5-8be1-ac3c7c5ea47d] warden (1.2.8) lib/warden/proxy.rb:335:in `_perform_authentication'
[18ca5a07-0693-4dd5-8be1-ac3c7c5ea47d] warden (1.2.8) lib/warden/proxy.rb:110:in `authenticate'
[18ca5a07-0693-4dd5-8be1-ac3c7c5ea47d] warden (1.2.8) lib/warden/proxy.rb:120:in `authenticate?'

ローカルのクッキーを削除

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

bundle installすると"can't find gem bundler…"というエラーが発生

bundle installでエラーが出る

エラー内容

bundle installを実行したところ、
find_spec_for_exe': can't find gem bundler (>= 0.a) (Gem::GemNotFoundException)
というエラーが発生してbundleinstallできない。

原因

rubyとbundlerのバージョンに注意!

rubygemとbundlerのバージョンの組み合わせによって発生するエラーらしい。

解決法

  • bundlerのバージョンを下げる

最新ではなく少し前のバージョンを指定してinstallしてあげる。

$ gem install bundler -v '1.17.3'

そもそもの確認

  • rubyとbundlerの場所を確認する。

rubyとbundlerが片方ローカルを参照していて、もう片方はグローバルを参照しているなど、そもそもローカルにgemが入っていなかったケース。

$ which ruby
/Users/hoge/.rbenv/shims/ruby
$ which bundler
/Users/hoge/.rbenv/shims/bundler

参考

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

【初心者向け】1番初めにやる、Ruby on Rails環境構築(Mac)

はじめに

Railsチュートリアル以降ずっとcloud9で開発してきましたが、cloud9上のエラーに時間を使ってしまったり、読み込みが遅かったり、業務に支障が出たりするので、流石にそろそろ1からしっかりと開発環境を作ってみようと思います。

環境構築

①Command Line Toolsインストール

コマンドラインツールとは、プログラミングの環境を構築したり実際にプログラムを実行したりする際に、コマンドを入力して操作ができるアプリケーション、CUI(キャラクターユーザーインターフェース)のことです。

(↔︎マウスなどで操作する通常アプリケーション:GUI(グラフィカルユーザーインターフェース)

Xcodeのバージョンが6.1以降の場合、Command Line Toolsは自動的にインストールされるので、Xcodeをダウンロードしていきます。

①Appleの「developerアカウント」にログイン
②『Download Tools』へ
③「Xcode」ダウンロード

ちなみにXcodeは、
・テキストエディタ
・インターフェースの作成(Interface Builder)
・デバッグ
・ビルド
・テスト
・シミュレーター(iOS Simulator)
・ソースの管理
などの必須機能を備えたものです。

②Homebrewインストール

Homebrewとは、Mac OS Xオペレーティングシステム上でソフトウェアの導入を単純化するパッケージ管理システムのひとつです。

①あるかどうか確認(Xcodeが入ればHomebrewも入っているはず)

$ brew -v

②念のためアップデート

$ brew update

③rbenvインストール

rbenvとは、~/.rbenv/以下で、インストールした様々なRubyバージョンを管理し、状況に応じて必要になるRubyのバージョンを簡単に切り替えてくれるコマンドラインツールです。

①あるかどうか確認

$ rbenv -v

②念のためアップデート

$ brew upgrade rbenv

③無ければインストール

$ brew install rbenv ruby-build

④Rubyの最新バージョンをインストール

①インストール可能なRubyのバージョンを確認

$ rbenv install --list

②現時点で最新の「2.7.0-dev」を入れる

$ rbenv install 2.7.0-dev
$ rbenv global 2.7.0-dev
$ rbenv rehash

③バージョンが反映されているか確認

$ ruby -v

⑤Bundlerインストール

Bundlerとは、gem同士の互換性を保ちながらパッケージの種類やバージョンを管理してくれるgemです。
複数人、または複数環境で開発を行う際、各環境で使用するものに合わることができます。

Ruby2.6.0よりBundlerは標準添付されてるので、上記の通りやっていれば既にインストールされているはずです。

①念のため確認

$ bundle -v

②念のためアップデート

$ gem update bundler

③無ければインストール(Ruby2.5.5以前を使用していた場合、等)

$ gem install bundler

⑥MySQLインストール

(SQLiteを使用する場合この設定は不要です)

MySQLとは、世界で最も利用されているデータベース管理システムです。

LAMP環境(「Linux」+「Apache」+「MySQL」+「PHP(またはRuby)」)でサーバーを構築する企業が多く、よく利用されています。

①MySQLをインストール

$ brew install mysql

②起動

$ mysql.server start

Starting MySQL
. SUCCESS! 

⑦Railsインストール

最後です。
GemfileにRailsを加え、インストールしていきます。
これができて、晴れて画面表示されます。

①作業するディレクトリを作成

$ mkdir ~/workspace
$ cd ~/workspace

②Rubyのバージョンを指定

$ rbenv local 2.7.0-dev

作業ディレクトリに.ruby-versionファイルが作成される

③Gemfileを作成する

$ bundle init

④Gemfile内の「# gem "rails"」のコメント解除

# frozen_string_literal: true

source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

gem "rails"

⑤Railsをインストール

$ bundle install --path=vendor/bundle
$ bundle exec rails -v
Rails 5.2.3

⑥Railsアプリ作成

$ bundle exec rails new test_app

⑦Webサーバー起動

$ rails server

http://localhost:3000/ へアクセス
下記の画面が表示されれば成功です。
スクリーンショット 2019-04-16 16.17.18.png

⑨※サーバーが立ち上がらない

railsはしっかり入っているのに、rails serverを実行すると

$ rails server
Rails is not currently installed on this system. To get the latest version, simply type:

    $ sudo gem install rails

You can then rerun your "rails" command.

と出て実行してくれませんでしたが、

下記を実行した後に無事動くようになりました。

$ gem install railties
$ rbenv rehash

上の画像が表示されました!!

参考

最速!MacでRuby on Rails環境構築
Ruby初学者のRuby On Rails 環境構築【Mac】
railsコマンドが使えないときにやったこと

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

RailsにRspecをいれてモデルのテストを書いてみよう[初心者向け]

こんにちは。
エンターシェアでエンジニアとして働いているじゅん(@BoNingennnN)です。

Railsでは標準でminitestが入ってきます。
しかし、弊社ではminitestを使わずRSpecを使っています。
また、個人プロジェクトでもRSpecを使っています。

今回はRailsプロジェクトにRSpecを導入する方法を説明し、そしてテストの手始めとしてモデルのテストを書いていこうと思います!

まずはRailsプロジェクトにRSpecを導入しよう

既存のプロジェクトにRspecを導入する際には、既存のtestを削除する必要があります。
まずtestディレクトリを削除しましょう。

続いてRspecのgemをいれていきます

Gemfile
group :development, :test do
  gem 'rspec-rails'
end
bundle install

もしまだ既存のプロジェクトでtest用のdbを作成していない場合はそれを作成します。
config/database.ymlにtest用の記述があることを確認したら以下のコマンドを打ちましょう

rails db:create

これでtest用のdbの作成が完了です。
続いてRspecの導入を進めます。
以下のコマンドでRspecの設定ファイルなどを生成しましょう。

rails g rspec:install

ここはお好みになりますが、testの実行結果が見やすいように以下の記述を.rspec内に書いておくといいです。

.rspec
 --format documentation

これでRspecの導入は完了しました!
早速以下のコマンドを実行してテストを実行しましょう。

bundle exec rspec

結果は、、

No examples found.
Finished in 0.00079 seconds (files took 0.25041 seconds to load)
0 examples, 0 failures

大成功です。
まだテストを書いていないので、0 expamleです。
exampleはテストの数、failuresは通らなかったテストの数を返します。
まだテストを書いていないので、もちろんexample、failures共に0です。

では続いて超初歩的なモデルのテストを書いていきましょう。

モデルのテストをRspecで書こう

ここからはモデルのテストを書きます。
ここではすでにPostモデルがあると仮定します。
(ここは各自のアプリケーションにあるモデルと置き換えて考えてください?‍♂️)

post.rb
class Post < ApplicationRecord
  validates :title, presence: true, length: {maximum: 20}
  validates :content, presence: true

  def content_length
    self.content.length
  end
end

こんな単純なモデルはありえないですが、入門ということで簡単なモデルにしました。

既存のモデルのテストを作るには以下のコマンドを実行します。

rails g rspec:model post

すると以下のファイルが生成されます。

spec/models/post_spec.rb
require 'rails_helper'

RSpec.describe Post, type: :model do
  pending "add some examples to (or delete) #{__FILE__}"
end

ここで先ほどと同様にtestを実行してみましょう。

bundle exec rspec

すると先ほどとは異なる出力が見られます。

Pending: (Failures listed here are expected and do not affect your suite's status)

  1) Post add some examples to (or delete) /Users/junya/workspace/myprojects/rails-rspec-test/spec/models/post_spec.rb
     # Not yet implemented
     # ./spec/models/post_spec.rb:4


Finished in 0.00684 seconds (files took 4.16 seconds to load)
1 example, 0 failures, 1 pending

注目して欲しいのは、exmapleが0から1に変わった部分です。
これは先ほど生成したpost_spceを生成したからです。
pendingとなっているのは、「このテストは一旦後回しにしますよー」という意味です。
生成されるspecファイルは、初期でpendingとなっています。
この部分を実際に書き換えていきましょう!

と、その前にまずモデルテストでテストすべきことを書いていきます。
基本的には、そのモデルのバリデーションのテストを書きます。
さらに、そのモデルがインスタンスメソッドを持っているのであればそのテストも書きますし、クラスメソッドを持っていればクラスメソッドのテストも書きます。また、scopeに関するテストももちろん必要です。

今回の例だと、バリデーションとインスタンスメソッドがあるので、それぞれのテストを書いていきます。

バリデーションのテストを書いてみる

早速バリデーションのテストを書いていきましょう。

post_spec.rb
require 'rails_helper'

RSpec.describe Post, type: :model do
  it "is valid with title and content" do
    post = Post.new(title: "test", content: "testcontent")
    expect(post).to be_valid
  end
end

先ほどpendingと書かれていた部分を削除し、実際にテストを書いてみました。
テストを書く際には

it "テストの内容の説明" do
  テストの処理
end

という形で書きます。
モデルテストを書く際には、まずちゃんとバリデーションが通ること(be_valid)をテストします。
ここでテストを実際に実行してみましょう。

bundle exec rspec

出力は以下のようになります。

.

Finished in 0.01384 seconds (files took 3.45 seconds to load)
1 example, 0 failures

見事に1exampleが実行され、failure(テストの失敗)は0です!
ここで一度テストをわざと失敗させてみましょう。

先ほど作成したテストの中身を少し書き換えてみます。

post_spec.rb
require 'rails_helper'

RSpec.describe Post, type: :model do
  it "is valid with title and content" do
    post = Post.new(title: "test", content: "testcontent")
    expect(post).not_to be_valid #toからnot_toに変更
  end
end

そしてテストを実行してみると、、、

F

Failures:

  1) Post is valid with title and content
     Failure/Error: expect(post).not_to be_valid
       expected #<Post id: nil, title: "test", content: "testcontent", created_at: nil, updated_at: nil> not to be valid
     # ./spec/models/post_spec.rb:6:in `block (2 levels) in <top (required)>'

Finished in 0.0629 seconds (files took 3.57 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/models/post_spec.rb:4 # Post is valid with title and content

見事に1example 1failureになっています!
テストが失敗したことがわかるかと思います。
こんな感じで、もし通らないテストがあるとちゃんと表示されます。

先ほど変更した部分を元に戻したら、バリデーションテストの続きを書いていきましょう。

今回のPostモデルには3つのバリデーションがあります。
・titleが存在すること
・titleの最大文字数は20文字
・contentが存在すること

それらのバリデーションのテストを実際に書いていきます

post_spec.rb
  it "is invalid without title" do
    post = Post.new(title: nil)
    post.valid?
    expect(post.errors[:title]).to include("can't be blank")
  end

  it "is invalid withoug content" do
    post = Post.new(content: nil)
    post.valid?
    expect(post.errors[:content]).to include("can't be blank")
  end

titleとcontentのpresence: trueのバリデーションのテストをまず書きました。
もしtitleがnilなら「titleは空欄じゃダメですよ」っていうエラーがあるよね、ということをテストしています。(contentも同様)
このパターンはバリデーションのテストの際によく出てくるパターンです。

続いて文字数の部分のテストを書きます。

post_spec.rb
  it "is invalid when title is more than 20 characters" do
    post = Post.new(title: ("a" * 21))
    post.valid?
    expect(post.errors[:title]).to include("is too long (maximum is 20 characters)")
  end

21文字だとエラーが出るよね、ということをテストしています。
本来だったら20文字の場合はエラーだなくてvalidだよねというのもテストした方が良さそうですが、ずいぶん長くなってきたので割愛します。

以上がバリデーションのテストです。
バリデーションのテストは結構パターンがあるので慣れればすんなり書けます。
また、バリデーションをうっかり忘れていた、なんてことも気付けたりしますので、そういう意味でもバリデーションテストはしっかり書いておいたほうがいいです。

インスタンスメソッドのテストを書いてみる

続いてインスタンスメソッドのテストも書いてみます。
今回の例だと、

post.rb
  def content_length
    self.content.length
  end

このcontent_lengthというインスタンスメソッドのテストを書きます。
インスタンスメソッドやクラスメソッドでは、適当に入力する値をいれ、その出力が正しいかをテストします。
と言ってもよく分からないかもしれないので、実際にコードを書いていきましょう。

post_rspec.rb
  it "returns length of content" do
    post = Post.create(title: "test", content: ("a" * 100))
    expect(post.content_length).to eq(100)
  end

なんとなく見ればわかるかと思いますが、contentが100文字なpostを作成し、
post.content_lengthが100と等しいことをテストしています。
これは非常に簡単な例ですが、複雑になってきても基本はこれです。
こんな感じでどんどんインスタンスメソッドやクラスメソッドのテストも書いていきましょう!!

さいごに

本当はもっと複雑なメソッドのテスト等も書きたかったのですが、最初から難しいめのテストを書くと挫折してしまう可能性があると思ったので、今回は超簡単なものだけにしました。
(本当はただ書くのが面倒くさかっただけかもです。笑)

今回の例は初歩の初歩で、factory_botも使っていませんし、モデル以外のテストも全く出てきませんでした。
実際のプロジェクトでテストを書くとなると、学ぶべきことは他にも色々ありますが、とりあえずはこのモデルの基本的なテストを書けるようになっておけばあとは色々ググりながらどうにかなるかと思います!

もし今担当しているプロジェクトや、個人開発のプロジェクトでテストを書いていないのであれば、まずはモデルテストから書いてみてください!

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

【学習アウトプット3】has_secure_passwordとvalidates :password, presence: trueの違い

背景

has_secure_passwordを設定したUserモデル

user.rb
class User < ApplicationRecord
  has_secure_password

が、以下のテスト

user_controller_test.rb
test "password should be exist when create" do
  @user.password = " "
  assert_not @user.valid?
end

で引っかかってしまう問題に悩んでいました。
(has_secure_passwordは空白にvalidationがかかると思っていたため https://qiita.com/Shantti-Y/items/19ea23b81f3421063fc5)

validates :password, presence: trueをつけるとテストをパスします。
じゃあ、has_secure_passwordのデフォルトvalidationとは一体...:rolling_eyes:

結論

Rails 4.2から以下のように変更されていたとのことです。

has_secure_password がデフォルトで空白のパスワードを許容するようになりました (例: 空白スペースのみのパスワード)。 https://railsguides.jp/4_2_release_notes.html

空白を許可したくない場合は別途validates :password, presence: true等の追加が必要みたいです。

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

devise(メール承認付き)のパラメータをコンソールで直接編集する

deviseで新規userを登録する

user.skip_confirmationでメール承認をスキップできる。

user = User.new(email: "hogehoge@mail.co.jp", password: "hogehoge")
user.skip_confirmation!
user.save

既存のuserを編集する

user.reconfirmationでメール承認をスキップする。

user = User.find_by(email: "hogehoge@mail.co.jp")
user.email = "fugafuga@mail.com"
user.skip_reconfirmation!
user.save
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rubyは最後に評価された式が戻り値になるというが、どのif文にも入らなかったらどうなるのか

経緯

  • Rubyを学び始めた頃のコードを直しているのですが、Javaエンジニアだったためかメソッド内に無駄なreturn文が多いです。
  • 直す最中に表題の件について気になったので、Rails cを使って試し、またRailsのビューから呼ばれた時はどうなるのかについても試してみました。

修正前

  • ひどい書き方ですね。。。
game.rb
  def get_msg
    msg = ""
    if self.gameset_flag
      if get_sum_top == get_sum_bottom #同クラス内の別のインスタンスメソッドを呼んでいます
        msg = "(引き分け)"
      elsif !self.top6
        msg = "(5回コールド)"
      elsif !self.top7
        msg = "(6回コールド)"
      elsif !self.top8
        msg = "(7回コールド)"
      elsif !self.top9
        msg = "(8回コールド)"
      end
    end
    return msg
  end

修正後

  • このメソッドをビューから呼んだ時に、どのif文にも入らなかった場合は、ちゃんと空文字で画面表示できるのか気になっていました。
game.rb
  def get_msg
    if self.gameset_flag
      if get_sum_top == get_sum_bottom #同クラス内の別のインスタンスメソッドを呼んでいます
        "(引き分け)"
      elsif !self.top6
        "(5回コールド)"
      elsif !self.top7
        "(6回コールド)"
      elsif !self.top8
        "(7回コールド)"
      elsif !self.top9
        "(8回コールド)"
      end
    end
  end

Rails c で動かしてみる

  • コード修正は今回の主旨ではないため、修正後のコードのみで試します。
irb(main):001:0> game = Game.new
(出力省略)
irb(main):002:0> game.get_sum_top
=> 0
irb(main):003:0> game.get_sum_bottom
=> 0

irb(main):004:0> game.gameset_flag = false
=> false
irb(main):005:0> game.get_msg
=> nil

irb(main):006:0> game.gameset_flag = true 
=> true
irb(main):007:0> game.get_msg
=> "(引き分け)"
  • どのif文にも入らない場合は、最初のif文の条件式が最後に評価されたことになります。
  • つまり self.gameset_flagnil ということで nil が返って来ているのがわかります。

画面表示はどうなる

  • 実際の画面キャプチャは貼れないのですが、結論としては問題ありませんでした(空文字がreturnされていた頃と表示に変化なし)。
  • つまり、修正前のコードのように、どのif文にも入らなかった時のための変数の初期化は不要ということになります(もちろん設計上空文字を返却する必要がある場合は、メソッドの最終行に空文字を書いて、空文字が最後に評価されるようにすると良いと思います)。

参考

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