edy hub

プログラミングやライフスタイルについて書き綴っています

Railsでモジュールを作ってインクルードして使うまで

特定の処理をモジュール化したい

Railsで独自実装などを記しておく、自前のモジュールを使いたい場合が誰にでもあると思います。 その際の準備など書き記しておきます。

方法

下記に則って進めましょう

  • 命名規則に沿ってモジュールを作る
  • app/libにそのモジュールを置く
  • 使用したいコントローラでincludeする

具体例

1. 命名規則に沿ってモジュールを作る

以下の命名規則に従ってモジュールを作ります。

  • ファイル名は小文字で書く
  • ファイル名の単語を_(アンダーバー)で区切る
  • クラス名(モジュール名)はアッパーキャメルケースで記述する

例えば、モジュール名がFooBarの場合、ファイル名はfoo_bar.rbとなります。

# lib/foo_bar.rb
class FooBar
  def hello
    puts 'Hello, World'
  end
end

2. app/libにそのモジュールを置く

上述の例で出したファイルのディレクトリにlibが登場しましたね。 作成したファイルはapp/lib配下に配置しましょう。

もしlib配下にさらにもう一段ディレクトリが存在した場合は、下記のパターンがあります。 例えば、lib/foo配下にファイルを設置するとします。

モジュールを用いる場合

# lib/foo/bar.rb
module Foo
  class Bar
    def hello
      puts "Foo::Bar: Hello, World"
    end
  end
end

moduleを用いない場合

# lib/foo/bar.rb
class Foo::Bar
  def hello
    puts "Foo::Bar: Hello, World"
  end
end

3. 使用したいコントローラでincludeする

例えば、controllers/sample_controller.rbでfoo_bar.rbのモジュールを使用する場合は以下のようにincludeします。これで当該モジュールが使えるようになりました。

class SampleController < ApplicationController
  include FooBar

  def index
    hello
    # => 'Hello, World'
  end

  ...
end

4.config/application.rbに一行追加

config.autoload_paths += %W(#{config.root}/lib)

これにて、autoloadの設定が完了し、命名の規約に従った場合に、lib ディレクトリ以下のファイルが自動的に読み込まれるようになります。

ただし、この記事だけを読んでも初歩の初歩でしか無いので、実務で使うとしたらこちらの記事が優れていると思うので、目を通すことをオススメします。

参考記事

Ruby on Rails で lib ディレクトリの自作クラスを使用する - Qiita

docker-compose upしたときに「A server is already running.」でサーバーが立ち上がらない問題

何が起きたか?

すでに動いているプロセスの影響でサーバの立ち上げがうまくいかない。

A server is already running. Check /myapp/tmp/pids/server.pid.

f:id:yuki-eda0629:20190609201411p:plain

解決方法

docker-compose up --buildする前にプロセスを消すようにした。

$ rm -f tmp/pids/server.pid

としてから、

$ docker-compose up --build を実行する。

補足

毎回プロセスを消すコマンドを打つのは面倒だし、忘れがちなのでdocker-compose.yml内に実行処理を書いておく。

rails serverの直前に実行したいので、下記のように記述した。

ポイントは、commandで複数実行することになるので、bash -cに変更したこと。

command: rails s -b 0.0.0.0 -p 3000 # 変更前
command: bash -c "rm -f tmp/pids/server.pid && rails s -b 0.0.0.0 -p 3000" # 変更後

Rspecを書く時に念頭においておきたいことのメモ

この記事の役割

  • 全体像をメインにメモをしていきます。
  • 各論も含むかもしれませんが、ボリュームが増大した場合は別記事に切り分けます。

体系的なまとめ

参考: RSpecを綺麗に書くための基本Rule - Qiita

この記事からの学び

命名規則

「AAメソッドは、BBの時、CCをDDします。」

AA : Describe → コントローラーのメソッド名を表記

describe 'GET #show'
describe 'GET /api/v1/users'

BB : Context → 状況を表記

when/withで始める

context "when book is present"
context "with valid params"

CC : Subject → テスト対象を表記

# eqの場合
subject{ assings(:book) }
subject{ Book.find(1)}

# change/render/redirect/http statusの場合
subject {Proc.new { get: index }}
subject {Proc.new { get :show, id: 1 }}
subject {Proc.new { get :new, id: 1 }}
subject {Proc.new { get :edit, id: 1 }}
subject {Proc.new { post :create, id: 1, book: @valid_params }}
subject {Proc.new { patch :update, id: 1, book: @valid_params }}
subject {Proc.new { destroy :delete, id: 1 }}

DD : it → テスト対象に対する動詞を表記

# eqの場合
it "主語 is 目的語"
it "主語 has 目的語"

# changeの場合

it "create 目的語"
it "update 目的語"
it "delete 目的語"

# renderの場合
it "render the template名"

# redirectの場合
it "redirect to path名"

# http statusの場合
it "returns http ok"
it "returns http success"
it "returns http 204"

Puppeteerでスクレイピングをする

はじめに

const puppeteer = require('puppeteer');

ファイル内でpuppeteerを読み込む

ファイル読み込み

ファイル操作を行うライブラリ

const fs = require('fs');

node.jsはShift-jisをサポートしていないので、通常の方法で読み込むと、文字化けしてしまう。 iconv-liteは様々な文字コードを変換するモジュール。

const iconv = require('iconv-lite');

Puppeteerクラスを使う

Puppeteer module provides a method to launch a Chromium instance. The following is a typical example of using Puppeteer to drive automation:

puppeteer/api.md at master · GoogleChrome/puppeteer · GitHub より

const puppeteer = require('puppeteer');

puppeteer.launch().then(async browser => {
  const page = await browser.newPage();
  await page.goto('https://www.google.com');
  // other actions...
  await browser.close();
});
const browser = await puppeteer.launch();

JSの実行

JS実行は page.evaluate を使用します。 https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pageevaluatepagefunction-args

例えば、submit要素をクリックする。

await page.evaluate(({}) => {
              $('input[type="submit"]').click();
        },{});

CSVのダウンロード

await page.goto(DLURL);        
        await page._client.send('Page.setDownloadBehavior', { behavior: 'allow', downloadPath: './store' });
        await page.evaluate(({}) => {
              $('img[src="/master/common/btn_dl_01.png"]').click();
        },{});
        await page.waitFor(4000)

await page._client.send('Page.setDownloadBehavior', { behavior: 'allow', downloadPath: './store' }); がよくわからない・・・

Githubで会話されていた

Question: How do I get puppeteer to download a file? · Issue #299 · GoogleChrome/puppeteer · GitHub

Vim便利コマンド[削除編]

Vimの削除コマンド集

1文字削除

x

単語削除

dw

行削除

dd

指定行数削除

n(数字)dd

例:3dd → 3行削除

カーソルから行末まで削除

D

文字置換削除

"banana"という単語を削除したい時

:%s/banana//g

カーソル上の単語を削除

diw 

クォーテーションの内部を削除

di" or di'

カッコの内部の場合は、di(

d = delete
i = inner
", ', ( = target

HTMLタグの内部を削除

dit

カーソル上の単語を削除→インサートモード

ciw

クォーテーションの内部を削除→インサートモード

ci" or ci'

HTMLタグの内部を削除→インサートモード

cit

ファイル内の特定の文字列が含まれている行を削除

:g/{文字列}/d

ファイル内の特定の文字列が含まれていない行を削除

:v/{文字列}/d

フロントエンドのあれこれ

rgba

例えば、background-color: rgba(0, 0, 0, 0.85); という記述があったとする。

最後の0.85はアルファチャンネル=不透明度を表す。

つまり、 rgba(0, 0, 0, 0.85) とは、#000と同じ真っ黒を、不透明度85%の半透明にする、ということ。

vhとvw

vhは、 view height の略。 ブラウザの高さを100vhと定義する。 ブラウザの高さの半分なら50vh、10%なら10vhという用法で使う。

似たような単位として、 vw があり、これはview width の略。 ブラウザの横幅を100vwとして大きさを指定する時の単位となる。

line-hight

line-hightは1行あたりの高さを決めてくれる。 例えば、font-size が20pxのテキストに対して、line-height: 140% とすると、20 × 1.4で、行の高さは28pxになる。 このとき、line-hight: 1.4としても同様の値になる。

letter-spacing

letter-spacing は、テキストの文字間隔を指定するCSSプロパティ。 line-heightと同じく、font-sizeに対してどれくらいの広さを空けるかという考え方をする。

このときemという単位がよく用いられる。 その要素のfont-sizeを基準に、font-size の 1% が 0.01emとなる。