20200318のRubyに関する記事は17件です。

【12日目】jQuery(animate) Ruby(表示,変数,if)

はじめに

こんばんは。
progate jQuery終了しました!

さっそくRubyに入っています。
では、本日のまとめをしたいと思います。

本日の学び

  • progate jQuery 上級 ページ内の移動
  • progate Ruby1

jQuery

animateメソッド

$('.social-icon').hover( //マウスを乗せた時
  function(){
    $(this).animate({ //アニメーションを付ける
    'font-size':'30px' //どうなるのか
  },300);
},

scrollTopメソッド

$('#top-btn').click(function(){ //クリックしたとき
    $('html, body').animate({ //htmlとbody
      'scrollTop':0        //ページ最上部
    }, 500);
  });

$('header a').click(function(){ //クリックしたとき
    var id = $(this).attr('href'); //クリックしたhrefを変数idとし、
    var position = $(id).offset().top; //idのとび先の最上部を変数positionとし
    $('html, body').animate({ //htmlとbodyの
      'scrollTop':position   //positionの位置に移動
    },500);

Ruby

コンソール

puts "hellow World"
#putsの後は半角スペース
#文字列は""で囲う

puts "こんにちは#{name}さん"
#変数を文字列に入れ込む場合

変数

name = "John"
#変数の後に書いたコードに反映される
#前のコードには影響無し
#2単語以上は_で区切る

数式

X = X + 10
X += 10
#同意味

if文 真偽値

score=94
if score >= 80
 puts "頑張ったね"
elsif 条件2
 処理2
else
 処理3
end

puts score > 80 #真偽
true #結果

所感

Rubyに初めて触れましたが、コードがシンプルで分かりやすい印象を受けました。
まだ単純なコードですが、コードのルールが他の言語より覚えやすいですね。

ここからどのような使い方をするか言語の役割を意識しつつ、
勉強していこうと思います。

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

ローカルで行った変更点が本番環境に反映されない時の対処法

せっかくローカルで変更して上手くいっても、本番環境で変化がなければなんの意味もありません。

今回、ローカルホストではしっかり変わっているにも関わらず、本番環境(capistranoで自動デプロイ時)に反映されない時の対処法を書いていきます。

結論「unicornをkill」しましょう。

unicornをkillする手順

1.ターミナル

[ec2-user@本番環境 <リポジトリ名>]$ ps aux | grep unicorn

こちらをしていただくと

ec2-user 17877  0.4 18.1 588472 182840 ?       Sl   01:55   0:02 unicorn_rails master -c config/unicorn.rb -E production -D
ec2-user 17881  0.0 17.3 589088 175164 ?       Sl   01:55   0:00 unicorn_rails worker[0] -c config/unicorn.rb -E production -D
ec2-user 17911  0.0  0.2 110532  2180 pts/0    S+   02:05   0:00 grep --color=auto unicorn

このように表記されると思います。

一番上の行の5桁の数字(PID)をkillします。

kill -9 上記で確認したPID

あとはもう一度デプロイ するだけ

でも、毎回デプロイ のたびにこれをするのは手間ですよね。

なので、デプロイ 時に自動でunicornをkillしてstartしてくれる記述を書きましょう。

config/deploy.rb

after 'deploy:publishing', 'deploy:restart'
namespace :deploy do
  task :restart do
    invoke 'unicorn:stop'
    invoke 'unicorn:start'
  end

  desc 'upload master.key'
  task :upload do
    on roles(:app) do |host|
      if test "[ ! -d #{shared_path}/config ]"
        execute "mkdir -p #{shared_path}/config"
      end
      upload!('config/master.key', "#{shared_path}/config/master.key")
    end
  end
  before :starting, 'deploy:upload'
  after :finishing, 'deploy:cleanup'
end

こちらの

namespace :deploy do
  task :restart do
    invoke 'unicorn:stop'
    invoke 'unicorn:start'
  end

このように記述することで、デプロイ 時に自動でunicornを再起動してくれます。

私のような誰かの助けになれば幸いです!!!

それではまたどこかで^^

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

Mysql2::Error

MySQLが起動しない。

エラー内容

Mysql2::Error::ConnectionError (Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)):

前日まで問題なくRailsの勉強をしていました。作成したアプリケーションを確認するために

rails s

するとエラーがでました。

仮説

MySQLへアクセスするためのsockファイルを見つけれずアクセスできない。

トラブル解決手順

1.ターミナルに下記のコードを入力しデータベースの中身を見る。

$ ls -la /usr/local/var/mysql/

すると

total 380944
drwxr-xr-x  66 _mysql  _mysql      2112  3 17 23:50 .
drwxrwxr-x   4 user    admin        128 12 12 00:27 ..
drwx------  11 _mysql  _mysql       352  1 26 17:54 DataBaseDesignSample_development
drwx------   3 _mysql  _mysql        93  1 26 17:15 DataBaseDesignSample_test
drwx------   9 _mysql  _mysql       283  2 11 19:28 ajax_development
drwx------   3 _mysql  _mysql        36  2 11 19:27 ajax_test
-rw-rw----   1 _mysql  _mysql        56 12 12 00:30 auto.cnf
-rw-r-----   1 _mysql  _mysql         0  2 15 15:53 binlog.index

上記のような感じで表示される。

2.次に下記のコードを入力

$ ls -la /usr/local/var/

実行すると下記のような表示が出る。問題なさそう.....

drwxrwxr-x   4 user    admin    128 12 12 00:27 .
drwxr-xr-x  13 root    wheel    430  1 31 21:15 ..
drwxrwxr-x   4 user    admin    128 12 12 00:03 homebrew
drwxr-xr-x  36 _mysql  _mysql  3112  3 17 23:50 mysql

3.このコードを入力するとエラーが解決!

$ sudo mysql.server start
Starting MySQL
... SUCCESS! 

ちなみに下記のコードではエラーの解決にはいたりませんでした。

$ mysql.server restart

最後に

同じ初学者の方は似たようなエラーで悩まされてると思います。
restartではなくstartと入力すること、初めにsudoと入力することでもっと強力な指令となるみたいです。
同じエラーで困る人のお役に立てればと思い投稿しました。
初学者の皆さん一緒に頑張りましょう!

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

Kinx プレビュー版リリース

Kinx プレビュー版のリリース

はじめに

「見た目は JavaScript、頭脳(中身)は Ruby、(安定感は AC/DC)」でお送りするスクリプト言語 Kinx。まだまだ途中だがリリースするのも意味があるだろうとの想定から、実行可能な形でパッケージングし、まずはプレビュー・リリースすることにしました。Windows 版の実行ファイルはアイコンもつけていい感じ。Linux は /usr/bin にインストールしてしまうので、一応気にしておいてください。

本題

↓ここです。

もちろん、git clone して make もできます。

本題、おしまい。

振り返り

元々はこの記事での「プログラマに馴染むシンタックスってのは C 系だよね、でも何で Ruby も Python も全然違うのでしょう」というところから始まった今回のプロジェクト。プロジェクト自体は去年末くらいから実質スタートしてたので、約 5 ヶ月くらいか。

元々からしてほぼ JavaScript な文法なので、作りながらではあるものの、既にすっかり私の手には馴染んでます。

まだ初版にはできませんが(おっとさっき気づいたのだが標準入力がない...)、結構色々試せるとは思います。

ほんのちょっと興味があれば

何か試してみてフィードバック貰えると非常に嬉しい。まぁ、既存の何かを置き換えるようなたいそうなモノではないので、ちょっとした提案とかこんなんあるといいんじゃない、とか、そういうライトな感じのご意見ください。

すみません、見返りはあまり無いと思います…。そういうの楽しめる方か、面白そうだと思ってくださる方向け。

おわりに

最後はいつもの以下の定型フォーマットです。

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

【rails db:createエラー】dependent dylib '/usr/local/opt/mysql/lib/libssl.1.1.dylib' not found for '/Library/Ruby/Gems/2.6.0/gems/mysql2-0.5.3/lib/mysql2/mysql2.bundle'

エラーをいろいろ試して解決しました。(めちゃくちゃな解決法ですが初心者なのでご容赦ください)

エラー内容

$ rails db:create

したところ

LoadError: dlopen(/Library/Ruby/Gems/2.6.0/gems/mysql2-0.5.3/lib/mysql2/mysql2.bundle, 0x0009): dependent dylib '/usr/local/opt/mysql/lib/libssl.1.1.dylib' not found for '/Library/Ruby/Gems/2.6.0/gems/mysql2-0.5.3/lib/mysql2/mysql2.bundle' - /Library/Ruby/Gems/2.6.0/gems/mysql2-0.5.3/lib/mysql2/mysql2.bundle

のエラーが発生。
'/usr/local/opt/mysql/lib/libssl.1.1.dylib'のファイルが無い?と書いてありました。

解決方法

他の方の参考にはあまりならないかもしれません。。。

homebrewでmysqlをインストールすれば、/usr/local/opt/mysql/lib/libssl.1.1.dylibファイルができると思い、
https://qiita.com/narikei/items/cd029911597cdc71c516
を参考に

$ brew install mysql
$ mysql.server start
$ bundle init
$ bundle install --path=vendor/bundle

を実施しました。

その後、アプリ内で改めて

$ rails db:create

したら、

Could not find mysql2-0.5.3 in any of the sources
Run `bundle install` to install missing gems.

というエラーが出たので、

$ bundle install

したら、

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

のエラーが出ました。
https://qiita.com/fukuda_fu/items/463a39406ce713396403
を参考に

$ bundle config --local build.mysql2 "--with-cppflags=-I/usr/local/opt/openssl@1.1/include"
$ bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl@1.1/lib"
$ bundle install

したところ、成功しました。改めて、

$ rails db:create

したところ、

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

のエラーが出たので、
https://qiita.com/carotene4035/items/e00076fe3990b9178cc0
を参考に

$ touch /tmp/mysql.sock
$ mysql.server restart

をした後

$ rails db:create

で無事にデータベースが作成できました。

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

Psych::SyntaxErrorの対処法

エラーの内容

s3に画像をアップさせる関係で、secrets.ymlを書き換えたら、rails sで以下のエラーが出た。

`parse': (<unknown>): did not find expected key while parsing a block mapping at line 13 column 1 (Psych::SyntaxError)

解決した方法

上記のエラーについて調べたところ、検索で上位表示される記事のほとんどで、ymlファイルのインデントがずれていることによるエラーが出ると書いてあった。

そこで、筆者はVScodeを利用していることから、(command)+Pを用いて、.ymlのつくファイルを検索しインデントのずれを探した。

まあ、.ymlファイルをいじったことは記憶に新しかった(s3関連でいじってる)ので、secrets.ymlをまず確認したところ、development、test、productionが全てずれていた。

これを戻し、rails sをし直すと、、、

できた!!!!!

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

【Rails】URLテキストにaタグを自動でつける

はじめに

ユーザーがフォームに投稿したURLテキストに自動でaタグをつけて表示できたらなーーと調べていたら、uriライブラリーのおかげでとても簡単にできたので、備忘録としてまとめます。

uriライブラリーを読み込む

Rubyの標準ライブラリーとして'uri'というURIを扱う標準ライブラリ-があるので、読み込みます。
https://docs.ruby-lang.org/ja/latest/class/URI.html

app/helpers/application_helper.rb
require "uri"

ヘルパーメソッドを作成

uriライブラリーを読み込んだapplication_helper.rbでメソッドを作成します。

app/helpers/application_helper.rb
require "uri"
#追加
def text_url_to_link(text)

  URI.extract(text, ['http', 'https']).uniq.each do |url|
    sub_text = ""
    sub_text << "<a href=" << url << " target=\"_blank\">" << url << "</a>"

    text.gsub!(url, sub_text)
  end

  return text
end
  1. URI.extractで、httpもしくはhttpsで始まるtextを url として取り出し、sub_text という変数に代入

2.
gsub!メソッドで textをsub_textに変換

3.
変換したtextを返す

該当のviewに表示させる

URLテキストにaタグをつけて表示させたい部分に、以下のように先ほど作成したメソッドを使用して、表示させます。

app/views/sample.html.erb
<%= text_url_to_link(h(該当する変数)).html_safe %>

これで、無事にURLテキストに自動でaタグをつけて表示してくれるようになります。

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

railsで学ぶテスト処理(rails チュートリアルで学んだことをまとめてみました)

この記事の説明について

この記事ではrails チュートリアルで学んだことを私なりにまとめてみました。
理解の浅い部分がありますので、間違いがある場合はどうぞご教授ください。

テストとは

開発をしながら、動作するかテストすること

テストの種類

・モデルテスト→モデルが機能している
・機能テスト→コントローラーとビューの連携
・統合テスト→ユーザー目線でうまく動作するか、全体的にテストって感じ?

それぞれ別のテストファイルにテストを書く

assert 内容 →内容通りならば成功、でなければ失敗

assert not 内容 →内容通りでなければ成功、内容通りならば失敗

assertに関してはこちらのサイトがわかりやすかったです。
Rails チュートリアル 【初心者向け】 テストを10分でおさらいしよう!

主な流れ

まず開発する前にテストの内容をtestfileに記述する
(ここで書くテスト内容はまだやっていない開発内容に関する事→開発しないとテストは成功しない)

開発をする(テストが成功する予定)

自動でテストor手動でコンソール内でrails test

補足

全てのtestはtest_helperを導入している
test_helperはtestディレクトリーの中にある。
test_helperの中にはtestで使う関数を書いている。
またapplication_helperをtest _helperの中に導入することで、実際の開発環境で使っている関数(例 login関数)をtestで使用できるようになる。

自動テスト

その中でも開発と同時並行で自動でテストする方法がある。開発で変更を加えるたびに自動でテストを子なってくれる。

自動テストを導入するためには
テストを自動でやってくれるGuardを取り入れる

Guard fileに自動テストするように指示を書く
詳しくはRuby on Rails チュートリアル

注意
Guardを使うときにspringという機能を使う
しかしspringがgitとの競合をしないように、.git ignoreファイルに、springを書きgitリポジトリに保存されないようにする

モデルテスト

モデル名test.rbに記述するテスト。(例 test/models/usertest.rb)

rails g model ~でモデルが作られると
testディレクトリにそのモデルのためのテストができる

書き方
まずモデルのインスタンスを作成する(主にseup関数で行う)

そのインスタンスが機能しているかや、複数のインスタンスの関係性が機能しているかなど確認する。

test/models/user_test.rb
require 'test_helper'

class UserTest < ActiveSupport::TestCase

  def setup #インスタンス作成
    @user = User.new(name: "Example User", email: "user@example.com")
  end

  test "name should be present" do
    @user.name = "     "
    assert_not @user.valid? #このテストの場合Userファイルで書いたvalidateが発動しているかテストしている
  end
end

機能テスト

controller_test.rbに記述するテスト。

rails g controller ~でコントローラーが作られると
testディレクトリにそのコントローラーのためのテストができる

書き方
まず必要な処理をsetupで書く

どのアクションを発動させるためにどのURLを発信するかを書き、assert関数でテスト内容を書く

test/controllers/users_controller_test.rb
require 'test_helper'

class UsersControllerTest < ActionDispatch::IntegrationTest

  def setup
  
  
  end

  test "should get new" do
    get users_new_url
    assert_response :success
  end
end

統合テスト

test/integration/統合テスト名_test.rbに記述するテスト。

rails g integration_test 〜でtestディレクトリに作られる。

書き方
まず必要な処理をsetupで書く

どのアクションを発動させるためにどのURLへ発信するかを書き、assert関数でテスト内容を書く
様々なURLへ発信して、如何にも実際に手で動かしているテストのように行う。

test/integration/microposts_interface_test.rb
require 'test_helper'

class MicropostsInterfaceTest < ActionDispatch::IntegrationTest

  def setup
  
  
  end

  test "micropost interface" do
  get root_path
  assert ...
  
  
  post microposts_path ...
  assert ...
  
  
  end
機能テストとの違いは一つのコントローラー内でのテストではなく、いろんなコントローラーに繋いでどうなるかなどをテストできる?

以下のサイトでいう結合テスト(内部)が機能テストで結合テスト(外部が)統合テスト?
単体テスト・結合テスト・総合テストの違い、観点や注意点を簡単に説明する

デバッグとは

デバッグとはバグをとる事

どんなバグが起きているか実行結果から知りたい場合

開発環境のみで、全てのレイアウトでparamsの中身が見れるようにする。
debug(params)とする→これでparamsの中身を見るという指示になる
applicationHTMLで共通レイアウトを作るときに、if文で開発環境にのみバクの内容が見れるようにする
詳しくはRuby on Rails チュートリアル

補足

fixturesとは

テストで使うためのデータベースにあるデータとして記述される。

ログインを実践する統合テストをしたい時
test.fixturesファイルに、ログインユーザーの情報を置く。ここにはテストで使用するユーザーの情報を置く

統合テスト
詳しくはRuby on Rails チュートリアルでfixtureで検索

テストで作ったインスタンスの値を知りたい時

テスト内で
assigns(インスタンス変数).データカラムとするとアクセスできる。
詳しくはRuby on Rails チュートリアルでassignsで検索

参考文献

参考文献:
Rails チュートリアル
Railsガイド
Ruby on Rails5 アプリケーションプログラミング
単体テスト・結合テスト・総合テストの違い、観点や注意点を簡単に説明する
Rails チュートリアル 【初心者向け】 テストを10分でおさらいしよう!

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

railsで学ぶテスト処理(rails チュートリアル)

この記事の説明について

この記事ではrails チュートリアルで学んだことを私なりにまとめてみました。
理解の浅い部分がありますので、間違いがある場合はどうぞご教授ください。

テストとは

開発をしながら、動作するかテストすること

テストの種類

・モデルテスト→モデルが機能している
・機能テスト→コントローラーとビューの連携
・統合テスト→ユーザー目線でうまく動作するか、全体的にテストって感じ?

それぞれ別のテストファイルにテストを書く

assert 内容 →内容通りならば成功、でなければ失敗

assert not 内容 →内容通りでなければ成功、内容通りならば失敗

assertに関してはこちらのサイトがわかりやすかったです。
Rails チュートリアル 【初心者向け】 テストを10分でおさらいしよう!

主な流れ

まず開発する前にテストの内容をtestfileに記述する
(ここで書くテスト内容はまだやっていない開発内容に関する事→開発しないとテストは成功しない)

開発をする(テストが成功する予定)

自動でテストor手動でコンソール内でrails test
で成功する

必要ならばリファクタリング

リファクタリングしてもエラー出ないかテスト

補足

全てのtestはtest_helperを導入している
test_helperはtestディレクトリーの中にある。
test_helperの中にはtestで使う関数を書いている。
またapplication_helperをtest _helperの中に導入することで、実際の開発環境で使っている関数(例 login関数)をtestで使用できるようになる。
詳しくはRuby on Rails チュートリアル

自動テスト

その中でも開発と同時並行で自動でテストする方法がある。開発で変更を加えるたびに自動でテストを行ってくれる。

自動テストを導入するためには
テストを自動でやってくれるGuardを取り入れる

Guard fileに自動テストするように指示を書く
詳しくはRuby on Rails チュートリアル

注意
Guardを使うときにspringという機能を使う
しかしspringがgitとの競合をしないように、.git ignoreファイルに、springを書きgitリポジトリに保存されないようにする

モデルテスト

モデル名test.rbに記述するテスト。(例 test/models/usertest.rb)

rails g model ~でモデルが作られると
testディレクトリにそのモデルのためのテストができる

書き方
まずモデルのインスタンスを作成する(主にseup関数で行う)

そのインスタンスが機能しているかや、複数のインスタンスの関係性が機能しているかなど確認する。

test/models/user_test.rb
require 'test_helper'

class UserTest < ActiveSupport::TestCase

  def setup #インスタンス作成
    @user = User.new(name: "Example User", email: "user@example.com")
  end

  test "name should be present" do
    @user.name = "     "
    assert_not @user.valid? #このテストの場合Userファイルで書いたvalidateが発動しているかテストしている
  end
end

機能テスト

controller_test.rbに記述するテスト。

rails g controller ~でコントローラーが作られると
testディレクトリにそのコントローラーのためのテストができる

書き方
まず必要な処理をsetupで書く

どのアクションを発動させるためにどのURLを発信するかを書き、assert関数でテスト内容を書く

test/controllers/users_controller_test.rb
require 'test_helper'

class UsersControllerTest < ActionDispatch::IntegrationTest

  def setup
  
  
  end

  test "should get new" do
    get users_new_url
    assert_response :success
  end
end

統合テスト

test/integration/統合テスト名_test.rbに記述するテスト。

rails g integration_test 〜でtestディレクトリに作られる。

書き方
まず必要な処理をsetupで書く

どのアクションを発動させるためにどのURLへ発信するかを書き、assert関数でテスト内容を書く
様々なURLへ発信して、如何にも実際に手で動かしているテストのように行う。

test/integration/microposts_interface_test.rb
require 'test_helper'

class MicropostsInterfaceTest < ActionDispatch::IntegrationTest

  def setup
  
  
  end

  test "micropost interface" do
  get root_path
  assert ...
  
  
  post microposts_path ...
  assert ...
  
  
  end
機能テストとの違い

違いは一つのコントローラーのアクション内でのテストではなく、rootingを通して様々なコントローラーに繋いでどうなるかなどをテストできる?
以下のサイトでいう結合テスト(内部)が機能テストで結合テスト(外部が)統合テスト?
単体テスト・結合テスト・総合テストの違い、観点や注意点を簡単に説明する

単体テスト

上記のテストでは実施しにくいテスト
helpersの中で書くことが多い?
例: 関数で読み出された文字列に誤字がないかとか

デバッグとは

デバッグとはバグをとる事

どんなバグが起きているか実行結果から知りたい場合

開発環境のみで、全てのレイアウトでparamsの中身が見れるようにする。
debug(params)とする→これでparamsの中身を見るという指示になる
applicationHTMLで共通レイアウトを作るときに、if文で開発環境にのみバクの内容が見れるようにする
詳しくはRuby on Rails チュートリアル

補足

fixturesとは

テストで使うためのデータベースにあるデータとして記述される。

ログインを実践する統合テストをしたい時
test.fixturesファイルに、ログインユーザーの情報を置く。ここにはテストで使用するユーザーの情報を置く

統合テスト
詳しくはRuby on Rails チュートリアルでfixtureで検索

テストで作ったインスタンスの値を知りたい時

テスト内で
assigns(インスタンス変数).データカラムとするとアクセスできる。
詳しくはRuby on Rails チュートリアルでassignsで検索

テストファイルのsetup関数で変数を作り、テストに採用したいときには変数は@が頭についておかないといけない。

test/controllers/static_pages_controller_test.rb
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
    assert_select "title", "Home | #{@base_title}"
  end

参考文献

参考文献:
Rails チュートリアル
Railsガイド
Ruby on Rails5 アプリケーションプログラミング
単体テスト・結合テスト・総合テストの違い、観点や注意点を簡単に説明する
Rails チュートリアル 【初心者向け】 テストを10分でおさらいしよう!

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

Docker環境にSystem Specを導入する

はじめに

Docer環境でRSpecのSystem Specを導入しようとしたところ、結構ハマったので、備忘録としてまとめます。

まず、Docer環境にSystem Specを実行するためには、いくつか方法があるらしい。
調査をしていると、メジャーな方法は以下の二つ(もっとあるかもしれませんが、、、)

1. Railsが動いているimageにchromeをインストールする方法
2. chrome用コンテナを立ち上げる方法

今回は2の方法でやってみました。

前提

Quickstart: Compose and Railsの通りに、Rails on Dockerの環境構築が済んでいる状態とします。
筆者の環境は
- Ruby 2.5.7
- Rails 5.2.4
です。

docker-compose.ymlを編集する

selenium_chromeのコンテナが立ち上がるようdocker-compose.ymlに追加していきます。
Dockerイメージにはselenium/standalone-chromeを使用します。

docker-compose.yml
version: '3'
services:
  db:
    image: postgres
    volumes:
      - ./tmp/db:/var/lib/postgresql/data
  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    depends_on:
      - db
      #追加
      - chrome
  #追加
  chrome:
    image: selenium/standalone-chrome:3.141.59-dubnium
    ports:
      - 4444:4444

gemを追加する

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

group :test do
  gem 'capybara', '>= 2.15'
  gem 'selenium-webdriver'
end

dockerをbuildして、bundle installします。

$ docker-compose build
$ docker-compose up -d

rspecの設定

rspecをインストールします。

$ docker-compose run web rails g rspec:install

headless chromeの設定

spec/rails_helper.rbにheadless chromeの設定を追加していきます。

/spec/rails_helper.rb
require 'capybara/rspec'

# headless chrome 設定①
Capybara.server_host = Socket.ip_address_list.detect { |addr| addr.ipv4_private? }.ip_address
Capybara.server_port = 3001   

Capybara.register_driver :selenium_remote do |app|
  url = "http://chrome:4444/wd/hub"
  opts = { desired_capabilities: :chrome, browser: :remote, url: url }
  Capybara::Selenium::Driver.new(app, opts)
end


 # headless chrome 設定②
RSpec.configure do |config|

  config.before(:each, type: :system) do
    driven_by :rack_test
  end

  config.before(:each, type: :system, js: true) do
    driven_by :selenium_remote
    host! "http://#{Capybara.server_host}:#{Capybara.server_port}"
  end
end

ポイント:
後半部分(# headless chrome 設定②)で、
js: trueを記述した場合のみ、seleniumドライバーが立ち上がるように設定しています。

ハマったポイント:
js: trueのテストを走らせたとき、Capybaraがseleniumサーバーを立ち上げて、先ほど設定したchromeコンテナで起動しているchromeを操作します。
しかし、Capybara.server_portを指定する部分(*)で、webコンテナで指定したポートと同じ3000を指定してしまうと、js: trueのテストを走らせたときに、webコンテナで指定したポートと競合してseleniumサーバーが立ち上がらずエラーとなってしまいます。
そこで、Capybara.server_port = 3000 3001
とすることで、競合することなく、無事サーバーが立ち上がり、テストが通るようになりました。

これで準備は整いました。
あとは、テストを実際に走らせるだけです。

実際にテストを走らせてみる

spec/system/test_spec.rb
require "rails_helper"

RSpec.describe 'Test', type: :system, js: true do
  example 'サンプルテスト' do
    #ここにテスト内容を記述
  end
end
$ docker-compose exec web bundle exec rpsec

これで、テストが通るはずです。

参考記事

下記の記事を参考にさせていただきました。
ありがとうございます。
- Docker で RSpec の System Spec を実行するための設定メモ
- Rails + Selenium + DockerでSystemSpecの環境構築
- Rails on Dockerにて、Headless ChromeでSystem Testをやってみた。

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

休日ならtrue、平日ならfalseを返すrubyメソッド

今日は、平日ならfalse、休日ならtrue値をとして返すメソッドを書いていきたいと思います。

呼び出し方:
sleep_in(weekday, vacation)

出力例:
sleep_in(false, false) → True
sleep_in(true, false) → False
sleep_in(false, true) → True

こちらを作っていきます。

まずはコードから

def sleep_in(is_weekday, is_vacation)
  if (is_weekday != true) || (is_vacation == false)
    puts "True"
  else
    puts "False"
  end
end


is_weekday = true
is_vacation = false

sleep_in(is_weekday,is_vacation)

細かくみていきます。

def sleep_in(is_weekday, is_vacation)
  if (is_weekday != true) || (is_vacation == false)
    puts "True"
  else
    puts "False"
  end
end

こちらで、メソッドsleep_inを定義しています。
引数にis_weekdayと、is_vacationをとっています。

メソッド内では、if文により条件分岐をしており、is_weekdayがtrueではないまたはis_vacationがfalseの時となっています。

つまり

is_weekdayがtrueの時もしくは
is_vacationがfalseの時にこのif文はtrueを返すようになっています。

is_weekday = true
is_vacation = false

こちらでは引数にtureとfalseを代入しています。

sleep_in(is_weekday,is_vacation)

ここでメソッドを呼び出しています。

以上で、weekdayつまり平日(ここではtrueを代入)がtrueでない時、vacationつまり休日(ここではfalseを代入)がfalseの時にTrueを返すメソッドが完成します。

今日はここまでで、失礼します^^

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

Gemfileにおける「>= 」と「~>」の違い

背景

Rails初心者の備忘録のため

基礎情報

gem 'sqlite3'

gemコマンドで特定のバージョン番号を指定しない限り、Bundlerは自動的に最新バージョンのgemを取得してインストールする

「>=」について

gem 'uglifier', '>= 1.3.0'

uglifierのバージョンが1.3.0以上であれば最新バージョンのgemがインストールされる。(uglifierはAsset Pipelineでファイル圧縮を行うgem)

「~>」について

gem 'coffee-rails', '~> 4.0.0'

coffee-railsのバージョンが4.0.0より大きく、4.1より小さい場合にインストールされる。 (これもAsset Pipelineで使うgem)

使い分けの理由

マイナーアップグレードですら問題を引き起こすことがあるから。

すべてRailsチュートリアルからの抜粋。完全に備忘録です

参照
https://railstutorial.jp/chapters/beginning?version=5.1#cha-beginning

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

学習記録 #1

cccscscscscscs

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

rails検索機能追加

はじめに

今回は投稿されたマイクロポストを入力された文字からあいまい検索する機能を追加します。

作るもの

railsのform_withヘルパーを利用した投稿の検索機能。(題材は自分のポートフォリオ)

対象読者

railsチュートリアル終了後等に何か機能を追加したい人等。

作成の流れ

1.対応するビューの作成
2.コントローラーの編集

1.対応するビューの作成

今回は検索フォームをroot_path上に設けます。(自分のポートフォリオがマイクロポストの一覧をroot_path(static_pages/home)に設けているため)

app/views/static_pages/home.html.erb
<%= form_with( url: root_path, class: 'search_form', method: :get, local:true) do |f| %>
  <%= f.text_field :search,class: 'field',value: params[:search]\
  placeholder: "スレ・コメント検索"%>
<%= f.submit '検索', class: "btn" %>

form_withを利用して検索フォームを作ります。各値は
url:root_path検索後に表示するページ
method:get(httpメゾット。今回はページの取得なのでget)
local:true(ajax処理(非同期通信)を無効にする。デフォルトではajaxで処理する。)
text_field: search 入力フォームになります。
value: params[:search]と値を設定しておくことで検索後も値を保持します。(URLのクエリから取得。)
あとはget動作を開始させるsubmitを配置します。

検索ボタンを押せばurlのページを表示しようとするので検索の処理は対応するコントローラーのアクション内に書きます。

2.コントローラーの編集

コントローラーで送られた値を処理しますが、コントローラー内に処理を全て書くとごちゃごちゃしてしまいますのでDBとやりとりをする箇所はmodel側で記述します。

app/controller.rb
    @microposts =  params[:search].present? ? Micropost.micropost_serach(params[:search]) :  Micropost.all

@microposts = params[:search].present?で値がsearchに値が入っているか(検索ボタンが押されているか)
値が入っていればmicropost_serachを動作させます。(中身は後ほどmodelに記載)値が入ってなければ、Micropost.allで全てのマイクロポストを表示させます。(そのあとは適宜ページネーション等に渡してください。)
ではmicropost_serachの中身です。

app/model/micropost.rb
def self.micropost_serach(search)
    Micropost.where(['title LIKE ?', "%#{search}%"])
end

whereメゾットとLIKE旬でマイクロポストの中からあいまい検索をします。

モデル名.where([カラム名前 LIKE ?, "検索したい文字列"])

検索したい文字列の両サイドにある「%」は任意の複数の文字列を表しています。
上記のは一つしかカラムを指定していませんが複数指定することもできます。

app/model/micropost.rb
def self.micropost_serach(search)
    Micropost.where(['title LIKE ? OR content LIKE ?', "%#{search}%", "%#{search}%"])
end

複数のカラムを指定する場合はカラム数に応じてORやANDで繋ぎ、検索したい文字列を増やしてあげると検索できます。

今回はさらに、マイクロポストにコメントされた文章も含めて検索してみます。
コメント機能についてこちら
https://qiita.com/E6YOteYPzmFGfOD/items/ef776d34908872ea19f7

app/model/micropost.rb
def self.micropost_serach(search)
    Micropost.includes(:comments).where(['microposts.title LIKE ? OR microposts.content LIKE ? OR comments.content LIKE ?',
    "%#{search}%", "%#{search}%", "%#{search}%"]).references(:comments)
end

これでコメント内も合わせて検索できるようになりました

#終わりに
最後までお読みいただきありがとうございました。検索文はいろいろパターンがあるので今後も新しい物を書いたときには記事にしてみようと思います。
ありがとうございました。

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

ツイッター風Railsアプリ最短復習(忙しい人の流し読みで開発シリーズ)

はじめに

こんにch… え?忙しい?? んじゃぁスタート!!!

具体的な手順

完成品GitHub

①アプリ立ち上げ

Terminal
$ cd Desktop
$ rails _5.2.4.1_ new cheaptweet -d mysql
$ cd cheaptweet
$ rails db:create
$ rails s
webBrowser
localhost:3000

rails.png

②テーブル作成

cheaptweet.jpeg

Gemfile
# 省略
gem 'devise'
Terminal
$ bundle install
$ rails g devise:install

control + c
$ rails s

$ rails g devise user
db/migrate/2020xxxxxxxxx_devise_create_users.rb
# 省略
 t.string :nickname,           null: false
# 省略
Terminal
$ rails db:migrate

aa.png

Terminal
$ rails g model tweet
db/migrate/2020xxxxxxxxxxxx_create_tweets.rb
# 省略
 t.string :text, null: false
 t.references :user, foreign_key: true, null: false
# 省略
Terminal
$ rails db:migrate

text.png

app/models/user.rb
#省略
 validates :nickname ,presence: true
 has_many :tweets
#省略
app/models/tweet.rb
#省略
 validates :text ,presence: true
 belongs_to :user
#省略

③会員登録・ログイン・ログアウトのみの基本循環構築

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

  protected
  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:nickname])
  end
end
Terminal
$ rails g devise:views
app/views/devise/registrations/new.html.erb
<!--省略-->
<div class="field">
  <%= f.label :nickname %><br />
  <%= f.text_field :nickname, autofocus: true %>
</div>
<!--省略-->
<!--  他の autofocus: true を削除 -->
Terminal
$ rails g controller tweets index
config/routes.rb
# get 'tweets/index'

#    |
#    v

resources :tweets, only: [:index]
root 'tweets#index'
#省略
app/views/layouts/application.html.erb
<!--省略-->
<body>
<!--↓追記↓----------------------------------------------->
  <header style="height: 50px; background-color: grey;">
    <% if user_signed_in? %>
      <%= current_user.nickname %>
      <%= link_to "ログアウト", destroy_user_session_path, method: :delete %>
    <% else %>
      <%= link_to "ログイン", new_user_session_path %>
      <%= link_to "会員登録", new_user_registration_path %>
    <% end %>
    <%= link_to "トップへ", root_path, style:"float: right;" %>
  </header>
<!--↑追記↑---------------------------------------------->
  <%= yield %>
</body>
<!--省略-->
app/views/tweets/index.html.erb
<div>※確認用</div>

main1.png main2.png
sign_up.png
login.png

④投稿(new→create)

config/routes.rb
# resources :tweets, only: [:index]

#    |
#    V

resources :tweets, only: [:index, :new, :create]
#省略
app/controllers/tweets_controller.rb
class TweetsController < ApplicationController
  def index
  end
####↓追記↓################################################
  def new
    @tweet = Tweet.new
  end
  def create
    @tweet = Tweet.new(tweet_params)
    if @tweet.save
      redirect_to root_path
    else
      render action: :new
    end
  end
  private
  def tweet_params
    params.require(:tweet).permit(:text).merge(user_id: current_user.id)
  end
####↑追記↑#################################################
end
new.html.erb
<%= form_with(model: @tweet, local:true) do |f| %>
  <%= f.text_area :text %>
  <%= f.submit '投稿' %>
<% end %>
app/views/layouts/application.html.erb
<!--省略-->
<body>
  <header style="height: 50px; background-color: grey;">
    <% if user_signed_in? %>
      <%= current_user.nickname %>
<!--↓追記↓----------------------------------->
      <%= link_to "投稿", new_tweet_path %>
<!--↑追記↑----------------------------------->
      <%= link_to "ログアウト", destroy_user_session_path, method: :delete %>
    <% else %>
      <%= link_to "ログイン", new_user_session_path %>
      <%= link_to "会員登録", new_user_registration_path %>
    <% end %>
  </header>
  <%= yield %>
</body>
<!--省略-->

hellob.png
hello.png

⑤一覧(index)

app/controllers/tweets_controller.rb
#省略
def index
####↓追記↓#####################################################
  @tweets = Tweet.all.includes(:user).order("created_at DESC")
####↑追記↑#####################################################
end
#省略
app/views/tweets/index.html.erb
× <div>※確認用</div>

<!--     |     -->
<!--     V     -->

<% @tweets.each do |t| %>
  <div><span style="color: red;"><%= t.user.nickname %></span><%= t.text %></div>
<% end %>

index.png
includesなし              includesあり
back1.png back2.png

⑥詳細(show)・編集(edit→update)・削除(destroy)

config/routes.rb
# resources :tweets, only: [:index, :new, :create]

#    |
#    V

resources :tweets
#省略
app/controllers/tweets_controller.rb
#省略
def show
  @tweet = Tweet.find(params[:id])
end
#省略
app/views/tweets/index.html.erb
×  <div><span style="color: red;"><%= t.user.nickname %></span><%= t.text %></div>

<!--    |    -->
<!--    V    -->

<div><%= link_to tweet_path(t.id) do %><span style="color: red;"><%= t.user.nickname %></span><%= t.text %><% end %></div>
app/views/tweets/show.html.erb
<div><span style="color: red;"><%= @tweet.user.nickname %></span><%= @tweet.text %></div>
<%= link_to "編集",  edit_tweet_path(@tweet.id) %><%= link_to "削除",  tweet_path(@tweet.id),method: :delete  %>
app/controllers/tweets_controller.rb
#省略
def edit
  @tweet = Tweet.find(params[:id])
end
def update
  @tweet = Tweet.find(params[:id])
  if @tweet.update(tweet_params)
    redirect_to tweet_path(params[:id])
  else
    render action: :edit
  end
end
def destroy
  @tweet = Tweet.find(params[:id])
  @tweet.delete
  redirect_to root_path
end
#省略
app/views/tweets/edit.html.erb
<%= form_with(model: @tweet, local:true) do |f| %>
  <%= f.text_area :text %>
  <%= f.submit '投稿' %>
<% end %>

削除後確認画面が欲しければ、

app/controllers/tweets_controller.rb
#省略
def destroy
  @tweet = Tweet.find(params[:id])
  @tweet.delete
#  redirect_to root_path
end
#省略
app/views/tweets/destroy.html.erb
<div>削除しました</div>
<%= link_to "トップに戻る", root_path %>

⑦編集・削除の権限設定

app/views/tweets/show.html.erb
× <%= link_to "編集",  edit_tweet_path(@tweet.id) %><%= link_to "削除",  tweet_path(@tweet.id),method: :delete %>

<!--    |    -->
<!--    V    -->

<% if user_signed_in? && current_user.id == @tweet.user_id %>
  <%= link_to "編集",  edit_tweet_path(@tweet.id) %><%= link_to "削除",  tweet_path(@tweet.id),method: :delete %>
<% end %>
app/controllers/tweets_controller.rb
class TweetsController < ApplicationController
####↓追記↓###############################################
  before_action :unless_signin, only: [:new, :create,]
  before_action :unless_mytweet, only: [:edit, :update, :destroy]
####↑追記↑###############################################

#省略

  private

#省略

####↓追記↓###############################################
  def unless_signin
    redirect_to tweets_path unless user_signed_in?
  end
  def unless_mytweet
    redirect_to tweets_path unless user_signed_in? && current_user.id == Tweet.find(params[:id]).user.id
  end
####↑追記↑###############################################
end

⑧一覧ページネーション

Gemfile
#省略
gem 'kaminari'
Terminal
$ bundle install
Terminal
control + c
$ rails s
# @tweets = Tweet.all.includes(:user).order("created_at DESC")

#    |
#    V

@tweets = Tweet.includes(:user).order("created_at DESC").page(params[:page]).per(5)
app/views/tweets/index.html.erb
<!--省略-->
<%= paginate(@tweets) %>

⑨コメント機能

cheaptweet (2).jpeg

Terminal
$ rails g model comment
db/migrate/2020xxxxxxxx_create_comments.rb
#省略
  t.string :text, null: false
  t.references :user, foreign_key: true, null: false
  t.references :tweet, foreign_key: true, null: false
#省略
Terminal
$ rails db:migrate

comment.png

app/models/user.rb
#省略
 has_many :comments
#省略
app/models/tweet.rb
#省略
 has_many :comments
#省略
app/models/comment.rb
#省略
 validates :text, presence: true
 belongs_to :user
 belongs_to :tweet
#省略
config/routes.rb
# resources :tweets

#    |
#    V

resources :tweets do
  resources :comments, only: :create
end
app/controllers/tweets_controller.rb
#省略
def show
  @tweet = Tweet.find(params[:id])
####↓追記↓#############################################
  @comment = Comment.new
  @comments = Comment.where(tweet_id: params[:id]).order("created_at DESC").page(params[:page]).per(5)
####↑追記↑#############################################
end
#省略
Terminal
$ rails g controller comments
app/controllers/comments_controller.rb
class CommentsController < ApplicationController
  def create
    redirect_to tweets_path unless user_signed_in?
    @comment = Comment.new(params_comment)
    @comment.save
    redirect_to tweet_path(params[:tweet_id])
  end
  private
  def params_comment
    params.require(:comment).permit(:text).merge(user_id: current_user.id, tweet_id: params[:tweet_id])
  end
end
app/views/tweets/show.html.erb
<!--省略-->
<% if user_signed_in? %>
  <%= form_with(model: [@tweet, @comment], local: true) do |f| %>
    <%= f.text_area :text %>
    <%= f.submit 'コメント'%>
  <% end %>
<% end %>
<% if @comments %>
  <% @comments.each do |c| %>
    <div><span style="color: blue;"><%= c.user.nickname %></span><%= c.text %></div>
  <% end %>
  <%= paginate(@comments) %>
<% end %>

come.png

⑩ユーザー投稿一覧

Terminal
$ rails g controller users show
config/routes.rb
# devise_for :usersより下に
#省略
resources :users, only: :show
#省略
app/controllers/users_controller.rb
class UsersController < ApplicationController
  def show
    @tweets = Tweet.where(user_id: params[:id]).order("created_at DESC").page(params[:page]).per(5)
    @nickname = User.find(params[:id]).nickname
  end
end
app/views/layouts/application.html.erb
× <%= current_user.nickname %>

<!--      |       -->
<!--      V       -->

<%= link_to user_path(current_user.id) do %><%= current_user.nickname %><% end %>
app/views/tweets/index.html.erb
× <div><%= link_to tweet_path(t.id) do %><span style="color: red;"><%= t.user.nickname %></span><%= t.text %><% end %></div>

<!--      |       -->
<!--      V       -->

<div><%= link_to user_path(t.user.id),style:"color: red;" do %><%= t.user.nickname %><% end %><%= link_to tweet_path(t.id) do %><%= t.text %><% end %></div>
app/views/tweets/show.html.erb
× <div><span style="color: red;"><%= @tweet.user.nickname %></span><%= @tweet.text %></div>

<!--      |       -->
<!--      V       -->

<div><%= link_to user_path(@tweet.user.id),style:"color: red;" do %><%= @tweet.user.nickname %><% end %><%= @tweet.text %></div>
app/views/users/show.html.erb
<p><%= @nickname %>の投稿一覧</p>
<% @tweets.each do |t| %>
  <div><%= link_to tweet_path(t.id) do %><%= t.text %><% end %></div>
<% end %>
<%= paginate(@tweets) %>

anna.png

⑪検索機能

Terminal
rails g controller tweets::searches
config/routes.rb
#省略
 namespace :tweets do
   resources :searches, only: :index
 end
#省略
# resources :tweets do より上に
app/models/tweet.rb
#省略
  def self.search(search)
    if search
      Tweet.where('text LIKE(?)', "%#{search}%").includes(:user)
    else
      Tweet.all.includes(:user)
    end
  end
#省略
app/controllers/tweets/searches_controller.rb
class Tweets::SearchesController < ApplicationController
  def index
    @tweets = Tweet.search(params[:keyword]).order("created_at DESC").page(params[:page]).per(5)
  end
end
app/views/tweets/index.html.erb
<%= form_with(url: tweets_searches_path, local: true, method: :get) do |f| %>
  <%= f.text_field :keyword %>
  <%= f.submit "検索" %>
<% end %>
<!-- 省略 -->
app/views/tweets/searches/index.html.erb
<%= form_with(url: tweets_searches_path, local: true, method: :get) do |f| %>
  <%= f.text_field :keyword %>
  <%= f.submit "検索" %>
<% end %>
<% @tweets.each do |t| %>
  <div><%= link_to user_path(t.user.id),style:"color: red;" do %><%= t.user.nickname %><% end %><%= link_to tweet_path(t.id) do %><%= t.text %><% end %></div>
<% end %>
<%= paginate(@tweets) %>

まとめ

網羅的でいい教材ですね。

これで難しい場合は以下をまわってみてください。

超最低限のRailsアプリを丁寧に作る(もう一度きちんと復習して初心者を卒業しよう)
『メッセージを投稿』できる最低限のRailsアプリを丁寧に作る(これで初心者完全卒業!)

次のレベルに行きたければ以下に行ってみてください。

『メッセージと複数画像の投稿』ができる最低限のRailsアプリを丁寧に作る
『2ページ遷移して会員登録』できる最低限のRailsアプリを丁寧に作る(deviseをウィザード形式に拡張)
『非同期でのメッセージ投稿』が理解できる最低限のRailsアプリを丁寧に作る(Ajax苦手の自分とお別れしよう)

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

RspecでProcess.fork内のメソッドを検証したい

fork内のメソッドコールを単純に検証するとうまくいかない

こんなクラスがあるときに

class Dog
  def crow(str)
    p str
  end

  def walk
    Process.fork do
      crow('bowbow!')
    end
  end
end

walkメソッド内でcrowメソッドが呼び出されていることを検証しようとしてこんなspecを書いてみるとうまく通りません

  let(:dog) { Dog.new }

  it {
    expect(dog).to receive(:crow).with('bowbow!').once
    dog.walk
  }
Failures:

  1) Dog is expected to receive crow("bowbow!") 1 time
     Failure/Error: expect(dog).to receive(:crow).with('bowbow!').once

       (#<Dog:0x00005571aad36820>).crow("bowbow!")
           expected: 1 time with arguments: ("bowbow!")
           received: 0 times

forkブロック内は別プロセスなので検証できないのですね。

結論

こういう場合はProcessをmock化してしまうのが手っ取り早いようです。

  let(:dog) { Dog.new }

  it {
    expect(Process).to receive(:fork) do |&block|
      expect(dog).to receive(:crow).with('bowbow!').once
      block.call
    end

    dog.walk
  }

expect_any_instance_of も利用できます

  let(:dog) { Dog.new }

  it {
    expect(Process).to receive(:fork) do |&block|
      expect_any_instance_of(Dog).to receive(:crow).with('bowbow!').once
      block.call
    end

    dog.walk
  }

引数の検証がちゃんとできているのか確認するためにあえて間違った引数を検証してみます。

  let(:dog) { Dog.new }

  it {
    expect(Process).to receive(:fork) do |&block|
      expect(dog).to receive(:crow).with('purrr').once
      block.call
    end

    dog.walk
  }
Failures:

  1) Dog is expected to receive crow("purrr") 1 time
     Failure/Error: crow('bowbow!')

       #<Dog:0x00005588d1a8ed78> received :crow with unexpected arguments
         expected: ("purrr")
              got: ("bowbow!")

ちゃんと検証してくれているようです。

参考

https://stackoverflow.com/a/6159391

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

[Rails]hamlでのform_with/form_for/form_tagの書き方

はじめに

hamlでのformの書き方がまとまっていなかったのでまとめる

form_tagform_forRails5.1で非推奨となっており、将来的にform_withに置き換えられる予定です。
極力、Rails5.1以上form_withの使用を推奨します。

Railsのformの種類

1. form_tag

  • 関連するモデルがない時に使用する(検索機能など)
  • inputタグを用いる(ビルドヘルパーを用いない)
<%= form_tag users_path do %>
  <%= text_field_tag :email %>
  <%= submit_tag %>
<% end %>

2. form_for

  • 関連するモデルがある時に使用する(投稿機能など)
  • ビルドヘルパー(form.xxxx)を用いる
<%= form_for @user do |form| %>
  <%= form.text_field :email %>
  <%= form.submit %>
<% end %>

3. form_with

  • Rails5.1以上は問答無用で ###form_tag/form_forとの違い
  • form_withで自動でパスが選択されるので、HTTPメソッド(getpostなど)を指定する必要が無い
  • コントローラーから渡されたActiveRecordを継承するモデルのインスタンスが利用できる
  • form_withは、form_forとform_tagの機能を組み合わせたもの、とイメージすると分かりやすい
#関連するモデルがない場合 → urlの指定のみで、modelの記述がない
<%= form_with url: users_path do |form| %>
  <%= form.text_field :email %>
  <%= form.submit %>
<% end %>
#関連するモデルがある場合 → modelの記述のみで、urlの指定は不要
<%= form_with model: @user do |form| %>
  <%= form.text_field :email %>
  <%= form.submit %>
<% end %>

hamlでの書き方

この記事のメインはこちら

form_tag

ビルドヘルパー(f.text_fieldなど)は記述しない点に注意

= form_tag users_path do 
  = text_field_tag :email
  = submit_tag

form_for

= form_for @user do |f|
  = f.text_field :email
  = f.submit

form_with

#関連するモデルがない場合 → urlの指定のみで、modelの記述がない
= form_with url: users_path do |f|
  = f.text_field :email
  = form.submit
#関連するモデルがある場合 → modelの記述のみで、urlの指定は不要
= form_with model: @user do |f|
  = form.text_field :email
  = form.submit

参考記事

【Rails】form_for/form_tagの違い・使い分けをまとめた
【Rails 5】(新) form_with と (旧) form_tag, form_for の違い

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