20190710のRubyに関する記事は25件です。

今日の学習

やったこと

・クラスメソッドについて
・オブジェクトについて
・継承について

学んだこと

ruby クラス使い方
→メソッドなどの処理などを入れる箱のようなもの.
この入れ物のなかに処理を書くのが基本。

qiita.rb
# Stringという型(クラス)の値をnewで作成し変数whoへ代入
who = String.new("jobs")

#whoにはString型の値が入っている
p who

上記はStringクラスからnewしてString型の値を作成し、変数whoへ代入している。
そしてp whoでwhoの中身の値を表示している。

実行結果

"jobs"

次のクラスはUserクラスの型からnewしてUserクラスの値を作成し、変数userに値を代入している。

qiita.rb
Userという型(クラス)の値をnewで作成し変数userへ代入
user = User.new

userにはUser型の値が入っている
p user  A

user.name = "user"
p user.name (B)

実行結果
<User:0x00007fbde51ca2f0>
”user"

実行結果(A)の出力結果が得られている。この場合Rubyのクラスの表示方法として決められている定型フォーマットに沿った何かしらのクラスであるという意味のUser:0x00007fbde51ca2f0という表示になっている。

(B)は、Userクラスのメソッドの出力である。

・クラスとインスタンス
クラスには処理を書いていくが、実際に処理を行うときはクラスからインスタンスというものを生成して、処理を行わせる。インスタンスの生成には「new」メソッドを使用する。

class User
  def name
    @name
  end

  def name=(name)
    @name=name
  end

end

user = User.new
user.name="yutaka"
p user.name

実行結果

"yutaka"

このようにクラスを使うときは基本的にnewメソッドを使用してインスタンスを生成して処理を行うことを特に意識しておく。

☆よく言われる例としてはクラスがたい焼きの型、インスタンスがたい焼きなどと言われる。
つまりクラスからインスタンスが生成されといったイメージが大切。
またインスタンスはそれぞれ独立して値を持つことができる。

class User
  def name
    @name
  end

  def name=(name)
    @name = name
  end

end

user1 = User.new
user2 = User.new
user1.name = "yutaka"
user2.name = "hanako"
p user1.name
p user2.name

実行結果

”yutaka”
"hanako"

・クラスの継承
あるクラスの定義を他のクラスの処理に引用すること。

補足教材

・クラスのinitializeについてhttps://www.sejuku.net/blog/21170
・ruby クラス使い方まとめ https://www.sejuku.net/blog/15328
https://www.youtube.com/watch?v=cLD2I5QvrCU

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

今日学んだ事

7/10(水)

●groupメソッド

・テーブルのレコードを指定したカラムでまとめた状態で取得する。

コード

モデル.group(カラム名)

・idが一番小さいコードの1件が表示されるが、裏側ではまとめられた状態で取得されている。
・具体的に何個まとまっているか個数は分からない。

●countメソッド

・配列などの要素数を返すメソッド。
・groupメソッドに続けて使うと、まとめられたそれぞれのレコードの数が取得できる。
コード

モデル.group(カラム名).count

・返り値はハッシュとなる

●keysメソッド

・ハッシュはkeysメソッドを持っている
・ハッシュのキーだけを取り出し、配列として返すメソッド

●mapメソッド

・配列の中身を1つずつ取り出してブロックという構文を繰り返し実行する。
・ブロックの返り値を集めた新しい配列を作成する。
コード

配列オブジェクト.map{|ele| ブロックの処理}

●order('count_カラム名').count(カラム名)

・指定したカラムをグルーピングし、それぞれのレコード数でソートできる

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

【Rails】ユーザ作成

Railsのユーザ作成について

Railsでログイン機能を実装する場合に、ユーザ作成を行うと思います。
今回は、その、ユーザ作成機能について説明していきます。

使用するコントローラ

toppagesコントローラ(サインアップページへ移行するurlがある)
-index

usersコントローラ
-index,show,new,create

の二つです。toppages,usersのように、語尾に「s」を付けているのは、あとあと便利になってくるからです。

使用するモデル

Userモデル
-name:string email:string password_digest:string

ユーザ名、メールアドレス、パスワードを入力とします。

Gemファイルに

gem 'bcrypt', '~>   '

のような記述がありますが、railsに提供されている認証機能です。
この行のコメントアウトを消し、

$ bundle install

を実行し、railsのサーバを再起動させましょう。

また、railsで「bcrypt」を使用する際は、モデル作成時に、

password_digest:string

の記述が必須となります。この記述が無ければ認証ができなくなるので注意しましょう。

コントローラ

topppagesコントローラは、ページの表示だけなので、usersコントローラのみを記述します。

users.rb
class UsersController < ApplicationController
  def index
    @users = User.all.page(params[:page])
  end

  def show
    @user = User.find(params[:id])
  end

  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    if @user.save
      flash[:success] = 'ユーザを登録しました。'
      redirect_to @user
    else
      flash.now[:danger] = 'ユーザの登録に失敗しました'
      render :new
    end

  end

  private

  def user_params
    params.require(:user).permit(:name, :email, :password, :password_confirmation)
  end
end

特筆すべきなのはcreateアクションのuser_paramsのところです。
ストロングパラメータの、password_confirmationは、確認用のパスワードのことです。
password_confirmationが記述されることで、パスワードの確認をプログラムがいい感じにやってのけてくれます。

モデル

ユーザモデルに、has_secure_passwordと記述することでbcryptの認証機能を呼び出すことが出来ます。

user.rb
class User < ApplicationRecord
    has_secure_password
end

ユーザ作成画面

CSSも適用してない最低限の画面です。

new.html.erb
<h1>Sign up</h1>
<p>
<%= form_for(@user) do |f| %>
<p>
<div class="form-group">
    <%= f.label :name, 'Name' %>
    <%= f.text_field :name, class: 'form-control' %>
</div>
<div class="form-group">
    <%= f.label :email, 'Email' %>
    <%= f.email_field :email, class: 'form-control' %>
</div>
<div class="form-group">
    <%= f.label :password, 'Password' %>
    <%= f.password_field :password, class: 'form-control' %>
</div>
<div class="form-group">
    <%= f.label :password_confirmation, 'Confirmation' %>
    <%= f.password_field :password_confirmation, class: 'form-control' %>
</div>
<P>
<%= f.submit 'Sign up', class: 'btn btn-primary btn-block' %>

<% end %>
show.html.erb
<h3 class="panel-title"><%= @user.name %></h3>

これでユーザ作成に必要な主要な部分は完成しました!

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

RailsのログからRubyGemsによるwarningを非表示にする方法

現象

Ruby v2.6とRails5.1系でRubyがRails側のGemに対してものすごい数のwarningを出すようになりました。
具体的には、ActiveRecordの内部で BigDecimal.new を呼んでいるようで、それに対してwarningが出ています。

こんな感じのエラーが出る
.../vendor/bundle/ruby/2.6.0/gems/activerecord-5.1.7/lib/active_record/connection_adapters/mysql/database_statements.rb:32: warning: BigDecimal.new is deprecated; use BigDecimal() method instead.

Ruby v2.6では明示的にwarningを出すようになったからだそうです。
ref: Ruby 2.6 の変更点 - Numeric, BigDecimal BigDecmial.new が非推奨

対処法

対処法としてはJeremy Evans氏作のruby-warning gemを使うと良さげです。
具体的には下記のような処理をconfig/initializers配下に置いておくと、Railsが起動される前に読み込まれて、Gemに起因するwarningがログに出なくなります。

*開発環境ではログに出るようにしておくと、「あ、このGemアップデートしなきゃ」などが分かっていいかなと思います。

initializer配下にこんな感じのを置いておく
unless Rails.env.development?
  Gem.path.each do |path|
    Warning.ignore(//, path)
  end
end

他にもっとスマートな方法をご存知の方がいらっしゃいましたら、ご指摘お願いします。 :pray:

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

RailsをBootstrapVueで動かす

初投稿です

RailsでBootstrapとVue.jsを使う方法を調べると、
Vue.jsをrails new project --webpack=vueで入れてきて、
BootstrapはGemfileにgem 'bootstrap'を書いてbundle installしてjsやscssをいじって、、、
というのがオーソドックスなやり方のよう

ちょっと面倒なのと、なぜかvueファイルのtemplateに書いたtooltipがちゃんと効いてくれなかったので、Bootstrapをgemで入れないようにして、yarnでBootstrapVueを入れるようにしてみた

BootstrapVue

おなじみBootstrapとVue.jsが合体したもの
公式サイト

やったこと

プロジェクト作成(webpackでvueもインストール)

$ rails new bootstrapvue_rails --webpack=vue

yarnでBootstrapVueをインストール

$ cd bootstrapvue_rails
$ yarn add bootstrap-vue

画面を用意して、ルーティングしてあげる

$ rails g controller Home index
config/routes.rb
Rails.application.routes.draw do
  root to: 'home#index'
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end

画面のjsファイルを作る

app/javascript/packs/home.js
import Vue from 'vue/dist/vue.esm'
import BootstrapVue from 'bootstrap-vue'
import App from '../app.vue'

import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'

Vue.use(BootstrapVue)

document.addEventListener('DOMContentLoaded', () => {
  const app = new Vue({
    el: '#hello',
     data: {
      message: "Can you say hello?"
    },
    components: { App }
  })
})

vueファイルを作る

app/javascript/app.vue
<template>
  <div id="app">
    <p>{{ message }}</p>
    <div class="text-center my-3">
      <b-button v-b-tooltip.hover title="Tooltip content">Hover Me</b-button>
    </div>
  </div>
</template>

<script>
export default {
  data: function () {
    return {
      message: "Hello Vue!"
    }
  }
}
</script>

<style scoped>
p {
  font-size: 2em;
  text-align: center;
}
</style>

viewで読み込む

app/views/home/index.html.erb
<h1>Home#index</h1>
<p>Find me in app/views/home/index.html.erb</p>

<div id='hello'>
  {{message}}
  <app></app>
</div>

<%= javascript_pack_tag 'home' %>

サーバーを立ち上げたらtooltipが効いてくれてる

$ ./bin/webpack-dev-server
$ rails s

スクリーンショット 2019-07-10 21.05.55.png

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

BootstrapVueをRailsに導入してみる

初投稿です

RailsでBootstrapとVue.jsを使う方法を調べると、
Vue.jsをrails new project --webpack=vueで入れてきて、
BootstrapはGemfileにgem 'bootstrap'を書いてbundle installしてjsやscssをいじって、、、
というのがオーソドックスなやり方のよう

ちょっと面倒なのと、なぜかvueファイルのtemplateに書いたtooltipがちゃんと効いてくれなかったので、Bootstrapをgemで入れないようにして、yarnでBootstrapVueを入れるようにしてみた

BootstrapVue

おなじみBootstrapとVue.jsが合体したもの
公式サイト

やったこと

プロジェクト作成(webpackでvueもインストール)

$ rails new bootstrapvue_rails --webpack=vue

yarnでBootstrapVueをインストール

$ cd bootstrapvue_rails
$ yarn add bootstrap-vue

画面を用意して、ルーティングしてあげる

$ rails g controller Home index
config/routes.rb
Rails.application.routes.draw do
  root to: 'home#index'
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end

画面のjsファイルを作る

app/javascript/packs/home.js
import Vue from 'vue/dist/vue.esm'
import BootstrapVue from 'bootstrap-vue'
import App from '../app.vue'

import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'

Vue.use(BootstrapVue)

document.addEventListener('DOMContentLoaded', () => {
  const app = new Vue({
    el: '#hello',
     data: {
      message: "Can you say hello?"
    },
    components: { App }
  })
})

vueファイルを作る

app/javascript/app.vue
<template>
  <div id="app">
    <p>{{ message }}</p>
    <div class="text-center my-3">
      <b-button v-b-tooltip.hover title="Tooltip content">Hover Me</b-button>
    </div>
  </div>
</template>

<script>
export default {
  data: function () {
    return {
      message: "Hello Vue!"
    }
  }
}
</script>

<style scoped>
p {
  font-size: 2em;
  text-align: center;
}
</style>

viewで読み込む

app/views/home/index.html.erb
<h1>Home#index</h1>
<p>Find me in app/views/home/index.html.erb</p>

<div id='hello'>
  {{message}}
  <app></app>
</div>

<%= javascript_pack_tag 'home' %>

サーバーを立ち上げたらtooltipが効いてくれてる

$ ./bin/webpack-dev-server
$ rails s

スクリーンショット 2019-07-10 21.05.55.png

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

あなたはRailsチュートリアルで一体なにを学んだというのか【5章】

  • 注意:プログラミング歴29日の初心者が書いています

  • 注意:間違っていたら優しく教えてください(喜びます)

「Ruby on Rails チュートリアル実例を使ってRailsを学ぼう」
https://railstutorial.jp/

素晴らしいチュートリアルに感謝します。

5.1.1 ナビゲーション

link_toについて

link_toはRailsのヘルパー(viewsで使える関数)です。
最終的には<a>タグが生成されます。
第1引数はリンクテキスト、第2引数はURLです。

 link_to "sample app", '#', id:"logo" 

カッコが省略されています。関数です。

 link_to("sample app", '#', id:"logo" )

image_tagについて

image_tagもRailsのヘルパー(viewsで使える関数)です。
最終的には<img>タグが生成されます。
第1引数は画像のsrc、第2引数はここではalt属性です。

image_tag("rails.png", alt: "Rails logo")

第一引数として、単に画像ファイル名のみを指定した場合は、assetディレクトリ内のimagesディレクトリから自動で画像を引っ張ってきてくれます。

5.1.2 BootstrapとカスタムCSS

アセットパイプラインについて

↓がわかりやすい
「railsのアセットパイプラインについて解説する」@hogehoge1234
https://qiita.com/hogehoge1234/items/9a94ebc93c5f937502cd

アセットパイプラインとは、htmlファイルと、css,javascript, imgファイルを自動で統合できるようにする仕組みです。

そもそも、webサイトの表示は、主に以下の3つをブラウザが読み込むことで実現される。

  • htmlファイル

  • cssファイル

  • JavaScriptファイル

*imgファイル

これらを一つのファイルで実現することは可能だが、わかりやすいように通常は別々のファイルで作って、最後にそれぞれをhtmlファイルにリンクさせる。

Railsにおいては、

  • htmlファイルに相当するhtml.erbファイルはviewsディレクトリに保存します。

  • cssとJavascriptとimgファイルはassetディレクトリ内部にある、それぞれのディレクトリに保存します。

さらに言うと、cssファイルではなくsassというcssの便利バージョンになっています。sassファイルからcssファイルに変換(コンパイル)しないとブラウザが読み込めないのですが、アセットパイプラインにはコンパイラも含まれています。

つまり、assetディレクトリに入っているファイルたちが、あたかもパイプの中を通りながら1つのファイルに統合されて出てくるようなイメージです。

Railsサーバーの再起動が必要なタイミング

  • Rubyのバージョンを変更したり、

  • Gemfileを変更したり、

  • Railsの内部クラスから何かを変更した場合は、

再起動する必要があります。

5.1.3 パーシャル (partial)

renderについて

renderはヘルパー(viewsに使える関数)の呼び出しをします。
テンプレートを呼び出して表示させるためによく使われます。

テンプレート(要は繰り返し使うhtml部分など)は、partial(パーシャル)という仕組みを使って、コードを一つのファイルにまとめておきます。

その際、パーシャルのファイル名は、_(アンダースコア)で始まるファイル名にします。

render 'layouts/shim'

これは、/_shim.html.erbというファイルを探してその内容をレンダリング(表示)します。
先頭の_(アンダースコア)html.erbなどの余分な内容は省略して記述します。

もちろん、パーシャルにするコードは別ディレクトリに用意しておく必要があります。

5.2.1 アセットパイプライン

アセットディレクトリについて

assetsディレクトリは、その内容によって、以下3つのディレクトリに含まれています。

  • app/assets: 現在のアプリケーション固有のアセット

  • lib/assets: あなたの開発チームによって作成されたライブラリ用のアセット

  • vendor/assets: サードパーティのアセット

それぞれのassetsディレクトリの内部には、CSS、JavaScript、Imagesのディレクトリが存在します。

マニフェストファイルについて

統合させたり読み込ませるCSSやJavaScriptを指定したり設定したりするファイルです。

プリプロセッサエンジンについて

.erb.scssなど、拡張子を読み取って、.html.cssにコンパイルできるように加工してくれます。

その他の加工について

ファイルすべてに対して 不要な空白やインデントを取り除く処理を行い、ファイルサイズを最小化してくれます。結果として、読み込みが早くなります。

5.3 レイアウトのリンク

名前付きルート

root_path -> '/'
root_url  -> 'http://www.example.com/'

例えば、ルートに関してはすでにrootという名前付きルートが定義されています。
ここに_pathメソッドや_urlメソッドを使用することで、名前付きルートの中身を見てみることができます。

get 'static_pages/help'

上記を、以下の名前付きルートに変換します。

get  '/help', to: 'static_pages#help'

読み方は、
『GETリクエスト(ページを取得しろ)が /help に送信されたとき、
StaticPagesコントローラーのhelpアクションを呼び出してくれ』です。

  test "should get help" do
    get help_path #これ
    assert_response :success
    assert_select "title", "Help | Ruby on Rails Tutorial Sample App"
  end

テストコードの修正をします。
これは、helpという名前付きルートに対して、_pathメソッドを使用し、
/static_pages/helpというパスを取得しています。

5.3.4 リンクのテスト

統合テスト

統合テストは、複数のコントローラの動きをチェックするテストのことです。

assert_select "a[href=?]", about_path

?の中身は、第2引数のabout_pathになります。
つまり、<a href="/about">...</a>というaboutページへのパスを含む<a>タグがあるかどうかのチェックです。

$ rails test:integration

上記コマンドで動かします。

5.4.1 Usersコントローラ

Usersコントローラの生成 (newアクションを追加)

「newアクション」とは、Railsの7アクションの1つです。何かを新規作成する際のアクションです。

get  '/signup',  to: 'users#new'

ルーティングに/signupを追加したことによって、signup_pathでページへのパスを表現できるようになりました。

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

わたしがRailsチュートリアルで学んだこと【5章】

  • 注意:プログラミング歴29日の初心者が書いています

  • 注意:間違っていたら優しく教えてください(喜びます)

「Ruby on Rails チュートリアル実例を使ってRailsを学ぼう」
https://railstutorial.jp/

素晴らしいチュートリアルに感謝します。

5.1.1 ナビゲーション

link_toについて

link_toはRailsのヘルパー(viewsで使える関数)です。
最終的には<a>タグが生成されます。
第1引数はリンクテキスト、第2引数はURLです。

 link_to "sample app", '#', id:"logo" 

カッコが省略されています。関数です。

 link_to("sample app", '#', id:"logo" )

image_tagについて

image_tagもRailsのヘルパー(viewsで使える関数)です。
最終的には<img>タグが生成されます。
第1引数は画像のsrc、第2引数はここではalt属性です。

image_tag("rails.png", alt: "Rails logo")

第一引数として、単に画像ファイル名のみを指定した場合は、assetディレクトリ内のimagesディレクトリから自動で画像を引っ張ってきてくれます。

5.1.2 BootstrapとカスタムCSS

アセットパイプラインについて

↓がわかりやすい
「railsのアセットパイプラインについて解説する」@hogehoge1234
https://qiita.com/hogehoge1234/items/9a94ebc93c5f937502cd

アセットパイプラインとは、htmlファイルと、css,javascript, imgファイルを自動で統合できるようにする仕組みです。

そもそも、webサイトの表示は、主に以下の3つをブラウザが読み込むことで実現される。

  • htmlファイル

  • cssファイル

  • JavaScriptファイル

*imgファイル

これらを一つのファイルで実現することは可能だが、わかりやすいように通常は別々のファイルで作って、最後にそれぞれをhtmlファイルにリンクさせる。

Railsにおいては、

  • htmlファイルに相当するhtml.erbファイルはviewsディレクトリに保存します。

  • cssとJavascriptとimgファイルはassetディレクトリ内部にある、それぞれのディレクトリに保存します。

さらに言うと、cssファイルではなくsassというcssの便利バージョンになっています。sassファイルからcssファイルに変換(コンパイル)しないとブラウザが読み込めないのですが、アセットパイプラインにはコンパイラも含まれています。

つまり、assetディレクトリに入っているファイルたちが、あたかもパイプの中を通りながら1つのファイルに統合されて出てくるようなイメージです。

Railsサーバーの再起動が必要なタイミング

  • Rubyのバージョンを変更したり、

  • Gemfileを変更したり、

  • Railsの内部クラスから何かを変更した場合は、

再起動する必要があります。

5.1.3 パーシャル (partial)

renderについて

renderはヘルパー(viewsに使える関数)の呼び出しをします。
テンプレートを呼び出して表示させるためによく使われます。

テンプレート(要は繰り返し使うhtml部分など)は、partial(パーシャル)という仕組みを使って、コードを一つのファイルにまとめておきます。

その際、パーシャルのファイル名は、_(アンダースコア)で始まるファイル名にします。

render 'layouts/shim'

これは、/_shim.html.erbというファイルを探してその内容をレンダリング(表示)します。
先頭の_(アンダースコア)html.erbなどの余分な内容は省略して記述します。

もちろん、パーシャルにするコードは別ディレクトリに用意しておく必要があります。

5.2.1 アセットパイプライン

アセットディレクトリについて

assetsディレクトリは、その内容によって、以下3つのディレクトリに含まれています。

  • app/assets: 現在のアプリケーション固有のアセット

  • lib/assets: あなたの開発チームによって作成されたライブラリ用のアセット

  • vendor/assets: サードパーティのアセット

それぞれのassetsディレクトリの内部には、CSS、JavaScript、Imagesのディレクトリが存在します。

マニフェストファイルについて

統合させたり読み込ませるCSSやJavaScriptを指定したり設定したりするファイルです。

プリプロセッサエンジンについて

.erb.scssなど、拡張子を読み取って、.html.cssにコンパイルできるように加工してくれます。

その他の加工について

ファイルすべてに対して 不要な空白やインデントを取り除く処理を行い、ファイルサイズを最小化してくれます。結果として、読み込みが早くなります。

5.3 レイアウトのリンク

名前付きルート

root_path -> '/'
root_url  -> 'http://www.example.com/'

例えば、ルートに関してはすでにrootという名前付きルートが定義されています。
ここに_pathメソッドや_urlメソッドを使用することで、名前付きルートの中身を見てみることができます。

get 'static_pages/help'

上記を、以下の名前付きルートに変換します。

get  '/help', to: 'static_pages#help'

読み方は、
『GETリクエスト(ページを取得しろ)が /help に送信されたとき、
StaticPagesコントローラーのhelpアクションを呼び出してくれ』です。

  test "should get help" do
    get help_path #これ
    assert_response :success
    assert_select "title", "Help | Ruby on Rails Tutorial Sample App"
  end

テストコードの修正をします。
これは、helpという名前付きルートに対して、_pathメソッドを使用し、
/static_pages/helpというパスを取得しています。

5.3.4 リンクのテスト

統合テスト

統合テストは、複数のコントローラの動きをチェックするテストのことです。

assert_select "a[href=?]", about_path

?の中身は、第2引数のabout_pathになります。
つまり、<a href="/about">...</a>というaboutページへのパスを含む<a>タグがあるかどうかのチェックです。

$ rails test:integration

上記コマンドで動かします。

5.4.1 Usersコントローラ

Usersコントローラの生成 (newアクションを追加)

「newアクション」とは、Railsの7アクションの1つです。何かを新規作成する際のアクションです。

get  '/signup',  to: 'users#new'

ルーティングに/signupを追加したことによって、signup_pathでページへのパスを表現できるようになりました。

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

ruby正規表現のUnicode プロパティ(とPOSIX文字クラス)

皆様は正規表現をお使いでしょうか?
コードを書くことを生業にしている方なら常日頃とは言わずとも、幾度も相手にしたことがあると思います。

私は結構よく使います。ただし、コードに書き込むのではなくテキストエディタで。
これが割と便利です。練習にもちょうどいい。

何かそれっぽい名前の変数や関数を適当なあたりをつけてgrepする際に、大文字、小文字、キャメルケースにスネークケース、よくあるタイプミスなんかもうまく書けば緩衝して一発で探してきてくれます。
うまく書けば。


しかし、その正規表現は使い捨て。
たまにコーディングする時も結構単純なもの。目的に適うものを書き上げるのが当然の目的であって正規表現にこだわる必要すらない。
せいぜい半角数字を捕まえる時に [0-9] と書くのをやめて \d と書いてみて変わったことをした気分になる程度という体たらく。
書くたびにそれっぽいものをググって拾って魔改造、という感じ。

UnicodeプロパティだとかPOSIX文字クラスだとかいう連中がいることは知ってはいるが使ったことはあっただろうか?

そこで、せっかくの機会なのでいくらか調べてここに書き留めておくことにしました。

rubyでの正規表現を想定しています。
rubularは便利ですね。


日本語相手の正規表現

先ほど少し書いたように、数字にマッチさせたい場合 [0-9] という文字クラスを指定することがよくあるかと思います。
また、同様にアルファベットにマッチさせたい場合 [a-zA-Z] などと指定したりするかもしれません。
一般的な英数字、または記号程度ならこの書き方で正直事足りるような気がします。
しかし、このような文字クラスでの指定は日本語の場合少し癖のあるものになりがちです。

例えば「正規表現 ひらがな」なんかで検索すると [ぁ-ん] と表記するといいよ。と書いてあることがままあります。(小さい"あ"から始まります)
実際にUnicodeを確認してみたところ、小さい"ぁ"は普通の"あ"の前にあります。なので小さい"あ"から指定を始める必要があるようですね。
スクリーンショット 2019-07-10 6.04.25.png


ちなみにこの画像をみてもわかるようによくネット上で見かける[ぁ-ん]という文字クラスの指定では"ゔ"以降のひらがなを捉えられません。
スクリーンショット 2019-07-10 6.09.47.png


それよりもこれを調べていて痺れたのは"ん"以降のひらがなですね。

"ゝ"や"ゞ"なんかはまだ見たことはありますが U+309F の彼は一体何者なのでしょうか、そもそもお前は本当にひらがななのか?なんと打てば出てくるのかすら全くわかりません。
wikipediaによると ゟ←これ はよりと読み、「現状ではコードポイントを設定していないため、PCのテキスト上に表示できない。」ということらしいが・・・。
手紙の最後に「〜ゟ」と記名したり、「ロシアゟ愛を込めて」なんて具合に使うのだろうか。
合略仮名という分類の文字らしいです。


打ち方がわからないでいうと"ゕ"と"ゖ"もなかなか謎です。"lka"とか"xka"とか打っても"ヵ"としか出てきません。挙句、変換を行うとmacは異なる注釈をつけて同じ文字を3回紹介してくれます。
スクリーンショット 2019-07-10 6.21.51.png
と、ただひらがなを正規表現で捕まえようというだけで早くも苦労に塗れてきました。


Unicode プロパティ

少し話がそれ気味だったような気がしますが、ここでやっとUnicode プロパティが登場します。
ruby(というかonigmo正規表現ライブラリ)では\p{property-name}と記述します。

rubyではonigmoで使えるプロパティが使えます。
カタカナ\p{Katakana}とか、漢字\p{Han}とか、タガログ語\p{Tagalog}とか。
上記リンク参照


かな

このUnicode プロパティを使ってひらがなを補足したかったら\p{Hiragana}と書くだけで、先述の問題も全て解消して、現代の日本人は見たことも無いようなひらがなまで捕まえてくれます。
スクリーンショット 2019-07-10 6.48.19.png


ここで\p{Hiragana}に含まれている文字はどんなものがあるのか気になります。
どうも\p{}はUnicodeのScriptsを参照するらしいです。
http://www.unicode.org/Public/UNIDATA/Scripts.txt

これによるとHiraganaの中身はこんな感じ。

3041..3096    ; Hiragana # Lo  [86] HIRAGANA LETTER SMALL A..HIRAGANA LETTER SMALL KE
309D..309E    ; Hiragana # Lm   [2] HIRAGANA ITERATION MARK..HIRAGANA VOICED ITERATION MARK
309F          ; Hiragana # Lo       HIRAGANA DIGRAPH YORI
1B001..1B11E  ; Hiragana # Lo [286] HIRAGANA LETTER ARCHAIC YE..HENTAIGANA LETTER N-MU-MO-2
1B150..1B152  ; Hiragana # Lo   [3] HIRAGANA LETTER SMALL WI..HIRAGANA LETTER SMALL WO
1F200         ; Hiragana # So       SQUARE HIRAGANA HOKA

# Total code points: 379

一番上の行を例に、左から

・3041..3096 : Unicode 文字コード範囲
・Hiragana : プロパティ名(\p{}の中身)
・Lo : Unicode一般カテゴリ(詳しくはUNICODE CHARACTER DATABASEのGeneral Category Valuesの項を参照)
・[86] : 包含文字数(読んで字のごとく、86文字)
・HIRAGANA LETTER SMALL A..HIRAGANA LETTER SMALL KE : プロパティ説明(これも読んで字のごとく、小さい"あ"から小さい"け"まで)

そのほかにも複数のグループが含まれていて合計379もの文字がHiraganaプロパティには含まれているようです。
50音順とはなんだったのか。


ちなみに先ほどの結果を見てお気付きの方もいらっしゃるかもしれませんが、このHiraganaプロパティ、長音記号は含まれていません。
スクリーンショット 2019-07-10 6.48.19.png


意図したものなのか否か。何れにせよ伸ばし棒も捕まえたければちゃんと[\p{Hiragana}ー]と文字クラスに含めておきましょう。
スクリーンショット 2019-07-10 8.33.25.png
ただ、長音記号には似たような形のものがいっぱいあるので、純粋な長音記号しか許可しないようにしているとハイフンを入力しながら「伸ばし棒が通らない!」と怒られるかも。

\p{Katakana}も同様に長音記号は含まれていません。


ただし、[ぁ-ん]これにはこれで魅力があると思っています。

ひらがなにマッチする正規表現を書こうとした時、頭に思い浮かべたのが50音順+濁点・半濁点程度の一般的なひらがな達にとどまるなら\p{Hiragana}は過剰でしょう。
見たことのない記号のような文字などが通過してきてしまいます。

こういう時には[ぁ-ん]を使っていくのが良いのではないでしょうか。


漢字

漢字を捉える正規表現は[一-龠]とか[一-龥]などをネットでは見かけたりします。(これはUnicodeの話でありShift_JISでは違う表記になります。)
まぁ、常用する漢字ならこの範囲で十分カバーしており、これより先は言語学者でもなければ使わないだろうと言う腹ですね。

当然これに収まらない漢字もありますが、ここで\p{Han}と書くとこれが解決。
約9万字にのぼるあらゆる漢字を拾ってくれます。


さらにこの\p{Han}拾うのは日本語の漢字に止まりません。
中国語の簡体字や繁体字、韓国語の漢字にもマッチしてくれて、ベトナム語の漢字(があることを今回初めて知った。)にもマッチするそうです。

最近話題になった"令"を例にしてみましょう。新元号「令和」の令です。
この漢字は、韓国語にも同じ形の漢字があり、別のコードが与えられているということで少し前にちょっと一部界隈で話題になりました。
qiitaにもいくつか記事があります。

s = "令令"
puts s.codepoints.collect {|cp| sprintf("U+%04X", cp) }.join(", ")

# => U+4EE4, U+F9A8

# 下記ページ参照
# https://ref.xaio.jp/ruby/classes/string/codepoints

これを正規表現に与えます。
スクリーンショット 2019-07-10 12.14.37.png
こちらはダメ
スクリーンショット 2019-07-10 12.14.49.png
こちらはうまく両方を取ってくれました。


その他

当然、言語関連以外にも算術記号\p{Sm}その他記号\p{P}アンダースコア\p{Pc}

ハイフンやダッシュなど長音記号っぽい者達にマッチする\p{Pd}という子もいますが、これはあらゆるハイフンやダッシュの親戚もマッチしてしまうので ←こんな見たこともない子もマッチしちゃうかも。


ちなみに、\p{P*}というプロパティたちは全て\p{P}の部分集合です。
PはPunctuationの略で句読点のほか、約物なんて訳されたりします。

記号全般っぽいですが算術記号\p{Sm}は見ての通り約物に含まれていません。こちらはSymbolカテゴリに含まれています。
ここのGeneral Category Valuesや
ここなどでP*に含まれているものが何者か注意しておくと良いかもしれません。


POSIX 文字クラス

似たようなものでPOSIXブラケットと言うものもあります。こちらはonigmoに限らず、Shift_JISだとかEUCだとかUnicodeでなくとも使えたりするようです。

こちらはruby正規表現ドキュメントに使用できるクラス名とその内容が列挙されています。

[:alnum:] 英数字 (Letter | Mark | Decimal_Number)
[:alpha:] 英字 (Letter | Mark)
[:ascii:] ASCIIに含まれる文字 (0000 - 007F)
[:blank:] スペースとタブ (Space_Separator | 0009)
[:cntrl:] 制御文字 (Control | Format | Unassigned | Private_Use | Surrogate)
[:digit:] 数字 (Decimal_Number)
[:graph:] 空白以外の表示可能な文字(つまり空白文字、制御文字、以外) ([[:^space:]] && ^Control && ^Unassigned && ^Surrogate)
[:lower:] 小文字 (Lowercase_Letter)
[:print:] 表示可能な文字(空白を含む) ([[:graph:]] | Space_Separator)
[:punct:] 句読点 (Connector_Punctuation | Dash_Punctuation | Close_Punctuation | Final_Punctuation | Initial_Punctuation | Other_Punctuation | Open_Punctuation)
[:space:] 空白、改行、復帰 (Space_Separator | Line_Separator | Paragraph_Separator | 0009 | 000A | 000B | 000C | 000D | 0085)
[:upper:] 大文字 (Uppercase_Letter)
[:xdigit:] 16進表記で使える文字 (0030 - 0039 | 0041 - 0046 | 0061 - 0066)
[:word:] 単語構成文字 (Letter | Mark | Decimal_Number | Connector_Punctuation)

ドキュメントにも'エンコーディングによってこれらの POSIX 文字クラスの挙動が 異なります。'と記載されている通り、Unicode以外のエンコーディングではマッチする文字が異なるようなので、onigmoのドキュメントを参照する必要があります。


個人的にUnicode プロパティが使えるならこちらを殊更使う必要は生じないと考えています。
何よりこのドキュメントがかなりの誤解を招く。こちらの記事のコメントでも白熱しております。

上記記事でわかるのは[[:alpha:]][[:alnum:]]はかな漢字にマッチすると言うことです。
先ほどのドキュメントによると一見、英数字や英字にしかマッチしないように見えるのに。
スクリーンショット 2019-07-10 13.50.47.png


ここでちゃんと(onigmoのドキュメント)[https://github.com/k-takata/Onigmo/blob/master/doc/RE.ja] を見てみましょう。

POSIXブラケットの項目には Unicode以外の場合、 Unicodeの場合 と分けてマッチする文字が記載されています。

Unicode以外の場合は

alnum 英数字
alpha 英字
そしてUnicode場合は
alnum Letter | Mark | Decimal_Number |
alpha Letter | Mark |
と書いてあります。


つまり、Unicodeはアルファベットを Letter | Mark の2カテゴリだと認識していると言うことだと考えられます。

ということは、ABCDEあいうえお白發中もLetterカテゴリなのでalphaだし、
こんな奴も[[:alpha:]] [[:alnum:]]は我々の直感に反して見事拾ってきます。
スクリーンショット 2019-07-10 14.13.12.png


最後に

マッチする文字がどのようなものかを正確に認識した上で利用するならば[[:alpha:]]も便利ではあるのでしょう。
ただ、コーディングする場合は当然、いずれ他人の目に触れることになるでしょう。
その時、そのコードをみた人は「/[[:alpha:]]/だから言語を問わず単語を構成する文字がかかるんだな。」と認識できるでしょうか。

少なくともこの記事を書く前の私なら絶対に思わないでしょう。きっと[A-Za-z]と同等だと認識したはずです。そして、この認識が間違っていることに気がつくのも非常にこんなんだと思います。

そんなことを気にするくらいなら迷わず[A-Za-z]を使います。
POSIX文字クラスに関しては、「この程度なら普通に正規表現を書けばいいじゃん。」です。

Unicode プロパティも前述の通り微妙に直感に反してきたりしますが、POSIX文字クラスに比べると有用性が高い印象です。
積極的に使っていきたいですね。


参考

[正規表現] Unicode 文字プロパティ (01) -- 概要
正規表現クラス[:alnum:]の罠

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

rails runner で Please specify a valid ruby command or the path of a script to run.

問題:lib以下のディレクトリを読み込んでくれない

スクリプトはこんな感じ

#lib/batch/push.rb
class Test
  def self.push
    require 'json'
    result = TalkHistory.where(call_status: 'skyway_ringing').where(call_duration: nil).where('talked_at>?',Time.zone.now - 1.days).count("id")
    result_hash = {"count"=> result}

    File.open("test.json","w") do |file|    
      JSON.dump(result_hash,file)
    end
    #jsonファイルのアップロード
    require 'aws-sdk'
    s3 = Aws::S3::Resource.new(
      :region => 'ap-northeast-1',
      :access_key_id => ENV['ACCESS_KEY_ID'],
      :secret_access_key => ENV['SECRET_ACCESS_KEY']
    )
    bucket = s3.bucket('testbucket0709')
    bucket.object('test').upload_file("test.json")
    puts bucket.object('test').exists?
    puts bucket.object('test').get.body.read
  end
end

実行すると...

rails ruuner 'Test.push'
=>
Please specify a valid ruby command or the path of a script to run.
Run 'bin/rails runner -h' for help.

uninitialized constant Test

autoload_pathsを確認

$ bin/rails r 'puts ActiveSupport::Dependencies.autoload_paths'
/Users/satou/projects/koetomosql/lib
/Users/satou/projects/koetomosql/lib/
/Users/satou/projects/koetomosql/lib/tasks/
/Users/satou/projects/koetomosql/lib/batch/
/Users/satou/projects/koetomosql/lib/assets/
/Users/satou/projects/koetomosql/app/assets
/Users/satou/projects/koetomosql/app/channels
/Users/satou/projects/koetomosql/app/controllers
/Users/satou/projects/koetomosql/app/controllers/concerns
/Users/satou/projects/koetomosql/app/helpers
/Users/satou/projects/koetomosql/app/jobs
/Users/satou/projects/koetomosql/app/mailers
/Users/satou/projects/koetomosql/app/models
/Users/satou/projects/koetomosql/app/models/concerns
/Users/satou/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activestorage-5.2.3/app/assets
/Users/satou/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activestorage-5.2.3/app/controllers
/Users/satou/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activestorage-5.2.3/app/controllers/concerns
/Users/satou/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activestorage-5.2.3/app/javascript
/Users/satou/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activestorage-5.2.3/app/jobs
/Users/satou/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activestorage-5.2.3/app/models
/Users/satou/projects/koetomosql/test/mailers/previews

問題なさそう
でもコンソールで確認するとクラスを読み込めてない...

Loading development environment (Rails 5.2.3)
irb(main):001:0> Test
Traceback (most recent call last):
        1: from (irb):1
NameError (uninitialized constant Test)

解決

ディレクトリ名とファイル名をクラス名と合わせる必要があるらしい!!
以下の記事の最後のほう!!
あーむかついた!
Rails Runnerを使ってみる

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

Mac にHomebrew を導入する

HomebrewはMacのOSXなか一番人気が集まっているパッケージ管理ツールである。

事前準備:

Homebrewのインストールには、Xcode Command Line Toolsのインストールが必要
もしXcode Command Line Toolsがインストールがインストールされ中たら以下のコマンドでインストールして置きましょ

xcode-select --install

インストール:

Homebrewは以下のコマンドで直接インストールできます。

$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

次に/usr/local/binを$PATH環境変数に追加するのを忘れましょう

$ echo 'export PATH="/usr/local/bin:$PATH"' >> ~/.bash_profile

上記、手順が終わったら、以下のコマンドでHomebrewが正しくインストールされている事を確認しましょう

$ brew doctor

使用方法:

あるパッケージをインストールしたい場合は簡単に以下ようにコマンドを叩きます。

$ brew install <package_name>

もし、Homebrewのパッケージリストを更新したい場合は

$ brew update

インストールされたパッケージに更新が必要なパッケージがあるかないか確認するには

$ brew outdated

パッケージ名を指定して更新したい場合は

$ brew upgrade <package_name>

キャッシュされた古いパッケージをクリアするには

$ brew cleanup

インストールされたパッケージのリストとパージョンを確認するには

$ brew list --versions

以上、Homebrewのインストール方法と簡単な運用方法を纏めました。

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

rbenvで環境切り替えたとき用にRubyのrequire一覧を出すTool

TL;DR (長い三行で)

rbenvでRubyのVersionを入れ替えたときに,Gemが入ってなくてrequire xxxでエラーが出る
・エラー出るたびにgem install xxxするのしんどい
・いまあるrequire xxxを全部リストアップするToolつくるで

できたもの

gen_require_lines.rb
#! /usr/bin/env ruby
#! ruby
# ENCODING: UTF-8

#### SEARCH ALL .RB FILES UNDER PWD
def get_rb_files(root_dir)
  rb_files = []

  Dir.entries(root_dir).each { |entry|
    next if entry.start_with?('.')

    entry_full_path = "#{root_dir}/#{entry}"

    case File.ftype(entry_full_path)
      when 'directory'
        sub_results = get_rb_files(entry_full_path)
        rb_files += sub_results

      when 'file'
        if entry.end_with?('.rb')
          rb_files << entry_full_path
        end

      else
        # NOP.
    end
  }

  return rb_files
end

total_rb_files = get_rb_files(Dir.pwd)
total_rb_files.sort!

#### PARSE EACH .RB
require_lines = []
total_rb_files.each { |rb|
  File.open(rb) { |file|
    file.each_line { |line|
      line.force_encoding('UTF-8')
      line.chomp!
      line.scrub!
      line.strip!

      if !line.match(/^require\s/).nil?
        require_lines << line
      end
    }
  }
}
require_lines.uniq!
require_lines.sort!

#### OUTPUT
require_lines.each { |line|
  puts line
}

まとめると

こんなTool作るハメになる前に,外部依存関係はちゃんと管理しましょう.

---///

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

【Rails】sendを使ってメタプロっぽい書き方をしたので記しておく

タイトル通り、sendメソッドを使ってメタプロっぽい書き方をやってみたので書き残しておく。

説明

deviseで clientcreatorという2つのモデルを用意している。
それぞれ、nameが登録されているか/されていないかによって、ログイン後の繊維ページが異なるが、
clientとcreator間での法則性は同一である。
↓こんな感じ

name登録済み name未登録
client client_mypage_path edit_client_path(current_client)
creator creator_mypage_path edit_creator_path(current_creator)

send使ってafter_sign_in_path_for

application_controller.rb
class ApplicationController < ActionController::Base
  helper_method :current_resource, :current_resource_model, :other_side_model, :registered_name?

  def current_resource
    if client_signed_in?
      current_client
    elsif creator_signed_in?
      current_creator
    end
  end

  def current_resource_model
    return unless current_resource
    current_resource.class.to_s.downcase
  end

  # ログイン後に遷移するpathを設定
  def after_sign_in_path_for(resource)
    return unless current_resource
    resource_mypage_path = send(current_resource_model + "_mypage_path")
    edit_resource_path = send("edit_" + current_resource_model + "_path", current_resource)

    registered_name? ? resource_mypage_path : edit_resource_path
  end

  def registered_name?
    current_resource&.name.present?
  end

このように、複数のdeviseモデルでの法則的なコードを1つにまとめて記述する時に役に立ちそう。

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

ハッシュの様々な記述法

今回は、3つのハッシュの記述法を紹介する。

1.ハッシュロケットのみの記述法

hash1 = { "key" => "value"}

2.ハッシュロケットおよびシンボルの記述法

hash2 = { :key => "value"}

3.シンボルのみの記述法

hash3 = { key: "value"}

※keyと:(コロン)の間にスペースがあると、構文エラーになる。

最近では、ハッシュロケットを用いた記述法がなされることは少なく、シンボルのみの記述法が主流になっているみたいである(あくまで、自分の感想の範囲内)。

<参考記事>
http://mikanmarusan.hatenablog.com/entry/2017/12/29/005632
https://qiita.com/yukimura1227/items/8c972efb27667dfac5cd
https://qiita.com/YusukeHigaki/items/18db85aa9cba3cb42569

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

ハッシュの2つの記述法

今回は、2つのハッシュの記述法を紹介する。

1.ハッシュロケットおよびシンボルの記述法

hash2 = { :key => "value"}

2.シンボルのみの記述法

hash3 = { key: "value"}

※keyと:(コロン)の間にスペースがあると、構文エラーになる。

最近では、ハッシュロケットを用いた記述法がなされることは少なく、シンボルのみの記述法が主流になっているみたいである(あくまで、自分の感想の範囲内)。

ちなみに、ハッシュとしては別物ではあるが、以下のようにハッシュと似たような書き方がある。

文字列としての書述法

hash1 = { "key" => "value"}

<参考記事>
http://mikanmarusan.hatenablog.com/entry/2017/12/29/005632
https://qiita.com/yukimura1227/items/8c972efb27667dfac5cd
https://qiita.com/YusukeHigaki/items/18db85aa9cba3cb42569

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

あなたはRailsチュートリアルで一体なにを学んだというのか【4章】

  • 注意:プログラミング歴29日の初心者が書いています

  • 注意:間違っていたら優しく教えてください(喜びます)

「Ruby on Rails チュートリアル実例を使ってRailsを学ぼう」
https://railstutorial.jp/

素晴らしいチュートリアルに感謝します。

4.1.1 組み込みヘルパー

組み込み関数ってなんですか

組み込み関数とは、プログラミング言語がもともと用意してくれている関数のことです。
ビルトイン関数とも言います。

ヘルパーってなんですか

viewで使える関数のことをrailsではヘルパーと呼んでいます。

つまり、
「組み込みヘルパー」とは

  • 「railsがもともと用意してくれている」

  • 「viewで使える関数」

のことです。

4.1.2 カスタムヘルパー

カスタムヘルパーってなんですか

  • 「自分でカスタムした(自分で作る)」

  • 「viewで使える関数」

ということになります。

リスト 4.2: full_titleヘルパーを定義する

「Home」ページにアクセスした際に、Home | Ruby on Rails Tutorial Sample App ではなく、Ruby on Rails Tutorial Sample Appのみを表示させたい。
しかし、現状のコードのまま実装を進めると、|(縦棒)が残ってしまいます。

「full_title」関数(ヘルパー)を作って、|(縦棒)が残らないようにしましょう。

viewで使いたい関数はhelperディレクトリ内のファイルに記述する

これです。ここで言いたいのは多分これです。
「viewで使いたい関数はhelperディレクトリ内のファイルに記述すること」

ヘルパーの中身

module ApplicationHelper
    # ページごとの完全なタイトルを返します。
  def full_title(page_title = '') #1
    base_title = "Ruby on Rails Tutorial Sample App" #2
    if page_title.empty? #3
      base_title #4
    else
      page_title + " | " + base_title #5
    end
  end
end

#1: full_title関数の定義・引数page_title = ''は、『引数としてpage_titleをとる。引数の指定がない場合は' 'を引数とする』という意味です。

#2: 変数base_title"Ruby on Rails Tutorial Sample App"を代入。

#3: page_titleに対して.empty?メソッドを用いて、変数内に値が存在するかどうかで条件分岐させます。

#4: .empty?メソッドは、変数が空ならTrueを返します。 page_titleが空のとき、base_titileのみを返します。
(ちなみに、Rubyではメソッドがtrueまたはfalseを返す場合、メソッド名に?がついています。)

#5: 変数内に値が存在する場合、page_title|(縦棒)base_titleを返します。


application_helper.rbに書き込まれた上記の内容は、railsの力によって、自動的にapplication.html.erbで使用可能になります。

apprication.html.erbの中身

<title><%= full_title(yield(:title)) %></title>

タイトルタグのコードです。
ヘルパーで定義した、「full_title」関数を呼び出しています。

引数には、yieldメソッドでページごとにprovideで設定してあるタイトルを呼び出しています。

Homeページから「Home | 」を取り除く

まずはテストから作り初めて、それからテストを通す実装をします。

  test "should get home" do
    get static_pages_home_url
    assert_response :success
    assert_select "title", "Ruby on Rails Tutorial Sample App"#←ココ
  end

home_urlのgetリクエストに対して、
titleは"Ruby on Rails Tutorial Sample App"を表示
というテストです。

rails testすると当然失敗します。
なぜなら、home.html.erbprovideメソッドがタイトルとして"Home"を指定しているからです。

テストを通すためには、
home.html.erbから、provideメソッドの行を取り除きます。

4.3.2 ブロック

ブロックは、メソッドの引数として渡すことのできる処理のかたまりです。
{}波括弧do ... endの部分がブロックです。

test "should get home" do
  get static_pages_home_url
  assert_response :success
  assert_select "title", "Ruby on Rails Tutorial Sample App"
end

テスト文も、じつはtestメソッドが、引数としてブロックをとっています。
do ... endで挟まれた処理がtestメソッドの引数になっています。

4.4.5 ユーザークラス

class User
  attr_accessor :name, :email #アクセサメソッド

  def initialize(attributes = {}) #initializeメソッド
    @name  = attributes[:name]
    @email = attributes[:email]
  end

  def formatted_email #インスタンスメソッドの定義
    "#{@name} <#{@email}>"
  end
end

#アクセサメソッド
インスタンス変数に、クラス外からアクセスできるようになります。

#initializeメソッド
User.newを実行すると自動的に呼び出されるメソッドです。
.newと同時に実行されます。

#インスタンスメソッドの定義
メソッドを呼び出すことで、
"ユーザー名 <メールアドレス>"という文字列を返すメソッドです。
特に意味はないです。

 user = User.new(name: "Michael Hartl", email: "mhartl@example.com")

上記のように使えます。

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

[Rails]既存のデータベースにRailsで接続してActiveRecordでレコードを抽出する方法

やりたいこと

[Rails]gem"whenever"を使って定期的にタスクを実行するの続きです
今回は その2:既存のデータベースにRailsで接続してActiveRecordでレコードを抽出する をやります

config/database.ymlの中身を変更

development:
  adapter: mysql2
  database: データベース名
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: ユーザ名
  password: パスワード
  host: ホスト
  port: ポート番号

既存のデータベースのスキーマ情報を新規Railsプロジェクトにコピーする

参考記事
Rails - schema.rb(既存DBを使ったアプリ作成)
既存DBを使ってRails

以下のコマンドでスキーマ情報がdb/schema.rbに書き込まれる

rake environment -t RAILS_ENV=development db:schema:dump

空のマイグレーションファイルを生成して中身を先ほどコピーしてきたschema.rbに置き換えてマイグレートする

rails g migration create_table
中身を書き換えてから
rails db:migrate

モデルを生成する

テーブルの数だけ作るらしいです(正直まだ理解できてません)
でも作らないとエラー吐かれるので作りました...
オプション指定するとマイグレーションファイル生成するのを防ぐことができます

rails g model モデル名 --migration false

ここまで設定したらActiveRecord使えるようになりました!

lib/tasks/testsql.rb

namespace :testsql do
  desc "sqlの定期送信"
  task sql: :environment do

    require 'json'
    result = TalkHistory.where(call_status: 'skyway_ringing').where(call_duration: nil).where('talked_at>?',Time.zone.now - 1.days).count("id")
    result_hash = {"count"=> result}
    result_json = JSON.generate(result_hash)

    File.open("test2.json","w") do |file|    
      file.puts result_json
    end

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

Rails6 のちょい足しな新機能を試す50(scaffold 編)

はじめに

Rails 6 に追加されそうな新機能を試す第50段。 今回は、 scaffold 編です。
Rails 6 では、 belongs_to な関係のあるモデルがあるアプリを scaffold で作った場合に、 belongs_to で指定される親モデルの表示のされ方が変わりました。
...ってなんだか良くわかりませんね。

実際にやってみた方がわかりやすいです。

Ruby 2.6.3, Rails 6.0.0.rc1, Rails 5.2.3 で確認しました。Rails 6.0.0.rc1 は gem install rails --prerelease でインストールできます。

$ rails --version
Rails 6.0.0.rc1

rails プロジェクトを作る

$ rails new rails6_0_0rc1
$ cd rails6_0_0rc1

scaffold を使う

scaffold で Author と Book の CRUD を作成します。Book は、 Author に属します。

$ bin/rails g scaffold Author name
$ bin/rails g scaffold Book title author:references

seed データを作る

Author と Book のデータを1つずつ作成します。

db/seeds.rb
author = Author.create(name: 'Dave Thomas')
Book.create(title: 'Programming Ruby', author: author)

データベースを作る

データベースを作って seed データを登録します。

$ bin/rails db:create db:migrate db:seed

rails server を実行して Book のデータを表示する

rails server を実行します。

$ bin/rails s

http://localhost:3000/bookshttp://localhost:3000/books/1 で一覧画面と詳細画面を表示します。

Rails 5 では

一覧画面でも詳細画面でも、Author はAuthorオブジェクト( Author#to_s )を表示します。

一覧画面

rails5index.png

詳細画面

rails5show.png

Rails 6 では

一覧画面でも詳細画面でも、Author は ID ( Author#id ) の 1 を表示します。

一覧画面

rails6index.png

詳細画面

rails6show.png

試したソース

試したソースは以下にあります。
https://github.com/suketa/rails6_0_0rc1/tree/try050_scaffold

参考情報

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

[Rails]gem"whenever"を使って定期的にタスクを実行する

やりたいこと

その1:定期的にSQLを発行して返ってきたデータをjson形式でファイル出力する
その2:既存のDBにRailsで接続してActiveRecordでレコードを抽出する
その3:AWSのS3ストレージにjsonファイルをアップロードする
この記事ではその1だけ

gem"whenever"を利用した定刻処理の実装

この記事の通りにやりました。記事書いてくれた人ありがとうございます。

参考記事
[初学者]whenever を使って定期的にバッチ処理を行う(公開設定編)

コードの全体像

namespace :testsql do
  desc "sqlの定期送信"
  task sql: :environment do

    #SQLの接続
    require "mysql2"
    require 'json'

    client = Mysql2::Client.new(host: '******', username: ENV["DB_USERNAME"], 
      password: '******', database: ENV["DATABASE"])
    result = client.query("select count(id) from talk_histories 
      where call_status = 'skyway_ringing' and call_duration is NULL and talked_at > (now() - interval 1 day)")

      puts result #=> <Mysql::Result>オブジェクトが返ってくる
    result.each do |r|
      puts r  #=> {"count(id)"=>85} 
      puts r["count(id)"] #=> 85
      $count = {count: r["count(id)"]} #グローバル変数$countにハッシュ形式で格納
    end

    #ファイル作成
    File.open("test.json","w") do |text|
      text.puts $count
    end

    #jsonファイルのアップロード
    require 'aws-sdk'
    s3 = Aws::S3::Resource.new( #S3リソースの作成
      :region => 'ap-northeast-1',
      :access_key_id => '******',
      :secret_access_key => '******',
    )

    bucket = s3.bucket('testbucket0709') #バケットの作成
    bucket.object('test2').upload_file("test2.json") #.objectの引数がキーになる
    puts bucket.object('test2').exists? #"test2"のキーを持つオブジェクトがバケットにあるか確認
    puts bucket.object('test2').get.body.read #オブジェクトの読み込み

  end
end

問題:出力したファイルがJSON形式になっていなかった

json形式になっているかどうかの確認はこちらでやりました
JSONLint

参考記事
RubyでのJSONの書き込み
RubyでJSONを扱うときに便利な関数まとめ

僕はハッシュなら全部JSONなんじゃないのとか思ってましたがよく見ると全然違いますね

ハッシュ

{"json"=>"12345"}

JSON

'{"rails": {"json": "12345"}}'

どうやらRubyのライブラリを使うそうです
JSON.generate(配列)とするとjson形式のファイルができるっぽい

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

form_tagをform_forに書き換える

初めまして!
Rails初学者が初めてQiitaで書きます!

form_forってどうやって書いたらいいの?


アプリを作成する際に苦戦したので備忘録として記事を残しておきます。

form_for基本形
<%= form_for (modelobject, option) do |f| %>
 フォームコントロールの設定
<% end %>

これ書いたらformが作成されると思っていましたが、うまくいきません。

まずはビューの部分を記述する


new.html.erb
<div class="contents row">
 <%= form_for @post do |form| %>
//@postにフォームコントロール内で入力する値を入れる//
  <h5>タイトル</h5>
   <%= form.text_field :content, placeholder: 'content' %>
  //ブログのタイトルを入力する為のtext_field
  <h5>本文</h5>
   <%= form.text_field :content, placeholder: 'content' %>
  //ブログの本文を入力する為のtext_filed
  <%= form.submit "SENT" %>
 //送信ボタン
 <% end %>
</div>

次にcontrollerを編集する


posts_controller.rb
class PostsController < ApplicationController

  before_action :move_to_index, except: [:index, :show]
  def new
    @post = Post.new
    //新規作成された値は@postに入れる
  end
  //~省略~

これでform_for内で入力した値は@postに渡されます!
新規作成のフォームは完成したので次は編集する時のフォームの書き方。

編集のビュー部分の作成


edit.html.erb
<div class="contents row">
  <%=form_for @post, url => {action: 'update'} do |form|%>
  //form_forのupdateアクションを明示する為にaction:を指定
  <h5>タイトル</h5>
     <%= form.text_field :title, placeholder: 'title:最大文字数20文字まで' %>
   <h5>本文</H5>
     <%= form_text_field :content. placeholder 'content'%>
   <%= form.submit "SENT" %>
 <% end %>
</div>

次にcontrollerを編集する


posts_controller.rb
class PostsController < ApplicationController
  before_action :set_post, only: [:edit, :show]
  //共通のアクションはcallbackする為、before_action内に設定
〜省略〜
  def show
  end

  def edit
  end

  private

  def set_post
    @post = Post.find(params[:id])
  end

  def post_params
    params.require(:post).permit(:content, :title)
  end
end

以上でform_forでフォームの新規作成と編集ができるようになりました!

最後に


筆者について

TEXH::EXPERT渋谷校の夜間クラスで4月からRuby・Railsの学習をしています。
記載内容に不備・不足があればご指摘いただけると幸いです。
至らぬ点ばかりですので、改善点がありましたらどんどんご指摘下さい!

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

#Ruby / #Rails - FactoryBot でエイリアスを呼び出すみたいに、元の定義をコピー・継承して別名を作る

Ruby / # Rails-Copy and inherit the original definition to create an alias, just like calling an alias in FactoryBot

Factoryの中にFactoryを書くだけで良いらしい。こいつは使える!

factory :user do
  name { 'SomeName' }

  factory :alice do
      name { 'Alice' }
  end

  factory :bob do
      name { 'Bob' } 
  end
end
FactoryBot.create :user
FactoryBot.create :alice
FactoryBot.create :bob

FactoryGirlチートシート - Qiita

Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/2259

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

nested attributes 使用時に毎回新規登録が行われてしまう

概要

accepts_nested_attributes_for を使って、とあるレコードの編集時に、関連レコードの新規作成/更新 を行うようにしたつもりだったのですが、なぜか常に新規登録扱いになってしまい、SQL発行時に Duplicate entry でエラーになる、という事象がおこっていました。

原因は大したことなかったのですが、これにハマったのが2度目だったので自戒のため記事に残しておくことにした次第です。よろしければお付き合いください。

環境

  • Ruby 2.5.1
  • Rails 5.2.2.1

結論

先に結論を書いておきます。
id を permit メソッド内で許可していなかったから。 です。

ハマるときに限って、意外と原因は大したことなかったりします。

舞台設定

順に説明していきます。まず今回の Model と Controller について記載します。

Model

Parent が親で、Child が関連モデルです。名前がいまいちですがご容赦ください:sweat_smile:

parent.rb
class Parent < ApplicationRecord
  has_one :child
  accepts_nested_attributes_for :child, allow_destroy: true
end
child.rb
class Child < ApplicationRecord
  belongs_to :parent
  self.primary_key = :parent_id
end

Controller

問題の原因はここにあります。ここではあえて問題が再現する状態のままにしています。

child_controller.rb
class ChildController
  def update
    if @parent.update(child_params)
      # リダイレクト先は適当に書いたただの例なので気にしないでください
      redirect_to detail_page_path(@parent)
    else
      render :edit
    end
  end

  def child_params
    params.require(:parent).permit(
      # parent側もいろいろ指定がありますがここでは省略してます
      child_attributes: %i[title _destroy]
    )
  end
end

問題の解消方法

前述コントローラの child_params メソッド内を下記のように変更すると解消します。結論で書いたとおりですが、id を permit メソッド内で許可するキーに追加しています。

- child_attributes: %i[title _destroy]
+ child_attributes: %i[id title _destroy]

そもそもこの id って?

まずはこちらをご覧ください。これは child_controller に対応したビューの一部です。このようなフォームを作成しています。

child.html.erb
<%= form_with(model: @parent, local: true) do |form_parent| %>
  <!-- parent のフォームは省略 -->
  <%= form_parent.fields_for :child, @parent.child.build do |form_child|%>
    <%= form_child.text_field :title, placeholder: 'なんか入力してくれ' %>
  <%end%>
<%end%>

そして、実際に生成される child 分のフォームは以下のような html になります。

item.html
<input placeholder="なんか入力してくれ" type="text" value="" name="parent[child_attributes][title]" id="parent_child_attributes_title">
<input type="hidden" value="2" name="parent[child_attributes][id]" id="parent_child_attributes_id">

おや?
parent[child_attributes][id] という、自分では作成した覚えのない input hidden のフォームが生成されています。これが id パラメータの正体のようです。value 属性に入っているのは childs の主キーである parent_id の値でした。

どうやらこの値を見て、新規登録か、既存レコードの更新かを区別しているようです。新規登録の際は value に何も入っていません。そのため、コントローラ側の処理で id を permit メソッド内で許可しておかないと、常に新規登録として扱われてしまう、ということです。

ここで注意が必要なのが、主キーのカラム名は parent_id であるにも関わらず、input タグの name 属性には必ず id という名前が使用される という点です。DBのカラム名でそのまま考えると permit には parent_id を書いてしまいがちなんですが、主キーが送信されているパラメータの名前は常に id という名前であるため間違えないように気をつけましょう。でないと僕の二の舞になります。こんなミスする人は僕だけかもしれませんが

参考

余談

とはいえ、Rails はほんとにDB保存系の処理を書くのが楽ですね。そもそも最近の ORM ってみんなこんなかんじなんでしょうか?Laravel の ORM とかどうなんだろう、ということをふと考えました。

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

Ruby基礎知識

2019/7/10

Ruby学習

puts "Hello World"

出力結果がコンソールに表示される

数値の出力と足し算/引き算

puts 数字の出力
puts 1 + 1 足し算
puts 1 - 1 引き算
puts 1 * 1 掛け算
puts 1 / 1 割り算
puts 9 % 2 余り算
puts "1 + 1" 文字列として表示される

変数とは

※イメージ
→変数=値を入れておく箱
スクリーンショット 2019-07-10 9.00.47.png

変数の定義

※重要※

プログラミングの「=」は「左の変数に右の値を入れる」という意味で、これを代入

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

コンフリクトの発生原因について(merge)

rubyでコードを書く時みなさん基本的には作業用ブランチを作成して、主にそこでコード書く。完了したらcommitして、masterブランチにmergeする。
しかし初学者にありがちなmergeをしたら、(master|MERGEING)になってそこからgitコマンドが使えなくなった経験はございませんか??
そんな初学者向けに陥りやすい原因と解決策について一つのやり方(正しいかは別)として参考程度に考えていただけたらなともいます。

コンフリクトとは

相反する意見、態度、要求などが存在し、互いに譲らずに緊張状態が生じること。 対立、軋轢。プログラミング(ruby)に関しては主に現場ではgit cloneした時なんかに生じるエラーになるかと思われます。しかし、今回はbranch作成してmasterブランチでのmergeに起きるエラーについてかいていきます。

発生原因

基本的にはコンフリクトは「衝突」のような意味合いもあるので、mergeする際の衝突をイメージできるかと思います。
では、mergeの衝突を具体例を持って説明したいと思います。

1、1つのmergeしてないブランチを作成する
git checkout -b Test1

2、ここではREADME.mdファイルでのコンフリクトをさせるための文を書きます
ruby:README.md
'コンフリクト1を作成しました。'

3、保存が終わったらcommitまでしていきます。
git add -A
git commit -m Test1
git checkout master

4、mergeをせずに手順1にもどり同じことをする(TestとREADMEの数だけ変えています)

5、手順3まで終わったら今masterブランチにいる状態だと思います。ここでまず最初にコミットしたTest1をmergeします。
git merge Test1
ruby:README.md
'コンフリクト1を作成しました。'

空白だったとこに無事反映されています。

6、では次に2つ目に作ったTest2をmergeします。
git merge Test2
スクリーンショット 2019-07-10 7.55.32.png
すると次はエラーがでてしまいました。

7、ここの文だけでもREADMEファイルに問題があるのは明白なのですが、一応ステータスの方でも確認をしておきましょう。
git status
スクリーンショット 2019-07-10 7.58.13.png

赤文字でmodifiedとかかれファイル名もREADME.mdと書かれてますね。

8、次は問題のREADMEファイルをみてみましょう。
スクリーンショット 2019-07-10 8.03.22.png
先ほど文が2個表示されていますが、なにやらいらないものがついてきちゃってますね。
HEAD ... 最後にmergeしたもの
Test2 ... 2個めにmergeしたもの

まとめ

このように1つ目のブランチをmergeせずに2つ目のブランチ作成して作業するとこのように食い違いが起きるわけです。Test2mergeしようとしてもブランチにはコンフリクト1を作成しました。という文は含まれていないのですから、ここでコンフリクトという現象が発生します。特に初心者のかたはmergeをうっかり忘れて次のブランチを作成していまい、コンフリクトが発生する(私も何回かやっていました。笑)ので落ち着いてgit log等も確認しながら作業進めていきましょう!

すこしでも初学者のかたの役にたてたらなと思います
また、何か間違っているところ、こうした方がいい等のご意見いただましたらよろしくお願いします。

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

railsのcontrollerからjavascriptに対して変数を渡す

About

railsからjavascriptに対して変数を渡す方法の一つについて記載しています。
html.erbファイル内にscriptタグでjavascriptを書いた場合に変数を渡せる方法です。

Environment

この記事ではmacbook(unix)にインストールしたruby 2.5.1p57, Rails 5.2.3を使用しています。

変数の渡し方

controller内での変数の定義

まずは変数をcontroller内で定義します。
今回は配列を渡してみます。

sleeps_controller.rb
class UsersController < ApplicationController

  def show
    @user = User.find(params[:id])
    @sleeps = @user.sleeps.order('date DESC').includes(:user).limit(14).reverse
  end
end

html.erbで変数を受け取る

ここからは力技です。参考までにamchartsのスクリプトを拝借しています。
他に良い方法があると思いますので、最終手段くらいに思っていただければと思います。
また、良い方法がある方、コメントいただけると幸いです。

show.html.erb
<!-- Chart code -->
<script>
    //略
    // Add data
    var sleepings = '<%= @sleeps %>'
    // 以下略
</script>

この様にすることで、javascriptの変数として、文字列を渡すことができます。
ただし、ここで注意しなくてはいけないのが、あくまで javascript側には文字列が渡されるだけ、ということです。

そのため、以下の様に文字列を分解して、配列に変換しています。
文字列の[]をそれぞれ置換の要領で削除し、カンマでsplitし、配列化します。

show.html.erb
<!-- Chart code -->
<script>
    //略
    // Add data
    var sleepings = '<%= @sleeps %>'.replace(/\[/g, "").replace(/\]/g, "").split(',');
    // 以下略
</script>

これでjavascriptにrailsのcontrollerから値を渡す事ができます。
...ゴリ押し感が否めないですが。

最後に

ここまでゴリ押し感が強いものを共有するべきか悩みましたが、同じ様な悩みを抱えている方が少しでもいらっしゃれば、その方の助けになるかもと思い書きました。
さらに良い方法がありましたら、是非教えてください!

筆者について

TECH::EXPERTにて4月よりruby, railsを学習している未経験エンジニアです。
記載内容に不備・不足があればご指摘いただけると幸いです。
至らぬ点ばかりですので、改善点がありましたらどんどんご指摘下さい!

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