セキュリティ系の勉強・その他開発メモとか雑談. Twitter, ブログカテゴリ一覧
本ブログはあくまでセキュリティに関する情報共有の一環として作成したものであり,公開されているシステム等に許可なく実行するなど、違法な行為を助長するものではありません.

ethereum

きっかけ

ブロックチェーンについて調べていたら、無料ツールによるマイニングに興味をそそられたので、とりあえず走らせてみた。運よく、VR系の研究室なのでグラボを積んでるPCがたくさんありました。ラッキー。

ハッシュレート(MH/s)

ハッシュレートとは、1秒間の計算量とのこと。これは、グラボの種類である程度決まるっぽい。下のサイトにハッシュレート一覧が掲載されていた。 https://netank.net/26850.html

ethereum

今回採掘してみるのは、ethereum。 理由として、ウォレットの準備が楽であった(MyEtherWallet)。しかし、これの採掘にはRadeon系のグラボが最適だそうで。残念ながらうちにはGeForce系しかありません。

やってみた結果

GeForce 980Ti GeForce1080
PC 32GB, Corei7, 3.4GHz 32GB, Corei7, 4.0GHz
回線(google ping/down/up) 5ms,16,86Mbps,157.93Mbps 5ms,6.21Mbps,32.04Mbps
MH/s 1.939MH/s 21.08MH/s

上のリンク先のハッシュレート表では、1080はだいたい20.0~22.0MH/sだったので、ほぼ同じ数値を出している感じですね。回線が悪いのは気にしないでください。

収益

このサイトで計算

GeForce 980Ti GeForce1080
1ヶ月 $ 0.8161 $ 8.84

上の結果はPool Fee=2%で電気代は考慮しない設定としています。 うーん、グラボ一枚だけではどうしても効率は上がらなそうです。まぁ趣味程度のものってことで大丈夫です。

【mysql5.7】Library not loaded: /usr/local/opt/mysql/lib/libmysqlclient.21.dylib

症状

$ bin/rails db:migrate:reset
rails aborted!
LoadError: dlopen(/Users/196/Documents/プロジェクト名/vendor/bundle/ruby/2.5.0/gems/mysql2-0.5.2/lib/mysql2/mysql2.bundle, 9): Library not loaded: /usr/local/opt/mysql/lib/libmysqlclient.21.dylib

経緯

  1. mysql8系導入済み
  2. gitからrailsプロジェクトclone
  3. プロジェクトがmysql5.7を使ってた
  4. mysqlをダウングレード
  5. migration走らせると上のエラー

ダメだったもの

ダウングレードしたくない。 qiita.com

~18.dylibのファイルはあったが、~21.dylibはなかった。 qiita.com

成功したもの

mysql2のgemを入れ直す。 note.mu

$ bundle exec gem uninstall mysql2
$ bundle install

CarrierWave デフォルトの画像を表示する default_url

前置き

下のページで画像をアップロードする機能は実装済【Rails】CarrierWaveとrmagickで画像アップロード機能を作る | おすすめのプログラミングスクール比較!最短で上達するなら?

画像が保存されていない場合のデフォルトの画像を呼び出したい

default_urlというメソッドが用意されています。これを$ rails g uploader imageで生成したクラスに実装する事で、自分が設定したいデフォルトの画像を呼び出すことが可能です。 github.com

class ImageUploader < CarrierWave::Uploader::Base
  def default_url(*args)
    "/images/" + [version_name, "default.png"].compact.join('_')
  end
end

この場合、/public/images/下に画像を保存しておく

呼び出し方

下の様に呼び出す際に、imagenilか判断して自動で呼ばれます。

current_user.image.url

画像の名前はdefault.pngにしておく。

サイズ指定

一番上の参考リンク通りに実装した場合、下の様な実装になっているはず。

class ImageUploader < CarrierWave::Uploader::Base  
 
 # リサイズしたり画像形式を変更するのに必要
  include CarrierWave::RMagick
 
 # 画像の上限を640x480にする
  process :resize_to_limit => [640, 480]
 
  # 保存形式をJPGにする
  process :convert => 'jpg'
 
  # サムネイルを生成する設定
  version :thumb do
    process :resize_to_limit => [300, 300]
  end
   
  version :thumb100 do
    process :resize_to_limit => [100, 100]
  end
 
  version :thumb30 do
    process :resize_to_limit => [30, 30]
  end
....
end

そして次の様に呼ぶことで、リサイズした画像のurlを取得できる。

current_user.image.thumb20.url

この時、default_url側に渡される名前はthumb20"+"default.pngとなるため、サイズの指定も可能になる。つまりファイル名をthumb20_default.pngとしておく。

【Ruby On Rails】ネストとガード節

ネストがひどい

下のコードがスマートじゃない。(リダイレクトのパスとかは適当です)

# hoge_controller.rb
  def destroy
    if target = User.find_by(id: params["id"])
      if current_user.unfollow(target) #フォローを外すみたいな動作
        flash[:info] = I18n.t("hoge.destroy.success")
      else
        flash[:danger] = I18n.t("hoge.destroy.failure")
      end
    else
      flash[:danger] = I18n.t("hoge.destroy.user_not_found")
    end  
    redirect_to(root_path)
  end


RuboCop先生曰く、制御構文で条件式のネストは避けましょう。とのこと。ガード節を使います。

ガード節

不正なデータを弾きたいときはガード節を使いましょう。 ガード節とは、できるだけ素早く関数から抜けられるようにと 関数の先頭に置かれている条件文のことです。
https://github.com/fortissimo1997/ruby-style-guide/blob/japanese/README.ja.md#no-nested-conditionals

return ~ unlessを使用して、予期しない条件の場合はこれ以降関係ないっすよ。ってしてあげることで、見た目的にも読みやすくなる気がします。if~elseが適しているものとして、条件分岐に相対性があるものとの噂もあったので、

# hoge_controller.rb
  def destroy
    target = User.find_by(id: params["id"])
    return redirect_to(root_path, flash: { danger: I18n.t("hoge.destroy.user_not_found") }) unless target

    if current_user.unfollow(target)
      flash[:info] = I18n.t("hoge.destroy.success")
    else
      flash[:danger] = I18n.t("hoge.destroy.failure")
    end
    redirect_to(root_path)
  end

余談

上のコードのガード節でfind_by行までまとめて1行で書く場合、

return redirect_to(root_path, flash: { danger: I18n.t("hoge.destroy.user_not_found") }) unless (target = User.find_by(id: params["id"]))

とかけますが、target変数の出どころがわかりにくいので、2行にしてます。また、上記の場合、unlessの条件に()つけないと、RuboCop先生に注意されますが、コード自体は走ります。(==のタイポと思われる)

【RSpec】before句がdescribeスコープ外にも影響する

環境

RSpec 3.8
ruby 2.5.3p105 (2018-10-18 revision 65156) [x86_64-darwin18]
Rails 5.2.2

問題

ひとまずテストする内容だけ列挙して後から中身を実装していこうなんて考えることがあります。そして以下の状況になった時にひとまず走らせてみるかと思うこともあります。

describe HogeController,type: :request do
  let(:user){create(:user)}                  # factory_botでユーザ生成

  describe "GET #get" do
    let(:get_page){get hoge_path}
    before{  login_as(user) }                # ログインするヘルパー
  
    context "ログインしてアクセス" do
      it "has status 200" do                   # レスポンスが帰ってくる
        get_page
        expect(response).to eq have_http_status(:ok)
      end
      it "別ページへリダイレクトしない" do  # ここはまだ実装してない
      end
    end
  end  
  
  describe "GET #create" do
    let(:post_create){post hoges_path, params:{~~}}
    
    context "ログインしていなかったら" do
      it "ログインページへリダイレクト" do
        post_create
        expect(response).to redirect_to(login_path)    # ここでエラー。ログイン状態での処理が成功していることになっている。以前は成功しているテスト。
      end
    end
  end
end

このコントローラでは、アクションの前にログインしていなかったらログインページへリダイレクトする様にbefore_actionにて定義されています。しかし、上のテストを走らせるとcreateのテストでコケます。getテストのスコープ内ではbefore句でログイン処理を定義していますが、これはcreateのスコープ外なので影響されないはずです。

結論

getテストのスコープの最後の未実装のテストが悪さをしている様です。

検証

describe HogeController,type: :request do
  let(:user){create(:user)}                  # factory_botでユーザ生成

  describe "GET #get" do
    let(:get_page){get hoge_path}
    before{  login_as(user) }                
  
    context "ログインしてアクセス" do
      it "has status 200" do                   
        get_page
        expect(response).to eq have_http_status(:ok)
      end
            # 未実装の処理を削除
    end 
  end  
  
  describe "GET #create" do
    let(:post_create){post hoges_path, params:{~~}}
    
    context "ログインしていなかったら" do
      it "ログインページへリダイレクト" do
        post_create
        expect(response).to redirect_to(login_path)   
      end
    end
  end
end

結果:テスト成功

describe HogeController,type: :request do
  let(:user){create(:user)}                  # factory_botでユーザ生成

  describe "GET #get" do
    let(:get_page){get hoge_path}
    before{  login_as(user) }                
  
    context "ログインしてアクセス" do
      it "has status 200" do                   
        get_page
        expect(response).to eq have_http_status(:ok)
      end
      it "別ページへリダイレクトしない" do
        get_page   # とりあえず何か書いてみる
      end
    end
  end  
  
  describe "GET #create" do
    let(:post_create){post hoges_path, params:{~~}}
    
    context "ログインしていなかったら" do
      it "ログインページへリダイレクト" do
        post_create
        expect(response).to redirect_to(login_path)   
      end
    end
  end
end

結果:テスト成功

以上より、中身が未実装のものがあると、before句の処理内容がロールバックされずに残っていると考えられるかなと。

検証2

describe HogeController,type: :request do
  let(:user){create(:user)}                  # factory_botでユーザ生成

  describe "GET #get" do
    let(:get_page){get hoge_path}
    before{  login_as(user) }                
  
    context "ログインしてアクセス" do
      it "has status 200" do                   
        get_page
        expect(response).to eq have_http_status(:ok)
      end
      it "別ページへリダイレクトしない" do
        get_page   # とりあえず何か書いてみる
      end
      it "未実装のテストがあるよ" do # ここのテストはそのまま
      end
    end
  end  
  
  describe "GET #create" do
    let(:post_create){post hoges_path, params:{~~}}
    
    it "ここに未実装のテスト" do  # ここに未実装のテストをさらに書きます。
    end
    context "ログインしていなかったら" do
      it "ログインページへリダイレクト" do
        post_create
        expect(response).to redirect_to(login_path)   
      end
    end
  end
end

結果:テスト失敗

describe HogeController,type: :request do
  let(:user){create(:user)}                  # factory_botでユーザ生成

  describe "GET #get" do
    let(:get_page){get hoge_path}
    before{  login_as(user) }                
  
    context "ログインしてアクセス" do
      it "has status 200" do                   
        get_page
        expect(response).to eq have_http_status(:ok)
      end
      it "別ページへリダイレクトしない" do
        get_page   # とりあえず何か書いてみる
      end
      it "未実装のテストがあるよ" do # ここのテストはそのまま
      end
    end
  end  
  
  describe "GET #create" do
    let(:post_create){post hoges_path, params:{~~}}
    
    it "ここに未実装のテスト" do 
      post_create                              # とりあえず何か実装してみる 
    end
    context "ログインしていなかったら" do
      it "ログインページへリダイレクト" do
        post_create
        expect(response).to redirect_to(login_path)   
      end
    end
  end
end

結果:成功
context"ログインしていなかったら"句の該当テスト前に、上の二つと同じ様にテストを挟んでみても、同じ結果になりました。it前で実行されたbefore句の内容は何か処理がなければ、ロールバックされない様ですね。詳しいことを知っている方がいれば、教えていただけると嬉しいです。