RailsAPIモードを使っているときにrequest_specでログイン・ログアウトを実装

こんにちは!kossyです!



さて、今回はRailsAPIモードで認証機能周りのrequest_specでログイン・ログアウト状態を再現したい時の方法を
ブログに残してみたいと思います。




環境
Rails 5.1.6
Ruby 2.5.1
rspec 3.8.0
devise_token_auth 1.1.3




support直下にmoduleを定義したファイルを作成し、rails_helper.rbに読み込ませるだけ



supports直下にファイルを作成します。

spec/supports/authentication_helper.rb(名前は任意)

module AuthenticaitionHelper
  HTTP_HELPERS_TO_OVERRIDE = [:get, :post, :patch, :put, :delete]

  # ログイン状態にする
  def login(user)
    @user = user
    @auth_token = @user.create_new_auth_token # devise_token_authのメソッド 参考: https://www.rubydoc.info/gems/devise_token_auth/0.1.37/DeviseTokenAuth%2FConcerns%2FUser:create_new_auth_token
  end

  # ログアウトする
  def logout
    @user = nil
    @auth_token = nil
  end

  # 参考: https://gist.github.com/blaze182/3a59a6af8c6a7aaff7bf5f8078a5f2b6
  HTTP_HELPERS_TO_OVERRIDE.each do |helper| # 定数に対して繰り返し処理を実行
    define_method(helper) do |path, **args| # def get(path) のようなメソッドを動的に定義 
      add_auth_headers(args) # privateメソッドの呼び出し
      args == {} ? super(path) : super(path, **args) # argumentsが空ハッシュなら定義元のメソッドを実行、空でなければ定義元のメソッドをargumentsを引き連れて実行
    end
  end

  private
   # tokenをセットするprivateメソッド
    def add_auth_headers(args)
      return unless defined? @auth_token # @auth_tokenが定義されていなければ処理終了 https://www.xmisao.com/2014/03/30/checking-if-a-variable-is-defined.html
      args[:headers] ||= {} # args[:headers]がnilなら{}を代入
      args[:headers].merge!(@auth_token) # args[:headers]に@auth_tokenを代入
    end

end

作ったモジュールをrails_helper.rbで読み込む記述を追加します。

RSpec.configure do |config|

  省略

  Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f } #support directoryをrequire
  config.include AuthenticationHelper, type: :request #type: :requestのときにRequestHelperをinclude
end


これで例えばFactoryBot等でuserを定義している場合、

user = FactoryBot.create :user
login user

等でログイン状態を再現できます。





参考にさせていただいた記事
type: :requestのテストでsign_in/sign_outする - Qiita

Railsのgem 'active_hash'で都道府県データを作成してみた

こんにちは!kossyです!





さて、今回はRailsでモデルに都道府県データを持たせずに、
active_hashで持たせる方法について、ブログに残してみたいと思います。




環境
Rails 5.2.3
Ruby 2.6.3
MacOS Mojave
active_hash 2.2.0

事前準備

例によってプロジェクトを新規作成して試してみます。

$ rails new active_hash_test

$ cd active_hash_test

次にactive_hashを導入します。

./Gemfile

gem 'active_hash'

で、bundle install。

$ bundle install



次にモデルを作成します。

$ rails g model Address prefecture_id:integer city:string

Running via Spring preloader in process 21996
      invoke  active_record
      create    db/migrate/20190108110055_create_addresses.rb
      create    app/models/address.rb
      invoke    test_unit
      create      test/models/address_test.rb
      create      test/fixtures/addresses.yml

そのままrails db:migrateします。

$ rails db:create
$ rails db:migrate

次はモデル周りを記述します。





Addressモデルの編集とPrefectureモデルの作成

まず、Prefectureモデルを作成してみます。
モデルの作成、と言うと、rails g modelしたくなりますが、
今回はActiveHash::Baseを継承したPrefectureモデルを自作します。
ActiveHash::Baseを継承したモデルを作成すると、ActiveRecordのメソッド(allとか)が使えるようになります。
他にどんなメソッドが使えるようになるか気になる人は、下の手順でPrefectureモデルを定義して、コンソールで、

$ Prefecture.methods

と入力してみてください。




以下実装です。

app/models/prefecture.rb

class Prefecture < ActiveHash::Base
  self.data = [
      {id: 1, name: '北海道'}, {id: 2, name: '青森県'}, {id: 3, name: '岩手県'},
      {id: 4, name: '宮城県'}, {id: 5, name: '秋田県'}, {id: 6, name: '山形県'},
      {id: 7, name: '福島県'}, {id: 8, name: '茨城県'}, {id: 9, name: '栃木県'},
      {id: 10, name: '群馬県'}, {id: 11, name: '埼玉県'}, {id: 12, name: '千葉県'},
      {id: 13, name: '東京都'}, {id: 14, name: '神奈川県'}, {id: 15, name: '新潟県'},
      {id: 16, name: '富山県'}, {id: 17, name: '石川県'}, {id: 18, name: '福井県'},
      {id: 19, name: '山梨県'}, {id: 20, name: '長野県'}, {id: 21, name: '岐阜県'},
      {id: 22, name: '静岡県'}, {id: 23, name: '愛知県'}, {id: 24, name: '三重県'},
      {id: 25, name: '滋賀県'}, {id: 26, name: '京都府'}, {id: 27, name: '大阪府'},
      {id: 28, name: '兵庫県'}, {id: 29, name: '奈良県'}, {id: 30, name: '和歌山県'},
      {id: 31, name: '鳥取県'}, {id: 32, name: '島根県'}, {id: 33, name: '岡山県'},
      {id: 34, name: '広島県'}, {id: 35, name: '山口県'}, {id: 36, name: '徳島県'},
      {id: 37, name: '香川県'}, {id: 38, name: '愛媛県'}, {id: 39, name: '高知県'},
      {id: 40, name: '福岡県'}, {id: 41, name: '佐賀県'}, {id: 42, name: '長崎県'},
      {id: 43, name: '熊本県'}, {id: 44, name: '大分県'}, {id: 45, name: '宮崎県'},
      {id: 46, name: '鹿児島県'}, {id: 47, name: '沖縄県'}
  ]
end


app/models/address.rb

class Address < ApplicationRecord
  extend ActiveHash::Associations::ActiveRecordExtensions
  belongs_to_active_hash :prefecture
end

belongs_to_active_hashメソッドでアソシエーションも組めるってわけです。
extend ActiveHash::Associations::ActiveRecordExtensionsしないとprefectureモデルを使えません。
詳しく知りたい方はGemの中を覗いてみてください。
参考: active_hash/associations.rb at master · zilkey/active_hash · GitHub




これで準備完了です。
では、コンソールで試してみます。

$ rails c

# 以下はログです

[1] pry(main)> @address_1 = Address.create(prefecture_id: 1, city: '函館市')                                                                                       
   (0.2ms)  SAVEPOINT active_record_1
  Address Create (41.0ms)  INSERT INTO `addresses` (`prefecture_id`, `city`, `created_at`, `updated_at`) VALUES (1, '函館市', '2019-01-08 11:41:41', '2019-01-08 11:41:41')
   (0.3ms)  RELEASE SAVEPOINT active_record_1
=> #<Address:0x00007fc9f8cbf420
 id: 1,
 prefecture_id: 1,
 city: "函館市",
 created_at: Tue, 08 Jan 2019 11:41:41 UTC +00:00,
 updated_at: Tue, 08 Jan 2019 11:41:41 UTC +00:00>
[2] pry(main)> @address_2 = Address.create(prefecture_id: 13, city: '新宿区新宿')                                                                                        
   (0.3ms)  SAVEPOINT active_record_1
  Address Create (0.3ms)  INSERT INTO `addresses` (`prefecture_id`, `city`, `created_at`, `updated_at`) VALUES (13, '新宿区新宿', '2019-01-08 11:42:05', '2019-01-08 11:42:05')
   (0.2ms)  RELEASE SAVEPOINT active_record_1
=> #<Address:0x00007fc9f8a7cb40
 id: 2,
 prefecture_id: 13,
 city: "新宿区新宿",
 created_at: Tue, 08 Jan 2019 11:42:05 UTC +00:00,
 updated_at: Tue, 08 Jan 2019 11:42:05 UTC +00:00>
[3] pry(main)> @address_1.prefecture.name                                                                                                                                
=> "北海道"
[4] pry(main)> @address_2.prefecture.name                                                                                                                                
=> "東京都"

って感じで、prefecuture_idにPrefectureモデルに定義したハッシュのidを渡して、@address.prefecture.nameで名前を取れちゃいます。
もちろんPrefecture.find でハッシュを取ってこれます。

都道府県を選択するセレクトボックスを生成したい時は、

# hamlで書いてます

= f.collection_select :prefecture_id, Prefecture.all, :id, :name

って感じで、
f:id:kossy-web-engineer:20190307221245p:plain
こんな感じで設定できます。

検索機能も、詳細はこちらの記事に譲るとして、
Rails初心者が「form_with」を使って検索機能を実装してみた。 - Qiita
form_with でシンプルなサーチフォームを作成する | deadwood


f:id:kossy-web-engineer:20190512134125p:plain
こんな感じのチェックボックス式の検索フォームがあったとして、

view

<%= f.collection_check_boxes :prefecture_id, Prefecture.all, :id, :name %>

controller

@results = Address.where('prefecture_id IN(?)', params[:prefecture_id])

IN検索機能を使って、受け取ったprefecture_idを持つAddressテーブルのレコードを取得しています。



蛇足ですが、delegateを使えば@address.nameでも県名が取れたりしちゃいます。
Active Support コア拡張機能 - Railsガイド

app/models/address.rb

class Address < ApplicationRecord
  extend ActiveHash::Associations::ActiveRecordExtensions
  belongs_to_active_hash :prefecture
  delegate :name, to: :prefecture
end

ログ

@address = Address.create(prefecture_id: 1, city: '猿払村') 

 @address.name                                                                                                                                             
=> "北海道"


あとは、app/models/address.rbに、

def full_address
  "#{name}#{city}"      #delegateしているのでnameだけで都道府県名が取れる
end

メソッドを定義すると、
@address.full_addressで、
都道府県名と市町村を連名で表示するような実装もできます。




active_hashさん、Prefectureモデルに静的データを持たせるよりも楽でいいですね。




ちなみに、active_hashで静的データを持つことの是非についてはこちらが詳しかったです。
blog.sesere.net




参考にさせていただいたサイト
https://blog.sesere.net/entry/2017/07/23/180000_1
GitHub - zilkey/active_hash: A readonly ActiveRecord-esque base class that lets you use a hash, a Yaml file or a custom file as the datasource
https://blog.otsukasatoshi.com/entry/2017/04/20/003756
Active Support コア拡張機能 - Railsガイド

factoryBotの{ }はどういう挙動になるのか

こんにちは!kossyです!




アウトプットが大事だと頭ではわかっていながら、
AmazonPrimeVideoにどっぷりの正月休みでした、、、笑

もう新年明けて仕事も始まっているので、
気持ちを切り替えて粛々とブログを更新していきます。




さて、今回はRailsのテストでテストデータを簡単に生成できるGem、
factoryBotでファクトリファイルを記述する際に使用する、
{}を使った記法でどういう挙動になるのか、ブログに残してみたいと思います。




ブロックで囲むと、遅延評価される

結論から言うとタイトル通りになります。
これだけでわかれば苦労しないので、もう少し解説します。



遅延評価とは、今回のケース(FactoryBotを使う)で言えば、テストデータを生成する時に評価されると言う意味になります。
ブロック構文を使わないと、rspecの立ち上げ時に評価されますが、
{}を使って値を定義すれば、FactoryBotを使ってインスタンスを生成しようとした時に、
値が評価されます。



それでもわからねぇ()

上記のことを上司から説明されましたが、実際の動きを確認しないと腑に落ちません。


ってことで、コンソールで試してみます。

$ rails c test --sandbox

このコマンドで、テスト環境のコンソールをDBの中身を変更させずにいじることができます。
(正確に言うとexit時にrollbackが走って変更がリセットされる)
別にsandboxいらないんですけどね、、、笑


早速試してみます。

factories

# user.rb

FactoryBot.define do
  factory :user do
    name                  { Faker::Name.name }
    email                 { Faker::Internet.email }
    password              { 'test1234' }
    password_confirmation { 'test1234' }
    role                  { 0 }
    created_at              Time.now # <- ブロック無し
    updated_at             Time.now # <- ブロック無し
  end
end



# review.rb

FactoryBot.define do
  factory :review do
    bookname { 'Perfect Ruby' }
    content  { 'テストだよ' }
    language { 'Ruby' }
    level    { '初級' }
    created_at { Time.now } #<- ブロックあり
    updated_at { Time.now } #<- ブロックあり
    user
  end
end

これでコンソールで試してみます。

$ rails c test --sandbox


# 以下はログ

[1] pry(main)> FactoryBot.create :user
   (0.3ms)  SAVEPOINT active_record_1
  User Exists (0.7ms)  SELECT  1 AS one FROM `users` WHERE `users`.`email` = BINARY 'danellekuhlman@goodwinfay.com' LIMIT 1
  User Exists (0.4ms)  SELECT  1 AS one FROM `users` WHERE `users`.`name` = BINARY '増田 美緒' LIMIT 1
  User Exists (0.5ms)  SELECT  1 AS one FROM `users` WHERE `users`.`email` = BINARY 'danellekuhlman@goodwinfay.com' LIMIT 1
  SQL (0.5ms)  INSERT INTO `users` (`email`, `encrypted_password`, `created_at`, `updated_at`, `name`) VALUES ('danellekuhlman@goodwinfay.com', '$2a$04$cKY02.d3veqIt4Clqc7fA.m1NhAYarMjsEbGxbK9H24urUcyVziQq', '2019-01-07 21:17:31', '2019-01-07 21:17:31', '増田 美緒')
   (0.3ms)  RELEASE SAVEPOINT active_record_1
=> #<User id: 10, email: "danellekuhlman@goodwinfay.com", created_at: "2019-01-07 12:17:31", updated_at: "2019-01-07 12:17:31", name: "増田 美緒", role: "user">
[2] pry(main)> FactoryBot.create :user
   (0.3ms)  SAVEPOINT active_record_1
  User Exists (0.5ms)  SELECT  1 AS one FROM `users` WHERE `users`.`email` = BINARY 'shannonveum@greenfelderbode.biz' LIMIT 1
  User Exists (0.3ms)  SELECT  1 AS one FROM `users` WHERE `users`.`name` = BINARY '林 莉子' LIMIT 1
  User Exists (0.3ms)  SELECT  1 AS one FROM `users` WHERE `users`.`email` = BINARY 'shannonveum@greenfelderbode.biz' LIMIT 1
  SQL (0.7ms)  INSERT INTO `users` (`email`, `encrypted_password`, `created_at`, `updated_at`, `name`) VALUES ('shannonveum@greenfelderbode.biz', '$2a$04$vr6dTtCBjX5ZHfLr1scLQumF.Fe3JbZBPo6Sg8rdcPOVeJ/LZLhOm', '2019-01-07 21:17:31', '2019-01-07 21:17:31', '林 莉子')
   (0.3ms)  RELEASE SAVEPOINT active_record_1
=> #<User id: 11, email: "shannonveum@greenfelderbode.biz", created_at: "2019-01-07 12:17:31", updated_at: "2019-01-07 12:17:31", name: "林 莉子", role: "user">
[3] pry(main)> FactoryBot.create :user
   (0.2ms)  SAVEPOINT active_record_1
  User Exists (0.3ms)  SELECT  1 AS one FROM `users` WHERE `users`.`email` = BINARY 'boyce@corkery.io' LIMIT 1
  User Exists (0.3ms)  SELECT  1 AS one FROM `users` WHERE `users`.`name` = BINARY '藤本 大樹' LIMIT 1
  User Exists (0.3ms)  SELECT  1 AS one FROM `users` WHERE `users`.`email` = BINARY 'boyce@corkery.io' LIMIT 1
  SQL (0.3ms)  INSERT INTO `users` (`email`, `encrypted_password`, `created_at`, `updated_at`, `name`) VALUES ('boyce@corkery.io', '$2a$04$DLgUxLniJfVlU9d/0ZtF/ev1W3q6yzXn.C85OMB5wwKytp8R6sPoe', '2019-01-07 21:17:31', '2019-01-07 21:17:31', '藤本 大樹')
   (0.2ms)  RELEASE SAVEPOINT active_record_1
=> #<User id: 12, email: "boyce@corkery.io", created_at: "2019-01-07 12:17:31", updated_at: "2019-01-07 12:17:31", name: "藤本 大樹", role: "user">

注目してほしいのは、created_atの値です。
どのレコードも、'2019-01-07 21:17:31'で作成されています。

次はreviewの方をコンソールで試します。

$ rails c test --sandbox

[4] pry(main)> FactoryBot.create :review
   (0.6ms)  SAVEPOINT active_record_1
  User Exists (1.2ms)  SELECT  1 AS one FROM `users` WHERE `users`.`email` = BINARY 'zoila@hane.io' LIMIT 1
  User Exists (0.5ms)  SELECT  1 AS one FROM `users` WHERE `users`.`name` = BINARY '杉山 大地' LIMIT 1
  User Exists (0.4ms)  SELECT  1 AS one FROM `users` WHERE `users`.`email` = BINARY 'zoila@hane.io' LIMIT 1
  SQL (0.5ms)  INSERT INTO `users` (`email`, `encrypted_password`, `created_at`, `updated_at`, `name`) VALUES ('zoila@hane.io', '$2a$04$NGsicKSVqrz0I2CfikbozuLLcAZGlgYkiQmLu0dzzj2uKXOjKE/Vu', '2019-01-07 21:17:31', '2019-01-07 21:17:31', '杉山 大地')
   (0.2ms)  RELEASE SAVEPOINT active_record_1
   (0.3ms)  SAVEPOINT active_record_1
  SQL (30.9ms)  INSERT INTO `reviews` (`user_id`, `bookname`, `content`, `language`, `level`, `created_at`, `updated_at`) VALUES (13, 'Perfect Ruby', 'テストだよ', 'Ruby', '初級', '2019-01-07 21:24:12', '2019-01-07 21:24:12')
   (0.2ms)  RELEASE SAVEPOINT active_record_1
=> #<Review:0x00007fc5afcfaf18
 id: 3,
 user_id: 13,
 bookname: "Perfect Ruby",
 content: "テストだよ",
 language: "Ruby",
 level: "初級",
 created_at: Mon, 07 Jan 2019 21:24:12 JST +09:00,
 updated_at: Mon, 07 Jan 2019 21:24:12 JST +09:00,
 image: nil>
[5] pry(main)> FactoryBot.create :review
   (0.3ms)  SAVEPOINT active_record_1
  User Exists (0.6ms)  SELECT  1 AS one FROM `users` WHERE `users`.`email` = BINARY 'bev@toy.name' LIMIT 1
  User Exists (0.4ms)  SELECT  1 AS one FROM `users` WHERE `users`.`name` = BINARY '前田 杏' LIMIT 1
  User Exists (0.4ms)  SELECT  1 AS one FROM `users` WHERE `users`.`email` = BINARY 'bev@toy.name' LIMIT 1
  SQL (0.4ms)  INSERT INTO `users` (`email`, `encrypted_password`, `created_at`, `updated_at`, `name`) VALUES ('bev@toy.name', '$2a$04$jWBf1xZ3Mq3frPFPZwPrfeTAtnxbL2r1byrkAN2VfurltZppKtVrK', '2019-01-07 21:17:31', '2019-01-07 21:17:31', '前田 杏')
   (0.3ms)  RELEASE SAVEPOINT active_record_1
   (0.2ms)  SAVEPOINT active_record_1
  SQL (0.5ms)  INSERT INTO `reviews` (`user_id`, `bookname`, `content`, `language`, `level`, `created_at`, `updated_at`) VALUES (14, 'Perfect Ruby', 'テストだよ', 'Ruby', '初級', '2019-01-07 21:24:19', '2019-01-07 21:24:19')
   (0.2ms)  RELEASE SAVEPOINT active_record_1
=> #<Review:0x00007fc5b51029a8
 id: 4,
 user_id: 14,
 bookname: "Perfect Ruby",
 content: "テストだよ",
 language: "Ruby",
 level: "初級",
 created_at: Mon, 07 Jan 2019 21:24:19 JST +09:00,
 updated_at: Mon, 07 Jan 2019 21:24:19 JST +09:00,
 image: nil>
[6] pry(main)> FactoryBot.create :review
   (0.2ms)  SAVEPOINT active_record_1
  User Exists (0.4ms)  SELECT  1 AS one FROM `users` WHERE `users`.`email` = BINARY 'ferdinandyundt@satterfieldhalvorson.com' LIMIT 1
  User Exists (0.3ms)  SELECT  1 AS one FROM `users` WHERE `users`.`name` = BINARY '野口 悠' LIMIT 1
  User Exists (0.3ms)  SELECT  1 AS one FROM `users` WHERE `users`.`email` = BINARY 'ferdinandyundt@satterfieldhalvorson.com' LIMIT 1
  SQL (0.4ms)  INSERT INTO `users` (`email`, `encrypted_password`, `created_at`, `updated_at`, `name`) VALUES ('ferdinandyundt@satterfieldhalvorson.com', '$2a$04$WovEde/7WJawJLYJBkqbRuElisVtJR.yW96Rqvk95AUqsRp1HBfq6', '2019-01-07 21:17:31', '2019-01-07 21:17:31', '野口 悠')
   (0.2ms)  RELEASE SAVEPOINT active_record_1
   (0.2ms)  SAVEPOINT active_record_1
  SQL (0.4ms)  INSERT INTO `reviews` (`user_id`, `bookname`, `content`, `language`, `level`, `created_at`, `updated_at`) VALUES (15, 'Perfect Ruby', 'テストだよ', 'Ruby', '初級', '2019-01-07 21:24:21', '2019-01-07 21:24:21')
   (0.2ms)  RELEASE SAVEPOINT active_record_1
=> #<Review:0x00007fc5b3e954f0
 id: 5,
 user_id: 15,
 bookname: "Perfect Ruby",
 content: "テストだよ",
 language: "Ruby",
 level: "初級",
 created_at: Mon, 07 Jan 2019 21:24:21 JST +09:00,
 updated_at: Mon, 07 Jan 2019 21:24:21 JST +09:00,
 image: nil>

めっちゃ長いですが、見るべき所はこちらもcreated_atだけです。

'2019-01-07 21:24:12'
'2019-01-07 21:24:19'
'2019-01-07 21:24:21'

3つのレコード全ての値が異なっています。







これが遅延評価だ!!

ブロックで囲まなかった方は、コンソールの立ち上げ時にfactoryの値が評価されて(Time.nowの値が決まる)いますが、
ブロックで囲ったTime.nowの方は、factoryを呼び出す(レコードを生成する)たびにTime.nowが行われているのがわかります。



コンソールで試すと理解が進みますね。



参考にさせていただいた記事
RSpecにおけるFactoryGirlの使い方まとめ - Qiita
FactoryGirlチートシート - Qiita

ng new でプロジェクト名に_(アンダースコア)は使えないという罠

こんにちは!kossyです!




本日気になったニュースはこちら
headlines.yahoo.co.jp

iphoneめっちゃ高いですよね。
円高だった頃はまだ安かったイメージですけど、
Zenfoneとかその他ローエンド?なAndroid端末とはとんでもない価格差になった感があります。

もう一回円高になれば多少は安くなるかもしれないですけど、
その頃には不景気になってそうですね、、、










さて、今回はangular cliで使えるコマンドである、
ng new での新規プロジェクト作成の際に、_(アンダースコア)は使えないという知見を得ましたので、
ブログに残しておこうかと思います。




エラーログ
このコマンドを実行したら、

$ ng new pr_angular

こんなエラーログが。

Schematic input does not validate against the Schema: {"name":"pr_angular","version":"7.1.3","routing":false,"style":"css"}
Errors:

  Data path ".name" should match format "html-selector".


Schematic input does not validate against the Schema
でグーグル検索しても英語のドキュメントしか出てこなかったので仕方なく読む。

すると、


Just got the same error with an underscore in the project name.

というコメントを発見。
"私もプロジェクト名に_を使ったら同じエラーに遭遇したよ"
というような感じでしょう。

pr_angularとしていたのを、
pr-angularとしたら、
無事に新規プロジェクトを作成できました。



グーグル翻訳最高ですね。

TLSプロトコルの解説スライド

こんにちは!kossyです!




12月からエンジニアとして働き出して、業務で今まで全く使っていない技術を使うことになったので、
基礎を固める学習に時間を取られブログを全く更新できていませんでした、、、




この土日はゆっくりできそうなので、ブログも更新したいと思います。




さて、今回はTLSプロトコルに関して詳しく解説されているスライドを見つけたため、
ご紹介できればと思います。




speakerdeck.com

ほんとに通信面の知識には疎いので、
業務に慣れてきたら通信周りを鍛えたいです、、、

Consoleでモデルの出力を整形するGem 'Hirb'

こんにちは!kossyです!




本日気になったニュースはこちら
headlines.yahoo.co.jp

解雇規制の緩和が行われるまでは、共存の状態が続くのではないでしょうか。
もっとも、その領域に口を出す政治家が現れるかはわかりませんが、、、









さて、今回はRailsのREPL環境であるpry上で、モデルの出力を整形して
表示してくれるGem'Hirb'の導入方法について、
ブログに残してみたいと思います。




環境
Rails 5.1.6
Ruby 2.5.1
MacOS Mojave





gemの導入

hirbとhirb-unicodeというgemを導入します。

Gemfile

group :development do
  gem 'hirb'
  gem 'hirb-unicode'
end

irbを使用する場合はこのままでも使えるのですが、
pryを導入している場合はこのままでは使えないので、
.pryrcというファイルをアプリケーションファイル直下に作成します。





.pryrcの作成

.pryrc

begin
  require 'hirb'
rescue LoadError
  # Missing goodies, bummer
end

if defined? Hirb
  # Slightly dirty hack to fully support in-session Hirb.disable/enable toggling
  Hirb::View.instance_eval do
    def enable_output_method
      @output_method = true
      @old_print = Pry.config.print
      Pry.config.print = proc do |*args|
        Hirb::View.view_or_page_output(args[1]) || @old_print.call(*args)
      end
    end

    def disable_output_method
      Pry.config.print = @old_print
      @output_method = nil
    end
  end

  Hirb.enable
end

これでconsole上でモデルの出力を整形できます。
こんな感じで出力されます。

f:id:kossy-web-engineer:20181202122210p:plain

localhost:3000/rails/info でルーティング一覧が見られる

こんにちは!kossyです!




本日気になったニュースはこちら
www.tv-tokyo.co.jp

本日のことでもないしニュースでもないですが(笑)

ビニールハウスってデッドスペースが多いですし、
野菜を縦に育てるという発想が素晴らしいですね。

野菜を一年中安価で提供できるのはいいと思いますが、
このサービスを利用した事業者が増えすぎて、野菜市場が下落してしまい、
事業が立ち行かなくなってしまう危険性はあると思っています。










さて、今回は、記事にするほどでもないかもしれませんが(というかいつもそうかもしれない笑)、
rails routesに換わるルーティングの確認の仕方を見つけたので、
ブログに残してみたいと思います。




環境
Rails 5.1.6
Ruby 2.5.1
MacOS Mojave





localhost:3000/rails/infoにブラウザからアクセスするとルーティングの一覧が表示される

見出しで話が完結するのですが、開発環境でlocalhost:3000/rails/infoにアクセスすると、
f:id:kossy-web-engineer:20181130172804p:plain

こんな感じで出力されます。

path表示とurl表示を切り替える機能と、
マッチするURLをソートできる機能が搭載されています。

URLはlocalhost:3000/rails/info/routesなのですが、
localhost:3000/rails/infoにアクセスすると、自動的にroutesにリダイレクトされます。



今までターミナルでrails routesしていたのですが、
もういらないですね。

RSpecでdeviseを使う方法

こんにちは!kossyです!




本日気になったニュースはこちら
dev.classmethod.jp

サーバレスについて少し調べてみましたが、よくわかりませんでした、、、
オンプレやレンタルサーバとも違うみたいですね。

このサービスを用いることで、オンプレやレンタルサーバと比較して
ランニングコストを抑えることができると仮定するならば、
今後はクラウドサーバー環境構築のノウハウを蓄積するよりも、
こちらの技術のノウハウを貯めた方がいいかもしれません。











さて、今回はRailsのテストフレームワークであるRSpecで認証系のGemとして有名なdeviseを使う方法を
ブログに残してみたいと思います。



環境
Rails 5.1.6
Ruby 2.5.1
RSpec 3.8.0
MacOS Mojave





マクロファイルの作成

controller_macros.rbという名前でファイルを作成し、loginメソッドを定義します。
macrosってなんだ?と思いましたが、
マクロ(ヘルパーメソッド)を定義してフィーチャースペックのユーザー切替えを楽に行う - Qiita

こちらによると、マクロ = ヘルパーメソッド
という認識で間違いなさそうです。

以下参考コードです。

spec/support/controller_macros.rb

module ControllerMacros
  def login(user)
    @request.env["devise.mapping"] = Devise.mappings[:user]
    sign_in user
  end
end


マクロファイルの読み込み

次にmacrosファイルを読み込む記述をします。
include以降の記述でdeviseとmacrosを読み込む処理を記述しています。

spec/rails_helper.rb

RSpec.configure do |config|
  Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
  config.include Devise::Test::ControllerHelpers, type: :controller
  config.include ControllerMacros, type: :controller
end

これでRSpec内でdeviseを使うことができます。





参考にさせていただいたサイト
rspecのテスト環境でdeviseにログインする方法【rails】 - Qiita
マクロ(ヘルパーメソッド)を定義してフィーチャースペックのユーザー切替えを楽に行う - Qiita

Railsにおけるturbolinksの無効化の手順

こんにちは!kossyです!




本日気になったニュースはこちら
aws.amazon.com

AWSで提供されているDynamoDBにトランザクション機能が追加されるそうです。
が、当方インフラ面には疎いので、何がすごいのかわかりません、、、
他の方の意見を引用すると、


今まで、DynamoDBとRDBMSの違いを説明するときは、トランザクション対応しているかどうかと発言していましたが、
だんだん優劣の説明が難しくなってきましたw。特に最近の立て続けのアップデートはかなり強力でした。
ネイティブでの暗号化、ポイントインタイムリカバリ対応、トリガー、グローバルテーブル、
KMS対応、ローカルテスト、アクセラレータ、そして、今回のトランザクション対応によって、
多くのデータベースの移行先や、新規サービスのデータベース基盤として、DynamoDBを検討できるのではないでしょうか。
とくに、サーバーレスとかIoTのバックエンドとしてDynamoDBは無くてはならない存在です。
今後の更なる進化にも期待したいですね。

出典: DynamoDBのトランザクションについてFAQ形式で答えてみる #reinvent | DevelopersIO

とのことでした。
トランザクションに対応したことで、DynamoDB一択、ということになっていくのでしょうか。










さて、今回はRailsで標準で組み込まれている、
turbolinksを無効化する手順について、ブログに残してみたいと思います。




そもそもturbolinksってなにしてくれてるの?

Turbolinksはリンクを生成する要素であるa要素のクリックをフックにして、
移動した先のページをAjaxで取得します。

その後、取得ページのデータが遷移前のページと同じものがあれば再利用し、
title・body要素を置き換えて表示します。
データを再利用するので、アプリケーションの速度向上などのパフォーマンスの向上を
させることができます。

Railsと一緒に使われるイメージがあるTurbolinksですが、
iOSやAndoroid環境でも使用することができます。
github.com




本題

回り道をしてしまいましたが、これからTurbolinksの無効化手順を説明します。


まずはGemfileからTurbolinksを削除します。

gem 'turbolinks', '~> 5'  # この行を削除

bundle updateします。

$ bundle update

次に、application.jsのTurbolinksをrequireしている部分を削除します。

//= require turbolinks  # この行を削除

そして、レイアウトファイルでTurbolinksを読み込んでいる部分を削除します。

# この2行を削除

= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload'
= javascript_include_tag 'application', 'data-turbolinks-track': 'reload'

これでTurbolinksを削除できます。

SSH通信の概要

こんにちは!kossyです!




本日気になったニュースはこちら
jp.techcrunch.com

太っ腹ですね。
Progateをはじめとした各種プログラミング学習サービスの充実度は
本当に素晴らしいもので、初学者向けの学習環境の整備はめちゃめちゃ進んでいる印象です。
ただ、今まではWeb系コンテンツの充実度ばかりが進行していた気がしますので、
今回のAmazonの発表でWeb系以外のコンテンツもどんどん充実してほしいなと思います。










さて、今回はSSH通信の概要についてブログに残してみたいと思います。




SSHとは?

暗号や認証技術を用いて、セキュアにリモートコンピュータと通信を行うための通信プロトコルのことです。
プロトコルとは、大雑把に言ってしまうと、通信を行う際の決め事、です。

どんなメリットがあるのか

きちんとセキュアにSSH通信が行われていれば、以下のようなメリットが得られます。

①通信が盗聴される危険性を回避できる
②バックアップを取りたい時に、サーバ上で圧縮して、ファイルを一括ダウンロードできるので、アップロード・ダウンロード時に
 時間短縮ができる
③リモート(遠隔)サーバ上でファイルの操作や編集が安全にできる


より詳しく

SSH通信が中で何を行なっているか、とても詳しく解説してくれています。
qiita.com

実際の設定までカバーされています。
qiita.com



通信周りの知識がまだまだ足りていないと感じています。。。