20190701のRubyに関する記事は23件です。

Python on Djangoで基本的なCRUDとAuthを備えた家計簿を作る

リンク

https://github.com/ItoYo16u/django_crud

自分用メモ+α: 余裕があるときに追記します。

Djangoの構成

Djangoはプロジェクトレベルとアプリケーションレベルの層がある。

プロジェクトの中に家計簿のCRUDを実装したcrudアプリケーション、ユーザー認証機能を実装したaccountsアプリケーションをつくる。

追記したプロジェクト内のアプリケーションはmanage.pyと同じ階層にあるsettings.pyのINSTALLED_APPS内に追記する。

 Hello World

$ django-admin startproject <project_name>

gitignoreをmanage.pyと同じ階層に追加

.gitignore
*.pyc
*~
__pycache__
myvenv
db.sqlite3
/static
.DS_Store
$ git init
$ python3 manage.py createapp <app_name>
$ python3 manage.py migrate
$ python3 manage.py createsuperuser

python manage.pyとしている記事もあるが、Syntax errorになるのでpython3 manage.py...としている。

以下を追加

urls.py
from app_name import views

urlpatterns =[
  path('',views.index,name="index"),
  #.............省略............
  #.............省略.............
  path('app_name/',include('app_name.urls'))
]
app_name/urls.py
from django.urls import path
from . import views
app_name='app_name'
urlpatterns=[
  path('',views.index,name="index"),
# nameを指定しておくことでtemplates側から
# "{% url 'app_name:name'  %}"で呼び出せる。
# railsの場合、controller_name_method_name_pathが自動で設定される。便利。
]
views/index.py
def index(request):
  return HttpResponse("Hello, world.")
$ python3 manage.py runserver
GET localhost:8000/

基本的なCRUD

Create, Read, Update, Delete機能を作る。

Create

formのレイアウト設定がややめんどくさい。Railsの場合は、formのクラスやスタイルをviews(Djangoのtemplates)で指定できるが、Djangoの場合、forms.pyで設定しないといけないのでbootstrapなどのCSSフレームワークが使いづらい。

Read

views(Railsでいうコントローラ)内のメソッドにパラメタをリクエストと一緒に渡す。

views.py
def show(request,id=None):
    target= get_object_or_404(TargetModel.objects,pk=id)
    return render(request,"app_name/show.html",{'rec':rec})
# renderで変数をテンプレートに渡して、htmlをレンダリングして、返す。

Djangoはそんなに好きじゃないけど、get_object_or_404()はそこそこ便利


以下はRuby on Railsの場合

hoge_controller.rb
def show
  @target= TargetModel.find(params[:id]) #request parameterはparams[:params_name]で取得できる
  #あとは自動で、hoge/show.html.erbがレンダリングされて返される。
  # html以外を返す場合などは、renderメソッドを使って明記する
end

Update

Delete

Railsはlink_toにmethod: :DELETEを付与できるが、Djangoではできない。HTMLと同様にGETかPOSTしか送れない。
(ライブラリを使えばできるらしい)
DjangoのCRUDについて調べているとDELETEにGETを使っている記事がいくつか見つかるが、なるべくPOSTを使うべき。


※Railsの場合、

=link_to "hoge",foo_bar_path,method: :delete
routes.rb
DELETE 'foo/bar' ,to: 'foo#bar'
foo_controller.rb
def bar
  # 処理内容
end

と直感的に書けるが,Djangoの場合はそうはいかないようだ。


基本的なAuth

Djangoにデフォルトで搭載されているUserモデルとAuthを使う。

Ruby on Railsの場合、デフォルトでは認証機能はないのでdeviseというgemを導入して、devise:installなどのコマンドをうったり、ルーティング設定したりしないといけないのでややめんどくさい。
基本のユーザーは

from django.contrib.auth.models import User

で呼び出せる。

今回は家計簿なのでモデルは

  • User has many 家計簿
  • 家計簿 belongs to User

の関係にある。

Djangoのデフォルトの認証viewsのメソッドが用意されているが、SignUpだけは用意されていないので、自前で作る必要がある。

sign up用のviewをつくる

アクションを認証済ユーザーに制限する

@login_required #をアクションの直前につける

3.リダイレクトを設定する

@login_required #がついている場合,自動でリダイレクト
# リダイレクト先はsetting.py LOGOUT_REDIRECT_URL で指定する
# 2と3はRuby on Railsの場合こう書ける
before_action :authenticate_user! #オプション,only: [:method_name],except: [:method_name],....

共通部分のpartial化

header, footerなどの共通部分は、Railsと同じようにpartial化できる。(Djangoの場合、partialというよりも、継承といったほうが正しいが、、、)

PythonAnywhereにデプロイする

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

【Rails】カラムの合計値を求める!

やりたいこと

保存されているデータの特定のカラムの合計値を出したい!と思いました。
最初考えたのは、

①取得したいカラムのモデルをeach文で1件ずつ取得し、そのデータのカラムを一度配列にする
②↑の配列に対してsumメソッドで合計を求める

これでも全然問題なかったのですが、
sumメソッドの引数で直接カラム名を指定し、合計値を求めることも出来ると知ったのでまとめます!

カラムの合計を求める方法①

これは私がもともと考えていたやり方です。

test.rb
#booksテーブルのpriceカラムの合計値を求めたい場合
array = [] #空の配列を用意し、
Book.all.each do |book|
  array << book.price 
  #bookテーブルのレコードを1件ずつ取り出し、priceカラムのデータを配列に入れる
end
array.sum #ここで合計を求める

カラムの合計を求める方法②

次に、もっと簡単な1行でできるやり方です。

test.rb
Book.all.sum(:price)

これだけでいけました。
sumメソッドの引数でカラムを指定できるとは知らなかったです!
とても楽ですね:relaxed:

また、さらにオプションを付けることもできます!
興味のある方はぜひこちらのサイトをご参考ください!
http://railsdoc.com/references/sum

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

GitHub リポジトリの作成方法(ローカル環境)

新規作成したアプリのリポジトリをGitHub上で作る

まずは、アプリの作成(今回はデータベースにポスグレを使用)

$ rails new (アプリ名) -d postgresql

GitHubにアクセス

①new repositoryボタンを押す。

②リポジトリ名を決めて、Create repositoryボタンを押す。

GitHubとローカルをSSH接続

SSHという認証技術を使用して、GitHubとローカルをSSH接続する。
⇨セキュリティの脆弱性の観点から、一般的には公開鍵認証方式を使用。
(ここで、公開鍵秘密鍵という概念が出てくるが、ここでは説明は割愛)

SSH keyの作成

$ ssh-keygen -t rsa -C "GitHubに登録した自分のメールアドレス"

Overwrite (y/n)?の箇所で、yを入力しEnterを押すと、秘密鍵と公開鍵が作成される。
id_rsaというファイルが秘密鍵で、id_rsa.pubが公開鍵。

公開鍵の登録とGitHubとの接続確認

公開鍵をGitHubに登録する。
catコマンドを使用するとファイルの中身が確認できるので…

$ cat ~/.ssh/id_rsa.pub

上記コマンドを実行すると、ssh-rsaから始まり、自分のメールアドレスで終わる長い文字の羅列が表示される。「ssh-rsa」からメールアドレスの末尾までをすべてコピー。

GitHub上に公開鍵を置く

①ヘッダ右上の自分の画像をクリックして、settingをクリック。

SSH and GPG keysをクリックし、さらにNew SSH Keyをクリック。

スクリーンショット 2019-07-01 22.30.46.png

keyのところにコピーした公開鍵の中身を貼り付ける。

スクリーンショット 2019-07-01 22.34.07.png

GitHubとの接続が正常にできているか確認

# 接続確認コマンド
$ ssh -T git@github.com
# 接続結果
Hi (GitHubの登録名)! You've successfully authenticated, but GitHub does not provide shell access.

このように表示されたら、基本的には接続成功!!!

GitHubのリポジトリにソースコードを送信する

GitHubリポジトリの送り先SSHプロトコルURLを取得

ローカル上で、送り先のSSHプロトコルURLをGitHubからコピー。
(SSHプロトコルURLは、git@から始まる。
httpsから始まるURLは、パスワード認証方式でアクセスすることになる。)

GitHubのリポジトリを登録する

ローカル上で、GitHubリポジトリの送り先SSHを登録する。
⇨git remote addコマンドを使用。

$ git remote add origin(=省略名) (コピーしたSSHプロトコルURL)
$ git remote -v
# 送り先SSHの確認例
origin  git@github.com:〜 (fetch)
origin  git@github.com:〜 (push)

git pushコマンドの利用

登録したリモートリポジトリ(GitHubリポジトリ)に、ソースコードを送信する。

$ git push origin(=省略名) ブランチ名

⬇︎こうするとmasterブランチへコードが送信される。

$ git push origin master

…以上が、ローカル環境下で書いたソースコードを、作成したリポジトリに送信する流れ

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

GitHub リポジトリの作成方法

新規作成したアプリのリポジトリをGitHub上で作る

まずは、アプリの作成(今回はデータベースにポスグレを使用)

$ rails new (アプリ名) -d postgresql

GitHubにアクセス

①new repositoryボタンを押す。

②リポジトリ名を決めて、Create repositoryボタンを押す。

GitHubとローカルをSSH接続

SSHという認証技術を使用して、GitHubとローカルをSSH接続する。
⇨セキュリティの脆弱性の観点から、一般的には公開鍵認証方式を使用。
(ここで、公開鍵秘密鍵という概念が出てくるが、ここでは説明は割愛)

SSH keyの作成

$ ssh-keygen -t rsa -C "GitHubに登録した自分のメールアドレス"

Overwrite (y/n)?の箇所で、yを入力しEnterを押すと、秘密鍵と公開鍵が作成される。
id_rsaというファイルが秘密鍵で、id_rsa.pubが公開鍵。

公開鍵の登録とGitHubとの接続確認

公開鍵をGitHubに登録する。
catコマンドを使用するとファイルの中身が確認できるので…

$ cat ~/.ssh/id_rsa.pub

上記コマンドを実行すると、ssh-rsaから始まり、自分のメールアドレスで終わる長い文字の羅列が表示される。「ssh-rsa」からメールアドレスの末尾までをすべてコピー。

GitHub上に公開鍵を置く

①ヘッダ右上の自分の画像をクリックして、settingをクリック。

SSH and GPG keysをクリックし、さらにNew SSH Keyをクリック。

スクリーンショット 2019-07-01 22.30.46.png

keyのところにコピーした公開鍵の中身を貼り付ける。

スクリーンショット 2019-07-01 22.34.07.png

GitHubとの接続が正常にできているか確認

# 接続確認コマンド
$ ssh -T git@github.com
# 接続結果
Hi (GitHubの登録名)! You've successfully authenticated, but GitHub does not provide shell access.

このように表示されたら、基本的には接続成功!!!

GitHubのリポジトリにソースコードを送信する

GitHubリポジトリの送り先SSHプロトコルURLを取得

ローカル上で、送り先のSSHプロトコルURLをGitHubからコピー。
(SSHプロトコルURLは、git@から始まる。
httpsから始まるURLは、パスワード認証方式でアクセスすることになる。)

GitHubのリポジトリを登録する

ローカル上で、GitHubリポジトリの送り先SSHを登録する。
⇨git remote addコマンドを使用。

$ git remote add origin(=省略名) (コピーしたSSHプロトコルURL)
$ git remote -v
# 送り先SSHの確認例
origin  git@github.com:〜 (fetch)
origin  git@github.com:〜 (push)

git pushコマンドの利用

登録したリモートリポジトリ(GitHubリポジトリ)に、ソースコードを送信する。

$ git push origin(=省略名) ブランチ名

⬇︎こうするとmasterブランチへコードが送信される。

$ git push origin master

…以上が、ローカル環境下で書いたソースコードを、作成したリポジトリに送信する流れ

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

activerecordを使って簡単なコマンドラインアプリケーションを作ってみた

目的とやったこと

rubyとActiveRecordの勉強のために、簡単なコマンドラインベースの「todo管理アプリケーション」を作成した。

開発環境詳細

言語:ruby2.5.3
DB:sqlite3
なお、当然ながらDBアクセスにActiveRecordを利用している。

動作している様子

todoapp.gif
※念のため言っておくと、Cドライブ直下で実行しているのは私のユーザ名を晒したくないからで、Qiita投稿のためだけにそうしています。

仕様概要

よくあるタスク管理アプリをコマンドラインで実現している。
CRUDを一通り実装しており、ユーザインタフェースはキーボード入力のみ。
DBはsqliteで実現しており、テーブルは一つだけ(tasksテーブル)。項目は以下の通り
 id・・・タスクを一位に定めるための整数値。自動採番かつuniqueである。
 name・・・タスクの名前
 content・・・タスクの詳細
 status・・・タスクの状態。アプリ的には未着手、着手中、完了の3つがあり、それぞれ整数値としている。
なお、updateについて、何も入力をしない場合は現状の項目のままである。(一応工夫しているアピール)

ソースコード

相変わらずのクソコードではあるが以下を参照のこと
https://github.com/gitk47320/todoapp
コマンドラインベースとはいえMVCを意識しています。データ操作、ユーザインタフェースは分離している。特にControllerなんて完全にrails意識しているし。。。

今後やっていきたいこと

・バリデーションの実装
・タスクアラート機能(遅延気味のタスクをアラートするとか)
・全体的にリファクタリングしたい。view側の実装をmodel側にもう少し持っていけないかなーとは思っている。

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

Ruby on railsとは?

Railsの事前カリキュラム

どんな記事?

ruby on railsとはなんなのか?ということ自分の中でアウトプットするための記事です、どうか暖かく見守ってください

ruby on railsとは?

ruby on railsは簡単にいうとWebアプリケーション開発を開発するためのフレームワークです。

ここではそもそもフレームワークが何なのかとrailsで使われているコーディングをするシステム(MVCモデル)、rubyとの違いを勉強していきます。

フレームワーク

フレームワークとは、Webアプリケーションを機能させるために必要な共通部分を予め用意するものになります。

アプリケーションの開発者は独自に必要なHTML/CSSやRubyの記述に時間を割くことができるので、開発効率が向上します。

MVCモデル

Railsではユーザーからのリクエスト->ビュー->コントローラー→モデルの順番に処理が行われます。

このようにモデル(model)とビュー(view)とコントローラー(controller)を使用して処理を行なうシステムをそれぞれの頭文字を取ってMVCモデルと呼ばれています。

以下の図に処理の流れを簡単にまとめました。

MVC画像

rubyとruby on railsの違い

よく間違えられるのですがRuby on Railsはプログラミング言語ではないです。

プログラミング言語は、前テキストで学んでいただいたと思うのですが他にはpythonやJava,Cなどがありましてその名の通りプログラムを実装・実行するための言語です。

例えば、前テキストでRubyを使い足し算や掛け算などの計算、条件に合わせたプログラムの実行、配列作成などを行なったと思います。

一方でフレームワークであるRailsは足し算などをすることはできません。

ruby on railsでできること

webアプリケーション開発

インターネット上に公開されているWebサイトはRuby, Ruby on Railsを使って作ることが可能です。

RubyとRuby on Railsを使ってWebサイトを作るメリットはRuby on Railsというフレームワークによる開発スピードです。

Ruby on Railsは非常によく出来たフレームワークで、Webアプリケーションの開発をするために最適化されたツールになります。

ここではRuby, Ruby on Railsで開発されているwebサービスをいくつか紹介します。

クックパッド

クックパッド画像
引用元:クックパッド https://cookpad.com/

マネーフォワード

マネーフォワード画像
引用元:マネーフォワード https://moneyforward.com/

Airbnb

Airbnb画像
引用元:Airbnb https://www.airbnb.jp/

スマートフォンアプリ開発

iOSアプリの開発はobject-cやswift、Androidアプリの開発はJavaやKotlinが一般的です。

しかしRubyでも「RUBYMOTION」(http://www.rubymotion.com/jp/)

というソフトを使うことにより、AndroidアプリやiOSアプリを開発することが可能になります。

ruby on railsの特徴

初心者に優しい

ruby on railsが初心者に優しい理由は主に2つあります

1つはシンプルにコーディングできることです。

Railsはコードが短く、簡単な書き方ができます。

それによりコーディング量が少なくなり、短く速い開発を行うことができるメリットがあります。

また次に説明するDRYの原則により、同じコードを何度も繰り返して使うことなく、規約に従った開発を行うことにより自分で設定を行うことなくコーディングを行えます。

これはコードを読んだり書いたりすることの慣れていない初学者には大きなメリットになります。

2つ目はrubyが日本発祥の言語だということです。

これにより日本語の情報がオンラインで豊富に手に入ります。

また、コミュニティが活発で初心者でも非常に学びやすい環境が整っています。

例えばruby on railsを使ってオリジナルのアプリケーションを作っている中で遭遇したことのない様なエラーが出たとしても

そのエラーに遭遇している人をオンライン上で見つけることが簡単なので素早くエラーを解決しアプリケーション開発を行うことができます。

DRY (Don’t Repeat Yourself)原則

Ruby on Railsには、「Don’t Repeat Yourself(繰り返しを避けよ)」というDRY原則という原則があります。

DRY原則とは、自分でやった事を2度繰り返さないという意味です。

同じことをソースコードやファイルの中で何度も記述すると、アプリケーションの仕様変更などがあった時に、一部を変更し忘れてしまう可能性があります。

少しイメージがつきづらいと思うので例を出して説明していきたいと思います。

例えば今ここで

今hour時です       #hourは変数で中身は数字です

という文字列を100回出力したいとします、みなさんだったらどのようにコードを書くでしょうか?

まさかputsメソッドを使って100回出力しないですよね、基本的にはwhileやfor文を使って繰り返しをさせます。

ではなぜputsメソッドを使って100回出力させない方がいいのでしょうか?

例えば上記の文字列を

今hour時minutes分です       #minutesは変数で中身は数字です

に変更したいとしましょう、繰り返し構文を使っていないコードを変更するとしたら100回も変更を加えなければなりません。

ただ繰り返しの構文を使っているとしたらその中の文字列1行を変更するだけですみます。

このようにRuby on Railsでは、DRY原則を意識して開発することで、効率の良いアプリケーションを作成することができます。

直感的にデータベースを操作することができる

そもそもデータベースとは?

データベースとは一定の形式で整理されたデータの集まりです、現実世界にあるデータベースの例を出すとタウンページなどがわかりやすいと思います。

タウンページは基本的に場所名+電話番号が整理された形でずっと並んでいますよね。

コンピューターの中にもタウンページのようにデータが整理され集合がありましてそれをデータベースと言います。

一般的にデータベースを扱う場合、データベース言語「SQL」を書く必要があります。

SQL言語とはデータベースを操作するための言語です。

例えばTwitterなどを思い浮かべて見てください、Twitterにログインが成功した時には自分のユーザー情報が表示されますよね。

これはユーザーの情報が入っているデータベースに対してSQL言語を書くことによってユーザー情報を表示することができています。

ではこれを直感的に操作できるとはどういうことか

例えば、データベースのproductsテーブルからプロダクトIDが1のデータを取得する場合、SQLを使うと以下のように書かなければいけません。

 SELECT * FROM products WHERE id = 1

しかしRailsアプリケーションでデータベースを扱う場合は、SQLを書く必要がなく

@product = Product.find(1)

という1行を記述するだけで、データを取得することができます。

これから学習していくテキストの中でもデータベースを扱う場面が多々あると思うのですが

ruby on railsを使っていることで上記の様に直感的にデータベースを扱うことができるようになります。

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

今日学んだ事(自分用)

7/1(月)

●UI(ユーザーインターフェース)

・ユーザーがPCとやりとりする際の入力や表示方法などの仕組み

●UX(ユーザーエクスペリエンス)

・サービスによってユーザーが得られる体験

───────

●アジャイル開発

・ソフトウェア開発のプロジェクトの進め方。短期間で開発を見直す手法。

●erb記法

・HTMLにRubyスクリプトを埋め込む

●スクリプト

・プログラムの流れ
1.プログラミング(人間の言葉でコンピュターへの命令を記述する)
2.コンパイル(1で書いた内容をPCがわかる言葉に翻訳する)
3. 2の内容にしたがってPCが仕事する
・スクリプト言語は2のコンパイルを飛ばし
プログラミング⇨PCが仕事する流れ

●eachメソッド

・要素を1つずつ取得し出力させる

オブジェクト.each do |変数|
例.
fruits = ["apple","orange","melon"]
 fruits.each do |a|
puts a
end

出力
apple
orange
melon

・このような繰り返しメソッドを、イテレートまたはイテレータという。

●order(順序)メソッド

・DBからデータの取得時にデータを並び変える事ができる
・DESC(降順)
・ASC(昇順)
コード

モデル名.order('カラム名 順序')

●limitメソッド

・データをいくつ取得するか指定するメソッド
コード

モデル名.limit('取得件数')

●orderメソッドとlimitメソッドを一緒に使う時

モデル名.order('カラム名 順序').limit(取得件数)

●find(見つける)メソッド

・引数に指定したidをもつ情報を1件だけ取得する
・作品の個別ページの移行の時などに使う

例.
User.find(1)

●rake routesコマンド

・HTPPアクションの一覧を見る事ができる
・リクエスト、パスに対してのコントローラ、アクション名が確認できる

ターミナル.
rake routes

以上

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

Rubyのモジュールの用途について

Rubyのモジュールの用途(4つ)

①モジュールのミックスインincludeもしくはextend,prependできる(異なるモデルで共通したメソッドを使用するときなど)

  • includeとextendの違いが分からないときはこちら
  • prependとはなんぞや
    • 同名のメソッドがあったときに、ミックスインしたクラスよりも先にモジュールのメソッドを呼ぶ

②モジュールを利用した名前空間の作成(異なるモデルで同じ名前のモデルを作成するとき)

Class::instance.new(implement, 0)

③関数や定数を提供するモジュールの作成

  • 何気なくターミナルで"puts"を叩けるのはkernelというmoduleのおかげ
  • ancestorsメソッドを使えばクラスやモジュールがどの順番で探索されるか確認できる。

④状態を保持するモジュールの作成

  • モデルにデータを保持する必要がなければモジュールにしておくことができる。
  • 下記記述が必要になってくるため注意。
model.rb
 attr_accessor :implement

Railsのmodelのconcernは?

  • Railsのconcernは異なるモデルの中でも同じメソッドやスコープを使用するときに活用できる。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rubyのモジュールの用途について(学習メモ)

Rubyのモジュールの用途(主に4つ)

①モジュールのミックスインincludeもしくはextend,prependできる(異なるモデルで共通したメソッドを使用するときなど)

  • includeとextendの違いが分からないときはこちら(参考)
  • prependとはなんぞや
    • 同名のメソッドがあったときに、ミックスインしたクラスよりも先にモジュールのメソッドを呼ぶ
    • 既存メソッドの置き換え

②モジュールを利用した名前空間の作成(異なるモデルで同じ名前のメソッドを作成するとき)

Class::instance.new(implement, 0)

③関数や定数を提供するモジュールの作成

  • 何気なくターミナルで"puts"を叩けるのはkernelというmoduleのおかげ
  • ancestorsメソッドを使えばクラスやモジュールがどの順番で探索されるか確認できる。

④状態を保持するモジュールの作成

  • モデルにデータを保持する必要がなければモジュールにしておくことができる。
  • 下記記述が必要になってくるため注意。
model.rb
 attr_accessor :implement

Railsのmodelのconcernは?

  • Railsのconcern(参考)は異なるモデルの中でも同じメソッドやスコープを使用するときに活用できる。

refinementsについて

メソッドの有効範囲(スコープ)を指定できる。

model.rb
module Hoge 
 refine Class do 
    def method 
      hogehoge 
    end
  end
end

class Model
  using Hoge 

  ・・・省略・・・

  def refinement_method
    #ここの範囲だけメソッドが有効となる。
    @~~~.method
  end 
end
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

enum_helpについて

はじめに

enumをしようする中でenum_helpというgemを使用したためenum_helpについてまとめる。

enumとは

enum_helpの説明の前にenumについてまとめたいと思います。
enumは数字を何かしらの値と紐付けているようなデータの管理をしている場合に有効なものとなります。

class ShippingBurden < ApplicationRecord
  has_many :items
  enum name: [:select_shipping_burden, :postage_included, :freight_collect]
end

このようにmodel内でenumを定義することでf.selectなどでhamlにoptionを記述しなくても数字で値を表示できるようになります。

しかし、このままでは表示される値が英語表記のまま表示されてしまいます。
そんな時に英語を日本語表記に変える時に必要となるのがenum_helpです。

仕様方法

まずはじめに、gemのenum_helpをgemfileに記述します。

gem 'enum_help'

そして、bundle install

次に、config直下にja.ymlというファイルを作成し、そこに日本語表記の記述をします。

ja:
  enums:
    shipping_burden:
      name:
        postage_included: '送料込み(出品者負担)'
        freight_collect: '着払い(購入者負担)'

最後にaplication.rbにja.ymlを適応させる記述を書きます

config.i18n.default_locale = :ja

これで日本語表記で表示させることが可能になります。

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

to_iとto_s

to_iとto_sについて

どっちがどっちか分からなくなることが多いので、まとめます!

*to_i・・・iの意味はinteger(整数)
*to_s・・・sの意味はstring(文字列)

使い分け方法

それぞれの使い方について、詳しくみていきます。

number1 = 10 #数値
number2 = "15" #文字

上記を利用してそれぞれのメソッドを利用していきます。

to_iメソッド

文字列オブジェクトに対してto_iメソッドを使うと、その文字列を数値オブジェクトに変換することができる!
つまり、

puts number1 + 5  #出力結果 15
puts number2 + 5  #エラー

#numberyyyを出力させるためにto_iメソッドを使うと
puts number2.to_i + 5  #出力結果 20

ということになります!

to_sメソッド

数値オブジェクトに対してto_sメソッドを使うと、その数値を文字列オブジェクトに変換することができる!
つまり、

puts number1 + "歳の誕生日です"  #エラー
puts number2 + "歳の誕生日です"  #出力結果 15歳の誕生日です

#numberxxxを出力させるためにto_sメソッドを使うと
puts number1.to_s + "歳の誕生日です"  #出力結果 10歳の誕生日です

ということになります!

まとめ

このto_iはgetsメソッドと共に使われることが多いですね。
どちらも似ていて間違いやすいので気をつけて使っていきたいと思います!

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

active storage で単数から複数にした時に気をつけるべきポイント

N+1 問題を解決するためのスコープを複数形にする

.with_attached_image

.with_attached_images

受け取るパラメータを配列にする

params.require(:reports).permit(:content, :image)

params.require(:reports).permit(:content, images: [])

アソシエーションを複数形にする

has_one_attached :image

has_many_attached :images

バリデーションを複数形にする

こちらのバリデーションは下記のgemを使用した例です
activestorage-validator

validates :image, blob: { content_type: %w(image/png image/jpg image/jpeg) }

validates :images, blob: { content_type: %w(image/png image/jpg image/jpeg) }

番外編

Active Interaction で静的型付けをする場合、string ではなく array にする

デフォルトが nil だとエラーになるので注意してください

string :image, default: nil

array :images, default: []
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

記事を投稿・詳細表示・一覧表示・編集・削除するやり方について

環境

OS:MacOS Mojave 10.14.15
IDE:Cloud9
ruby:2.6.3
Rails:5.0.7.2

準備

routing作成

まずはルーティングを準備していきます。

routes.rb
resources :aritcles

正しく反映されているか、rails routesコマンドで確認してみましょう。

console
$ rails routes
Prefix Verb   URI Pattern                  Controller#Action

    articles GET    /articles(.:format)          articles#index
             POST   /articles(.:format)          articles#create
 new_article GET    /articles/new(.:format)      articles#new
edit_article GET    /articles/:id/edit(.:format) articles#edit
     article GET    /articles/:id(.:format)      articles#show
             PATCH  /articles/:id(.:format)      articles#update
             PUT    /articles/:id(.:format)      articles#update
             DELETE /articles/:id(.:format)      articles#destroy

正しく反映されていますね。
しかし、この状態でリクエストを送ろうとすると以下の画像のようにルーティングエラーが発生します。
スクリーンショット 2019-06-29 15.19.34.png

このエラーの原因は「リクエストを処理するためのコントローラーがないため」です。
なので、次はarticlesコントローラーを作成します。

articlesコントローラーの作成

以下のコマンドでarticlesコントローラーを作成します。

console
$ rails g controller articles
Running via Spring preloader in process 9066
      create  app/controllers/articles_controller.rb
      invoke  erb
      create    app/views/articles
      invoke  test_unit
      create    test/controllers/articles_controller_test.rb
      invoke  helper
      create    app/helpers/articles_helper.rb
      invoke    test_unit
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/articles.coffee
      invoke    scss
      create      app/assets/stylesheets/articles.scss

articlesコントローラーが作成されました。
しかし、このままではarticlesコントローラーに対するアクションが作成されていないので、URLにリクエストを送っても、Unknow actionエラーが返されてしまいます。
なので、次はactionを指定します。(一旦、newアクションだけを指定していきます。)

/training/app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
  def new

  end
end

/articles/newでアクセスしてみます。
すると、今度は以下のようなエラーが発生します。
スクリーンショット 2019-06-29 15.50.23.png

ArticlesController#missing a templateはarticlesコントローラーのnewアクションに対応するテンプレート、つまりビューがないために起こるエラーです。

なので、今度は対応するviewを作成します。

console
$ touch app/views/articles/new.html.erb

エラーは解消されたと思いますが、入力されたデータを送信して管理する場合は、モデルを作成してDBとやり取りする必要が生じてくるので、Articleモデルを作成していきます。

Articleモデルの作成

今回は、articlesテーブルにtitleカラムとcontentカラムを用意したいので以下のコマンドを実行してArticleモデルを作成します。

console
$ rails g model Article title:string content:text
Running via Spring preloader in process 4656
      invoke  active_record
      create    db/migrate/20190630012101_create_articles.rb
      create    app/models/article.rb
      invoke    test_unit
      create      test/models/article_test.rb
      create      test/fixtures/articles.yml

続いて、出来上がったマイグレーションファイルを実行していきますが、その前に作成したマイグレーションファイルに誤字等ないか確認します。

/training/db/migrate/hogehoge_create_articles.rb
class CreateArticles < ActiveRecord::Migration[5.0]
  def change
    create_table :articles do |t|
      t.string :title
      t.text :content

      t.timestamps
    end
  end
end

問題なさそうなことが確認できたので以下のコマンドでマイグレーションを実行していきます。

console
$ rails db:migrate
== 20190630012101 CreateArticles: migrating ===================================
-- create_table(:articles)
   -> 0.0060s
== 20190630012101 CreateArticles: migrated (0.0065s) ==========================

articlesテーブルが作成されたことが確認できたので、次からはそれぞれ機能ごとに必要な処理をモデル、コントローラー、ビューに実装していきます。
※ルーティングは既に揃っているので加えて作成する必要はありません。

記事を投稿・詳細表示する

articleコントローラーにnew,create,showアクションを追加していきます。

/training/app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
  def new
    #空のArticleオブジェクトを生成
    @article = Article.new
  end

  def create
    @article = Article.new(article_params)
    if @article.save
      redirect_to @article #@articleはarticle_path(@article)と同義
    else
      #エラー時は再度、記事登録画面を表示させる
      render :new
    end
  end

  def show
    @article = Article.find(params[:id])
  end

  private
    #ストロングパラメータでpermitに渡された値以外を受け取らないようにする
    def article_params
      params.require(:article).permit(:title,:content)
    end
end

newアクション内で空っぽのArticleクラスのインスタンスを作る理由は、form_forメソッドに空のインスタンス渡された時は、submitした時にcreateアクションが実行されるように設定されているからです。
反対に、空でない場合はupdateアクションが実行されます。

まだこれだけだと、showアクションに対応するviewが足りていないのでそれを作ります。

console
$ touch app/views/articles/show.html.erb

続けてviewも登録した内容が分かるように書いていきます。

/training/app/views/articles/show.html.erb
<table>
  <tbody>
        <tr>
            <th>タイトル</th>
            <td><%= @article.title %></td>
        </tr>
        <tr>
            <th>内容</th>
            <td><%= @article.content %></td>
        </tr>
  </tbody>  
</table>

ここまで作ったら実際に記事登録画面(article/new)でtitleに「hoge」、contentに「hogehoge」と入力して送信ボタンを押してみましょう。

スクリーンショット 2019-06-30 15.43.07.png

↑こんな感じでDBに登録された値がうまく表示されていないでしょうか?

記事を一覧表示する

articleコントローラーにindexアクションを追加してallメソッドで登録されている値を全て取り出し@articlesに格納します。

/training/app/controllers/articles_controller.rb
class ArticlesController < ApplicationController



def index
    @articles = Article.all    
end
  private
    def article_params
      params.require(:article).permit(:title,:content)
    end
end

indexアクションに対応するviewがないので作成して、登録された値が全て確認できるようにviewを調整します。(次の「記事を編集する」で使用する編集リンクを先に実装しています。したがって、今はエラーが出ても問題ありません)

console
$ touch app/views/articles/index.html.erb
/training/app/views/articles/index.html.erb
<table>
  <tbody>
      <tr>
          <th>タイトル</th>
          <th>内容</th>
      </tr>
      <% @articles.each do |article| %>
      <tr>
          <td><%= article.title %></td>
          <td><%= article.content %></td>
          <td><%= link_to '編集',edit_article_path(article) %></td>
      </tr>
      <% end %>
  </tbody>  
</table>

適当に記事登録画面で何か追加してみて/articlesにアクセスするとこれまで作成したデータが一覧で表示されます。

スクリーンショット 2019-07-01 10.35.56.png

記事を編集する

articlesコントローラーにeditアクションとupdateアクションを追加し、それに対応するviewを追加していきます。

/training/app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
 ・
 ・
 ・
  def edit
    @article = Article.find(params[:id])
  end

  def update
    @article = Article.find(params[:id])
    if @article.update(article_params)
      redirect_to @article
    else
      render :edit
    end
  end
  
 ・
 ・
  private
    def article_params
      params.require(:article).permit(:title,:content)
    end
end

console
$ touch app/views/articles/edit.html.erb
/training/app/views/articles/edit.html.erb
<h1>編集画面</h1>
<%= form_for @article do |f| %>
  <p>
    <%= f.label :title, "タイトル" %><br>
    <%= f.text_field :title %>
  </p>

  <p>
    <%= f.label :content, "内容" %><br>
    <%= f.text_area :content %>
  </p>

  <p>
    <%= f.submit %>
  </p>
<% end %>

findメソッドで該当する記事をDBから取り出し、それを@articleに格納して、view(edit.html.erb)のform_forメソッドに渡します。
この時、form_forメソッドに渡されたインスタンス変数には空ではなく値が入っているため、送信ボタンを押下時にはupdateアクションが実行されます。

記事を削除する

articlesコントローラーにdestroyアクションを追加します。

/training/app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
 ・
 ・
 ・
  def destroy
    @article = Article.find(prams[:id])
    if @article.destroy
      redirect_to articles_path
    else
      redirect_to article_path(@article)
    end
  end
 ・
 ・
 ・
end

リンク押下時に削除できるように一覧画面のviewに削除リンクを追加していきます。

<table>
  <tbody>
      <tr>
          <th>タイトル</th>
          <th>内容</th>
      </tr>
      <% @articles.each do |article| %>
      <tr>
          <td><%= article.title %></td>
          <td><%= article.content %></td>
          <td><%= link_to '編集',edit_article_path(article) %></td>
          <td><%= link_to '削除',article_path(article),
                          method: :delete,data: {confirm:'削除してもいいですか?'}%></td>
      </tr>
      <% end %>
  </tbody>  
</table>

methodオプションでhttpメソッドをdeleteに指定してあげることで、確認ダイアログのOKボタンが押された時に、destroyアクションが実行されます。

補足

今回は、要点をまとめるために記事を作成したためArticleモデルにバリデーションやリレーションを追加したりや入力箇所(newやedit)の重複部分をパーシャルを使ってまとめたりはしておりません。
なので、その辺りは適宜カスタマイズしていただきますようよろしくお願いします。

最後に

誤っている箇所や追記した方が良い点等ございましたら
編集リクエストやコメントの方でご指摘していただけると幸いです。

参考
Railsを始めたばかりの人向け!Railsの仕組みを一から理解しながらブログを作成する

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

【Rails 備忘録】デプロイする時に定番で使うコマンド

はじめに

備忘録です。

デプロイで使うコマンド

前提条件として、
AWS EC2環境/var/www/app/ 配下でgit cloneさせます。

git clone

言わずもがなgit cloneです。

git pull

言わずもがなgit pullです。

bundle install

bundle install --path=vendor/bundle --without development test

assets precompile

bundle exec rails assets:precompile RAILS_ENV=staging

migrate

bundle exec rails db:migrate RAILS_ENV=staging

rails server起動

bundle exec rails s -e staging -d

rails server停止

ps aux | grep rails (rails s -e staging -d のプロセスidを見つける)
kill プロセスid

rails コンソール

bundle exec rails c -e staging

ちなみに

上記はstaging環境でのコマンドとなります。
production環境の場合、stagingproductionに変更すればOK。

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

Rails6 のちょい足しな新機能を試す43(ActiveRecord Cache編)

はじめに

Rails 6 に追加されそうな新機能を試す第43段。 今回は、 ActiveRecord Cache 編です。
Rails 6 では、 has_manybelongs_to などの関連がある model の reload 時の ActiveRecord のキャッシュに関連する動作が修正されています。 reload しているのに、データベースから読み直されず、キャッシュの古い値が取得されてしまう動作がなくなり、一貫性が感じられる動作になっています。

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

プロジェクトを作る

$ bin/rails new rails6_0_0rc1
$ cd rails6_0_0rc1

モデルを作る

has_manybelongs_to の関係を作るため、 Author, Book, Edition の3つのモデルを作成します。

本 ( Book ) には1人の著者 ( Author ) がひもづき ( belongs_to )、複数の版 ( Edition ) が存在します。

$ bin/rails g model Author name
$ bin/rails g model Book title author:references
$ bin/rails g model Edition name book:references

has_many を追加する

AuthorBook にそれぞれ has_many を追加します。

app/models/author.rb
class Author < ApplicationRecord
  has_many :books, dependent: :destroy
end
app/models/book.rb
class Book < ApplicationRecord
  belongs_to :author
  has_many :editions, dependent: :destroy
end

db:migrate を実行する

一旦、ここで、 db:migrate をしておきます。

$ bin/rails db:create db:migrate

Controller と View を作る

Book controller と index View を作ります。

$ bin/rails g controller books index

初期データを登録するメソッドを定義する

BooksController に初期データを登録するプライベートメソッド initialize_data を作成します。
毎回同じデータでテストできるように、一旦、データを削除してから、 Author , Book , Edition のデータを作成するようにします。

app/controllers/books_controller.rb
class BooksController < ApplicationController
  ...
  private

  def initialize_data
    Author.first&.destroy
    author = Author.create(name: 'Dave Tomas')
    book = Book.create(title: 'Pragmatic Programer', author: author)
    Edition.create([{ name: '1st', book: book }, { name: '2nd', book: book }])
  end
end

model に値を修正するメソッドを追加する

各モデルにそれぞれの値を更新するメソッドを追加します。
普通にDBの値を更新すると、今回の事象が確認できないので、Threadを作って、Thread の中で更新します。
Thread#join を使って更新が終わるまで待つようにします。

Book モデルの title を更新するメソッドを追加します。

app/models/book.rb
class Book < ApplicationRecord
  ...
  def self.fix_title
    Thread.start do
      Book.where(title: 'Pragmatic Programer').update(title: 'Pragmatic Programmer')
    end.join
  end
end

同じように、Author モデルの name を更新するメソッドを追加します。

app/models/author.rb
class Author < ApplicationRecord
  ...
  def self.fix_name
    Thread.start do
      Author.where(name: 'Dave Tomas').update(name: 'Dave Thomas')
    end.join
  end
end

Edition モデルにも name を更新するメソッドを追加します。

app/models/edition.rb
class Edition < ApplicationRecord
  ...
  def self.fix_name
    Thread.start do
      Edition.where(name: '2nd').update(name: '20th Anniversary Edition')
    end.join
  end
end

book.reload のキャッシュの動作を試すメソッドを作る

book.reload のキャッシュの動作を試すプライベートメソッドを作ります。
book.reload の前に booktitle を更新します。

app/controllers/books_controller.rb
class BooksController < ApplicationController
  ...
  private
  ...
  # try book.reload
  def try_book_reload
    book = Book.first
    @old_title = book.title
    Book.fix_title
    @new_title = book.reload.title
  end
end

book.reload_author のキャッシュの動作を試すメソッドを作る

book.reload_author のキャッシュの動作を試すプライベートメソッドを作ります。
book.reload_author の前に authorname を更新します。
更新の前後で、 Author.find を呼び出します。

app/controllers/books_controller.rb
class BooksController < ApplicationController
  ...
  private
  ...

  # try book.reload_author
  def try_book_reload_author
    book = Book.first
    author_id = Author.first.id
    @old_author_name = Author.find(author_id).name
    Author.fix_name
    @reloaded_author_name = book.reload_author.name
    @new_author_name = Author.find(author_id).name
  end
end

book.editions.reload を試す

book.editions.reload のキャッシュの動作を試すプライベートメソッドを作ります。
book.editions.reload の前に editionname を更新します。

app/controllers/books_controller.rb
class BooksController < ApplicationController
  ...
  private
  ...

  # try book.editions.reload
  def try_book_editions_reload
    book = Book.first
    @old_editions = book.editions.reload.map(&:name)
    Edition.fix_name
    @new_editions = book.editions.reload.map(&:name)
  end
end

index メソッドを修正する

index メソッドを修正します。
これまで作ったプライベートメソッドを順に呼び出します。
index は GET メソッドなので、データを登録したり更新したりするのは RESTful ではないので、良くないです。
今回は動作確認のためなので、見逃してください。

app/controllers/books_controller.rb
class BooksController < ApplicationController
  def index
    initialize_data

    try_book_reload
    try_book_reload_author
    try_book_editions_reload
  end
  ...
end

View を作成する

Controller で求めた値を表示するように View を修正します。

app/views/books/index.html.erb
<h1>Books#index</h1>

<table>
  <thead>
    <tr>
      <th>variable</th>
      <th>value</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>@old_title</td>
      <td><%= @old_title %></td>
    </tr>
    <tr>
      <td>@new_title</td>
      <td><%= @new_title %></td>
    </tr>
    <tr>
      <td>@old_author_name</td>
      <td><%= @old_author_name %></td>
    </tr>
    <tr>
      <td>@reloaded_author_name</td>
      <td><%= @reloaded_author_name %></td>
    </tr>
    <tr>
      <td>@new_author_name</td>
      <td><%= @new_author_name %></td>
    </tr>
    <tr>
      <td>@old_editions</td>
      <td><%= @old_editions %></td>
    </tr>
    <tr>
      <td>@new_editions</td>
      <td><%= @new_editions %></td>
    </tr>
  </tbody>
</table>

Rails 5 では

画面を表示すると以下のようになります。
データを更新していますが、 @new_author_name の値と @new_editions の値は変わっていません。
キャッシュが働いているためです。
rails5.png

Rails 6 では

画面を表示すると以下のようになります。
@new_author_name の値と @new_editions の値は更新後の値に変わっています。

rails6.png

試したソース

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

参考情報

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

なぜサードパーティ・ライブラリを避けるべきなのか?

最近のプログラミング言語1は標準ライブラリが充実していますが、標準ライブラリが使いにくいために、別のサードパーティが普及している事も多いです。

例えばRubyでは、標準ライブラリのnet/http に対し、faraday がよく使われます。

しかし、私は先日あるプロジェクトであえてfaradayを避けnet/httpを使うことを選びました。私は以下のような理由から、サードパーティ・ライブラリは避けるべき(時もある)と思っています。

昔話:Pythonをシェルスクリプトで書き直した

「シェルスクリプトをPythonで」ではありません。

若い頃あるプログラムを任された私は「RHELなら標準でPythonがインストールされている。このプログラムは RHEL でしか動かさないんだから、Pythonで書いてもいいだろう。PythonはBashより可読性も高いし、クールだ!」と考え、Pythonで書いた結果、先輩にゲンコツ(の絵文字)を食らいました。

というのも、任されたプログラムが、商用パッケージのアップデート用スクリプトだったからです。「RHELでしか動かさない」ものの、RHEL のバージョンは顧客によりまちまちでした(4.x 〜 5.x)。

Python では複数のバージョンで動くスクリプトを書くのは注意が必要です(2.4にはwith文が無い!)。気を付けて書いたとしても、そのスクリプトが将来のバージョンでも動く保証はありません(2.5ではwithという変数名は使えない!)。

一方、シェルスクリプトはどのRHELでも同じように動作することが期待できます(少なくともPythonよりは確実性が高い)。

サードパーティはコントロールできない

さて、サードパーティ・ライブラリの話です。

サードパーティ・ライブラリはあなたの所有物ではありません。ゆえに、ライブラリが削除されたり、大きな変更が加わったりすることを止めることはできません。

これが如実に現れたのが、2016年のleft-pad問題でした2。left-padというライブラリが公開停止されたことで、それに推移的に依存していたReactやBabelなどの有名ライブラリが動作しなくなったのです。

「left-padは極端な例だろう」と思われるでしょう。でも、メジャーバージョンアップで後方互換性が無くなるのは、珍しいことではありません。そうなったら、

  1. 自分のコードを新バージョン向けに修正する(もちろん、テスト等の工数もかかる)
  2. もはやメンテされない旧バージョンを使い続ける(場合によってはフォーク版を作る)

という選択に迫られます。

そんなリスクを追うぐらいなら、多少不便でも標準ライブラリで書いた方が良いのではないですか?

そのサードパーティ、そんなに重要?

さて結局、サードパーティ・ライブラリを使うかどうかは、

  • バージョンアップ時の書き換えにかかるコスト
  • 得られる利便性

この2つを天秤にかけることになります。

あなたが書いているのが「長期間使うが滅多に変更はしないコード」の場合は、「最後に触ったのが3年前だから勘所が思い出せない」「開発環境構築から始めないといけない」「保守フェーズなので工数が取れない」といったことが起きがちなので、最初に標準ライブラリと多少格闘した方が、後々のコストは安いでしょう。一方、書き捨てスクリプトや、頻繁に手を加えるコード0なら、書き換えのコストはゼロあるいは低くなります。

また、例えばPythonでデータ分析処理を書くとき pandasnumpy といったライブラリは不可欠でしょう(明らかに利便性がコストに勝ります)。一方、付加的な処理(分析結果の保存とか)で楽をするためにrequests を導入するというなら、それはちょっと考え直した方がいいかもしれません。


  1. "Batteries included" が売りのPythonは1991年登場なので「最近」という表現はちょっと変ですが。 

  2. left-pad については、こちらの記事で解説されています: NPMとleft-pad : 私たちはプログラミングのやり方を忘れてしまったのか? | POSTD 

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

Ruby mysql2 で prepareする際の注意点

Ruby mysql2の動作でよくわからないところ

Ruby mysql2でqueryとprepareで動作が違う。これが仕様なのかどうなのかわからない。

バージョン

ruby : ruby 2.1.1.p76
mysql2 : 0.5.2

準備

検証用テーブルを作成。

create.sql
CREATE TABLE t_test (
  no int(11) DEFAULT NULL,
  test_date date DEFAULT NULL,
  article varchar(256) DEFAULT NULL
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8
;

検証用データを挿入。

insert into t_test values
('1',now(),'date on'),
('2',null,'date null'),
('3','0000-00-00','date space')
;

データ確認

mysql> select * from t_test ;
+------+------------+------------+
| no   | test_date  | article    |
+------+------------+------------+
|    1 | 2019-07-01 | date on    |
|    2 | NULL       | date null  |
|    3 | 0000-00-00 | date space |
+------+------------+------------+
3 rows in set (0.00 sec)

mysql> select * from t_test where test_date is null;
+------+-----------+-----------+
| no   | test_date | article   |
+------+-----------+-----------+
|    2 | NULL      | date null |
+------+-----------+-----------+
1 row in set (0.00 sec)

mysql> select * from t_test where test_date <> '0000-00-00';
+------+------------+------------+
| no   | test_date  | article    |
+------+------------+------------+
|    3 | 0000-00-00 | date space |
+------+------------+------------+
1 row in set (0.00 sec)

ま、当たり前の結果。

Rubyからデータを取得してみる。

queryで抽出してみる。

mysql2_query.rb
#! /usr/local/bin/ruby
require 'mysql2'
require 'pp'

cli = Mysql2::Client.new(:host => '127.0.0.1', :username => '***', :password => '***', :database => '***' ,:encoding => 'utf8')

sql1 = %{select no,test_date,article from t_test limit 10}
ret1 = cli.query(sql1 ,:symbolize_keys => true)
ret1.each do |row|
    p row
end

queryでデータを呼び出すと普通に出力される。

[anno@sv1]~/bin% ./mysql2_query.rb
{:no=>1, :test_date=>#<Date: 2019-07-01 ((2458666j,0s,0n),+0s,2299161j)>, :article=>"date on"}
{:no=>2, :test_date=>nil, :article=>"date null"}
{:no=>3, :test_date=>nil, :article=>"date space"}
[anno@sv1]~/bin% 

prepare + executeで抽出してみる。

mysql2_prepare_1.rb
#! /usr/local/bin/ruby
require 'mysql2'
require 'pp'

cli = Mysql2::Client.new(:host => '127.0.0.1', :username => '***', :password => '***', :database => '***' ,:encoding => 'utf8')

sql2 = %{select no,test_date,article from t_test limit ?}
stmt = cli.prepare(sql2)
ret2 = stmt.execute('10' ,:symbolize_keys => true)
ret2.each do |row|
    p row
end
[anno@sv1]~/bin% ./mysql2_prepare_1.rb
/usr/local/lib/ruby/gems/2.1.0/gems/mysql2-0.5.2/lib/mysql2/statement.rb:7:in `new': invalid date (ArgumentError)
        from /usr/local/lib/ruby/gems/2.1.0/gems/mysql2-0.5.2/lib/mysql2/statement.rb:7:in `each'
        from /usr/local/lib/ruby/gems/2.1.0/gems/mysql2-0.5.2/lib/mysql2/statement.rb:7:in `_execute'
        from /usr/local/lib/ruby/gems/2.1.0/gems/mysql2-0.5.2/lib/mysql2/statement.rb:7:in `block in execute'
        from /usr/local/lib/ruby/gems/2.1.0/gems/mysql2-0.5.2/lib/mysql2/statement.rb:6:in `handle_interrupt'
        from /usr/local/lib/ruby/gems/2.1.0/gems/mysql2-0.5.2/lib/mysql2/statement.rb:6:in `execute'
        from ./mysql2_prepare_1.rb:18:in `<main>'
[anno@sv1]~/bin% 

prepareでデータを呼び出すとエラーが出る。invalid date???

prepare + executeで抽出してみる(その2)。

dateでエラーとのことなので、日付がnullのデータを排除してselectしてみると成功。

mysql2_prepare_2.rb
#! /usr/local/bin/ruby
require 'mysql2'
require 'pp'

cli = Mysql2::Client.new(:host => '127.0.0.1', :username => '***', :password => '***', :database => '***' ,:encoding => 'utf8')

sql2 = %{select no,test_date,article from t_test where test_date <> '0000-00-00' limit ?}
stmt = cli.prepare(sql2)
ret2 = stmt.execute('10' ,:symbolize_keys => true)
ret2.each do |row|
    p row
end
[anno@sv1]~/bin% ./mysql2_prepare_2.rb
{:no=>1, :test_date=>#<Date: 2019-07-01 ((2458666j,0s,0n),+0s,2299161j)>, :article=>"date on"}
[anno@sv1]~/bin% 

結論

理由はわからないけど、prepareでデータ抽出をするときは日付データがnullは許容されないらしい。

  • SQL側で文字列に変化させてからデータ抽出をする
  • prepareをあきらめてqueryで抽出する
  • テーブル構造で日付にnull,0000-00-00を許容しない様子にする。 どれかで対処する。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

配列のメソッドまとめ!

こんにちは!

最近雨模様が続いてますね...

梅雨が明けて真夏の日々が待ち遠しいです:relaxed:(←夏生まれ)

はい!

今回は、ブロックを扱う配列のメソッドの中でも、特に使用頻度の高いメソッドをまとめていきます!

それではLet's GO!

mapメソッド

mapメソッドは各要素に対してブロックを評価した結果を新しい配列に返します!

具体例を交えながら説明していきますね!

例えば、以下のように配列の各要素に5を足した新しい配列を作るコードがあります。

sample.rb
numbers = [0,1,2,3,4,5]
plus_numbers = []
numbers.each do |number|
  plus_numbers << number + 5
end

plus_numbers #=> [5,6,7,8,9,10]

ここでmapメソッドの登場です!!!

mapメソッドを使うと、ブロックの返り値が配列の要素となる新しい配列が形成されるため、mapメソッドの返り値をそのまま変数に入れることができます!

それでは見てみましょう!

sample.rb
numbers = [0,1,2,3,4,5]
plus_numbers = numbers.map do |number|
  number + 5
end

plus_numbers #=> [5,6,7,8,9,10]

selectメソッド

selectメソッドは、各要素に対してブロックを評価して、その返り値が真の要素を集めた配列を返すメソッドです!

同じく具体例を交えながら説明していきますね!

例えば、以下のようにすると、"e"を含んだ値だけを集めた配列を新たに作ることができます!

sample.rb
colors = ["red","blue","yellow","black"]
new_colors = colors.select do |color|
  color.include?('e')
end

new_colors #=> ["red","blue","yellow"]

rejectメソッド

rejectメソッドはselectメソッドの反対で、ブロックの返り値が真になった要素を除外した配列を返します!

例えば、以下のようにすると、"e"を含んだ値を除いた配列を新たに作ることができます!

sample.rb
colors = ["red","blue","yellow","black"]
new_colors = colors.reject do |color|
  color.include?('e')
end

new_colors #=> ["black"]

findメソッド

findメソッドは、ブロックの返り値が真になった最初の要素を返します!

例えば、以下のようにすると、"e"を含んだ最初の要素を返します!

sample.rb
colors = ["red","blue","yellow","black"]
new_colors = colors.find do |color|
  color.include?('e')
end

new_colors #=> ["red"]

以上となります!

配列のメソッドは使い方次第でとても便利なので知っておくだけでもかなり幅が広がると思いました!

何かご意見等ございましたら、お気軽にコメントお願いします!

ご静聴ありがとうございました!:relaxed:

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

任意の文字列の最初の2文字を最後尾に持ってきて その文字を出力するメソッド

任意の文字列の最初の2文字を最後尾に持ってきて その文字を出力するメソッドの作り方

ex)
left2('Hello') → 'lloHe'
left2('Ruby') → 'byRu'
left2('oh') → 'oh'

def left2(str)
  left2 = str.slice!(0,2)
  puts str + left2
end

slice!メソッドを調べても出てこなかったので、ご存知の方は教えていただけると幸いです。

<参考記事>
https://ref.xaio.jp/ruby/classes/string/slice
https://ref.xaio.jp/ruby/classes/array/slice
https://www.javadrive.jp/javascript/array_class/index8.html

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

tan(x)を何度も微分する

はじめに

だいぶ前ですが、Twitterで「RT(Favだったかな?)の数だけtan(x)を微分する」というつぶやきを見ました。わりとRT/Favされてて収拾がつかなくなっていたようです。

$\tan(x)$は$\sin(x) / \cos(x)$なので、一度微分すると、

$$
\frac{d}{dx} \tan{x} = \frac{1}{\cos^2{x}}
$$

もう一度微分すると、

$$
\frac{d^2}{dx^2} \tan{x} = \frac{2 \sin{x}}{\cos^3{x}}
$$

と、いい感じにややこしくなっていきます。

最近、シンボリックな微分コードが欲しくなったところだったので、その練習として、tan(x)を微分するコードを書いてみましょう。

方針

$\tan{x}$を微分するとき、$\tan{x} = \sin{x}/\cos{x}$にして、$f(x)/g(x)$という分数の微分公式、

$$
\frac{d}{dx} \frac{f(x)}{g(x)} = \frac{f'(x) g(x) - f(x)g'(x)}{g^2(x)}
$$

を使いたくなります。しかし、プログラムで微分する場合は、

$$
\tan{x} = \cos^{-1}{x} \sin{x}
$$

という形にしたほうが扱いやすいです。

いま、$\cos{x}$と$\sin{x}$のべき乗の積、$\cos^m{x} \sin^n{x}$を考えましょう。これを微分すると、

$$
\frac{d}{dx} \cos^{m}{x} \sin^{n}{x}
= -m \cos^{m-1}{(x)} \sin^{n+1}{(x)}
+ n \cos^{m+1}{(x)} \sin^{n-1}{(x)}
$$

と、やはり$\cos^m{x} \sin^n{x}$の形しかでてきません。なので、$\tan{x} = \cos^{-1}{x} \sin{x}$という形からスタートして、後は上記のルールに従って計算していけば、何度でも微分できることになります。

コード

というわけで、そのままコードに落としてみましょう。デフォルト値があるハッシュを使えばあっという間です。$\cos^{m}{x}\sin^{n}{x}$を、[m,n]という配列で表し、この配列をキーとして、係数vをハッシュとして登録しましょう。

def diff(h)
  h2 = Hash.new(0)
  h.each do |key, v|
    m, n = key
    h2[[m-1,n+1]] += v*n if !m.zero?
    h2[[m+1,n-1]] -= v*m if !n.zero?
  end
  h2
end

h = Hash.new

h[[-1,1]] = 1

5.times do
  h = diff(h)
  p h
end

実行するとこんな感じです。

$ ruby tan.rb
{[-2, 2]=>1, [0, 0]=>1}
{[-3, 3]=>2, [-1, 1]=>2}
{[-4, 4]=>6, [-2, 2]=>8, [0, 0]=>2}
{[-5, 5]=>24, [-3, 3]=>40, [-1, 1]=>16}
{[-6, 6]=>120, [-4, 4]=>240, [-2, 2]=>136, [0, 0]=>16}

これを見て気が付きました。

$\cos^{m}{x}\sin^{n}{x}$を、[m,n]という配列で表すと、これを微分すると[m+1, n-1][m-1, n+1]しか出てきません。つまり、$\cos^m{x}$と$\sin^n{x}$の係数の和m+nは常に一定です。

最初に$\tan{x} = \cos^{-1}{x} \sin{x}$からスタートしているので、常に$m+n=0$が成立します。つまり、$\tan{x}$を何度微分しても、$\tan{x}$のべき乗の線形和で表せる、ということです。

改めて微分の式を書くとこんな感じになります。

\begin{align}
\frac{d}{dx} \tan{x} &= \tan^2{x} + 1 \\
\frac{d^2}{dx^2} \tan{x} &= 2 \tan^3{x} + \tan{x} \\
\frac{d^3}{dx^3} \tan{x} &= 6 \tan^4{x} + 8\tan^2{x} + 2\\
\end{align}

これを、パスカルの三角形的な形にするとこんな感じになるでしょう。

image.png

で、ここまで考えたところで、Twitterで先行研究があることを教えていただきました。

あるだろうなと思ってましたが、やっぱりありましたね・・・

まとめ

Rubyで$\tan{x}$を何度も微分するコードを書いてみました。っていうか、コードを書く前に「$\tan{x}$を何度微分しても$\tan{x}$のべき乗しか出てこない」という事実に気が付かなかったのはアホすぎますね。

この、tan(x)を何度も微分して、その係数がどんどん増えてややこしくなっていくという奴、なんとなくL Systemを思い出しますね。

参考文献

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

【Ruby】1 - 0.8� = 0.2 にしたい (浮動小数点誤差)

小数点の演算で誤差がでてしまった

> 1 - 0.8
=> 0.19999999999999996

0.2 を期待しているのに、誤差が生じてしまってます。
引かれるほうに小数点つけても同じ。

> 1.0 - 0.8
=> 0.19999999999999996

bigdecimalをrequireすると良い、とあったのでやってみました。

> require  'bigdecimal'
> BigDecimal("1") - BigDecimal("0.8")
=> 0.2e0

BigDecimalの引数はString型にして、誤差のない数を演算機に伝えてる(と理解した)。
答えに指数部分がついてきました。理由はわからなかったけど、to_fすれば指数部分は消えました。(あとで調べる)

> require  'bigdecimal'
> (BigDecimal("1") - BigDecimal("0.8")).to_f
=> 0.2

答えに整数が欲しいとき

例えば消費税計算とか。1800 * 1.08 の答えは1944が返ってきて欲しいのに、、、

> 1800 * 1.08
=> 1944.0000000000002

こういう時にBigDecimal使う。

> require 'bigdecimal'
=> true
> (BigDecimal("1800") * BigDecimal("1.08")).ceil
=> 1944

ceilは「自身と等しいかより大きな整数のうち最小のものを返す」のでBigDecimal使わないとこうなる。

> (1800 * 1.08).ceil
=> 1945

参考

[Ruby]消費税計算にはBigDecimalを使いましょう
instance method Float#ceil

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

1 - 0.8� = 0.2 にしたい(浮動小数点問題)

浮動小数点問題でちょっと苦しんだのでメモします。Rubyです。

小数点の演算で誤差がでてしまった

> 1 - 0.8
=> 0.19999999999999996

0.2 を期待しているのに、誤差が生じてしまってます。
引かれるほうに小数点つけても同じ。

> 1.0 - 0.8
=> 0.19999999999999996

ググったらbigdecimalをrequireすると良い、とあったのでやってみました。なおBigDecimalの引数はString型にしないとエラーになるもよう。

> require  'bigdecimal'
>(BigDecimal("1") - BigDecimal("0.8")).to_f
=> 0.2

ちなみにto_fしないと指数がついてくる。なぜなのか。

> require  'bigdecimal'
>(BigDecimal("1") - BigDecimal("0.8")).to_f
=> 0.2e0

以下「プロを目指す人のためのRuby入門」の人の記事から(答えに整数が欲しいとき)

参考にしたのはこのQiitaです。
[Ruby]消費税計算にはBigDecimalを使いましょう

例えば消費税計算とか。1800 * 1.08 の答えは1944が返ってきて欲しいのに、、、

> 1800 * 1.08
=> 1944.0000000000002

こういう時にBigDecimal使う。

> require 'bigdecimal'
=> true
> (BigDecimal("1800") * BigDecimal("1.08")).ceil
=> 1944

ceilは「自身と等しいかより大きな整数のうち最小のものを返す」のでBigDecimal使わないとこうなる。

> (1800 * 1.08).ceil
=> 1945

instance method Float#ceil

ふむふむ。

ポエムです

抽象化と具体化が苦手なので(プログラミングするにあたって致命的なのでは...)、手元にメモ帳と電卓を置いて勉強しているんですが、パソコンの演算結果に誤差が出て慌てました。今の自分の頭で理解できる範囲だと、これがいいのかなと思ったのですが、他に最適解ありそう。(to_fしたりroundで丸めたり、とかも考えたのですがいい感じの桁数を判断するのって難しいなと思ったり...)

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

【Ruby】1 - 0.8� = 0.2 にしたい(浮動小数点問題)

浮動小数点問題でちょっと苦しんだのでメモします。Rubyです。

小数点の演算で誤差がでてしまった

> 1 - 0.8
=> 0.19999999999999996

0.2 を期待しているのに、誤差が生じてしまってます。
引かれるほうに小数点つけても同じ。

> 1.0 - 0.8
=> 0.19999999999999996

ググったらbigdecimalをrequireすると良い、とあったのでやってみました。なおBigDecimalの引数はString型にしないとエラーになるもよう。

> require  'bigdecimal'
>(BigDecimal("1") - BigDecimal("0.8")).to_f
=> 0.2

ちなみにto_fしないと指数がついてくる。なぜなのか。

> require  'bigdecimal'
>(BigDecimal("1") - BigDecimal("0.8")).to_f
=> 0.2e0

以下「プロを目指す人のためのRuby入門」の人の記事から(答えに整数が欲しいとき)

参考にしたのはこのQiitaです。
[Ruby]消費税計算にはBigDecimalを使いましょう

例えば消費税計算とか。1800 * 1.08 の答えは1944が返ってきて欲しいのに、、、

> 1800 * 1.08
=> 1944.0000000000002

こういう時にBigDecimal使う。

> require 'bigdecimal'
=> true
> (BigDecimal("1800") * BigDecimal("1.08")).ceil
=> 1944

ceilは「自身と等しいかより大きな整数のうち最小のものを返す」のでBigDecimal使わないとこうなる。

> (1800 * 1.08).ceil
=> 1945

instance method Float#ceil

ふむふむ。

ポエムです

抽象化と具体化が苦手なので(プログラミングするにあたって致命的なのでは...)、手元にメモ帳と電卓を置いて勉強しているんですが、パソコンの演算結果に誤差が出て慌てました。今の自分の頭で理解できる範囲だと、これがいいのかなと思ったのですが、他に最適解ありそう。(to_fしたりroundで丸めたり、とかも考えたのですがいい感じの桁数を判断するのって難しいなと思ったり...)

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