20190318のRubyに関する記事は21件です。

PG::ConnectionBad の対処法

PostgreSQLが使えない時

railsでrail s や rails db:migrate
などのコマンドを使用した際にいかのようなエラーが出た時の対処法です。

could not connect to database postgres: could not connect to server: No such file or directory
        Is the server running locally and accepting
        connections on Unix domain socket "/tmp/.s.PGSQL.5432"?

この様な場合は、SQLサーバーが起動していない事が多いそうです。

サーバーのインストールなどの経験は無く、
はじめてのことであったのでかなり苦戦しました。

インストールするだけでは使えない

SQLサーバーはインストールするだけではだめで、起動することで使用可能になります。

自動でSQLサーバー立ち上がる設定や環境に慣れてしまっているせいで、
自分で起動する感覚が僕にはありませんでした。

以下のコマンドを実行することで無事にエラー解決が出来ました!

 $ sudo service postgresql start
    Starting postgresql service:                              [  OK  ]

参考

以下のサイトが参考になりました。

https://www.postgresql.jp/
https://lets.postgresql.jp/

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

fileds_for の使い方

fields_forとは

  • 複数のモデルを扱う form を作りたい時に使用するもの

基本的な使い方

例えばpageモデルと pageモデルとhas_onecategoryモデルを同じformで扱いたいとするとこんな感じになる

<%= form_with model: @page do |f| %>
  <%= f.fields_for :category do |ff| %>
    <%= ff.text_field :name %>
  <% end %>
<% end %>

http://railsdoc.com/references/fields_for

Controller

class PagesController < ApplicationController

  def new
    @page = Page.new
  end
end

Model

class Page < ApplicationRecord
  has_one :category
end

has_manyな場合

こちらもcategorycategoriesに変わっただけで、こんな感じでいける

<%= form_with model: @page do |f| %>
  <%= f.fields_for :categories do |ff| %>
    <%= ff.text_field :name %>
  <% end %>
<% end %>

http://railsdoc.com/references/fields_for

Controller

class PagesController < ApplicationController

  def new
    @page = Page.new
  end
end

Model

class Page < ApplicationRecord
  has_many :categories
end

子の方に最初から複数のformを出したい時

この場合はちょっとcontrollerの方で先に子の方をbuildしてあげれば良い
これでfields_forのブロックの中が3回繰り返される

<%= form_with model: @page do |f| %>
  <%= f.fields_for :categories do |ff| %>
    <%= ff.text_field :name %>
  <% end %>
<% end %>

http://railsdoc.com/references/fields_for

Controller

class PagesController < ApplicationController

  before_action :build_page, only: %i(new)
  before_action :build_categories, only: %i(new)

  def new
  end

  private

  def build_page
    @page = Page.new
  end

  def build_categories
    for i in 1..3 do
      @page.categories.build
    end
  end
end

Model

class Page < ApplicationRecord
  has_many :categories
end
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RubyとRubyonRailsの違いは? 初心者が超初心者に向けて解説してみる

初めまして、だるまです。

Webエンジニアになるため、とか、初心者は勉強しやすいと聞いた、とかで
RubyやRubyonRailsを勉強している人は多いかと思います。
(自分もその1人)

ただ単語の意味は知っているけど、RubyやRubyonRailsの違いがイマイチわからない・・・
と思っている方もいるのではないでしょうか。

そんな方のためにこの記事を書いてみました。
読んでもらえればざっくりとこんなものなんだな、と理解してもらえると思います!

 まずは全体像を把握しよう!

RubyやRubyonRailsを把握するためにもまずは全体像を把握することが大切です。

よくTwitterに例えられるのでざっくりとTwitterでどんな動きをしているのか見てみましょう。

無題.png

もしPCでTwitterを使用しており、DM(ダイレクトメール)の通知がきてて見ようと思ったとき、
PCではクリックしてDMが表示されて終わり、ですが、実際は上記図のように
①PCがサーバにDMの情報を要求
②サーバが内部でDMのデータを探してPCへ渡す
という処理が行われています。

そう、このサーバが行っている処理を実現するためのものがRuby、RubyonRailsなのです!

 で、結局Ruby、RubyonRailsってなんなの?

ここでようやく本題です。
Webで探すと大体以下の言葉で書かれています。
Ruby・・・プログラミング言語
RubyonRails・・・フレームワーク

これが非常にわかりにくい!

この言葉のまま初心者なりに解説すると、
上記の図で説明したサーバの処理は、Rubyというプログラム言語で動いている。
ただし、Rubyで1からTwitterのようなアプリケーションを作成するのは超大変。
なので、よく使う機能が既に用意されているRubyonRailsを使用する。
という感じになります。

これでもわかりにくいですよね。
なのでラーメンで例えてみます。

ラーメンを作ろうと思ったとき、
麺、スープを全て1から作ろうとする・・・Rubyで1からアプリを作ろうとしている行為
インスタント買ってきて自分なりにアレンジして作る・・・RubyonRailsを使ってアプリを作ろうとしている行為

どちらとも最終的にラーメンができあがりますが、
麺やスープを自分で最初から作ろうとすると超大変ですよね。
ただインスタントを買ってきてある程度作られている状態(フレームワークがある状態)から作ると
簡単に素早くラーメンが作れます。

RubyはWebアプリを作るための大元の言語。
ただRubyで最初から作るのは大変なので、
よく使う機能がまとめられたRubyonRails(フレームワーク)を利用してWebアプリを開発する。

なんとなく理解してもらえたでしょうか?
1人でもなんとなく理解してもらえたら嬉しいです!

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

ruby-rubocop is not working in vscode

solution

settings.json
{
    "editor.formatOnSaveTimeout": 5000,
}

environment

macbook pro 2018 13inch
visual studio code

https://stackoverflow.com/questions/48030698/vscode-vscode-ruby-rubocop-how-to-auto-correct-on-save

Per this comment on the vscode-ruby-rubocop GitHub, you can use the following settings:

{
    "editor.formatOnSave": true,
    "editor.formatOnSaveTimeout": 5000,
    "ruby.rubocop.executePath": "path/where/rubocop/is/located",
    "ruby.format": "rubocop",
}

Just applied them to my user settings on my local box and it appears to work. VS Code was throwing an error for my ruby.rubocop.executePath setting saying it wasn't executable, and removing the line appears to not cause that error to show, and still formats my code accordingly. Setting a lower timeout (I tried 2500) also seems to break auto format on saving, so I'd suggest leaving it at 5000.
ローカルボックスの自分のユーザー設定にそれらを適用するだけで、うまくいくようです。私のruby.rubocop.executePathの設定にVS Codeが実行可能ではないというエラーを投げていたため、行を削除してもそのエラーが表示されないように見えますが、それでもコードは適切にフォーマットされます。より短いタイムアウトを設定すると(私は2500を試した)保存時に自動フォーマットを壊すように思われるので、私はそれを5000のままにすることをお勧めします。

https://github.com/misogi/vscode-ruby-rubocop/issues/49#issuecomment-417617844

following is working for me:

{
    "editor.formatOnSave": true,
    "editor.formatOnSaveTimeout": 5000,
    "ruby.rubocop.executePath": "path/where/rubocop/is/located",
    "ruby.format": "rubocop",
}

色々やったのにうまくいかなかった。
エディターの設定を直せばうまくいくとは想像できなかった。(ずっとrubocopの設定を検索していた)
まあ、これで自動フォーマットされるし、サボれる( ・∇・)!!

https://qiita.com/sensuikan1973/items/219a843e4654e6c2e10d
https://qiita.com/astronaughts/items/760d56fb5674707a9a0f
https://qiita.com/ovrmrw/items/86310cb9ad5707ea27ee
https://marketplace.visualstudio.com/items?itemName=misogi.ruby-rubocop

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

document自動保存

メモを手書きでマークダウンで書いてそれをそのままdocumentにすると手間が省けるのではと思いつき実践しました。

やりたいこと図

スクリーンショット 2019-03-16 22.35.03.png

メモはBAMBOO slateというスマートパッドを選択しました。ボタンを押すだけでアプリに保存できる優れものです。保存した時にtextで保存できる機能をいかして保存したいサービスのAPIを叩いてデータを保存します。

ファイルの参照

今回は特定のディレクトリ配下をチェックして変更があった時にそれをトリガーにしてAPIを叩きます。rubyのguardを使うことにしました。

guard :shell do
  watch(/(.*).txt/) { `bash ./script/main.sh ` }
end

あとはscriptを書いてguardを実行

bundle exec guard

結果

実際に書いた文字
スクリーンショット 2019-03-18 22.19.33.png

字が綺麗ではありませんね。

ドキュメントに保存された結果はこちら

スクリーンショット 2019-03-18 22.20.33.png

やや成功といったところでしょうか。
やりたいことがだいたいできたのが成果ですね。判定が微妙になりそうな文字は自分で定義し直してもいいかもしれない。
 

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

Ruby 学習記録2

3/18 Ruby の学習記録2です。
学習記録1の方でMarkdown記法のアドバイスをいただき、プレビュー画面を見ながらなるべく見やすくデザインできるようになりました。
さらにアドバイスありましたらお気軽にコメントお願いします!

【オブジェクト】

  • Rubyの世界では全てのデータオブジェクトと呼ぶ
  • Rubyはオブジェクトを中心に考える言語
    (例)
    • 文字列オブジェクト
    • 数値オブジェクト
    • 配列オブジェクト
    • ハッシュオブジェクト
  • オブジェクトは「メソッド」と呼ばれる技のようなものを使用できる
    (例)
    • lengthメソッド
    • eachメソッド  
       

【返り値】

  • Rubyでは全てのものを式として捉える
    → 式には答えがある
    → その答えを「返り値」という(↔︎return)

 

【クラスとインスタンス】

  • クラスとは、とある種類のオブジェクトの共通の属性とメソッドをまとめて定義しておく型
  • オブジェクト同士には共通する部分が存在し、その共通する性質をクラスという型で定義すると効率的に個々のオブジェクトを生成することができる
  • クラスに基づいて生み出されたオブジェクトのことをインスタンスと呼ぶ
  • Rubyにはあらかじめ定義されているクラスが存在する
    (例)
    • 文字列オブジェクト → Stringクラス
    • 配列オブジェクト → Arrayクラス
    • 数値オブジェクト → Integerクラス
    • ハッシュオブジェクト → Hashクラス

「書き方」

qiita.rb
  class クラス名
    変数やメソッドの定義
  end
qiita.rb
 (例)
  class Sample
    puts "Hello world!"
  end

 

【クラスメソッドとインスタンスメソッド】

・クラスメソッドはクラスで共通の情報を使った処理に使用する
・インスタンスメソッドはインスタンスごとの個別の情報(属性値)を使った処理に使用する

「書き方」

qiita.rb
 (例)
  class Number
    def self.number_count(num1, num2) # <= クラスメソッドはメソッド名の前にself.を付ける
      return num1 * num2
    end

    def show_number(num1,num2) # <= インスタンスメソッドはself.をつけない
      puts "#{num1}#{num2}をかけた答えは#{num1 * num2}です!"
    end
  end

  number = Number.new
  puts number # <= #<Number:0x00007fcf1505fa00>と出力される
                   #インスタンスの生成に成功しているということ

  puts Number.number_count(3,5) # <= 15と出力される
    # クラスメソッドの呼び出しはクラス名.メソッド名(引数)
  number.show_number(3,5) # <= 3と5をかけた答えは15です!と出力される
    # インスタンスメソッドの呼び出しはインスタンス名.メソッド名(引数)

 

【クラスメソッドとインスタンスメソッドの違い】

特徴 クラスメソッド インスタンスメソッド
定義方法 メソッド名の前にselfをつける メソッド名の前にselfをつけない
用途 属性は関係ない共通の処理 インスタンスごとの属性を用いる場合
呼び出せるオブジェクト クラス自身 クラスのインスタンス

 

【クラス変数とインスタンス変数】

クラス変数

  • クラス変数はクラス内であればどこでも使えるのでクラスメソッド、インスタンスメソッドの両方で使うことが可能
  • クラスを通して値が共通の情報に使用する

「書き方」

qiita.rb
 (例)
  class Sample
    def sample_c
      @@test = "HELLO"
    end
  end 

  # @@test  ←  クラス変数

インスタンス変数

  • インスタンス変数は共通の属性としてインスタンスに定義できる変数
  • 個々のインスタンスによって別々に設定可能
  • newメソッドで新しく生成されたインスタンスごとに値が変わることもある

「書き方」

qiita.rb
 (例)
  class Sample
    def sample_i
      @test = "Hello"
    end
  end 

  # @test ← インスタンス変数

 

【initializeメソッド】

  • インスタンスの生成と同時に実行したい処理を自動的に実行するメソッド

「書き方」

qiita.rb
 (例)
  class Sample
    def initialize
      puts "新たなインスタンスが生成されました"
    end
  end 

  sample = Sample.new
  # "新たなインスタンスが生成されました"と表示される

 

【クラスの継承】

  • あるクラスに定義されたメソッドを別のクラスで利用できるようにすることを継承と言う
  • 元となる「親クラス」とそれを引き継ぐ「子クラス」からなる

「書き方」

qiita.rb
  class 子クラス名 < 親クラス名
qiita.rb
 (例)
  class Iphone
    def name
      puts "iphoneです"
    end

    def series
      puts "シリーズは8です"
    end
  end
qiita.rb
 (例)
  class Black < Iphone # クラスの継承
    def color_black
      puts "色は黒です"
    end
  end
qiita.rb
  (例)
  class White < Iphone # クラスの継承
    def color_white
      puts "色は白です"
    end
  end
メソッド名 Iphone(親クラス) Black(子クラス) White(子クラス)
name
series
color_black × ×
color_white × ×
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

puts とは

puts とは

puts とは、「(puts に続く文字や数字を)表示して」という意味のお願いです。

このお願いを「メソッド」と言い、puts に続く文字や数字を「オブジェクト」と言います。(文字オブジェクトとか整数オブジェクトと呼ぶ)

puts はRuby という言語で学ぶ一番最初のメソッドです。

書き方

puts  "文字"
puts  数字

puts のあとに半角スペースが入ります。

また、文字オブジェクトの場合は“ ”(ダブルクォーテーション)で囲う必要があります。それにより文字情報と認識され、ダブルクォーテーションを除外し文字のみで出力されます。

test.rb
puts "こんにちは"
puts 2020

↓出力($ ruby test.rb)

こんにちは
2020

計算もできる

putsのあとに計算式を入れることで計算結果を表示することが出来ます。

calc.rb
puts 6+3
puts 6-3
puts 6*3
puts 6/3

↓出力($ruby calc.rb)

9
3
18
2

下2つに見慣れない記号がありますが、計算結果を見ておわかりのとおり、

* = ×
/ = ÷

という意味になります。
キーボードで×や÷がないので*と/で代用する形になります。

ちなみに+ , - , * , / は代数演算子といいます。

puts , print , p

実はputs 以外にも後ろに続くオブジェクトを表示するメソッドがあります。それが「print メソッド」と「pメソッド」です。

どちらもputs と同じく「表示して」とお願いするためのメソッドですが、若干性質が異なります。

●puts → 出力のあと改行される。
●print → 出力のあと改行されない。
●p → 数値はそのまま表示、文字列はダブルクォーテーションで挟まれた状態で表示される。出力のあと改行される。

説明だと意味がよくわからないかもしれませんが、文字と数字の2つのオブジェクトで試すと違いが分かりやすいです。

test.rb
puts 30,"歳"

print 30,"歳"

p 30,"歳"

↓出力($ ruby test.rb)
30

30歳

30
"歳"

pメソッドは基本「デバック」のために使われます。
「デバック」とは、問題があって動かない部分(バグ)の原因を調べて正すことを言います。

まとめ

・putsは文字や数字のオブジェクトを「表示する」ためのメソッド
・putsは計算もできる(+ , - , * , / は演算子と言う)
・「表示する」メソッド
●puts → 出力のあと改行される。
●print → 出力のあと改行されない。
●p → 数値はそのまま表示、文字列はダブルクォーテーションで挟まれた状態で表示される。出力のあと改行される。

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

Rubyリファレンスを読んでの、メモ

オブジェクト指向スクリプト言語 Ruby リファレンスマニュアル を読んだ。
以前に授業で突かれて分からないもの、今後出てきそうなもの、知らないものをメモる。

字句構造

予約語

回避方法はあるが、使わない方が身のため。

BEGIN    class    ensure   nil      self     when
END      def      false    not      super    while
alias    defined? for      or       then     yield
and      do       if       redo     true     __LINE__
begin    else     in       rescue   undef    __FILE__
break    elsif    module   retry    unless   __ENCODING__
case     end      next     return   until

変数と定数

クラス変数@@

@@で始まる変数はクラス変数

親クラスに、子クラスで既に定義されている同名のクラス変数を追加したら、 子クラスのクラス変数が上書きされる。

class Foo
end
class Bar < Foo
  @@v = :bar
end
class Foo
  @@v = :foo
end
class Bar
  p @@v       #=> :foo
end

定数

  • アルファベット大文字で始まる
  • 定義されている定数に代入を行おうとすると、警告を出すが、代入される
  • クラス定義の外(トッ プレベル)で定義された定数は Object に所属する
    • あるクラスまたはモジュールで定義された定数を外部から参照する ためには::演算子を用いる。
    • Objectクラスで定義の定数(トップレベルの定数と言う)を確実に参照するには左辺無し。
module M
  I = 35
  class C
  end
end
p M::I   #=> 35
p M::C   #=> M::C
p ::M    #=> M

M::NewConst = 777   # => 777

リテラル

バックスラッシュ記法

文字列中でバックスラッシュの後に記述する文字によって、意味を持たせる事ができます。

  • \t タブ(0x09)
  • \v 垂直タブ(0x0b)
  • \n 改行(0x0a)
  • \e エスケープ (0x1b)
  • \s 空白 (0x20)
  • \nnn 8 進数表記 (n は 0-7)
  • \xnn 16 進数表記 (n は 0-9,a-f)

%記法

バックスラッシュの数をコードから減らす効果
配列式では、文字列の配列やシンボルの配列を簡単に表現できる

  • %!STRING! または %Q!STRING!: ダブルクォート文字列
  • %q!STRING! : シングルクォート文字列
  • %w!STRING! : 要素が文字列の配列(空白区切り)
%w(foo bar bazz)
== ['foo', 'bar', 'baz']
  • %W!STRING! : 要素が文字列の配列(空白区切り)。式展開、バックスラッシュ記法が有効
v = "c d"
%W(a\ b #{v}e\sf #{})
=> ["a b", "c de f", ""]
  • %s!STRING! : シンボル。式展開、バックスラッシュ記法は無効
  • %i!STRING! : 要素がシンボルの配列(空白区切り)
  • %I!STRING! : 要素がシンボルの配列(空白区切り)。式展開、バックスラッシュ記法が有効

演算子

優先順位

&& > || > and or

a && b || c   #=> (a && b) || c
a || b && c   #=>  a || (b && c)

再定義できない演算子

 =  ?:  ..  ...  not  &&  and  ||  or  ::

多重代入

foo, bar = [1, 2]       # foo = 1; bar = 2
foo, bar = 1, 2         # foo = 1; bar = 2
foo, bar = 1            # foo = 1; bar = nil

foo, bar, baz = 1, 2    # foo = 1; bar = 2; baz = nil
foo, bar = 1, 2, 3      # foo = 1; bar = 2
foo      = 1, 2, 3      # foo = [1, 2, 3]
*foo     = 1, 2, 3      # foo = [1, 2, 3]
foo,*bar = 1, 2, 3      # foo = 1; bar = [2, 3]
# 左辺の最後の式の直前に * がついていると、対応する 左辺のない余った要素が配列として代入

&&と||

&& : 左辺を評価し、結果が偽なら、その値(つまり nil か false) を返す。
   左辺の評価結果が真なら、右辺を評価しその結果を返す

|| : 左辺を評価し、結果が真なら、その値を返す。
   左辺の評価結果が偽なら、右辺を評価し その評価結果を返す。

条件演算子

式1 ? 式2 : 式3
# 上と下は同じ
if 式1 then 式2 else 式3 end
# 例
x = 123456789
x%3 == 0 if "3x" : "hazure"
=> 3x

制御構造

unless

unlessはifと反対で、条件式が偽の時にthen以下の式を評価。elsifを指定できない。

制御構造(ifなど)の修飾子

式 if 式の様に、一行で書くやつ。
右辺の条件が真/偽の時にに、左辺の式を評価してその結果を返す。

retry

rescue 節で begin式からもう一度実行するのに使用。
処理が成功するまで処理を繰り返すようなループを作れる。

begin
  do_something # exception raised
rescue
  # handles error
  retry  # restart from beginning
end
# rescue 節以外で retry が用いられた場合にはSyntaxError`

クラス/メソッドの定義

呼び出し制限

  • public : 制限なし
  • private : 関数形式でしか呼び出せない
  • protected : ソッドを持つオブジェクトが selfであるコンテキストでのみ呼び出し可能。
  • nitializeは定義する場所に関係なく常に private
class Foo
  def foo
   p caller.last
  end
  protected :foo
end

alias

メソッドあるいはグローバル変数に別名をつけます。
メソッド名には識別子そのものかリテラル/シンボル を指定

# alias 新メソッド名 旧メソッド名
# alias 新グローバル変数名 旧グローバル変数名
alias foo bar
alias :foo :bar
alias $MATCH $&

undef メソッド名

メソッドの定義を取り消す

defined? 式

式が定義されていなければ、偽を返す。定義されていれば式の種別を表す文字列を返す

Ruby用語集

面白かった
リンク

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

もそ、プログラミングを学ぶ【Ruby on Rails】〜奥義!コントローラの継承〜

土日はしっかりバッチリ休息を取り、学習を再開させた もそ。
心身ともにリフレッシュして、これで勉強もスピードアップ!...なんてウマい話にはならず、頭を抱えながらカリキュラムと睨めっこをしています。

コントローラの継承とは?

さて今日は、この無駄に語感のかっこいい"コントローラの継承"について書いていきます。
なんかゲーム後半の、師匠から主人公への必殺技伝授みたいですよね(?)

コントローラについては以前まとめたMVCについてこちらをご参照ください。

コントローラはルーティングの指示に従って、アクション(処理)した結果をビューに渡す役割があります。
そして継承とは、継承元である他のオブジェクトのメソッドや特徴を引き継ぐことです。

図でもう少し視覚的に説明していきますね。
継承元となるコントローラから、メソッドや特徴を引き継ぐとします。

無題1148.jpeg

そうすると、引き継いだ方は元のコントローラで定義された特徴やメソッドを使うことができます。
要はパワーアップする感じです。

無題1148 2.jpeg

ざっくりとしたイメージですが、これがコントローラの継承です。
コントローラの継承をすることで、たとえばあるAのメソッドと特徴をもった特定のコントローラだけにbefore_actionの処理をすることも可能です。
逆に言えば、すべてのコントローラに共通した処理を行いたいときは継承元のコントローラに書き込むことで機能をもたせます。

つまり上の図で言うところの師匠コントローラにある処理を実行すれば、弟子コントローラたちすべてがそのメソッドなどを継承します。

--
いかがでしょうか?
相変わらずプログラミングには苦戦しているのですが、Qiitaに載せる用のイラストを短時間で描いて文を書いているうちに、若干イラストと文章のクオリティが上がっている気がします...
こういうのを本末転倒というのでしょうか...

イラストの質も上げつつ、プログラミングもしっかり理解をしていきたいです。
もそにもプログラミングを瞬時に理解できる機能を継承できたらいいのになあ。続く。

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

Gem::Ext::BuildError: ERROR: Failed to build gem native extension.が解決できない。

bundle install をするとエラーがでる。

ターミナルの内容はこちら

Fetching msgpack 1.2.9
Installing msgpack 1.2.9 with native extensions
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

    current directory: /Users/tech-camp/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/msgpack-1.2.9/ext/msgpack
/Users/tech-camp/.rbenv/versions/2.5.1/bin/ruby -r ./siteconf20190318-3361-1d5xqm2.rb extconf.rb
checking for ruby/st.h... *** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers.  Check the mkmf.log file for more details.  You may
need configuration options.

Provided configuration options:
    --with-opt-dir
    --without-opt-dir
    --with-opt-include
    --without-opt-include=${opt-dir}/include
    --with-opt-lib
    --without-opt-lib=${opt-dir}/lib
    --with-make-prog
    --without-make-prog
    --srcdir=.
    --curdir
    --ruby=/Users/tech-camp/.rbenv/versions/2.5.1/bin/$(RUBY_BASE_NAME)
/Users/tech-camp/.rbenv/versions/2.5.1/lib/ruby/2.5.0/mkmf.rb:456:in `try_do': The compiler failed to generate an executable file. (RuntimeError)
You have to install development tools first.
    from /Users/tech-camp/.rbenv/versions/2.5.1/lib/ruby/2.5.0/mkmf.rb:590:in `try_cpp'
    from /Users/tech-camp/.rbenv/versions/2.5.1/lib/ruby/2.5.0/mkmf.rb:1097:in `block in have_header'
    from /Users/tech-camp/.rbenv/versions/2.5.1/lib/ruby/2.5.0/mkmf.rb:947:in `block in checking_for'
    from /Users/tech-camp/.rbenv/versions/2.5.1/lib/ruby/2.5.0/mkmf.rb:350:in `block (2 levels) in postpone'
    from /Users/tech-camp/.rbenv/versions/2.5.1/lib/ruby/2.5.0/mkmf.rb:320:in `open'
    from /Users/tech-camp/.rbenv/versions/2.5.1/lib/ruby/2.5.0/mkmf.rb:350:in `block in postpone'
    from /Users/tech-camp/.rbenv/versions/2.5.1/lib/ruby/2.5.0/mkmf.rb:320:in `open'
    from /Users/tech-camp/.rbenv/versions/2.5.1/lib/ruby/2.5.0/mkmf.rb:346:in `postpone'
    from /Users/tech-camp/.rbenv/versions/2.5.1/lib/ruby/2.5.0/mkmf.rb:946:in `checking_for'
    from /Users/tech-camp/.rbenv/versions/2.5.1/lib/ruby/2.5.0/mkmf.rb:1096:in `have_header'
    from extconf.rb:3:in `<main>'

To see why this extension failed to compile, please check the mkmf.log which can be found here:

  /Users/tech-camp/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/extensions/x86_64-darwin-15/2.5.0-static/msgpack-1.2.9/mkmf.log

extconf failed, exit code 1

Gem files will remain installed in /Users/tech-camp/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/msgpack-1.2.9 for inspection.
Results logged to /Users/tech-camp/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/extensions/x86_64-darwin-15/2.5.0-static/msgpack-1.2.9/gem_make.out

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

In Gemfile:
  bootsnap was resolved to 1.4.1, which depends on
    msgpack

解決方法

エラーの起こっているディテクトリで以下のコマンドを実行

xcode-select --install

これを実行するとインストール画面がでるので、インストールし再度,bundle installすると無事インストール完了

疑問点

  • xcodeって?
  • msgpackではなく、bootsnapが原因だった?
  • そもそも上記2つってなに?
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RubyでModuleをレシーバとしたinstance_evalとmodule_eval

C#erがRubyのModuleについてのinstance_evalとmodule_evalを理解するのにハマった点をまとめておく。

サンプルに使用するモジュールの定義

module M
  CONST = "Module CONST"
  class << self
      CONST = "Module Singleton CONST"
  end
end

文字列を使用してinstance_evalする場合

モジュールの特異メソッドが定義される
モジュールの特異クラス内で評価

M.instance_eval(<<-CODE)
  def say
    p CONST
  end
CODE

M.say # => "Module Singleton CONST"

関数の定義はdef sayでもdef self.sayでも直接呼び出せる。
今の理解度では、def self.sayがOKな理由がわからない。
def self.sayは、特異クラスの特異クラスに定義されそうな気がするのだが。。。

文字列を使用してmodule_evalする場合

モジュールのインスタンスメソッドが定義される
モジュール内で評価

M.module_eval(<<-CODE)
  def self.say
    p CONST
  end
CODE

M.say # => "Module CONST"

関数の定義はdef self.sayでなければ直接呼び出せない。

コードでinstance_evalする場合

モジュールの特異メソッドが定義される
カレント(この場合はトップレベル)で評価

CONST = 'TOP LEVEL'
M.instance_eval{
  def say
    p CONST
  end
}

M.say # => "TOP LEVEL"

関数の定義はdef sayでもdef self.sayでも直接呼び出せる。
今の理解度では、def self.sayがOKな理由がわからない。

コードでmodule_evalする場合

モジュールのインスタンスメソッドが定義される
カレント(この場合はトップレベル)で評価

CONST = 'TOP LEVEL'
M.module_eval{
  def self.say
    p CONST
  end
}

M.say # => "TOP LEVEL"

関数の定義はdef self.sayでなければ直接呼び出せない。

class << Module を使用する場合

モジュールの特異メソッドが定義される
モジュールの特異クラス内で評価

class << M
  def say
    p CONST
  end
end

M.say # => "Module Singleton CONST"

関数の定義はdef sayでなければ直接呼び出せない。
文字列を使用してinstance_evalする場合と似ているが、def self.sayは直接呼び出せない。

深すぎるよ。。。

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

railsのキホンvol.8(ログイン機能)

ログイン機能

ログインページを作る

まず、ルーティングとコントローラを設定する。
usersコントローラのlogin_formアクションを定義する。

routes.rb
get "login" => "users/login_form"
users_controller.rb
def login_form
end

ビューでログインフォームを表示する。

login_form.html.erb
<p>メールアドレス</p>
<input name="email" value="<%= @email %>">
<p>パスワード</p>
<input type="password" name="password" value="<%= @password %>">
<input type="submit" value="ログイン">

フィームの送信

次に、フォームのあたいを送信できるようにloginアクションを作る。

routes.rb
post "login" => "users/login"
users_controller.rb
def login
end

ログインフォームの方もform_tagを追加しておく。

login_form.html.erb
#/loginへフォームの値を送信
<%= form_tag("/login") do %>
<p>メールアドレス</p>
<input name="email" value="<%= @email %>">
<p>パスワード</p>
<input type="password" name="password" value="<%= @password %>">
<input type="submit" value="ログイン">
<% end %>

また/loginで被っているが、post,getで異なったルーティングと認識されるので問題ない。

ユーザーを特定

loginアクションで、ユーザーを特定する処理をする。
情報が一致した場合はフラッシュメッセージとともに投稿一覧へ。
しなかった場合はエラーメッセージとともにログインフォームへ、初期値として入力済みのもの。

users_controller.rb
def login
    #ログインフォームで入力されたものが、データベースの情報とあっているか確認する
    @user = User.find_by(email: params[:email], password: params[:password])
    if @user
      flash[:notice] = "ログインしました"
      redirect_to("/posts/index")
    else
      @error_message = "メールアドレスまたはパスワードが間違っています"
      @email = params[:email]
      @password = params[:password]
      render("users/login_form")
    end
end

session変数

ページを移動してもユーザー情報を保持するためにsession関数を使う。
session[:キー] = 値
と記述をする。
今回は、ログインに成功した時にユーザー情報を保持しts保持したいので、loginアクションを追加修正する。

users_controller.rb
def login
    #ログインフォームで入力されたものが、データベースの情報とあっているか確認する
    @user = User.find_by(email: params[:email], password: params[:password])
    if @user
      session[:user_id] = @user.id
      ...
end

また新規登録時にそのままログイン状態にして、セッション変数で情報を保持する。

user_controller.rb
def create
    @user = User.new(
      name: params[:name],
      email: params[:email],
      image_name: "default_user.jpg",
      password: params[:password]
    )
    if @user.save
      #新規登録に成功すれば、ログイン状態にする
      session[:user_id] = @user.id
      flash[:notice] = "ユーザー登録が完了しました"
      redirect_to("/users/#{@user.id}")
    else
      render("users/new")
    end
  end

ログアウト機能

ログアウトする場合はセッションの値をからにする。
セッションの値を変更するときはpostとする。

routes.rb
post "logout" => "users#logout"
users_controller.rb
def logout
  session[:user_id] = nil
  flash[:notice] = "ログアウトしました。"
  redirect_to("/login")
end

ログイン中のユーザーを取得する

before_action

各コントローラの全アクションで共通の処理がある場合に使う。

ユーザー情報は全アクションで使うためapplication_controller.rb で処理を書いておく。
ここでは、set_crrent_userメソッドを定義する。

controllers/application_controller.rb
before_action :set_current_user
def set_current_user
  @current_user = User.find_by(id: session[:user_id])
end

アクセス制限

ログインしていない場合

ログインが必要なページを表示しようとした場合は、フラッシュメッセージとともにログインページに移動する、authenticate_userメソッドを作る。

controllers/application_controller.rb
def authenticate_user
    #ユーザー情報がない場合
    if @current_user == nil
      flash[:notice] = "ログインが必要です"
      redirect_to("/login")
    end
end

onlyを用いて、指定したアクションのみでメソッドを実行する。

users_controller.rb
before_action :authenticate_user, {only: [:index, :show, :edit, :update]}
posts_controller.rb
before_action :authenticate_user

ログインしている場合

ログインしている場合も同様に、アクセス制限のメソッドを作っておく。

controllers/application_controller.rb
def forbid_login_user
    if @current_user
      flash[:notice] = "すでにログインしています"
      redirect_to("/posts/index")
    end
end

対応するアクションに対してメソッドを適応させる。

home_controller.rb
before_action :forbid_login_user,{only: [:top]}
users_controller.rb
before_action :forbid_login_user, {only: [:new, :create, :login_form, :login]}

ユーザー編集の制限

自分以外のユーザーの編集をできないように制限をかける。

views/users/show.html.erb
#詳細ページのユーザーidとログインユーザーidが一致している場合は編集ok
<% if @user.id == @current_user.id %>
  <%! linl_to("編集","users/#{@user.id}/edit") %>
<% end %>

次にアクションの方でも制限しておく。
ensure_correct_userアクションを用いる。
ログインしているユーザーと編集したいユーザーが等しくないとき、投稿一覧ページへとリダイレクトさせる。

controllers/users_controller.rb
before_action :ensure_correct_user, {only: [:edit,:update]}
def ensure_correct_user
  if @current_user.id != params[:id].to_i
    flash[:notice] = "権限がありません。"
    redirect_to("/posts/index")
  end
end

to_iメソッド

params[:id]で帰ってくる数値は文字列になっているため、to_iメソッドを使うことによって、数値としてidを取得できる。

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

fastlaneのビルドを数秒短縮できるかもしれないtips

タイトルで全部説明出来そうだったので、思わせぶりなタイトルになってしまった。

対象

  • CarthageやCocoapodsを使っている
  • fastlaneでbadgeプラグインを使っている

上記に当てはまらない方は関係ないです。

不要なバッジ処理

アイコンにバージョンバッジを付けたい場合Fastfileで以下のように書くことが多いと思う。

add_badge(shield: "#{@version_number}-#{@commit_hash}-white")

が、このような書き方で実行すると、

\[13:50:07]: Start adding badges...
\[13:50:07]: '../App/Carthage/Module/Assets/Assets.xcassets/AppIcon.appiconset/Icon-App-iTunes.png'
\[13:50:08]: '../App/Carthage/ModuleB/Assets/Assets.xcassets/AppIcon.appiconset/Icon-App-iTunes.png'
...

のような感じで、CarthageやCococaPodsでCheckoutしたExampleプロジェクト内のアイコンにも処理が行われることがある。(これが十数秒かかったりする)
なので、

add_badge(shield: "#{@version_number}-#{@commit_hash}-white", glob: "/App/Core/Assets/Assets.xcassets/AppIcon.appiconset/*.{png,PNG}")

といった感じでglobでメインのアプリだけを指定してあげれば、この無駄な処理が省ける。
globは内部でcurrent_pathと連結されるので/から始める点に注意。

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

herokuでアプリが起動しない

スクリーンショット 2019-03-16 19.29.09.png
いつも見るこの画面。
いい加減、この表示からしっかり抜け出せるようになるためメモします。

各目次、参考文献のタイトルです。
中には今回の原因と関係ないものもありますが、気にしないでください。

参考記事一覧

①Ruby on RailsのファイルをHerokuのデプロイする方法

https://akihiko-s.com/heroku-deploy-rubyonrails/

Config/database.ymlを

production:
  <<: *default
  database: db/production.sqlite3

production:
  <<: *default
  adapter: postgresql
  encoding: unicode
  pool: 5

に変更。変化なし。

②heroku run rails db:migrateのエラー発生時の解決法

https://qiita.com/wann/items/6966f1022ce823a56cc5

node.jsのversionをアップデート。
$ nvm install v8.0.0

変化なし。

③Rails tutorial 1章でheroku loginできない時[Cloud9]

https://qiita.com/hama1/items/a86fde879326e5feb9ef

CLIのpluginが何も無いためアップデート。
$ heroku plugins:install heroku-repo

変化なし。

④heroku へデプロイでエラー「The page you were looking for doesn’t exist.」

http://stuby.hatenablog.com/entry/2014/02/02/163544

assetsをプリコンパイルしてなかったのが原因かも?
$ rake assets:precompile

変化なし。

⑤HerokuにWebアプリを公開する方法

http://0gravity000.sunnyday.jp/ProgramingNote/2016/08/24/tip_07_01_001/

パイプラインを作成し、Connect to GitHubを実施。

変化なし。

⑥Heroku + rails4.2 + Deviseで本番環境,ログアウト画面に遷移する際にエラー

https://ja.stackoverflow.com/questions/10980/heroku-rails4-2-deviseで本番環境-ログアウト画面に遷移する際にエラー

JavaScriptが正常に読み込まれていないため、ローカルにpublic/assetsディレクトリがあるなら消してcommit→pushで良いとのこと。

ーーーー途中

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

ツイッターのエラーメッセージで学ぶ英語

英語でエラーメッセージを書く時、英語ネイティブでない私は下記のような点に悩むことが以前はよくありました。

  • 先頭の文字を大文字にすべきか否か
  • 文章で書くべきか、短いフレーズにすべきか
    • (文章の場合)ピリオドを付けるべきか否か
  • 冠詞を付けるべきか否か
  • 形容詞を前置にすべきか後置にすべきか(例:'Not found user' それとも 'User not found')
  • エラーメッセージは文章でよいとして、エラークラス名はどうすべきか
    • エラークラス名にbe動詞は入れるべきか否か

『設計というのは名前が決まればだいたい終わったようなもの』教の私としては、名前付けには何よりもこだわりたい。

そうしていたところ、ツイッターのエラーメッセージがなかなかバリエーションに富んでいることに気付いたので、今後の参考になればと思い、エラーメッセージの特徴をまとめてみた。

紹介するエラーメッセージは Twitter API および Twitter gem から引用しています

引用しているエラーメッセージは Twitter API のレスポンスに含まれるものです。引用しているエラークラス名は Twitter gem で定義されているものです。

紹介しているエラーメッセージとエラークラス名は、一例としてRubyで下記のように使用されます。

begin
  api_client.request_something
rescue Twitter::Error::Unauthorized => e
  puts "##{e.class}, #{e.message}"
end

# => Twitter::Error::Unauthorized, Invalid or expired token.

該当するRubyコードやドキュメントのURLは下記の通りです。

認証に失敗している系のエラー

クラス名はTwitter::Error::Unauthorizedとなる。

Invalid or expired token.

トークンの有効期限が切れている場合。先頭は大文字、フレーズのみ、ピリオドで終わるというパターン。

You have been blocked from viewing this user's profile.

ブロックされているユーザーのプロフィールを見ようとした場合。がっつり文章パターン。

Could not authenticate you.

何らかの理由でOAuthに失敗している場合。文章で主語が省略されている。

文法としては正しくないが、gitのcommitメッセージも主語が省略されることが多く、少なくともエンジニア関係の文章に限るとこの書き方でもよいらしい。

Not authorized.

理由は分からないが極稀にでる認証のエラー。こんなに短くてもピリオドがあった方がよいらしい。

アカウントが凍結されている系のエラー

クラス名はTwitter::Error::Forbiddenとなる。

User has been suspended.

ユーザーが凍結されている場合。文章かつ現在完了(継続)用法を使っている。

非ネイティブが書くには「長すぎるかな?」と躊躇しそうな文章だが、これでもよいらしい。(今は慣れたので自分でもこう書く)

Your account is suspended and is not permitted to access this feature.

凍結されているユーザーの認証情報を使って何かしらのAPIにアクセスした場合。andで文章をつないでいる。

これ私にも長過ぎるように思えるが、理由が2つあるのでこれでもよいらしい。(これも慣れた)

You are unable to follow more people at this time. Learn more <a href='http://support.twitter.com/articles/66885-i-can-t-follow-people-follow-limits'\>here\.

単位時間あたりにフォローできる数の制限を超えた場合。文章かつHTMLタグ付き。

かなり前衛的だが、このエラーについての質問が多いと想定される場合はこれでもよいのかもしれない。

To protect our users from spam and other malicious activity, this account is temporarily locked. Please log in to https://twitter.com to unlock your account.

理由が不明だがたまにでるエラー。かなり長めの文章かつURL付き。

こっちはHTMLタグにはなっていない。ツイッター社の中でもエンジニアによってエラーメッセージの書き方に幅があるんだろうか。

You can't follow yourself.

自分のIDをフォローしようとした場合。ここまで読み進めている人にはもう見慣れたエラーメッセージになっているはず。

Could not determine source user.

ユーザー間の相互関係を変更するAPIでソースユーザーが見付からなかった場合。これももはやよくある形。

You cannot send messages to users you have blocked.

自分がブロックしているユーザーにDMを送ろうとした場合。can'tではなくcannotを使っている。省略形にするかどうかはどちらでもよいらしい。

You cannot send messages to users who are not following you.

自分のフォローしていないユーザーにDMを送ろうとした場合。関係代名詞を使うパターン。

これも非ネイティブの私が書く時は「長すぎるかな?」と躊躇してしまうが、へたに省略して対象が誰なのか分からなくなるよりはこの方がよいのだろう。

You are sending a Direct Message to users that do not follow you.

自分をフォローしていないユーザーにDMを送ろうとした場合。

直前のエラーメッセージとこのエラーメッセージを見比べた後なら、確かに関係代名詞以降の文章まで正確に書いた方がよいかも、と思わせられる。(もし書かなかったら紛らわし過ぎるので)

ユーザーが見付からなかった系のエラー

クラス名はTwitter::Error::NotFoundとなる。

User not found.

ユーザーをlookupしようとして見付からなかった場合。これに限らず、not foundは後置のパターンをよく見かける気がする。

余談だが、似たような例としてtoo many requestsは前置、rate limit exceededは後置という違いがある。単語によるものの、過去分詞で名詞を修飾する場合のエラーメッセージは後置になるらしい。(ただし例外も後述される)

No user matches for specified terms.

複数ユーザーのlookupを一括でしようとしたが1人もユーザーが見付からなかった場合。

termには様々な意味(後述)があるので非ネイティブとしてはこの単語は選びづらいが、少なくともこういう場合にも使える単語らしい。

termの意味の例
期間、期限、用語、条件(terms of use == 利用規約)

Sorry, that page does not exist.

何かしらのリソースが見付からなかった場合。ひとまず一言謝っておく時は先頭にSorry,と付けておけばよいらしい。

サーバーのキャパシティを超えてしまった系のエラー

クラス名はTwitter::Error::ServiceUnavailableとなる。

Over capacity

理由はよく分からないがたまにでるエラー。シンプルなフレーズかつピリオドがないパターン。

(エラーメッセージなし)

同じエラークラスで、エラーメッセージが空の場合がたまにある。エラークラス名で理由が十分に伝わる場合はこれでもよいらしい。

その他のエラークラス名

Twitter gemには他にもたくさんのエラーが定義されている。エラークラス名として参考になるのでそれらも引用しておく。code

RequestEntityTooLarge

「too + 形容詞」が後置になっているパターン。TooManyRequestsというエラークラス名もある。この2つから察する限り、どっちでもよいんだろうか?

AlreadyFavorited

「既に何かしら処理が終わっている」というエラーの場合、クラス名には「have + 過去分詞」は付けないらしい。

AlreadyRetweeted

これも上記の例と同様だが、エラーメッセージが少し特殊で、

sharing is not permissible for this status (Share validations failed)

となっている。先頭が大文字じゃない、かつ、カッコ書きでより具体的な理由が書かれている。このエラーメッセージだけ違う人が書いたんだろうか。

「カッコ書きで理由を書くことの是非」について、これまでの例を見る限りカッコ書きはあまり一般的ではないらしい。ひとまず私は滅多に使わないようにしている。

DuplicateStatus

この場合のエラーメッセージは、

Status is a duplicate.

となっている。duplicateが形容詞に思えるが、この場合は名詞の用法もあるらしい。重複した処理を許さない場合のエラーメッセージとして使えるかもしれない。

その他のエラー定数名

Twitter gemに定義されているエラー定数名から参考になりそうなものをいくつかピックアップ。code

UNABLE_TO_VERIFY_CREDENTIALS

何かができない場合は「unable to 動詞」でよいらしい。ちょっと長いようにも思えるのでご参考まで。

CANNOT_MUTE

何かができない場合のもっとシンプルな書き方はこちら。

OAUTH_TIMESTAMP_OUT_OF_RANGE

何かが範囲外であるという状況はよく見かけるが、そういう場合はこの書き方でよいらしい。

まとめ

質問何でもどうぞ!

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

Ruby on RailsでGitHubからクローンしてアプリを立ち上げるために気をつけること

Railsのアプリを1から制作するための環境設定は、どの参考書にも載っていますが、GitHubからクローンしてアプリを立ち上げるための情報を、網羅している情報源は見当たりませんでした。

私は、プログラミング未経験から独学で勉強していまして、GitHubからクローン(Clone)してアプリを立ちあげるのに、かなりつまづいてしまいましたので、初学者の方に参考にしていただければ幸いです。

ちなみに、現在はRSpecについて学ぼうとしているところでして、『Everyday Rails』の環境構築で迷った経験をもとにしています。(一般化して、汎用性の高い考え方にすることを目的としています。)

Ruby on RailsでGitHubからクローンしてアプリを立ち上げるために気をつけること

順番が重要でして、下記の通り進める必要があります。

1.Ruby/Ruby on Railsのバージョン確認
2.Gem関連のバージョン確認
3.データベースの設定

1.Ruby/Ruby on Railsの確認(インストール/バージョンアップ/バージョンダウン)

  • Ruby
  • Rails

RubyやRailsのバージョンは、GitHubの「README.md」というプログラムの仕様を記述するファイルに記載されているはずです。

2.Gem関連のバージョン確認(インストール/バージョンアップ/バージョンダウン)

  • Bundler
    • "gemfile"と"gemfile.lock"に従って、gemを管理をするライブラリ
  • Ruby-gems
    • gemを管理する仕組みで、Rubyで書かれたプログラムを管理するためのパッケージツール(ライブラリ)が簡単に使えるように配布されている場所

上記のバージョンを全てクリアした上で、下記コマンドでGemのバージョンを合わせます。
bundle install

RubyやRailsだけでなく、GemやBundler、Ruby-gemsのバージョンも確認することがポイントですね。

私の場合は、「Bundlerのバージョンをあげようとした時に、Ruby-gemsのバージョンが低いからだめ」というエラーが出たので、「先にRuby-gemsのバージョンを上げてから、Bundlerのバージョンを上げる」ことで解決できました。

3.データベース接続

  • データベース作成(bin/rails db:create)
  • マイグレーションファイル実行(bin/rails db:migrate)

データベースの設定は、クライアント側(自分のPC)で行う必要があります。

ここまでやれば、あとは「bin/rails server」でサーバーを起動して、アプリを立ち上げることができるはずです。

最後に

GitHubからクローンしてアプリを立ちあげるために、留意すべきことを列挙しました。

あとは、エラー文をググって解決の糸口を見つけるしかないですが、その際はUNIXコマンド(ターミナルでの操作)の知識をしっかりつける必要があるな、と感じている次第です。

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

引数オブジェクトの導入(Introduce Parameter Object)

image.png

1つずつリファクタリング技法まとめ
個人的に簡単かつ取り入れ易いと思うものから

目的

すぐ引き出せるようにする

基本作業サイクル

  • システムを動かして仕様を精査
  • テストメソッドを作成
  • テストの失敗を確認
  • テストの成功を確認
  • 小さい変更、随時テスト実行(パターン追加失敗確認->成功確認)
  • 最後テスト実行
  • 最後動作確認

引数オブジェクトの導入(Introduce Parameter Object)とは

複数ある引数を1つのオブジェクトにまとめること
引数の情報は変えずに数を減らすこと

ポイント

  • 複数の引数に関連性があることが自明、または同じ組み合わせで渡されている引数がある時に引数の情報をイミュータブルなクラスとして作成
  • 既存のメソッドにオブジェクト化した引数を追加し、少しずつ引数を差し替えて検証する
  • 既存の引数を削除できたら引数オブジェクトのクラスに債務のあるメソッドを移動する

class Doraemon
  attr_reader :calorie

  def eat(bean_paste, castella) 
    @calorie = bean_paste + castella
  end

  def large
    @calorie += 500
  end
end

   ↓

class Dorayaki
  attr_reader :calorie, :bean_paste, :castella

  def initialize(bean_paste, castella)
    @bean_paste = bean_paste
    @castella = castella
  end

  def large
    @calorie = @bean_paste + @castella + 500
  end
end

class Doraemon
  def eat(dorayaki) 
    dorayaki.bean_paste + dorayaki.castella
  end
end

書籍情報

Jay Fields (著), Shane Harvie (著), Martin Fowler (著), Kent Beck (著),
長尾 高弘(訳), リファクタリング:Rubyエディション
https://amzn.to/2VlyWML

雑感

何の組み合わせによる技法かを認識するためにも少しずつ行う

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

Nginx,Redis,MySQLを使ってほんの少し実践的なRails ActionCableと、iOS/Androidのサンプルアプリを作って全体像を学ぶ〜バックエンド編〜

前置き

「Rails ActionCableで双方向通信してみたい」「モバイルアプリでリアルタイム通信アプリ作りたい」と思いサンプルアプリを作ってみました。個々の詳細については既に解説してくださっている記事はありますので、大まかに環境構築やソースコードをご紹介します。以下の3部構成になっています。

お遊びサンプルの紹介

以下のアニメーションGIFをご覧ください。各ユーザーのアクティブ状況を表示して、メッセージをやりとります。もっと砕けた表現をするならば、筆者の愛犬たちが寝起きして、鳴いたり、遠吠えしたり、唸ったりします。
ios_demo.gif

このアプリでは大きく2つのActionCableの使い方があります。

  • 同じルーム内の全ユーザーにブロードキャスト
    • ルームに入る
      現在ルーム内にいるユーザー(以下、アクティブユーザー)にルームに入ったことを通知し、アクティブユーザーを取得します。そして、各ユーザーのアクティブ状況を表示します。
    • 「ワンワン」ボタンと「ワオーン」ボタン
      文字入力で任意の文字が送れないだけで、チャットでいうところの「メッセージ」とほぼ同義です。ボタンに対応したメッセージを送信します。
    • ルームから出る
      iOSなら「キャンセル」、Androidなら「←」をタップしたり、アプリを閉じたりするとルームから出たことにします。ルームに入るときと同様にアクティブユーザーを取得して、各ユーザーのアクティブ状況を表示します。
  • 自分にブロードキャスト
    • 「独り言」
      「独り言」ということで自分のみメッセージを受信します。

構成

以前作成した開発環境をベースにDockerで構築しています。この構成もGitHubに公開していますのでDockerfileやDocker Composeと併せてご覧ください。ここではサービス毎に主な設定をピックアップします。

MySQL

ActionCableへ接続する際にユーザー情報を取得する処理のために利用します。特筆することはありませんが、強いて言えばデフォルトの文字コードをutf8mb4にしています。

Nginx

  • ポート (nginx.conf / docker-compose.yml)
    自己署名証明書(所謂オレオレ証明書)ではSSLハンドシェイクの関係でうまく通信出来ませんでしたので、この環境では平文のWebSocket通信(ws://)を行うため80番ポートを許可します。なお、筆者環境では独自ドメインとLet' EncryptのSSL証明書でも動作確認しています。その場合は443番ポードで想定通り暗号化されたWebSocketの通信(wss://)ができることを確認しています。
  • WebSocket (nginx.conf)
    ActionCableのエンドポイントである「location /cable」はhttp(https)ではなくWebSocket(ws/wss)として通信できるようにします。

Rails

  • WebAPIモード
    WebのViewやフロントエンドは不要なのでWebAPIとしてプロジェクトを構築します。
  • MySQLのデフォルト文字コード: utf8mb4
    このサンプルアプリでは動作上の意味はありません。折角なので導入しただけです。

Railsは本記事の主題なので後ほど別途説明します。

Redis

  • サブスクリプションアダプター
    Railsのサブスクリプションアダプターには「Async」ではなく「Redis」を使います。
  • キャッシュ
    簡易的なデータストアに使います。

RailsでWebAPIを構築する

前述のとおり本環境はGitHubに公開していますので、この記事では要点のみ紹介します。

プロジェクトを作成する

Docker Composeを初期起動した時点で以下が実行されます。

docker/containers/rails/docker-entrypoint.sh
bundle exec rails new . -d mysql -f -T --api --skip-bundle

ActionCableを設定する

  1. originを許可
    Nginxの設定でも触れましたとおり自己署名証明書ではSSLハンドシェイクの関係でうまく通信出来ませんでした。この環境では平文のWebSocket通信(ws://)も許可します。正規のSSL証明書がインポートされていればwss://のみ指定すれば問題ありません。
    Androidエミュレーターで動作させるためにdisable_request_forgery_protectiontrueに設定して送信元の制限を緩めます。この設定をしないと以下のエラーが発生します。
    筆者はiOS版を開発してからAndroid版を開発しています。iOSシミュレーターでは発生しなかったのでRails側のログ調査を怠っており調査に時間が掛かってしまいました。

    log/development.log
    Request origin not allowed: 
    Failed to upgrade to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)
    
    volumes/app/config/environments/development.rb
    config.action_cable.allowed_request_origins = [ /wss?:\/\/.*/, /ws?:\/\/.*/ ]
    config.action_cable.disable_request_forgery_protection = true
    
  2. サブスクリプションアダプターにRedisを指定
    開発環境のアダプターはデフォルトでasyncです。プロダクション環境ではRedisが推奨(async非推奨)されています。ここではRedisを利用することにします。

    volumes/app/config/cable.yml
    default: &default
      adapter: redis
      url: <%= ENV.fetch("REDIS_URL") { "redis://cache:6379/0" } %>
      channel_prefix: app_production
    
    development:
      <<: *default
    

キャッシュストアを設定する

  1. Redis Gemをインストール
    Gemfileのコメントアウトを外します。

    volumes/app/Gemfile
    gem 'redis', '~> 4.0'
    
  2. キャッシュストアにRedisを指定
    デフォルトのconfig.cache_store = :memory_storeを書き換えます。
    ActionCableでRedisはDB番号0を指定しているので、キャッシュストアはDB番号1を指定しています。

    volumes/app/config/environments/development.rb
    config.cache_store = :redis_cache_store, { url: "redis://cache:6379/1", namespace: 'cache' }
    
  3. 開発環境でキャッシュストアを有効化
    app/tmpディレクトリにファイル「caching-dev.txt」を配置します。
    ファイルさえ配置すればよいのでtouch caching-dev.txtで作成してください。

モデルとマイグレーション

ほんの少し実践的にユーザーの情報がRDBに格納されていることを想定してモデルを作成します。

コンソール
$ bundle exec rails g model user account:string name:string
$ bundle exec rails db:migrate

その他、いくつか制約を加えてマイグレーションした結果以下のようになりました。ただし、追加した制約が無くても動作に影響はありません。

volumes/app/db/schema.rb
ActiveRecord::Schema.define(version: 2019_02_23_052441) do
  create_table "users", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC", force: :cascade do |t|
    t.string "account", null: false
    t.string "name", null: false
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["account"], name: "index_users_on_account", unique: true
  end
end

サンプルデータ(初期データ)を投入する

ActionCable以外の部分の説明が増えることを防ぐため、アプリ側のソースコードを簡略化しました。そのため、以下の3ユーザー以外は動作させることができません。
すみません:bow::bow::bow:

volumes/app/db/seeds.rb
User.create(account: 'chiyo', name: '千代')
User.create(account: 'eru', name: 'エル')
User.create(account: 'otome', name: '乙女')
コンソール
$ bundle exec rails db:seed

コネクションを設定する

公式とほとんど変わりません。アプリとWebAPIはステートレスにしたいのでユーザーの情報はCookieからではなくパラメーターから取得します。実際はOpenID Connectなどのアクセストークンの妥当性をチェックしてコネクションの可否を判断すると思います。

ユーザー情報のやりとり
request.params[:account]
volumes/app/app/channels/application_cable/connection.rb
module ApplicationCable
  class Connection < ActionCable::Connection::Base
    identified_by :current_user

    def connect
      self.current_user = find_verified_user
    end

    def disconnect
    end

    private
      def find_verified_user
        if verified_user = User.find_by(account: request.params[:account])
          verified_user
        else
          reject_unauthorized_connection
        end
      end
  end
end

チャンネルを作成する

コンソール
$ bundle exec rails g channel room
volumes/app/app/channels/room_channel.rb
class RoomChannel < ApplicationCable::Channel
    :
    :
end

デフォルトで作成されているメソッドと、サンプルアプリ向けに作成したメソッドを紹介します。(パブリックメソッドのみ)

subscribed

アプリ側からリクエストされたroomのパラメーターを取得します。サンプルアプリでは無条件にサブスクライブしますが、ユーザーとroomの検証を行って不正なアクセスだったら遮断するなどの処理があっても良いと思います。続いてstream_forを指定します。この表現が正しいかわかりませんが、送信先のグルーピングを指定するイメージです。

  • room全体
    @room(params[:room])を指定します。同じroomを指定(以下、同じルーム)しているアクティブユーザーにブロードキャストすることができます。
  • 自身のみ
    ユーザーのアカウントとroomを連結して自身のみを指定します。一意になれば何でも良いと思います。ブロードキャストではあるものの実質的に自身のみが宛先になります。

room_inは簡易的にルーム毎のアクティブユーザーを追加するメソッドです。このメソッドは説明程度に動作すれば良いので作りは甘いです:bow:

def subscribed
  @room = params[:room]
  @user = self.current_user.id.to_s + @room
  stream_for @room
  stream_for @user

  room_in(key: @room, account: self.current_user.account)
end

unsubscribed

暗黙的、明示的に関わらずサブスクライブを解除したとき、room_inとは反対にルーム毎のアクティブユーザーを削除します。このメソッドも同様に説明程度に動作すれば良いので作りは甘いです:bow:
また、ルームを出たことをアクティブユーザーにブロードキャストします。

def unsubscribed
  room_out(key: @room, account: self.current_user.account)

  # 全員に送ります。
  RoomChannel.broadcast_to(@room, account: self.current_user.account, type: :out)
end

greeting

各ユーザーはサブスクライブしたあと、アクティブユーザーに「ルームに入った」ことを通知します。このとき、roommate(※)を利用してアクティブユーザーのリストを送信します。このリストでアプリ側で表示している各ユーザーのアクティブ状況を更新しています。
※ roommateはルーム毎にアクティブユーザーを取得するメソッドです。前述のroom_in/room_outで管理しています。

def greeting
  # 全員に送ります。
  RoomChannel.broadcast_to(@room, roommate: roommate(key: @room), account: self.current_user.account, type: :in)
end

mumbling

「独り言」ボタンで自分自身だけにブロードキャストします。
「自身だけに通知した処理をつけたい」という理由ありきで実装しました:sweat:

def mumbling
  # 独り言です。
  RoomChannel.broadcast_to(@user, content: '(゚Д゚;)', account: self.current_user.account, type: :mumbling)
end

bark

「ワンワン」「ワオーン」ボタンで、その鳴き声を同じルームのアクティブユーザーに送ります。
多くのサンプルが公開されているチャットアプリだと、このメソッドが肝ですよね。

def bark(data)
  # 全員に送ります。
  RoomChannel.broadcast_to( \
      @room, content: data["content"], account: self.current_user.account, type: :bark)
end

起動する

  1. Docker Composeで起動

    $ cd docker
    $ docker-compose up
    :
    cache_1  | 1:M 09 Mar 2019 09:05:57.692 * Ready to accept connections
    :
    db_1     | Version: '5.7.25'  socket: '/var/run/mysqld/mysqld.sock'  port:   :
    3306  MySQL Community Server (GPL)
    :
    app_1    | Use Ctrl-C to stop
    
  2. ブラウザでトップページのにアクセス
    この環境では正規のドメインを取得していないので、とりあえずhostsに設定してください。
    image

動作を確認したいけれど・・・

本記事ではアプリからのアクセスを前提としてAPIモードでプロジェクトを作成しましたのでWeb向けのCoffeeScriptなどがありません。ここのご紹介はiOS/Android編に譲りたいと思います。

終わりに

ActionCableのドキュメントは分かりやすいと思います。しかし、事例や情報量が少ない上にBeta版の頃の情報も混在しており何が正しいか分かりづらい印象でした。筆者は構築した経験はありませんが、この点は「Socket.IO強し」と言ったところでしょうね。今回の構成が少しでもご参考になれば幸いです。

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

FactoryBotでテストデータ作成する方法

はじめに

こんにちわ!Ruby学習中のYukiと申します。
Rails Tutorialではminitest というテストフレームワークが使用されているのですが、現場ではRspecが使用されることが多いという記事をちらっと見つけたので、復習も兼ね,テストをRspecで記入しているのですが、その中でFactoryBotというGemを使用したのでここにまとめておきます。(今回はrspecでcontrollerをテスト作成する過程になります)

FactoryBotとは...


FactoryBotとは、テストデータの作成を手伝ってくれるGemです。
(以前はFactryGirlという名前でしたが変更されたようです。)
自力でテストデータを作成する事もできるようですが、FactryBotを使うと簡単に生成が可能になります。(便利ですねー!)

FactoryBotを使ってみる

テストデータの定義は、specの配下にfactories/モデル名.rb のようなファイルを作成し、この中で定義していきます。今回はuserというテストデータを定義します。

factries/user.rb
FactoryBot.define do
  factory :user do
    name { 'Yamada Tarou' }
    email { 'yamade@rails.com' }
    password { 'password' }
    password_confirmation { 'password' }
  end
end

この定義をテストで利用するには、

rspec/controllers/users_controller_spec.rb
RSpec.describe UsersController, type: :controller do
  let(:user){ FactoryBot.create(:user) }
end

これで、userをrspecテストで利用することができます。
(FactoryBotを省略できるようにする方法もありますが今回は省略します)

other_userも定義したい。。。

Railsチュートリアルで、ログインユーザーが別のユーザーの変更を行う処理(#updateや#destroyなど)のテストをしたいのでother_userも定義していきます。

factries/user.rb
FactoryBot.define do
  factory :user do
    name { 'Yamada Tarou' }
    email { 'yamade@rails.com' }
    password { 'password' }
    password_confirmation { 'password' }
  end
  factory :other_user, do
    name { 'Sato jirou' }
    email { 'sato@rails.com' }
    password { 'foobar' }
    password_confirmation { 'foobar' }
  end
end

=>NameError:
 uninitialized constact OtherUser

エラーが出てしまいます。
実は、FactoryBotデータを作成する際には、factory :モデル名 do ~ endとする必要があり、今回のように複数のユーザーを作る時には明示的クラスを指定しなければならないようです。故に、

factries/user.rb
/省略/
factory :other_user, class: User do
    name { 'Sato jirou' }
    email { 'sato@rails.com' }
    password { 'foobar' }
    password_confirmation { 'foobar' }
    admin { 'false' }
  end
end

とする事で、無事にテストユーザーを作成する事ができました。
これからも、学んだ事は積極的にアウトプットしていきますので少しでも参考になればと思います。

当方まだまだ学習中の身ですので、訂正等あればご指摘いただければと思います。

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

Ruby 学習記録1

佐々木庸輔と申します。
名古屋在住、現在プログラミングスクールに通う29歳です。
Qiitaはしばらく情報発信というよりは自分自身の学習記録として使用いたしますので、何卒よろしくお願いいたします。
(Sublime Textにて編集しているものを貼り付けたのですが、tagキーで開けた空白がQiitaには反映されてないみたいですね・・・後日編集いたします。)

 

3/17 Ruby

【メソッド】
・ある処理をまとめること
・引数を渡すと何かを返してくれるもの
・引数を受け取るとき、その名前はなんでもいい
・「書き方」
def メソッド名
end

・(例)
def number_count
puts "1"
puts "2"
puts "3"
end

number_count

【ハッシュオブジェクト】
・「書き方」
ハッシュ = {キー => バリュー}

・(例)
item1 = {"title" => "太陽"}
item2 = {:title =>"太陽"}
item3 = {title: "太陽"}
# ↑
# シンボルオブジェクト
puts item1["title"] # <= "太陽"と出力される
puts item2[:title] # <= "太陽"と出力される
puts item3[:title] # <= "太陽"と出力される

【配列オブジェクト】
・「書き方」
配列オブジェクト = [要素1,要素2,要素3,…]
・(例)
pencil_case = ["ペン","消しゴム","定規"]
puts pencil_case[0] # <= "ペン"と出力される

【to_iメソッド】
・文字列オブジェクトに対して使うと数字オブジェクトに変換する
【to_sメソッド】
・数字オブジェクトに対して使うと文字列オブジェクトに変換する

【繰り返し処理】
・「書き方」
while 条件式 do
処理
end
(条件式がtrueのときはずっと処理を繰り返しし続ける。終了させたい場合は条件式がfalseになるか、exitメソッドを指定する。)

・(例)
i = 0
while i <= 3 do
puts "この要素は#{(i + 1)}番目です"
i += 1
end

【<<メソッド】
・「書き方」
配列オブジェクト << 追加する要素
(配列の一番最後に追加要素が追加される)

【lengthメソッド】
・「書き方」
配列オブジェクト.length
(配列の中にいくつ要素があるのか返す)

【スコープ】
・ある変数を利用できる範囲のこと
・スコープの範囲外の変数を使おうとするとエラーが起こる

・(いい例)
def japan
capital = "東京"
puts capital
end

japan # <= "東京"と出力される

・(悪い例)

capital = "東京"
def japan
puts capital
end

japan # <= エラーが起こる

・引数を使うことでスコープ外にある変数をメソッドの中で使うことができる

【引数】
・プログラムでメソッドなどに渡すことのできる値のこと
・引数を使うことでスコープ外にある変数をメソッドの中で使うことができる
・引数は「メソッドを呼び出す部分」と「メソッドを定義している部分」両方に書く
・「メソッドを呼び出す部分」に書く引数と「メソッドを定義している部分」に書く引数の名前は、一致している必要はない

・(例)
def number_three(number)
puts number * 3
end

puts "数字を入力してください"
input = gets.to_i

number_three(input)
#入力した数字の3倍が出力される

・(例)
def rename(name)
name = "Mr.#{name}"
end

name = "Tanaka"
rename(name) name = rename(name)
puts name puts name
#Tanakaと出力される #Mr.Tanakaと出力される

【return】
・メソッド内で「return ◯◯」とするとreturnのあとに続けた式がそのメソッド自体の返り値になる
・returnを利用した時点で返り値が決まるため、メソッドはその行までで強制的に終了する

・(例)
def mixer(fruit)
puts "#{fruit}を細かく砕く"
return "#{fruit}ジュース"
end

mixer("ブドウ")
#ブドウを細かく砕く
puts mixer("ブドウ")
#ブドウを細かく砕く
#ブドウジュース

【eachメソッド】
「書き方」
配列オブジェクト.each do |変数|
処理
end

(例)
animals = ["いぬ", "ねこ", "ねずみ"]
animals.each do |animal|
puts animal
end
#いぬ
#ねこ
#ねずみ と出力される

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

変数とは

変数とは

変数とは、何か値を入れておく入れ物だと思って下さい。

数学の変数とは違う

例えば、

x = 1

という式があるとします。

数学では『右辺』と『左辺』が等しい。つまり、xと1が等しいという意味です。

しかしプログラミングにおいての意味合いは違います。

この場合であれば、xという入れ物のなかに1という数字を入れておくという意味になります。

変数のルール

  • 変数名の先頭は小文字を使用する。
  • Rubyで予め決められている予約語は使用できない。

  • ルールではないですが、、変数名は分かりやすい名称を使いましょう。

変数を使用してみる

example

入力

number = 5
puts(number)

出力

5

変数に入れる値は途中で変更できる

『変数』というくらいなので、中に入れる文字や数値は途中で書き換えることが可能です。

example1

入力

number = 5
puts(number)
number = 10
puts(number)

出力

5
10

数値だったものを文字列に変更することも可能です。(文字列だったものを数値にすることもできます。)

example2

入力

number = 5
puts(number)
number = "こんにちは"
puts(number)

出力

5
こんにちは

変数を使った計算


変数を使用して簡易的な計算プログラムを作成できます。

example

入力

x = 21000
y = 3000
puts x + y
puts x - y
puts x*y
puts x/y

出力

24000
18000
63000000
7

変数を使用して計算式を作ると、変数内の数字を変更するだけで様々な計算が出来るので便利です。

変数を交えた文字式を表示

文字式の中で変数を使用する場合は#{}で変数を囲みます。

example

入力

name = "Seiya"
puts "私の名前は#{name}です。"

出力

私の名前はSeiyaです。

ちなみに#{}を忘れると、、、

入力

name = "Seiya"
puts "私の名前はnameです。"

出力

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