20190711のRubyに関する記事は15件です。

cssで記述する基本的なレスポンシブ(メディアクエリ)

この記事で説明していること

  • メディアクエリについて
  • メディアクエリの書き方
  • その他

メディアクエリについて

メディアクエリとは、Webページの見栄えを記述するCSS3で追加された仕様の一つで、表示された画面環境に応じて適用するスタイルを切り替えることが出来る機能のこと。

画面サイズに応じてcssを変更することが出来る。


メディアクエリの書き方

<link rel="stylesheet" href="css/style.css" media="screen">

上記コードをhtmlに記載

@media screen and (min-width:299px){
  /*299px以下で適用する内容*/
}

@media screen and (min-width:300px){
  /*300px以上で適用する内容*/
}

@media screen and (min-width:600px){
  /*600px以上で適用する内容*/
}

上記コードをcssに記載
これで各画面サイズごとにcssを変更することが出来ます。

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

VSCodeでRubyを書く準備

Rubyを書き始めるにあたり、WebStormからVSCodeに完全移行しました。RubyMineまで買えない :money_with_wings:
1年半ほど前に使ったときは、動作がモッタリしてるな〜という印象でしたが(Sublimeが軽快すぎて)
今使ってみると結構さっくさくになってる!快適!
(ちなみにキーバインドはSublimeのバインドがそのまま使えて助かりました。癖ってなかなか変えられないですね...)

拡張機能 「Ruby」 をインストール

拡張機能検索で「ruby」と打てば1番上にでてきます。
Ruby言語に関して、デバッガー、Linter、自動補完など大体のことをカバーしてくれる必須拡張機能です。
この拡張機能の設定をしていきます。

Linter

スタイルガイドに沿わない汚いコードを怒ってほしい!のでlinterをいれます。

こんな感じ
Pasted_Image_2019_07_11_22_29.png
linterは rubocop にしました。
まずgemをグローバルインストールします。

$ gem install rubocop

デフォルトではlinterはオフになっているので、 VSCodeの settings.json で設定を書き加えます。

settings.json
"ruby.lint": {
  "rubocop": true
},


settings.json の開き方
⌘+, でGUIの設定画面を開き、右上のカッコ記号をクリックで切り替えられます
Settings_—_cl-bandai-brappers.png

以上!

もしエラーがでてたらVSCodeを再起動orリロードするか、それでもだめならパスの問題かもしれないです。
[Mac]VScode で ruby-rubocop が動かなくなったら executePath を設定してみよう - Qiita

より詳しい設定をしたい場合は、 .rubocop.yml ファイルに書いていきます。
RuboCopの設定アレコレ - Qiita

Formatting

手動でインデント揃える鬼畜作業はしたくないので、
ファイルを保存したときに自動一括整形するようにします。
formatterは最初rufoを入れてましたが、シングルクオート設定ができないみたいだったのでこちらもrubocopを使います。

settings.json
"[ruby]": {
  "editor.formatOnSave": true
},
"ruby.format": "rubocop",
"editor.formatOnSaveTimeout": 5000

RubyのREADMEにはタイムアウト時間を1500にしてねと書いてありますが、
1500だと足りないみたいです(ここではまったw)
cf. visual studio code - vscode( vscode-ruby + rubocop ) how to auto correct on save? - Stack Overflow

あとは拡張機能から 「endwise」 も入れておけばひとまず満足しました。
物足りなくなってきたらまた拡張していこうと思います :smiley:

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

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

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

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

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

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

6.1.1 データベースの移行

リレーショナルデータベースについて

テーブル型になっているデータベース。
よくあるデータベースの形です。
1つの行は1つのIDを示しており、それぞれのIDがnameやemailといったデータを持ちます。

マイグレーションについて

マイグレーションはデータベースへの追加や変更を行います。

rails generate model User name:string email:stringでUserモデル(データベース)が自動生成されますが、user.rbはまだ空っぽです。
そのかわり、db/migrateディレクトリにマイグレーションファイルが生成されています。

rails db:migrate

上記を実行することで、テーブルの作成を行います。
また、このマイグレーションファイルを使ってテーブルへの変更を元に戻す(ロールバックする)ことも可能です。

rails db:rollback

上記を実行すると、テーブルの作成を元に戻すことが可能です。

マイグレーションやロールバックを行うたびにdbディレクトリ内のdevelopment.sqlite3というファイルが更新されます。「DB browser」を利用してデータベースの中身を確認することができます。
https://sqlitebrowser.org/dl/

6.1.3 ユーザーオブジェクトを作成する

User.new
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil>

作成したUserクラスに対して、.newメソッドを使用すると、Userオブジェクト(Userインスタンス)を作成できます。
引数なしで呼び出した場合、idnameemailcreated_atupdated_atのプロパティはいずれもnillです。

user = User.new(name: "Michael Hartl", email: "mhartl@example.com")
=> #<User id: nil, name: "Michael Hartl", email: "mhartl@example.com",
created_at: nil, updated_at: nil>

引数にnameemailを指定する場合は、上記のように記述します。
ただし、idcreated_atupdated_atのプロパティはいずれもnillです。

.newで作成したオブジェクトに対して.saveメソッドを使用することで、データベースに保存されます。
idcreated_atupdated_atのプロパティは、この段階で決定されます。

User.create(name: "A Nother", email: "another@example.org")
#<User id: 2, name: "A Nother", email: "another@example.org", created_at:
"2016-05-23 19:18:46", updated_at: "2016-05-23 19:18:46">

.createメソッドを使用すれば、.new.saveを同時に行うことができます。

.destroyメソッドは、反対にオブジェクトを削除します。

6.1.4 ユーザーオブジェクトを検索する

User.find(1) #id==1 のオブジェクトを返す

.find()を使用すると、引数に合致するオブジェクトを返します。

User.find_by(email: "mhartl@example.com")

特定の属性で検索する場合は、.find_byが有効です。

 user.email
=> "mhartl@example.net"
 user.email = "foo@bar.com"
=> "foo@bar.com"
 user.reload.email
=> "mhartl@example.net"

.プロパティ名でそのオブジェクトのプロパティにアクセスし、上書きすることも可能です。
また、.reloadを実行すると、データベースの情報を元にオブジェクトを再読み込みするので、.save前であれば変更が取り消されたように見えます。
(実際は、保存前のデータをDBから再読み込みしているだけ)

6.2 ユーザーを検証する

6.2.1 有効性を検証する

require 'test_helper'

class UserTest < ActiveSupport::TestCase

  def setup
    @user = User.new(name: "Example User", email: "user@example.com")
  end

  test "should be valid" do
    assert @user.valid?
  end
end

UserTestクラス内のsetupメソッドは、テストが実行される直前に実行されます。
ここでは、Userオブジェクトがちゃんと作成できるかを確認するために、.newして
@userインスタンス変数に格納しています。

"should be valid"と名付けられたテストでは、.valid?メソッドで@userが有効かどうかを確認します。
.valid?メソッドは、後述する「バリデーション」を確認し、オブジェクトにエラーがない場合はtrueが返され、そうでなければfalseが返されます。

ここでは何もバリデーションを設定していないので、@user.valid?はtrueになります。

6.2.2 存在性を検証する

 test "name should be present" do
    @user.name = "     "
    assert_not @user.valid?
 end

まず、@user.nameにからの文字列を代入しています。名無しです。

assert_notは、引数がfailseもしくはnillのとき成功となります。

ここで注意したいのは、あなたはまだバリデーションをなにも設定していないので、名前が空欄だろうがなんだろうが、.@user.valid?trueだということです。

空欄を認めないバリデーションを設定しない限り、.@user.valid?trueなので、assert_notを含むテストは失敗します。

6.2.4 フォーマットを検証する

%w[]について

Rubyの%記法と呼ばれているものです。
以下にまとまっています。
『Rubyで%記法(パーセント記法)を使う』 @mogulla3
https://qiita.com/mogulla3/items/46bb876391be07921743

%w[]は配列を作ります。スペースで区切りを指定します。
カンマやクオーテーションを省略して配列を作ることができます。

test "email validation should accept valid addresses" do
    valid_addresses = %w[user@example.com USER@foo.COM A_US-ER@foo.bar.org
                         first.last@foo.jp alice+bob@baz.cn]
    valid_addresses.each do |valid_address|
      @user.email = valid_address
      assert @user.valid?, "#{valid_address.inspect} should be valid"
    end
  end

このテストでは、

  • まず、valid_addressに有効と思われるメールアドレスの例を配列として定義します。

  • 次に、.eachメソッドで配列の中身をひとつずつ取り出してassertにかけます。

  • assertメソッドの第2引数は、エラーメッセージになっています。assartが失敗した際に呼び出されます。

ちなみに、.inspectメソッドはオブジェクトや配列などに対して使用すると、対象の型に沿った文字列を返します。

正規表現について

validates :email, format: { with: /<regular expression>/ }

formatというオプションは引数に「正規表現(regex)」をとります。
正規表現は、文字列のマッチングに使うと便利な言語です。

/\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i

上記はメールアドレスを正規表現で表したものです。
「英数字の組み合わせ」@「英数字の組み合わせ」.「英数字の組み合わせ」

という内容です。

6.2.5 一意性を検証する

  test "email addresses should be unique" do
    duplicate_user = @user.dup
    @user.save
    assert_not duplicate_user.valid?
  end

@user.dup.dupメソッドはオブジェクトのコピーを作成して返すメソッドです。
@userのコピーを作成し、変数duplicate_userに格納しています。

@userと同じ情報を持つオブジェクトは、作成できてはなりません。

duplicate_user.valid?trueつまり有効なメールアドレスとして判定されると、テストは失敗します。

@userと同じ情報を持つオブジェクトの作成を許可しないよう、Userクラスにバリデーションを追加してテストが通るように修正します。

データベースのインデックスを追加する

class AddIndexToUsersEmail < ActiveRecord::Migration[5.0]
  def change
    add_index :users, :email, unique: true
  end
end

add_indexはRailsの関数です。テーブルにインデックスを追加します。

add_index :users, :email, unique: true
  • 第一引数はインデックスを追加するテーブル名(users

  • 第二引数はインデックスを追加するカラム名(email

  • 第三引数はオプション追加(unique: true

以下のようなオプションを設定できます。

:name #インデックスの名前
:unique #trueを指定するとユニークなインデックス
:length #インデックスに含まれるカラムの長さ

例えば、あるメールアドレスを使ってログインする場合、

  • インデックスを使わない場合だと、データベースの隅から隅まで検索をおこなわなければいけません。

* インデックスを貼っておけば、アルファベット順に検索したり、長さ順に検索したりできます。

このチュートリアルでは、ユニークであることを保証するためにインデックスを使っています。

6.32: email属性を小文字に変換してメールアドレスの一意性を保証する

class User < ApplicationRecord
  before_save { self.email = email.downcase }#コレ
  validates :name,  presence: true, length: { maximum: 50 }
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  validates :email, presence: true, length: { maximum: 255 },
                    format: { with: VALID_EMAIL_REGEX },
                    uniqueness: { case_sensitive: false }
end

before_saveはデータベースへの保存前に、引数の関数(コールバック関数)を実行します。

before_savenewされるたびに起動するので、selfnewしたインスタンス自身です。自分自身のメールアドレスに対して.downcaseで小文字に変換します。

なお、

self.email = self.email.downcase

の右辺selfを省略した書き方になっています。

6.33: リスト 6.32のメールアドレスの小文字化に対するテスト

  test "email addresses should be saved as lower-case" do
    mixed_case_email = "Foo@ExAMPle.CoM"
    @user.email = mixed_case_email
    @user.save
    assert_equal mixed_case_email.downcase, @user.reload.email
  end
  • まず、テスト用に"Foo@ExAMPle.CoM"大文字小文字を含むアドレスを用意

  • @user.emailに上書きし、.saveでデータベースに保存する...けど、

  • でも、データベースへの保存の前に、Userクラスのbefore_save { self.email = email.downcase }が起動。小文字にしてから@userは保存される。

  • "Foo@ExAMPle.CoM".downcaseを使用した文字列」と、「データベースに保存された文字列」が同じかどうかassert_equalで検証する。

【補足】メールアドレスの検証まとめ

  1. メールアドレスの長さは255文字を上限とするバリデーション追加
  2. 正規表現でメールアドレスを表現し、それに合わない文字列はNGとするバリデーション追加
  3. 大文字・小文字を区別せず、ユニークであるようバリデーション追加
  4. データベース内でもユニークであることを保証するため、インデックスをモデルに追加
  5. データベースへの保存の際に、データベースに保存される直前にすべての文字列を小文字に変換し、大文字・小文字の区別をさらに安全にする

6.3.1 ハッシュ化されたパスワード

class User < ApplicationRecord
  before_save { self.email = email.downcase }
  validates :name, presence: true, length: { maximum: 50 }
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  validates :email, presence: true, length: { maximum: 255 },
                    format: { with: VALID_EMAIL_REGEX },
                    uniqueness: { case_sensitive: false }
  has_secure_password #これ
end

Railsにおいてパスワードの実装は、以下をまず実装する。

  • データベースにpassword_digestカラムを追加する

  • モデルにhas_secure_passwordを追加する

  • bcryptをGemfileに追加する(よりセキュアに)

  • テストコード内の仮想インスタンスのプロパティにpassword: "文字列", password_confirmation: "文字列"を追加する(has_secure_passwordによって仮想属性が追加されているため)

6.3.3 パスワードの最小文字数

多重代入について

  test "password should be present (nonblank)" do
    @user.password = @user.password_confirmation = " " * 6
    assert_not @user.valid?
  end

  test "password should have a minimum length" do
    @user.password = @user.password_confirmation = "a" * 5
    assert_not @user.valid?
  end

passwordpassword_confirmationの2つの属性に同時に代入を行っています。

  • 上のテストは、スペースが6文字続く場合

  • 下のテストは、パスワードが5文字しかない場合

がfalseになるようテストしています。

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

ドットインストールのRuby on Rails 5 入門を履修する際に自身が体験したエラーの一例集

初投稿にあたって

 初投稿がいきなり失敗談から入る点やドットインストールのRubyの入門の項目を無視していきなりRuby on Railsの項目から入る点などツッコミどころはたくさんあるとは思いますが、どうかご容赦ください。

今回の投稿の理由

 とりあえずの初投稿ではありますが、今回の投稿の目的としては

・Qiitaへの投稿に慣れるための第一歩の練習としての投稿
・単純に備忘録として初心を忘れないようにメモしておきたかった
・失敗談を共有することである程度他者の参考になればという思い

 以上の点で記録を公開しようと思いました。

 自己紹介の記事がまだ無かったりプロフィール等が充実して居なかったりでどういう人物かも分かりにくいだろうとは思いますが、自分は今年の6月頃からRuby、HTML、CSSなどをドットインストールやProgateなどで学び始めたプログラミング勉強歴2ヶ月目の初学者だという認識で見てもらえればと思います。

 ではいきなりではありますが、早速以下よりエラーのパターンと自身が経験したその解決策の一例を挙げていきたいと思います。初心者ゆえ至らぬ点や言葉足らず、間違っている点などが多々あるとは思いますがよろしくおねがいします。
 
 また、現時点では技術的なトラブルというよりもそれこそ初心者にありがちな単純なスペルミスや記載ミスから起こったトラブルやエラーばかりなので深刻なトラブル等でお悩みの方のお力にはなれないかもしれません。

 今回の記事はドットインストールさんの動画で指定されている、Ruby on Rails 5入門を進めるやり方に沿った条件や環境を前提としています。

「#8の記事の一覧を表示してみよう」におけるトラブル・エラー

作成したはずのブログが表示されない。

 これが自身がRuby on Railsを学ぶ上で最初に体験したエラーでした。
#7までは特にこれといったトラブルも無く来れたのですが、(とはいえ直前の#7まではオートでファイルが作られたり特に難しい場面もありませんでしたが。)それまで詰まることも無く突然訪れたのがこのエラーでした。サーバーを立ち上げ、ブラウザにRuby on Railsのサイトを192.168.33.XXで表示するところまでは問題無くこなすことが出来たのですが、なぜか末尾に/postを付けて出来たブログにアクセスしようとしても全く出来なかったのです。
 最初は自身のMac側の通信や手元のソフトウェアの環境に問題があることや途中での手順にミスがあった可能性、直前にターミナル起動中にもう一つターミナルを捜査ミスで立ち上げてしまい、一部のデータを破損させてしまった可能性なども考えましたが、結論から言えばそれらに関しては何も問題はありませんでした。

 エラーの内容が確かRouting Errorなどでルーティング絡みでのトラブルだったと記憶しているのでroutes.rb等に問題があるのだろうとは思っていたのですが、当初はファイルの内容のどこが間違っているのか検討が付かずファイルを改めて作り直して再度手順の確認をしてみたりサーバーの再起動をしてみたり色々と試行錯誤をしてみましたが半日ほど原因が分からず途方に暮れていました。

原因

myblog/config/routes.rb内の記述のうち、

Rails.application.routes.draw do
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
  resources :posts 

  root "posts#index"

end

上記の

resources :posts

の欄の「resources」の綴りを間違って「resouces」と書き間違っており、単純なスペルミスに気付くことが出来ていませんでした。
 非常に情けなく初歩中の初歩のようなミスなのですが、自分で「resouces」と書いておきながら全く違和感を覚えることが出来ず、元々が「resources」という英単語においてuの後にrが無いといけないということを知らなかった知識不足がゆえのミスでした。他のファイルのコードも作例と何度も見返して探り続けましたがこの単純なミスに気付くまでに結構な時間を消費してしまいました。
 自身の英語力の低さにも絶望しましたが、やはり初歩の初歩、色んなところ、特に自分の中で思い込みになってしまっているような点を疑う視点の大事さも学びました。みなさんは僕のような単純なミスはあまりしないかもしれませんが、何をやってもダメそうな時は自分でも特におかしいと思っていないような常識だと思っているところから疑ってみましょう。

対策

単純かつ当たり前ですが「resouces」とタイプミスしていた箇所を「resources」と訂正して解決。
これで問題無く作成したブログが表示されるようになりました。

 エラーに対する原因と対策の内容のメモは取っておいたのですが、エラーメッセージをコピペしたり参考にするために回ったサイトのURLの記事などのメモを一切取れておらず(QiitaやPocketに記事のストックはあるものの、どの内容が正しい解決法なのかそうでないのかは把握出来ていない。)そうした点がまさに自身の浅薄さというか初心者たる点だなぁと改めて感じざるを得ませんでした。
 正しい記録だけ取って間違った手順や解決法は気にもとめずに解決したタイミングである程度流してしまっているところがありましたが、いずれその内容が役に立つ可能性もありましたし、間違った手順に流されそうになった経緯も忘れてしまう可能性があり、同じミスを繰り返さないようにするという反省はしにくいだろうなと考えました。
 記事を書いていて改めて実感したので今後はトラブルやエラーが起きた際には正しいトラブル解決法であっても間違った解決法を模索していてもいずれにしても全ての記録をしっかりと取りたいと思います。
 今回の内容的にトラブルのレベルとしては時間こそかかりましたが、それほど難しいものでもないと考えたのでterateilなどで誰にも相談や質問をせずに自身でもググるだけで解决できると考えたのですが、ミスの内容があまりにも単純で初歩的過ぎておそらくはむしろ相談した方が解決しにくかったかもしれません。(それでもズバリとミスを指摘してくれる方もいらっしゃったかもしれませんが・・・。)

「#13 画像にリンクを貼ってみよう」でのロゴにリンクが付加出来ず、ブログ自体の表示が出来なくなったエラー

 ロゴにリンクを貼り付ける作業をしていたら作業の終わった後からブログ自体を表示できなくなった。この時もエラーログをちゃんとメモることが出来ていなかったので確認は出来ないが、今同じミスをやり直してみたらSyntax Errorと出たのでその類のエラーだったと思う。

 8章以来はエラーもなく淡々と作業をこなせていたのですが、2度めのエラーがここでした。作業も進み何かしらのエラーが出ると検証しないといけない箇所が増えて来るのですが、幸いなことにエラーが起きた際にはエラーメッセージと共にありがたいことにこうやって表示してくれることに今回から気付いたのでいくらか楽にはなりました。

名称未設定.png
※注:今回は記事のために画像内では非常に分かりやすい形でのミスをしてこの画像例を作成しましたが、ミス自体の内容は今回の内容とは違うものとなっています。あしからず。理由は後述

これによって
myblog/app/views/layouts/application.html.erb内の

  <h1><%= link_to image_tag("logo.png", class: "logo"), root_path %></h1>

の中に何らかの問題があることは分かったのですが、当初上記の画像とはまた違った理由で自分のミスに気付くことが出来ていませんでした。
 

原因

 結論から言うと上記箇所のうち''で囲んでいたクォーテーションのうち、一箇所が半角ではなく全角打ちに気付かない内になっていたということでした。

対策

 上記コード内のクォーテーションを全て半角で打ち直し。個人的な対策方法としては全角半角の区別がしにくい''(シングルクォーテーション)をやめて全部""(ダブルクオーテーション)に統一した。

 上記に挙げた画像の問題点はといえば単純に「logo.png」の箇所のクォーテーションをわざと外すことで意図的にミスをしてエラーメッセージの表示を行っているので今回の原因とはまた違いますし、今回挙げた画像の例としては良くないとは思ったのですが、画像だと余計にクォーテーションの全角半角の違いには気付きにくいだろうと判断しやむを得ず別のパターンのエラーを載せることにしました。まさに自分もそれでハマってしまい、クォーテーションの全角半角が入れ替わってミスをしていることにこれまた長いこと気付けなかったのです。
 Progateか何かでプログラミングを学び始めたころ、まさにクォーテーションの全角半角にも気を付けないとコードは成立しないとうっすら教えてもらった記憶はあったのですが、早速自分がその罠にかかっているであろうということが想像出来ずまたしてもつまらないミスをしてしまいました。

「#20記事を更新してみよう」内でRouting Error

 再びあのにっくきRoutingu Errorに引っかかってしまいました。ですが、今回はまだましなのは#8で散々くだらない形でのミスを自身が犯していたので今回もそれに近い形でのトラブルだろうと楽観することが出来、重くは受け止めずに済みました。
 今回は先程のエラーと同じようにエラー時にどこの箇所がおかしいかを指摘してもらえるのも知っているので原因にたどり着くまでの早さも若干違っていました。

原因

myblog/app/views/posts/edit.html.erb内の

<%= form_for @post, url: post_path(@post) do |f| %>

<%= form_for @post, url: posts_path(@post) do |f| %>

としてしまっていたから。
具体的には「post_path(@post)~」とすべきところを「posts_path(@post)~」としてしまっていたことが原因ですね。

対策

該当箇所から「s」を削って訂正

 今回のミスもタイプミスといえばタイプミスなんですが、これまでの単純なものとやや性質自体は違うと思っていて、これがまさに自分がまだRuby on Rails自体にしろProgrammingというものにしろ理解がいまひとつ及んでいないということを実感することになるミスでした。
 自分もドットインストールさんの動画を見ながら作業をして居るのですが、どうしても動画を見返す際に置いてきぼりにされてしまうこともあり、巻き戻したり進めたりして見ていました。どうもそんな風に作業をしている際に取りこぼしがあったりするのかあとで動画の内容を記事にまとめたりしてくれている人のメモを見ながら聞いた覚えのないことがあって愕然とすることが多々有りました。これなんかがまさにそうでコードを記述する際にどうして「@post」と書くのか「Post」とするのか「Posts」とするのか使い分けのパターンをイマイチ理解しないままに言われるがままに記述を模写していて完全にこんがらがっていました。
 おそらくはターミナルで確認出来るルートのパスの違いなんだろうと思いますが、残念ながら動画内で何度も確認していたようには自身で出来ておらずここの理解が進んでいません。この点についてはもう一度動画を見直すなり復習するなりして再度見直していこうと思います。この点を自身の頭で解決せずにアプリの自作などを始めてしまうとエラーの地獄に堕ちて何が悪いのか正しいのか分からないままになってしまいそうなのでしっかりとやりたいと思います。

「#22 記事を削除できるようにしよう」で記事削除のアクションが通らずエラーになる。

原因

myblog/app/controllers/posts_controller.rb内でdestroyアクションのところで

具体的には「@post = Post.new(post_params)」のところが記述ミス。

def destroy
     @post = Post.new(post_params)
    @post.destroy
    redirect_to posts_path
end

と記述してしまっていた。

def destroy
    @post = Post.find(params[:id])
    @post.destroy
    redirect_to posts_path
end

が正しい表記。
このミスによってブログ記事の削除後のデータが送信出来ない状態になっていたようだ。

 これは単純なミスでした。動画内で該当箇所を他のところからコピペするように指示されていたのですが、その際に該当箇所以外のところから引用してしまいミスしてしまったものと思われます。
 ただしこの件においてもやや自分がどこが間違っていることになかなか気付けなかったのは悔しいものでした。

「#26コメントの一覧を表示しよう」でコメントを入力しても反映されずエラーとなる。

原因

myblog/app/controllers/comments_controller.rb内の

class CommentsController < ApplicationController

  def create
    @post = Post.find(params[:post_id])
    @post.comments.create(comment_params)
    redirect_to post_path(@post)
  end

  private
    def comment_params
      params.require(:comment).permit(:body)
    end
end

の上記コードのうち、

.permit(:body)

の記述をし忘れていた。おそらく動画を見ている際に指示された箇所のコピペをし損なうミスをしたのだと思う。

対策

該当箇所に不足していた「.permit(:body)」を記述して解決。

 直前のエラーがあったので今回も同じようにデータの送信に障害があるのだろうということはすぐに分かったのですが、今回もなかなか原因にたどり着くまでに時間はかかってしまいました。今回のミスを起こしたことに関しては単純に前回と同じく動画の指示に従う際にコピペの作業で該当箇所を取りこぼしてしまっていたというのが原因でした。何度か見返すことで対策は出来ることだったと思います。

まとめ

 自分がRuby on Rails 5 の入門を履修する過程で経験したトラブルやエラーは以上になります。
 最初に記事を書き始める頃には自分が味わったエラーの体験は原因がどれも違うものが多いんじゃないかな?って思いつつ書き始めたのですが、記事を書きながらざっと見直してみるとほとんど、というかほぼ全部が詰まらないタイプミスによるトラブルであることに気付いてしまいました。まぁプログラミングのミスやトラブルと言う物自体が大体そういうものなのかもしれませんが、自分はまだ初歩の初歩ですし本当に技術的なことには触れることが出来ておらずの状態なのでこれも仕方がないのかもしれません。原因に陥る傾向や経緯、紛らわしさはそれぞれである程度違っていたのでその差に気付きにくかったという側面も合ったかと思います。
 ただ、今のうちに反省しつつ単純なタイプミスを減らすように今後も気を付けるためのいい機会というかスタートだったのかもしれません。
 また、これは別にドットインストールさんがどうこうという問題ではなく自分の能力の不足だとは思うのですが、動画だけではまだ自分の能力では補いきれない部分も多く、動画学習の便利さも感じつつ先人の方たちが動画内容をQiitaやブログなどにまとめてくれていたのには非常に感謝しました。
動画の中ではどうしてもコード全体を俯瞰したシーンが無く自分の記述がどの程度まで合っているのか間違っているのかをざっくり確認する術が無かったので書面にて確認出来る手段があったのは非常に助かりました。Ruby on Railsの入門編だとは言いますがそれでも簡単とは個人的には思えず、それらのツールが無ければ自分には完走は無理だったように思います。
 今後はちょうどドットインストールののRuby on Railsの項目の無料分が大体終わったので少しずつ専門書を交えて知識を増やしながら次の段階、自主的な制作物としてのポートフォリオの制作に手を付け始めようかなと思っています。その際にはみなさんのアドバイスやお力をお貸しいただくことになるかと思いますのでよろしくおねがいします。

最後に

 内容が全く大したことが無かった割に要らない自分語りも多分に含めてしまったので無駄に長文になってしまった気がしますが、それでも自分としては文章を書く久しぶりのリハビリにちょうど良かったかなと思っています。昔はココではないところでTCGのブログなどをやったりしており多少文章は頻繁に書いていた時期なんかもあったのですが、もうそれも10年近くやっていなくて文章を書くと言っても最近ではTwitterに死にかけの語彙で叫んだり草生やしたりくだらないことばかりだったので、長文も全然書けていませんでした。今回の初投稿は非常に稚拙なもので自分でもダメだなと思う点ばかりでしたが、それは今後成長するための土台ということでいずれ自分でこの記事などを見返した際に酷いもの書いてたなって笑えるように精進して未来の自分に希望を託したいと思います。
 それでは長くなりましたが、自分の初投稿にみなさんお付き合いいただきありがとうございました。
ツッコミなどいただきはじめたらキリがないくらいかもしれませんが何かご意見ご指摘ご感想などありましたらぜひお願いいたします。

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

【Rails】ログイン機能について

sessionを使用したrailsのログイン機能についてのメモです。

ログイン機能の概要

sessionにユーザの情報があるかどうかを判断します。

sessionにユーザの情報が無い場合
→サインイン(ユーザ登録画面)へ
sessionにユーザの情報がある場合
→ログイン後のページを表示

というのがログイン機能基本的な流れかなと思います。

railsでは、sessionにユーザの情報を自動で暗号化して保持することができるので、こちらで考えることは少なくて済みます。

ユーザ登録について簡単にあとめた記事も公開しているので、参考にしてください。

コントローラ

ログイン機能で実装するのは、new,create,destroyのアクションです。

下記のコードがログイン機能のコントローラです。

session.rb
class SessionsController < ApplicationController
  def new
  end

  def create
    email = params[:session][:email].downcase
    password = params[:session][:password]
    if login(email, password)
      flash[:success] = 'ログインにしました'
      redirect_to @user
    else
      flash.now[:danger] = 'ログインに失敗しました'
      render 'new'
    end
  end

  def destroy
    session[:user_id] = nil
    flash[:success] = 'ログアウトしました'
    redirect_to root_url
  end

  private

  def login(email, password)
    @user = User.find_by(email: email)
    if @user && @user.authenticate(password)
      session[:user_id] = @user.id
      return true
    else
      return false
    end
  end
end

createアクションでは、ログインに成功すると、ユーザの詳細画面へ、ログインに失敗すればもう一度ログイン画面へとページ移行するようになっています。

login(email, password)では、入力されたemailとpasswordを引数に取り、ユーザが登録しているかどうかの確認を行っています。

view画面

ログイン画面です。CSSを適用していない最低限の画面です。笑

index.html
<%= form_for(:session, url: login_path) do |f| %>

    <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>

    <%= f.submit 'Log in', class: 'btn btn-primary btn-block' %>
<% end %>

<p>New user? <%= link_to 'サインアップ画面', signup_path %></p>

超見にくいですが、最低限のログイン画面です。
サインアップ画面は、ユーザ登録に記述してあります。

スクリーンショット (45).png

ログイン後の画面ですが、
下記のコードの中にログイン後に表示したいコードを記述します。

<% if logged_in? %>

ログイン後に表示したいコード

<% end %>

ログイン要求画面

ユーザがログインしていない場合に、ログインを要求する機能です。

アプリケーションコントローラに実装し、どのコントローラからでも呼び出せるようにします。

application_controller.rb
class ApplicationController < ActionController::Base

    def require_user_logged_in
        unless logged_in?
            redirect_to login_url
        end
    end

    def current_user
        @current_user ||= User.find_by(id: session[:user_id])
    end

    def logged_in?
        !!current_user
    end

end

require_user_logged_inによって、ユーザがログインしているかどうか判別するコードです。
アプリケーションコントローラに記述しているので、ほかのコントローラでも呼び出すことが出来ます
before_actioの中に記述するのがスマートです。

before_action :require_user_logged_in, only: [:index, :show]

以上です!これでログイン機能が実装できているはず!

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

【Rails】Active Storageで拡張子のvalidateを作成する時の注意点

はじめに

タイトル通りActive Storageで拡張子に関するvalidateを作成したところ、Userがサインアップする時にエラーが出てしまった。

事象

Userモデルに以下のような感じで、Active Storageでアップロードするimageに対して拡張子を指定するvalidateを作成した。

user.rb
class User < ApplicationRecord
  has_one_attached :image

  validate :image_content_type

  def image_content_type
    extension = ['image/png', 'image/jpg', 'image/jpeg']
    errors.add(:image, "の拡張子が間違っています") unless image.content_type.in?(extension)
  end

ところがこの後、userを新規アカウント登録させようとすると以下のエラーが出てしまった。

content_type delegated to attachment, but attachment is nil

スクリーンショット 2019-07-11 19.40.04.png

原因

今回の場合はUserをcreateする時にemailとpasswordしかpostしないので、
当然imageはparamsに乗らないため、image.attached?falseになります。
上記のエラーはimageがattachedされてないのにcontent_typeを呼び出したことによるエラーっぽいです。

解決方法

image.attached?falseの時はvalidateしないようにすれば解決なので、

user.rb
class User < ApplicationRecord
  has_one_attached :image

  validate :image_content_type, if: :was_attached?

  def image_content_type
    extension = ['image/png', 'image/jpg', 'image/jpeg']
    errors.add(:image, "の拡張子が間違っています") unless image.content_type.in?(extension)
  end

  def was_attached?
    self.image.attached?
  end

これで無事Userがcreate出来るようになりました。

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

listen gemで作成中のファイルが通知されないようにする

以下、Linuxでの話。

困りごと

listen gemでディレクトリを監視して、新規作成されたファイルに対し処理を行おうとした。

listener = Listen.to('./data') do |modified, added, removed|
  # 新規作成されたファイルに対して処理をしたいが...本当にこれでいい?
  added.each do |f|
    #...
  end
end

しかしサイズが大きいファイルをコピーした場合など、作成時に added、書き込み完了時に modifiedと、2回に分けて通知される場合がある。つまり added として通知されたファイルは、まだデータがすべて書き込まれていない、可能性がある。

困ったことに、 added通知の時点で書き込みが完了していたら、後の modified通知は来ない。後で modified通知が来るかどうか知る方法はないし、いつ来るかもわからない。

つまり、ファイルの作成が完了したかどうか、確実に検出する手段がないのだ。

解決策

コードを読んだ結果、undocumentedな機能ではあるが、バックエンドに対するオプションを直接指定できるとわかった。Linuxでのバックエンドはinotifyであり、どのイベントを検出対象とするか、 events オプションで制御できる。

標準では次のようになっている(:recursiveはrb-inotify用のダミーのオプションで、サブディレクトリを処理するためのもの)。

[
  :recursive,
  :attrib,
  :create,
  :delete,
  :move,
  :close_write
]

今回は書き込み完了=新規作成と見なしたい。つまり一度作成されたファイルの内容が変更されるケースは考慮しない。よって次のように変更した。

[
  :recursive,
  :close_write,
  :delete,
  :move
]

コードとしては次のような感じになる。

events = %i(recursive delete move close_write)

listener = Listen.to('./data', events: events) do |modified, added, removed|
  puts "新規追加されたファイル: #{modified}"
  puts "削除または移動されたファイル: #{removed}"
  puts "移動先のファイル: #{added}"
end
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS EC2で写真投稿機能を追加する方法

gem レシピ

Gemfile.
#image
gem 'rmagick'
gem 'paperclip'

#AWS
gem 'aws-sdk'

$ bundle install でインストール!!

データベースを用意していく

$ rails g paperclip [テーブル名] [カラム名]
$ rake db:migrate

view

・投稿ボタンを任意の場所に設置。

hoge.html.erb
<%= form.file_field :picture %>

.

・投稿後の写真を表示したい所に設置していく。

hogehoge.html.erb
<%= image_tag game.picture.url(:thumb) %>

model

モデル内に追加するコード

hoge.rb
has_attached_file :picture, styles: {medium: "300x300>",thumb: "100x100>"}
    do_not_validate_attachment_file_type :picture

controller

privateの関数内のパラメーター(hoge_params)に、写真の([:カラム名])を追加しておく。

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

+ AWS EC2で RubyonRail写真投稿機能を追加する

gem レシピ

Gemfile.
#image
gem 'rmagick'
gem 'paperclip'

#AWS
gem 'aws-sdk'

$ bundle install でインストール!!

データベースを用意していく

$ rails g paperclip [テーブル名] [カラム名]
$ rake db:migrate

view

・投稿ボタンを任意の場所に設置。

hoge.html.erb
<%= form.file_field :picture %>

.

・投稿後の写真を表示したい所に設置していく。

hogehoge.html.erb
<%= image_tag game.picture.url(:thumb) %>

model

モデル内に追加するコード

hoge.rb
has_attached_file :picture, styles: {medium: "300x300>",thumb: "100x100>"}
    do_not_validate_attachment_file_type :picture

controller

privateの関数内のパラメーター(hoge_params)に、写真の([:カラム名])を追加しておく。

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

Railsで動的なセレクトボックスを作る最も簡単な方法。

主に使用する言語はRuby(on Rails), JSです。

動的なセレクトボックスとは?

https://qiita.com/jnchito/items/59a5f6bea3d7be84b839

伊藤さんの書いているこちらの記事を見てみてください。

ここで記述されているセレクトボックスのように親要素が選択された時に子要素のセレクトボックスの中身が選択された親要素に紐づいている子要素になるというものをここでは動的なセレクトボックスと呼んでいます。

上記の記事ではルーティングを設定したり、ajaxの記述をしたりと色々していますが、ある要素を使えばこのセレクトボックスは簡単に実装できます。

結論:template要素を使う

ここでもCategory, SubCategoryのモデルでアソシエーションを組んで実装していきましょう。

class Category < ApplicationRecord
  has_many :sub_categories
end
class SubCategory < ApplicationRecord
  belongs_to :category
end

このアソシエーションによってCategoryモデルとSubCategoryモデルで1対多の関係性を築けました。

次はビューファイルの編集です。

= f.collection_select :category, Category.all, :id, :name, include_blank: "カテゴリーを選択してください"

- Category.all.each do |category|
 %template{id: "sub-category-of-category#{category.id}"}
  = f.collection_select :sub_category, categroy.sub_categories, :id, :name, include_blank: "サブカテゴリーを選択してください"

今の状況はこんな感じです。

<select name="category" id="category">
 <option value="1">カテゴリー1</option>
 .
 .
 .
</select>
<template id="sub-category-of-category1">#document-fragment</template>
<template id="sub-category-of-category2">#document-fragment</template>
<template id="sub-category-of-category3">#document-fragment</template>
<template id="sub-category-of-category4">#document-fragment</template>
<template id="sub-category-of-category5">#document-fragment</template>
.
.
.

template要素とは何か??

template要素は、ページの読み込み時に描画されず、後で JavaScript を使用してインスタンスを生成できるクライアント側のコンテンツを保持するメカニズムです。
(引用元:https://developer.mozilla.org/ja/docs/Web/HTML/Element/template

簡単にいうと、JavaScriptで操作して本文へと挿入しない限りはデベロッパーツールのHTML上には表示されるがビューの見た目には何も影響しないということです。

なのでjsファイル内での記述も書いていきましょう。
今回はjQueryで書いていきます。

jsファイル内の記述

$(document).on('turbolinks:load', function() {
 $(document).on('change', '#category', function() {
  let categoryVal = $('#category').val();
  if (categoryVal !== "") {
   let selectedTemplate = $(`#sub-category-of-category${categoryVal}`);
   $('#category').after(selectedTemplate.html());
  };
 });
});

ただ、このままだと初めは親要素のセレクトボックスしかなく、親要素を選択した際に子要素のセレクトボックスが現れるといった記述になることに加えて、一度選択して二度目の選択をする際に新しいセレクトボックスが生成されるという状況になってしまう。

少しビューファイルとjsファイルをいじってそれを直していきます。

= f.collection_select :category, Category.all, :id, :name, include_blank: "カテゴリーを選択してください"

= f.select :sub_category, [], include_blank: "サブカテゴリーを選択してください", class: "default-sub-category-select"

- Category.all.each do |category|
 %template{id: "sub-category-of-category#{category.id}"}
  = f.collection_select :sub_category, categroy.sub_categories, :id, :name, include_blank: "サブカテゴリーを選択してください"

これでページの読み込み時に親要素と子要素(option要素は何もない)が出来上がっている状況である。

ちなみにこの時のデフォルトで表示されている子要素のセレクトボックスのidが'sub_category'になっているということだけ覚えておいていただきたい。(jsファイルでの記述に使うから。)

そこからjsファイルの編集にうつる。

$(document).on('turbolinks:load', function() {
 //HTMLが読み込まれた時の処理
 let categoryVal = $('#category').val();
 //一度目に検索した内容がセレクトボックスに残っている時用のif文
 if (categoryVal !== "") {
  let selectedTemplate = $(`#sub-category-of-category${categoryVal}`);
  $('#sub_category').remove();
  $('#category').after(selectedTemplate.html());
 };

 //先ほどビューファイルに追加したもともとある子要素用のセレクトボックスのHTML
 let defaultSubCategorySelect = `<select name="sub_category" id="sub_category">
<option value>サブカテゴリーを選択してください</option>
</select>`;

 $(document).on('change', '#category', function() {
  let categoryVal = $('#category').val();
  //親要素のセレクトボックスが変更されてvalueに値が入った場合の処理
  if (categoryVal !== "") {
   let selectedTemplate = $(`#sub-category-of-category${categoryVal}`);
   //デフォルトで入っていた子要素のセレクトボックスを削除
   $('#sub_category').remove();
   $('#category').after(selectedTemplate.html());
  }else {
   //親要素のセレクトボックスが変更されてvalueに値が入っていない場合(include_blankの部分を選択している場合)
   $('#sub_category').remove();
   $('#category').after(defaultSubCategorySelect);
  };
 });
});

これで最初のビューに親要素・子要素のセレクトボックスが存在し、親要素が選択されていない場合はoption要素が何もないデフォルトのセレクトボックスが表示され、親要素が選択された際にその要素と紐づいた子要素が入ったセレクトボックスが現れるようになったと思う。ただIEがtemplate要素に対応してないみたいなの見たきがしないでもないからその辺りは注意してください。

リファクタリングはまた今度します。

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

Rails6 のちょい足しな新機能を試す51(MySQL default編)

はじめに

Rails 6 に追加されそうな新機能を試す第51段。 今回は、 MySQL default 編です。
Rails 6 では、 MySQL 8.0.13 以降のデータベースの場合に マイグレーションのカラムを追加するときに default オプションで式を指定できるようになりました。
言い換えると、MySQL 8.0.13 以降で カラムの default に式が使えるようになったことに、Rails が対応したということになります。

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

$ rails --version
Rails 6.0.0.rc1

今回は、IPアドレスをソートして表示する機能を作ってみたいと思います。

rails プロジェクトを作る

$ rails new rails6_0_0rc1
$ cd rails6_0_0rc1

scaffold で CRUD の機能を作る

scaffold で Host の CRUD を作成します。
カラム aton は、IPアドレスを数値に変換した値を保存します。

$ bin/rails g scaffold Host ip aton:integer

migration ファイルを編集する

migration ファイルを編集します。

ip カラムに null: false を指定します。
aton のデフォルト値は、MySQL の関数 INET_ATON() を使って ip のカラムを変換した値にします。
atonlimit: 5 を指定しているのは、 255.255.255 を数値に変換した時に正しい値が保存されるようにするためです。

db/migrate/20190706063437_create_hosts.rb
class CreateHosts < ActiveRecord::Migration[6.0]
  def change
    create_table :hosts do |t|
      t.string :ip, null: false
      t.integer :aton, limit: 5, default: -> { '(inet_aton(ip))' }

      t.timestamps
    end
  end
end

HostController#index を変更する

IPアドレスをソートして表示するために、 order を追加します。
ソートのキーは aton にします。

app/controllers/hosts_controller.rb
class HostsController < ApplicationController
  ...
  def index
    @hosts = Host.all.order(:aton)
  end
  ...
end

seed データを作る

1件ずつブラウザでデータを登録するのは面倒なので、seed データを作っておきます。

db/seeds.rb
Host.create(
  [
    { ip: '192.168.1.1' },
    { ip: '192.168.2.1' },
    { ip: '192.168.9.1' },
    { ip: '192.168.10.1' },
    { ip: '192.168.20.1' },
    { ip: '192.168.99.1' },
    { ip: '192.168.120.1' }
  ]
)

データベースを作る

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

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

rails server を実行して Host の一覧を表示する

rails server を実行します。

$ bin/rails s

http://localhost:3000/hosts で一覧画面を表示します。
IPアドレスの順番にソートされています。
host_order_by_aton.png

ちなみに order:ip を指定すると文字列としてソートされてしまいます。
host_order_by_ip.png

その他

ツッコミどころの多いソースかも知れませんが、今回は、あくまで default で式が使えることを確認する目的ですので見逃してください。
あと、今回は試してませんが、インデックスでも式を使うことができるようになっています。

試したソース

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

参考情報

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

コンテナど素人が、EC2からECSにシステムリプレースした話

LTの発表用に、gitpitchのスライドでまとめてみました。

スライド

https://gitpitch.com/matsuda-hiroki/slide?p=20190701_replace_EC2_to_ECS

反省点

gitpitchでの画像表示が崩れてしまう

qiitaへのスライド埋め込みがわからない

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

#Ruby #Rails + #rspec で rspec-benchmark gem を ”使わず" に速度検証・ベンチマークテストをする

Speed test and benchmark test "do not use" with rspec-benchmark gem with #Ruby #Rails + #rspec

ポイント

  • rspec を使うと色々とテストデータを作成/自動削除などしてくれるので、新しい仕組みを用意しなくて良い
  • rspec-benchmark gem がなぜかうまく動かなかった
  • 以下の例はデータ生成などはしていないが、 FactoryBot を組み合わせたりすると便利

速度を検証する

require 'benchmark'

describe 'sleep 5 seconds ( expect speed )' do
  subject do
    Benchmark.realtime { sleep 5 }
  end

  it { is_expected.to be < 6 }
end

# sleep 5 seconds ( expect speed )
#  should be < 6

速度は検証せず、標準出力で結果確認だけをする

require 'benchmark'

describe 'sleep 5 seconds ( not expect speed but stdout benchmark result )' do
  subject do
    Benchmark.realtime { sleep 5 }
  end

  it { puts subject }
end

# sleep 5 seconds ( not expect speed but stdout benchmark result )
# 5.003996700048447
#  example at ./spec/some_spec.rb:18

速度検証をしつつ、標準出力で結果も確認する

require 'benchmark'

describe 'sleep 5 seconds ( expect subject result and stdout benchmark result )' do
  subject do
    sleep 5
    true
  end

  it do
    subject_result = nil
    benchmark_time = Benchmark.realtime { subject_result = subject }
    puts benchmark_time

    expect(subject_result).to be true
    expect(benchmark_time).to be < 6
  end
end


# sleep 5 seconds ( expect subject result and stdout benchmark result )
# 5.005656399996951
#   should be < 6

結果の例

rspec -fd some_benchmark_spec.rb

image

Original by Github issue

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

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

ある社内SEが初めて作ったWebサービスの構成と昨今の何でもAWSに物申す

本番システム構成

サービス本体
Webサーバ:Nginx
APサーバ:Puma
DB:PostgreSQL
プログラム:Ruby on Rails
OS:CentOS7

さくらのクラウドで動かす。

バッチ処理
C#.NET
他省略。たいしたことやってない。


さくらのクラウドで動かす。

DBをサービス本体と共有して、やり取りしてる。今の時代はマイクロサービス的なAPI経由なんでしょうけど、
まあいつか・・・

検証環境
社内のそこらへんにあったWindowsPCにVMWareを入れて、その上に上記環境入れて動いています。
WMwareめっちゃいいですよ。壊れても消せばいいし、ファイルコピーすれば他のPC
もっていってもすぐに復元するし。バックアップもファイルコピーしておけばよいし。重いけど。
(ほんとはどっかーとかでやるのが一番いいって分かってる。分かってるんよ!まあいつか・・・)
社内SEの人はWindowsオンリーの人ばかりだと思います。ただ、Webサービス作るにあたっては
どうしてもLinux系のOSに慣れる必要がどうしてもあります。

なぜか。

本番環境は結局CentOS7を想定していたので、Windowsだとわけわからないエラーが出ます。
(実際にありました。Windowsではちゃんと動くのに検証環境持っていったら、動かないやつ。
 この時の原因はWindowsでしか動作しないPing系のGemを入れていたためでした。分からんて。
 そんなん。2日間かかりました。原因調べるの。)
まあ、でも開発はWindowsでしてますがね。てへ。

話は戻して、ちなみに本番は
今どきのクラウドサーバにおいて動かしてます。
でも、
AWSじゃないよさくらだよ。

なぜか。

日本のサービスだから、とっても分かりやすい。マニュアルも全部日本語やし、
初めてだったが、かなりスムーズに構築できた。
みんなクラウドと言えばAWSみたいな感じですが、取っつきやすさ、課金の
分かりやすさ(従量課金ではない)はさくらがダントツ。
※ちなみにうちの経営者はAWSで!ってミーハーな感じで言ってきてたので、
 従量課金で24時間動かしてたら、かなりコストいっちゃいますよ~
 想定よりかなりいっちゃう可能性ありますよ~。にやにや。とやんわり伝えたら、
 さくらで了承してくれました。

ちょっと言いたいこと(AWSに物申す。AWS信者にも。)

はっきり言って小規模の会社で、社内運用並み+αくらいのものであれば、
オンプレミス環境でもあまり問題にならないと思います。
(電源管理、インターネットの帯域管理、Windowsなら勝手に再起動しないでがある程度
求められますが、まあ稼働率90%あればええやん的な。ゆるい感じ。
かけるコストと内容と運用する時間とのバランスを考えると上記のような考えは全然ありです。
今までもこうしてきて、クレームほぼないし。お金を追加で払わなくてよいし。
ほんとに24時間絶対動かさないかんっていうやつであれば、じゃあクラウド考えましょうで良い。)
まあでも経営者はやたらとクラウドでって言うので、これも時代の流れでしょうか。
最初オンプレでも全然OKだと私は思います。なんかやばくなってきてからクラウドに移せばいいし。
オンプレミスからクラウドに移すっていう経験もとても良いものですよ♪

また、Webサービス作って、AWSに上げて、いい感じに構成してって、一般ピーポーからしたら
ものすごいハードル高い。
ローカルでもぎりぎり動いているのに、CentOSの理解に一苦労、AWSのドキュメント読みこんで、
AWSの理解に二苦労、ぐぐっても英語ばかりで三苦労ってなると、ほぼ挫折するはず。一般ぴーぽーは。
だから、ほぼ日本語で押し通せて、一番挫折しなさそうな Ruby → さくら という選択になりました。
ただ、さくらもしっかりしたクラウドで他のも似たようなもんだと考えると、
今ならたぶんAWSでも大丈夫な自信が無駄にあります。

ということで、一般ぴーぽー社内SEがWebサービス作るなら・・・

  • Ruby(on Rails) と さくら で決まり!一番挫折しない組み合わせですよ。ほんとにお勧め。
  • DBは何でもいいよ。好きなの。お勧めはPostgreSQL
  • エディタはVSCodeを使いましょう。
  • Teraterm(SSHでCentOSに入るためのツール。コピペが簡単にできるからとっても重宝する。)
  • WinSCP(ファイル転送ソフトだが、CentOSのファイルも見れる。ディレクトリ構成が一目瞭然

最後に

昨今の日本は生産性の向上が叫ばれていますが、ポイントとなるのは開発側の人間ではないです。
導入する側のITリテラシーにかかっています。そして導入側をリードするのが我々社内SEです。
実は生産性の向上に一番寄与するのが我々社内SEのはずなんです。業務フローも分かっていて、
ITの知識もあり、間に入って仕様の調整、工数調整できるのは我々です。
逆に社内SEがしっかりしていないところは、いわゆるベンダーの言いなり価格、言いなり仕様に
なります。自分もベンダー側の人間だったことがあるので・・・
結果、現場で使われない、意味不明な仕様の実装、無駄なお金が飛びます。

ただ、上記のしっかりしている社内SEになるには
レガシーな知識にとらわれず、最新のIT知識・その知識を持って簡単なサービスの実装
ができるほどの力は持っていないといけません。と私は思います。と私は思ったからこそ
今更Webサービス作ったりしています。
色々やっていると、実はフルスタックF/W(RubyだとRails)で全て作るような時代は
とうの昔に過ぎ去っており、サーバーサイドとクライアントサイドに明確に分けて
サーバーサイドはAPI実装が基本、クライアントサイドはSPAでの実装が基本というのが今の時代だそうです。
いわゆるマイクロサービス的な~♪ PayPayも3か月で組んだそうですよ。マイクロサービス的な
開発で。昔は考えられなかったのですが、インターネットの速度が劇的に向上したからこそ、こういうのが
できる時代になったんでしょうね。

まだまだ私はレガシー社内SEだったということで、今回のお話の締めにしたいと思います。
ああ、書いてすっきりした。

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

Rubyのclassの作り方

はじめに

まだ理解が浅いのですが、メモ用に書いてみました。

classの作成(インスタンス変数の数分、引数をとる)

rubyでちょとしたメモアプリなどを作成する時とかにclassを使っていたのですが、いつも以下のように書いてました。

class User
  attr_accessor :name, :age, :gender, :admin

  def initialize(name, age, gender, admin)
    @name = name
    @age = age
    @gender = gender
    @admin = admin
  end
end

user = User.new("sakakinn" ,29 ,"男性" ,true)
p user

出力結果↓

#<User:0x00007ff6db152550 @name="sakakinn", @age=29, @gender="男性", @admin=true>

この書き方だとuserを作成した時にキーがなくわかりずらいのかな。
また、以下のように引数の数が足りないとエラーになってしまいます。

class User
  attr_accessor :name, :age, :gender, :admin

  def initialize(name, age, gender, admin)
    @name = name
    @age = age
    @gender = gender
    @admin = admin
  end
end

user = User.new("sakakinn") # nameだけ入力した場合
p user

出力結果↓

Traceback (most recent call last):
        2: from ruby1.rb:12:in `<main>'
        1: from ruby1.rb:12:in `new'
ruby1.rb:4:in `initialize': wrong number of arguments (given 1, expected 4) (ArgumentError)

引数を1つにまとめた場合

paramsにまとめてみました。
上の場合と同じように出力されます。

class User

  def initialize(params)
    @name = params[:name]
    @age = params[:age]
    @gender = params[:gender]
    @admin = params[:admin]
  end
end

user = User.new(name: "サカキ", age: 29 , gender: "男性" , admin: true)
p user

出力結果↓

#<User:0x00007fd49887aa18 @name="サカキ", @age=29, @gender="男性", @admin=true>

@nameにだけ値を渡してみます。

class User

  def initialize(params)
    @name = params[:name]
    @age = params[:age]
    @gender = params[:gender]
    @admin = params[:admin]
  end
end

user = User.new(name: "サカキ")
p user

出力結果↓

#<User:0x00007fcf6515ea50 @name="サカキ", @age=nil, @gender=nil, @admin=nil>

エラーにならずちゃんと値がかえってきました。

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