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

【Ruby】rbenvの使い方(version `x.x.x' is not installed)

rubyのバージョンエラー

昔Githubに入れてたRailsのプロダクトを引っ張り出して動かそうとしたら、

version `x.x.x' is not installed

rubyのバージョンが違うらしい。。

rbenvコマンド

# リストを確認する
rbenv install --list

# インストールする
rbenv install x.x.x

# デフォルトで使用するバージョンを設定する
rbenv global x.x.x

## インストールしたRubyx.x.xを使用可能な状態にする
rbenv rehash

これで好きなバージョンのrubyで開発できます!

Railsも必要な人はこちらも追加

sudo gem install rails

おまけ

長くなりそうなので、省略しましたがこんなエラーも出てきました。
いくらインストール(sudo gem install rails)しても無限に出てくる、
有名なエラーなようです。
Macにデフォルトで入っているrubyとの干渉をしているので、、

Rails is not currently installed on this system. To get the latest version, simply type:

    $ sudo gem install rails

You can then rerun your "rails" command.

下記のコマンドでrbenvとruby-buildをインストール後、
本記事の設定を行うことで解消することが可能です。

brew install rbenv ruby-build

参考になれば幸いです。

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

[rails]deviseで登録・ログインができない問題

deviseで登録・ログインができない

deviseでユーザー登録とログイン画面を作成した後に、
デフォルト(email)以外の情報で登録・ログインをしたい時用の方法です。

viewページのフォームを編集したのに、登録・ログインできないトラップがありますので、
参考にしてください。

以下の場合、sing_upとaccount_updateのkeyを変更しています。

app/controllers/application.controller.rb
class ApplicationController < ActionController::Base
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected
    def configure_permitted_parameters
        if resource_class == User
            devise_parameter_sanitizer.permit(:sign_up, keys: [:name,:email])
            devise_parameter_sanitizer.permit(:sign_in,keys:[:email])
            devise_parameter_sanitizer.permit(:account_update,keys:[:name,:email])
    end
  end
end

defore _action

before_action :configure_permitted_parameters, if: :devise_controller?

before_actionは一種のフィルターのようなもので、application.contollerに記述することで、全てのコントローラーに対して、実行されます。

:devise_contoller?とはdeviseを生成した際にできるヘルパーメソッドの一つで、
deviseに関連する画面に飛ぶなら、ということです。
こうすることで全てのdevise画面でconfigure_permitted_parametersが起動します。

つまりもしそれがdeviseのコントローラーだったら(devise_controller?というメソッドの返り値がtrueだったら)configure_permitted_parametersを呼び出すということです。

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

【Ruby】共通鍵暗号のベンチマークテスト

はじめに

センシティブな情報を扱う際に、平文を暗号化しDBに保存し、取り出す時に復号化することがよくあります。

業務の中で、Rubyで暗号・復号化する方法を検討し、それぞれの方法でベンチマークテストを行う機会があったので、その時の内容をまとめました。

検討した方法は、Ruby標準ライブラリOpenSSL(自前の実装)とAWS Key Management Service(KMS)の2つになります。

自前の実装は計算コストが掛かりそうで、KMSはネットワークコストが掛かりそうなので、その点がどう結果に出るかが焦点になります。

暗号化方式

共通鍵暗号

送信者と受信者は1つの鍵を秘密に共有し、暗号化と復号化に共通の鍵を使う方式。同じデータを常に同じ暗号文に置き換えると、その頻度から平文が推測されてしまうため、同じデータでも違う暗号文に置き換えられるように初期化ベクトル(または、ソルト)を設定する。今回は初期化ベクトルを使用しました。

Rubyの標準ライブラリのOpenSSL::Cipherを使用した場合はこんな感じです。

def encrypt(plaintext, key, iv)
  enc = OpenSSL::Cipher.new('AES-256-CBC')
  enc.encrypt
  enc.key = key
  enc.iv = iv
  enc.update(plaintext) + enc.final
end

def decrypt(encrypted_data, key, iv)
  dec = OpenSSL::Cipher.new('AES-256-CBC')
  dec.decrypt
  dec.key = key
  dec.iv = iv
  decrypted_data = dec.update(encrypted_data) + dec.final

  # 復号化したデータはASCII-8BITであるため、強制的にエンコーディングを修正する
  decrypted_data.force_encoding("UTF-8")
end

plaintext = "暗号化する文字列"

key = "共通鍵"
iv = "初期化ベクトル"

# データの暗号化
encrypted_data = encrypt(plaintext, key, iv)

# データの復号化
decrypt(encrypted_data, key, iv)

公開鍵暗号

公開鍵で暗号化を行い、秘密鍵で復号化を行う方式。

Rubyの標準ライブラリのOpenSSL::Cipherを使用した場合はこんな感じです。

def encrypt(plaintext, public_key)
  Base64.encode64(
    public_key.public_encrypt(
      data, 
      OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING
    )
  )
end

def decrypt(encrypted_data, private_key)
  decrypted_data = private_key.private_decrypt(
    Base64.decode64(encrypted_data), 
    OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING
  )

  # 復号化したデータはASCII-8BITであるため、強制的にエンコーディングを修正する
  decrypted_data.force_encoding("UTF-8")
end

plaintext = "暗号化する文字列"

public_key = OpenSSL::PKey::RSA.new(File.read(public_key_file))
private_key = OpenSSL::PKey::RSA.new(File.read(private_key_file))

# データの暗号化
encrypted_data = encrypt(plaintext, public_key)

# データの復号化
decrypt(encrypted_data, private_key)

ベンチマークの概要

今回、暗号化する平文は数百文字の長文のため、公開鍵暗号が使用出来ない(少し工夫すれば使用は可能だが、推奨されていない)ため、共通鍵暗号を使用することにした。

ベンチマークには、Benchmarkライブラリを使用
https://docs.ruby-lang.org/ja/latest/class/Benchmark.html

require 'benchmark'

result = Benchmark.realtime do
  # ここに計測する処理を記載する
end

puts "#{result}s"

比較対象

  • Ruby標準ライブラリOpenSSL
  • KMS
  • KMS(VPCエンドポイントを設定)

ベンチマークの条件

  • 1000回実行した場合の合計秒数を計測
  • 暗号化だけ、復号化だけのそれぞれを計測

暗号化のベンチマークスクリプト

Ruby標準ライブラリOpenSSL

require 'openssl'
require 'base64'
require 'benchmark'

def encrypt(plaintext, key, iv)
  enc = OpenSSL::Cipher.new('AES-256-CBC')
  enc.encrypt
  enc.key = key
  enc.iv = iv
  enc.update(comment) + enc.final
end

data = <<-EOS
  長文・・・・・
EOS

key = "共通鍵"
iv = "初期化ベクトル"

result = Benchmark.realtime do
  1000.times do
    encrypt(plaintext, key, iv)
  end
end

KMS

require 'aws-sdk-s3'
require 'base64'
require 'benchmark'

class KMSClient
  REGION = 'ap-northeast-1'
  ALIAS_NAME = 'KMSのAlias Name'

  def initialize
    @client = Aws::KMS::Client.new(
      region: REGION,
      # VPCエンドポイントを設定した場合はregionの代わりにこちらを指定する
      # endpoint: 'https://vpce-xxxxx.kms.ap-northeast-1.vpce.amazonaws.com',
      access_key_id: '',
      secret_access_key: '',
    )
    @alias = @client.list_aliases.aliases.find { |a| a.alias_name == ALIAS_NAME }
  end

  def encrypt(plaintext)
    ciphertext = @client.encrypt(
      key_id: @alias.target_key_id,
      plaintext: plaintext
    )

    Base64.encode64(ciphertext.ciphertext_blob)
  end
end

plaintext = <<-EOS
  長文・・・・・
EOS

client = KMSClient.new

result = Benchmark.realtime do
  1000.times do
    client.encrypt(plaintext)
  end
end

puts "#{result}s"

復号化のベンチマークスクリプト

Ruby標準ライブラリOpenSSL

require 'openssl'
require 'base64'
require 'benchmark'

def decrypt(encrypted_data, key, iv)
  dec = OpenSSL::Cipher.new('AES-256-CBC')
  dec.decrypt
  dec.key = key
  dec.iv = iv
  decrypted_data = dec.update(encrypted_data) + dec.final
  decrypted_data.force_encoding("UTF-8")
end

plaintext = <<-EOS
  長文・・・・・・
EOS

key = "共通鍵"
iv = "初期化ベクトル"

encrypted_data = encrypt(plaintext, key, iv)

result = Benchmark.realtime do
  1000.times do
    decrypt(encrypted_data, key, iv)
  end
end

puts "#{result}s"

KMS

require 'aws-sdk-s3'
require 'base64'
require 'benchmark'

class KMSClient
  REGION = 'ap-northeast-1'
  ALIAS_NAME = 'KMSのAlias Name'

  def initialize
    @client = Aws::KMS::Client.new(
      region: REGION,
      # VPCエンドポイントを設定した場合はregionの代わりにこちらを指定する
      # endpoint: 'https://vpce-xxxxx.kms.ap-northeast-1.vpce.amazonaws.com',
      access_key_id: '',
      secret_access_key: '',
    )
    @alias = @client.list_aliases.aliases.find { |a| a.alias_name == ALIAS_NAME }
    p @alias
  end

  def encrypt(plaintext)
    ciphertext = @client.encrypt(
      key_id: @alias.target_key_id,
      plaintext: plaintext
    )

    Base64.encode64(ciphertext.ciphertext_blob)
  end

  def decrypt(ciphertext_blob)
    @client.decrypt(ciphertext_blob: Base64.decode64(ciphertext_blob)).plaintext
  end
end

plaintext = <<-EOS
  長文・・・・・
EOS

client = KMSClient.new

encrypted_data = client.encrypt(plaintext)

result = Benchmark.realtime do
  1000.times do
    client.decrypt(encrypted_data)
  end
end

puts "#{result}s"

ベンチマーク結果

暗号化

方法 秒数
Ruby標準ライブラリOpenSSL 0.006588994991034269
KMS 8.035557514987886
KMS(VPCエンドポイント) 7.766658762935549

復号化

方法 秒数
Ruby標準ライブラリOpenSSL 0.0037274740170687437
KMS 8.964495759923011
KMS(VPCエンドポイント) 7.9086791928857565

まとめ

やはり、KMSはネットワークコストが顕著に出て処理が遅くなるようです。これは、暗号・復号化のメソッド呼び出しの度にAWSへのネットワークアクセスが発生するため、このような結果になったのだと思います。VPCエンドポイントを設定し、VPC内で接続出来るようにすれば少し改善されるものの、やはり自前の実装には勝てないようです。ただ、セキュリティ向上のために暗号化に使用する鍵を長くすると、自前の実装でも計算コストが上昇するので、この点は注意が必要そうです。

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

[rails]deviseで作成したviewページの編集が反映されない

deivseで作成したviewページの編集が反映されない

deviseでデフォルトのログインページを編集し、画面を確認したところ、
編集内容が反映されていない問題が発生したので、解決方法を記録しておきます。

config/initializers/devise.rb
#config.scoped_views = false の記述箇所のコメントアウトを外し、falseをtrueに変更だけ
config.scoped_views = true

これだけで解決しました。

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

DMMWEBCAMPでの記録(未経験から就職まで)

はじめに

この度DMMWEBCAMPを卒業し、就職を決めることが出来たので学習の記録を書きます。

投稿しようと思ったきっかけ

以下記事を読ませて頂いて

【卒業生】DMMWEBCAMPに通おうか迷っている人に伝えたい事
https://qiita.com/yuki82511988/items/37be28f2486e166fd48f

僕もこれからプログラミングをやろうとしている方、学校に通おうと思っている方の役に立てればなという思いから書こうというところに至りました。

僕のこと

軽く自己紹介をします。

現在26歳今年27歳になります。
長野県出身でDMMWEBCAMPに通い転職する目的で引っ越しました。

MOSやワープロ検定1級を専門学校の時取得したくらいで、ターミナルやgithubを触ったことはありませんでした。
タイピングがちょっと速くてMicrosoft製品ちょっと使えるぜ!レベルです。
入学する半年くらい前にちょこっと本当に少しProgate(無料版)をやったり、SkillHuckという教材を購入して少しやった程度です。
ちなみにSkillHuckという教材に関しては、僕がその時動画学習が苦手だったのもあり動画を見ているうちに眠くなり2、3章やってやるのを辞めちゃいました。
勿体ないことをしました。
なのでプログラミングのイメージはあるけど種類や何が出来るかは知らないし、文字を出力するのはPタグを使えば良いんでしょ?ぐらいしか知らない状態です。笑

高校時代も決して頭が良い訳ではなく、どちらかという必死に悪ぶっている不真面目な方でした。
今ではちょっとした黒歴史です笑
商業高校(偏差値普通よりちょい下ぐらいで留年しかける)→専門学校(誰でも入れる)→医療機器の代理店営業という経歴です。

専門学校からは資格取得の勉強を一生懸命やり、クラスで上位の成績の人間にはなれて
大人になってから仕事は一生懸命やっていて、好きで仕事人間になっていましたが、
憧れであったり、物づくりをしてみたい、せっかくの人生だしやってみたいと思うことに挑戦してみたい、という思いからエンジニアを志しました。

なぜDMMWEBCAMPにしたのか

色々迷いましたがまず前提として、通学出来るところに焦点を絞って学校選びを始めました。
独学で勉強をやる習慣も無かったですし、多分オンラインだったり無料であればサボるだろうと思っていたからです。
さらに言えば学費もそこそこ無職で引越して一人暮らしとなればお金も当然かかる。
逆にここで投資すればサボろうとか諦めよう逃げようとか思わなくなるなと感じました。

選択肢は二つで
・DMMWEBCAMP
・テックキャンプ(確か)

転職保証でカリキュラムの内容も似ている中でどういう判断でDMMにしたのかというと

・学習期間が長い(最長4ヶ月)
・4ヶ月コースを受講することでキャッシュバックを受けれる(学費の6、7割)
・4ヶ月コースであればPythonかクラウドを学べる

就職支援はどこも凄そうだしな〜って思っていたのでこの3つで選びました。

特に学習期間が長いところに関してはメリットが多いなと思っていたんです。
期間が長ければそれだけサポートを受けながらもいろんな言語を独学で勉強したり、就活時必要になるポートフォリオのレベルとかも上げられると考えていました。
お金が持つだけ学習して、一番良い状態で就活に望みたいというところです。

ここから本題に入ります。

DMMWEBCAMPでの学習内容について

学習期間 2020/3月 〜 2020/6月

事前学習

まず事前学習として今後使っていくオンライン教材を1ヶ月前に配布されます。
僕はちょっとしか出来ませんでした。

引越しもそうですし、
前職が営業だったので送別会が2日に1回行われていたのです。笑
毎日2日酔いに近い状態です。
しかも独学の習慣もない。
カリキュラムは入学2日前から始めました。。

2020/3月(入学)

最初のガイダンスで隣の人のパソコンを覗き見した時に遥かに私より進んでいるのを見て本当に慌てました笑
え、まだ自分HTML2章なのにこの人もうRubyまでやってる、、、、

これはやばいと思いここから本気での学習がスタートします。
学ぶ内容はHTML,CSS,GitHub,Ruby,Rails,JavaScript,jQueryでした。
基本的にカリキュラムを自分で進めてわからなければ質問する形式なので、講義もなければ時間の指定もありません。
11時から22時の教室使用時間の中で好きな時間勉強するスタイルです。

毎日学校に行って、14時から22時くらいまで休憩を挟みつつ勉強しました。

提出しなければいけない課題が3つあり、2つ目までは期限ギリギリに終わるような実力レベルでしたが、
3つ目に関しては期限よりだいぶ前倒しで終わらせることが出来ました。

メンターさんがみんな良い人ですぐに助けてくれたので、自分の力だけで終わらせたとは言い難かったです笑

私には自分で解決する力がその時はまだ無いと認識していたのもあって少し調べてわからなかったらすぐに先輩なり、友達なり、メンターに聞きまくりました。多い時で10回は質問してましたね笑

慣れていないし、全然本質の理解が出来ていないので
エラーが出てエラーを調べても説明している文章の意味がわかんないんです。

なのでそこは頼って聞いた方が圧倒的に理解も早く深いですし、全然恥ずかしいことでもなく、成長するのかなと思っています。

まあ、私は元々そんな頭よく無いのでなおさらですね笑

1ヶ月目は後は余った時間を使って、JavaScriptのカリキュラムと
ProgateでRuby on Rails、HTML、CSS、Rubyの復習をして1ヶ月目は終了しました。
カリキュラムを終えた後のProgateは本当におすすめで
Ruby on Railsは特に復習になるので是非有料版に登録してやってみてください。

2020/4月 (2ヶ月目)

4/1 ~ 4/10 応用課題

応用課題が10個与えられます。ノルマは特にありません。
僕が終わらせることが出来たのは確か6個で7個目でつまずいたまま時間切れになりました。

ここではっきりと理解度や学習の差が出ます。

1ヶ月目に復習とかをあまりせずに良くわからないまま来てしまった方は応用課題をこなせても3つとかになると思います。そして更にここでの遅れというのはそのまま今後に繋がってくるのかなとも感じています。

なので1ヶ月目に曖昧にしてしまったことは調べるなり、
勉強するなり、メンターに聞きまくるなりしてしっかり理解しておかないと本当に周りに差を付けられてしまいます。
オフを取っている時間なんて無いんだと思います。

4/11 ~ 4/30 チーム開発

4人1組でECサイトの作成をします。
僕は当時Createアクションが苦手だとはっきり認識していたので、上手いことを言って結構難しめのところに取り組めました。
初めてのチーム開発は楽しかったですし、Gitのブランチの意味もここでちゃんと理解できたりCreataに苦手意識がなくなったりと得るものがめっちゃ多くて成長できました。
周りの人がレベル高めだったのもあって刺激を受けたり、教えてもらったりしながら取り組めました。

全体のレベルを拮抗させるようにチームを組んでくださるので、当時真ん中よりちょっと上くらいのレベルにいた僕には自分より出来る人がいるチームはとてもありがたかったです。

さっき書いた1ヶ月目で遅れを取ってしまった方は
基本的にあまり難しい機能の実装を経験できなくなると思います。
当然のことながら期日があるので、チームメンバーも任せてられないという現実があります。
割と忙しいですしね。
会社でも新人だったり、あまり仕事が出来ない人には難しい挑戦をさせないのと同じ感覚ですね。

なのでここでも一気にまた実力に開きが出てしまいます。
出来てた人はどんどん出来るようになり、出来なかった人はあまり成長しないまま進むという感じです。

もしこれから入学される方は1ヶ月目や事前学習を徹底的に頑張った方が良いと思います。

2020/5月 (3ヶ月目) ポートフォリオ作成

ここでは自分で考えたアイディアを元にしてポートフォリオを作成します。
設計からテスト、デプロイまで1人でやります(メンターには質問出来る)

僕はアイディア力に乏しいのもあって、バイクユーザー向けのSNSを作ろうと考えました。
ただSNS機能だけはなく、イベントを主催して人を集めることが出来るような機能も実装しました。

ポートフォリオは見たいと言ってくれればGithub含めお見せします。笑

一応機能としては

--SNS--
・ログイン
・画像投稿(配列を用いての複数投稿)
・コメント、いいね(非同期)
・フォロー(非同期)
・DM(非同期)
・コメントやいいね、フォローの通知
・閲覧数の取得
・APIを用いてのコメントの感情分析
・画像表示のスライドショー
・ハッシュタグ検索

--イベントーー
・イベント作成
・コメント、参加アクション(非同期)
・開催場所のGoogleMap表示(APIとJavaScriptで)
・参加中や主催したイベントを一目で確認できるカレンダー
・都道府県の表示をするためのgem
--その他--
・項目を選ぶことのできる検索機能
・Rspecテストで380項目
・携帯に対応したレスポンシブ対応
・会員登録しなくても機能の全貌が見えるゲストログイン機能
・https化
・ヘッダーメニューをjsやJqueryでアニメーション付きで実装

こんなもんですかね。
確かテーブル数は10ぐらいです。
王道の中では結構頑張ったと思います。笑

1ヶ月だけでは全ては実装できず結局次月に実装した機能もあります。

反省点をあげるのであれば、テーマを少し間違えたなと。
やはり就活している人の中にSNSを作る人って凄い多いらしくて、現状差別化が難しいです。
アイディア力が結構勝負でびっくりするような物が作れた方が注目されるのでは?
と感じるのでこれから作る方は
ちょっと工夫してみてください。

4ヶ月目 AI学習

正直全然わからないまま終わりました笑
2週間ぐらいでカリキュラムは終了したので、その後は就活に向けて考えがあって
あえてポートフォリオの更新を僕は重ねていました。

ポートフォリオの更新を重ねた理由

満足していなかったってのももちろんありましたが、
書類に載る物だったので、他の勉強をするよりここに力を入れる方が企業からの印象がいいんじゃないか?
と思って更新してました。
ポートフォリオに興味を持たれなければ、そもそもGitHubなんて見られないよな。っていう考えです。
レスポンシブ対応だったりRspecテストはこのタイミングでやりました。

これがどう就職活動に繋がったのかは後述します。

修了、そして就活へ

まずは担当のキャリアアドバイザーの方と面談します。
私が入社したいと思うような企業の希望を聞いてくださり、
それに沿った形で推薦をしていただくような流れです。

この時に書類の添削をするのですが、
ここでは結構修正して頂いてありがたかったです。

後は書類選考通過のお知らせを待ちます。

1ヶ月の中で私の書類選考が通った企業は2社でした。
友人の方が多くて若干悲しかったですが、それはしょうがないです。
年齢だったり、経験、ポートフォリオの内容を見て
それを総合的に判断した結果がこれなんだろうなと思いました。
コロナウィルスの影響もあり、なかなか就職が決まらない状況でもありましたから。

そこで面接を頂いた1社から内定を頂き、もう1社は最終選考前でしたがお断りし、
今回転職することができました。

採用頂いた企業様

面接でポートフォリオを見てくださったことを教えて頂きました。
特にRspecのところに関してはお褒め頂きましたし、スキルも高いと判断してくださったとのことでした。
私も自分の成長に繋がりそうな環境であり、WEB系、自社もSESもやってる、面接官の方に対する印象もとても良かったので内定を承諾しました。
あの時ポートフォリオの更新を重ねたのは間違った選択ではなかったなと感じています。

就活に関して思ったこと

自分から就職活動をしなかったので、非常に受け身だったなと反省しています。
このコロナウィルス下での採用状況だったのでもっと自分からも応募をかけた方が良かったなと感じました。

もちろん採用頂いた企業様に対しては行きたいと感じて面接を受けたのでありがたいと感じているのですが、
どうしても持っている選択肢が少なくなってしまうと、その中でしか物事を判断出来なくなってしまいます。
本当にここで決めてしまって良いのか。とか、でも就職できなくも困るなとか承諾期間中にあれこれと悩むことになります。

なので自分から選択肢を多くする努力をすることで、
自分の市場価値もはっきり見えて、本当に後悔のない転職活動ができるのでは?と思います。

就職活動中にやった方が良いと思うこと(主観)

よく面接で他にポートフォリオありますか?
って聞かれます。
面接官によってですが、そのポートフォリオは学校から半強制的に作らされた物であり、
自分の意志で作った物ではないとそう考える方もいらっしゃいます。

これは難しいですね本当に笑

自分で作りたいものを作っているのにカリキュラム的に作れと言われたから作ったみたいな笑

なので僕が思うに、別のフレームワークもしくはRailsでもう1つくらいポートフォリオはあった方が、プログラミングに対する姿勢は評価してもらえるのかなと感じています。(なくても学習を続けていれば一応評価はしてもらえますが、こっちの方が多分印象良いです)
僕はJavaなり、SQLなりRubyの復習を7月は行っていたのですが、
そもそもGitHubが見られなければ学習の様子は企業様には伝わらないんですよね。
であれば履歴書にポートフォリオを2つ載せた方が良いんじゃないかと。
それかもしくは一つのポートフォリオのレベルを極限にあげること。
そこまでやってる方って中々いないですから。
結構提出して更新を辞めちゃう人が多い印象です。

ただ僕の場合は選考でJavaのテストがあったので学習したことは全然無駄にならなかったんでそこは良かったです。

新しい言語を学ぶ場合はフレームワークまで使ってアプリ作れて初めて高評価に繋がると思うので、僕もどうせならそこまでやれれば良かったなーって今更ながら思います。

それと当たり前ですけど最低でもプログラミングとかその他何かしらの学習はしていないとダメですね。

ただし、勉強する言語にはこだわりすぎないこと。
僕もインフラエンジニアの友人や、IT関係の友人に色々と意見を聞いた上でこう思ったのですが、
よくインフルエンサーと呼ばれる方が言語に関してあれをやった方がいいとか、これはもう時代遅れだとか色々言ってるケースを見ますが、僕らはそもそも実務未経験で、実際の開発現場ですら知らない訳ですよ。
それなのに言語にこだわる理由もこだわれる理由も正直ないと思っていて、
しかもJava、PHPを今独学で勉強していますが、結構似てます。
なのであまりこだわらなくても恐らくどれかの言語の基礎がしっかり出来ているのであれば
実際のエンジニアと言われる方はそこまで苦労せずに新しい言語を取得出来てしまうんじゃないかなって感じました。
繋がる部分も多くて、JavaをやることでRubyを理解したりとかそういうことがよく起きるので、まだ就職していないのであればそんなに勉強する言語自体にはこだわらず、逆に柔軟に勉強をすることで見えてくるものがあると考えています。

その中で面白いと思ったものを勤めながらでも独学すればいいんじゃないかなって笑
自分が好きだなっていう風に感じる言語を勉強すればいいよ。って友人もよく言います。

なんでもとりあえずやってみようの方が純粋にやってて面白いです。

DMMWEBCAMPに向いていない人

やる気があまりない
人のせいにする
自分の実力を客観的に判断出来ない
わかったふりをする

どれかに当てはまる方には本当におすすめしません。
学習もサポートはしてくれますが、基本は自分1人でやっていきますので、わかったふりをしたりやる気があまり出ない人はどんどんと置いてかれます。
メンタルや性格の矯正はさすがにしてくれません笑

就活時もメンターがサポートしてくれるのはあくまで書類通過までで、
面接合否は全部自分に対する評価です。
落ちたり就職が決まらないのをメンターのせいにして自分を省みれない人には
本当におすすめできません。
自分の実力がないから書類に通らないし、自分の人間性なり考え方なり伝え方に問題があるから面接に落ちる。っていう風に自分を変えていこうとしない人は多分長い期間就職できないと思います。

まとめ

物凄く長くなってしまいました。笑
DMMに入ったことは全然後悔していなくて得たり良かったことが本当にたくさんありました。

お互いに研鑽したり応援し合ったり、卒業後も一緒に何か作ろうと言ってくれる友人を得れたこと、
深いレベルで自己分析をする手伝いや学習、就職の支援全般をメンターさんにしてもらえたこと、
プログラミングに関して独学で勉強する習慣がいつの間にかついたこと、
プログラミングを好きなままでカリキュラムを終えさせてくれたこと、
プログラミングが好きになれたこと(毎日やってます)、
何より就職できたことです。

現在検討されている方の何かヒントになれれば嬉しいです。
こんな微妙スペックの僕でしたが努力して転職できました!笑

本当にありがとうございました。
就職して今まで以上に頑張ります!

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

Rubyでキーとバリューを書く

3種類の参考を元に、keyとvalueの種類について以下にまとめていく。

1. hash1 = {"title" => "天気の子"}

2. hash2 = {:title => "天気の子"}

3. hash3 = {title: => "天気の子"}

hash1は文字列をキーに使っている。

hash2とhash3はシンボルをキーに使っている。

hash2とhash3は同じ内容であるが、hash3が最もシンプルな書き方になる。

ハッシュのキーとして使う場合は、シンボルの方が実行の速度が早いためシンボルの使用が推奨されています。

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

【チーム開発にて】他メンバーのブランチに移動して、rails sした時のエラー【Rails】

参考対象者

  • チーム開発初心者
  • Railsでのアプリ開発にて、データベース関連のエラーで困ってる方
  • Git初心者

環境

$ rails -v
Rails 6.0.3.1
$ ruby -v
ruby 2.7.0p0 (2019-12-25 revision 647ee6f091) [x86_64-darwin19]
$ git --version
git version 2.27.0
$ mysql --version
mysql  Ver 14.14 Distrib 5.7.29, for osx10.15 (x86_64) using  EditLine wrapper

状況

  • 他メンバーのブランチに移動し、レビューするために挙動確認したかったが、サーバーを立ち上げるときにエラーが出た。
  • どうやら、データベース関連のエラーらしい。

ActiveRecord::PendingMigrationError

https://qiita.com/KONTA2019/items/0444ae3b8c8936a56ee0

上記を参考に、解決する。
ちなみに私は、

$ rails db:migrate

で解決。

でも、その後次のようなエラーが。。。

Multiple migrations have the name ~~~.

結論から言うと、~~~には、マイグレーションファイル名が入ります。

私の場合は、

Multiple migrations have the name CreateUsers.

となって、自分のマイグレーションファイルを確認してみると、

$ rails db:migrate:status

 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20200618162841  Create tweetposts
   up     20200620004226  Change tweetposts to tweets
  down    20200621075518  Create posts
  down    20200623102444  Change posts to chats
  down    20200627042358  Create users
   up     20200627080839  Create users
   up     20200627083356  Add column to users
  down    20200627220915  Change datatype content of chats
   up     20200703201452  ********** NO FILE **********
  down    20200710035709  Add user id to tweets

ありましたね、CreateUsersファイル。

察しの良い方はお分かりだと思いますが、エラー文の内容から「同名のマイグレーションファイルか存在しているから、どちらを参考にデータベース構築をしたら良いかわからないよ」という状況と推測できます。

なので、
down 20200627042358 Create users
こちらのファイルを削除し、

$ rails db:migrate
$ bundle exec rails s

これにて、サーバーを起動することができました!

ちなみに、、、

マイグレーションファイルの、
up 20200703201452 ********** NO FILE **********

気になりますよね??

これ、ないファイルを参考にデータベースを構築してるという不可思議な現象なので、削除してしまいたいですね。

これの原因は、マイグレーションをdownさせる前に、マイグレーションファイルを削除してしまったため起こるものなのですが、解決方法は下記をどうぞ。

https://qiita.com/beanbeenzou/items/e8886071ab1e1cf7a9c0

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

献立プログラムを作成した

menu.rb
def search(menus)
  puts "検索する材料をひらがな入力してください"
  keyword = gets.chomp
  puts "-------------------------------"
  puts "検索材料:#{keyword}"

  result_array = menus.select { |menu| menu[:title].include?(keyword) || menu[:ingredients].include?(keyword) }
  if !result_array.empty?
    show_results(result_array)
  else
    puts "指定のキーワードでは見つかりませんでした\n\n"
  end
end


def show_results(results)
  puts "\n#{results.count}件見つかりました"
  results.each do |result|
    puts "-------------------------------"
    puts "メニュー: #{result[:title]}"
    puts "材料: #{result[:ingredients]}"
  end
  puts "-------------------------------\n\n"
end




def feeling(menus)
  puts "いまの気分はこれ!\n\n"
  num = rand(0..menus.length - 1)
  results = menus[num]
  puts "     ▼ ▼ ▼     \n\n"


  results.each do |result|
    puts result[1]
  end 
  puts "\n\n"
end


menus = []

  # 和風
  menu = {title:"肉じゃが",ingredients:"じゃがいも、たまねぎ、にんじん、ぶたにく"}
  menus << menu
  menu = {title:"ぶり大根",ingredients:"ぶり、だいこん"}
  menus << menu
  menu = {title:"TKG",ingredients:"たまご、ごはん、しろだし、しょうゆ"}
  menus << menu
  menu = {title:"あさりうどん",ingredients:"うどん、ねぎ、あさり"}
  menus << menu
  menu = {title:"あさりとキャベツの酒蒸し",ingredients:"あさり、ねぎ、きゃべつ"}
  menus << menu
  menu = {title:"豚肉のしょうが焼き",ingredients:"しょうが、ぶたにく、たまねぎ"}
  menus << menu
  menu = {title:"さばのアラ汁",ingredients:"みそ、しろだし、さばかん、ねぎ"}
  menus << menu
  menu = {title:"釜玉うどん",ingredients:"うどん、たまご、しろだし"}
  menus << menu
  # 洋風
  menu = {title:"カレー",ingredients:"たまねぎ、にんじん、ぶたにく、じゃがいも、かれーるー"}
  menus << menu
  menu = {title:"ハンバーグ",ingredients:"たまご、ひきにく、たまねぎ"}
  menus << menu
  menu = {title:"ポトフ",ingredients:"たまねぎ、にんじん、じゃがいも、ぶろっくべーこん、こんそめ"}
  menus << menu
  menu = {title:"ジャーマンポテト",ingredients:"じゃがいも、べーこん、にんにく"}
  menus << menu
  menu = {title:"オムライス",ingredients:"たまご、とりにく、とまと、たまねぎ"}
  menus << menu
  menu = {title:"グラタン",ingredients:"ばたー、こむぎこ、たまねぎ、まかろに、とりに、ちーず、ぎゅうにゅう"}
  menus << menu
  # 中華
  menu = {title:"スーラータンメン",ingredients:"たまご、にら、らーめん"}
  menus << menu
  menu = {title:"チャーハン",ingredients:"ぶたにく、ごはん、たまご、ねぎ"}
  menus << menu
  menu = {title:"回鍋肉",ingredients:"ぶたにく、きゃべつ、ぴーまん、こちゅじゃん、てんめんじゃん"}
  menus << menu
  menu = {title:"スープチャーハン",ingredients:"ぶたにく、たまご、ごはん、ねぎ、とりがら"}
  menus << menu
  menu = {title:"マーボー豆腐",ingredients:"とうふ、ごはん、ねぎ、ごまあぶら、まーぼーのもと"}
  menus << menu






bar = "-------------------------------"


while true do
  puts bar
  puts "\nあなたの「何作って食べよう……」を解決!!"
  puts "メニューを選択してください。\n\n"
  puts "0:材料からメニュー検索"
  puts "1:気分でメニュー検索"
  puts "2:登録一覧を表示"
  puts "3:終了します。\n\n"
  puts bar

  case gets.to_i
  when 0
    puts "0:材料からメニュー検索"
    search(menus)
  when 1
    puts "1:気分でメニュー検索"
    feeling(menus)
  when 2
    puts "2:登録一覧を表示"
    puts menus
  when 3
    puts "3:終了します。"
    exit

  else
    puts"無効な入力です。"
    puts bar
  end
end

what

・献立支援アプリ

why

・ポートフォリオの一つとして作成。
・調理の際に何を作ろうか長考することが多かったため

issue

・1を選択しランダム出力する際、和・洋・中のいずれかを選択させ、その中から出力する。
・レシピの作成手順も記載する
・レシピ一覧のコードをリファクタしたい

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

Ruby 例外処理

背景

Rubyの例外処理を描いたときに状況に応じた使い分けが必要だったので、備忘録としてまとめました。

begin rescue

  • エラーが発生しそうな処理に対して書く
  • エラーが発生したときにエラーログなどを書ける
begin
  1 / 0 // 例外を発生させる
rescue
  puts "エラーが発生しました"  
end  

raise

  • エラーを意図的に発生させる
  • 1 / 0をraiseに置き換えても成立する
begin
  raise
rescue
  puts "エラーが発生しました"  
end 

retry

  • エラーが発生しても再度beginの処理に戻る
  • 例の場合は無限ループしてしまうので、何度か実行してエラーであれば処理を抜けるような処理を書く
begin
  raise
rescue 
  retry // beginの処理を再度実行
end  

ensure

  • 正常に処理が終わってもエラーでも必ず実行される処理
begin
  // 正常処理
rescue => e
  // 例外処理
ensure
  // とりあえず実行される
end
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails]seedファイルへの記載方法色々

※自分への備忘として残しておくものです。
基本フォームでのデータ作成を理解してればなんとなくイメージつくものが多いと思います。

環境

Ruby 2.6.5
Rails 6.0.3

書き方あれこれ

①一個だけ作成(基本)

seed.rb
User.create!(
   email: "user@user.com",
   name: "user1",
   passowrd: "password"
)

レコードを作りたいモデルにcreate!アクション。
各カラムの値を与えてあげる。

②複数個デモデータを作成

seed.rb
 users = User.create!([
  {nickname: "guest", email: "guest@guest.com", password: "guest1234"},
  {nickname: "guest2", email: "guest2@guest.com", password: "guest5678"}, 
])

配列を用意。配列の各要素にハッシュの形でレコードデータを渡してあげることで作成が可能。

③複数個デモデータを作成(繰り返し処理)

seed.rb
20.times do |n|
  User.create!(
  name: "guest#{n+1}",
  email: "guest#{n+1}@guest.com",
  password: "guest#{n+1}0000",
 )
end

timesメソッドを使用してcreate!アクションを複数回実行。
uniquenessがあるカラムが重複しない様に値にnを含むことで各レコードに違う値を実装。

④配列を組み合わせる

seed.rb
stations = ["東京",
  "有楽町",
  "新橋",
  "浜松町",
  "田町",
  "高輪ゲートウェイ",
  "品川",
  "大崎" ,
  "五反田",
  "目黒",
  "恵比寿",
  "渋谷",
  "原宿",
  "代々木",
  "新宿",
  "新大久保",
  "高田馬場",
  "目白",
  "池袋",
  "大塚",
  "巣鴨",
  "駒込",
  "田端",
  "西日暮里",
  "日暮里",
  "鶯谷" ,
  "上野",
  "御徒町",
  "秋葉原",
  "神田"]

stations.length.times do |i|
  Station.create!(
    name: stations[i]
  )
end

配列を用意した後、その数だけ繰り返し処理を実行し、カラムには配列の値を与える。
(eachでも行けるはずだと思うんですがなぜかうまく行かずtimesで処理した)
配列を使用したのは別のカラムにもこの値を使い回したかったから。
(具体的に言うとこの後飲食店のデモデータを作る際に、店名に駅名を含めたかったのでこのやり方にした)

⑤attributes nestを含むレコードの作成

seed.rb
Item.create!(
  name: "ソファ",
  produce: "新品",
  price: 8000,
  images_attributes: [{image: File.open('./app/assets/images/index_item01.png',)}]
  )

ItemテーブルがImageテーブルをネストしていて、has_manyな関係の場合。
images_attributesは複数のレコードデータを持つので、配列を作ってその中にハッシュでImageテーブルのレコードデータを与えてあげる。

⑥今までの色々組み合わせ

seed.rb
10.times do |i|
  Shop.create!(
    name: "鮮魚商店 #{stations[i]}店",
    address: addresses[i],
    capacity: 40,
    mainimage: File.open('./app/assets/images/shops/shop1_1.jpg'),
    maincontent: "産地直送の海の幸を用意してお待ちしています!",
    likepoints: 0,
    station_ids: [i+1,i+2],
    introduces_attributes: [
      {subcontent: "落ち着いた店内で食事が楽しめます。",
        number: 1,
        subimage: File.open('./app/assets/images/shops/shop1_2.jpg')},
      {subcontent:"おすすめは海鮮盛り合わせです!",
        number: 2,
        subimage: File.open('./app/assets/images/shops/shop1_3.jpg')},
      {subcontent: "話し好きの店員があなたをお待ちしています!",
        number: 3,
        subimage: File.open('./app/assets/images/shops/shop1_4.jpg')}
    ]
  )
end

先ほどのstationsと言う配列を利用して、shopデータを複数作成している。
shopテーブルはintroducesテーブルをネストしていて、introducesテーブルに複数のレコードを渡したいのでハッシュの形で配列を渡している。
意外とそんなに複雑ではない。
(原因不明ですが最初これでうまく行かず、インデント整えたりしてたらなんか通りました。何だったんだ。。。)

まとめ

フォームでデータがどう送られているのかを勉強した時にだいぶ理解したのでseedファイルへの記載はそれほど悩みはしませんでしたが。
色々読みあさってる中で公式かなんかの文章で出てきた「配列はハッシュでとりだし、ハッシュは配列で取り出すことでデータを保存する」と言う言葉がすごくわかりやすかったなーと言う印象です(うろ覚え)

備忘として残しておきます。

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

NoMethodError in の undefined method `+' for nil:NilClass エラーが起こった話

ポートフォリオ作成中。またまたエラーが出ました。

エラー内容

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

NoMethodError in BalanceConfirmController#show_year

undefined method + for nil:NilClass

このエラーは、
NilClassnilオブジェクトに対して+のメソッドは定義されていないよ」
という意味みたいです。

該当コードはこちら

balance_confirm_controller.rb
    @balance_differences = [nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil,nil]
    0.upto(11) do |i|
            if @income_value_totals[i].present?
        @balance_differences[i] = @income_value_totals[i] - (@fixedcost_value_totals[i] + @variablecost_value_totals[i])
            end
    end

解決策

@balance_differences[i] = @income_value_totals[i] - (@fixedcost_value_totals[i] + @variablecost_value_totals[i])

@balance_differences[i] = @income_value_totals[i] - (@fixedcost_value_totals[i] ||+ @variablecost_value_totals[i])

+の前に||を入れることで解決!

||という記述は「nilガード」というそうです。
これは、
「代入先の変数がnilの時だけ、値を代入する」
という記述みたいです。

読んでいただきありがとうございます!


参考にしたサイトはこちら?
https://www.ryotaku.com/entry/2019/02/18/231458

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

[Ruby] 別ユーザで外部コマンドを実行する

前提

  • Ruby 2.7
  • Ubuntu 20.04
  • あんまり深く考えてない

以下のtest.sh というファイルを、superuser な Ruby から特定のユーザで起動したい。

#!/bin/bash
echo "test.sh ok"
id

実装

gid = 1001
uid = 1001

pid = fork do
  exit 127 unless Process::GID.change_privilege(gid) == gid
  exit 127 unless Process::UID.change_privilege(uid) == uid
  begin
    exec './test.sh'
  rescue  # Errno::ENOENT
    exit 127
  end
  exit 127  # なんかそれ以外のケース
end

res = Process.waitpid(pid)
puts 'complete'
p $?

実行結果

$ sudo ruby a.rb 
test.sh ok
uid=1001(****) gid=1001(****) groups=1001(****),0(root)
complete
#<Process::Status: pid 75202 exit 0>

注意点

  • spawnにはユーザを変更するような機能は無いので、forkしてからexecする。
  • 全部成功する前提であればこれは楽なんだけれども。失敗するケースのエラーハンドリングを考えたい。
    • forkしており別プロセスなので、変数は共有出来ないはず。IO.pipeも馬鹿っぽい
    • abort すると、exec成功時のアプリケーションで失敗したケースと見分けがつかない。
    • そこで、終了コード127(つまりENOENT)で失敗を伝える。exec成功時のアプリケーションで127を返されると見分けつかないが、それは無いとしておく。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

「Rails db:migrate」ができなくて苦戦した話。

ある時、rails db:migrateしようとしたら、
StandardError: An error has occurred, all later migrations canceled:
エラーが起こってしまいました。

まずrake db:resetしてから
もう一度rails db:migrateして解決を試みるも、

エラーが発生してrake db:resetすらできません。

ここでマイグレーションファイルの記載ミスがないか確認。

しかし、何度確認してもスペルミスはなし。

結構探しました。そしてある時、

「あ、全角はいってる。」

はい、解決です。

rails db:migrateできないときって、スペルミスとか、全角入ってた
とかいうことが僕は多いです。

単純なことなのですが、今回は原因究明にまあまあ時間かかりました。

僕を含め初心者は特に、マイグレーションファイルに手こずることが多いと思います。
rails始めたての最初のうちは
間違えてマイグレーションファイル消しちゃったり、rollbackしないで修正しちゃったり...
怖いですね。

「マイグレーションファイル取り扱いには気をつけないといけない」
ということを再認識しました。

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

deviseでのログイン画面実装

deviseでのログイン画面実装

1.Gemfileに「gem 'devise'」を追加

gem 'devise'

2.追加したdeviseを、アプリケーションに読み込ませる。
※gemを追加した時に忘れてはいけない

$ bundle install

3.deviseの初期設定

$ rails g devise:install

これでdeviseを使う準備は完了。

4.Userモデルとマイグレーションファイルを作成
rails g devise モデル名の記述は、devise独自のルールです。

$ rails g devise User

5.データベースへ反映
新しくUserテーブルをデータベースへ反映させます。

$ rails db:migrate

6.deivse用のログイン画面を作成

$ rails g devise:views

7.rails s -b 0.0.0.0でサーバー起動させ、画面確認

image.png

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

現場で学んだRailsリファクタリングの話

現場で学んだ話

Railsの開発で意識している一般的なアーキテクチャの話です。

fatコントローラー、fatモデルにならないように意識していることを備忘録メモ。乱文のため、適宜修正していきます。

コントローラーはシンプルに!!

コントローラーに追わせる責務は、究極的にこう考えています。

「インスタンスを作り、それに対してメソッドを実行して、レスポンスを返す」

これだけ。

こう言うのは最悪。

example.contoroller.rb
こんなアクションとかありえないです

def index
  @most_funded_projects = []
    most_funded_projects = Project.most_funded.includes(:main_image)
    most_funded_projects.each do |most_funded_project|
      break if @most_funded_projects.count >= 3
      if @site_project_descriptions[most_funded_project.id].present?
        @most_funded_projects << most_funded_project
      end
    end
    if @most_funded_projects.count < 4
      current_site.published_projects.order(updated_at: :desc).each do |project|
        break if @most_funded_projects.count >= 3
        @most_funded_projects << project
    end
  end 
end


コントローラーにゴリゴリのビジネスロジックが書かれていますね。こんなコントローラーをかつて書いてたりして、注意されました。scafoldとかでコントローラーを作ると以下のようなシンプルな形のコントローラーができると思いますが、基本的にはこんな感じに沿って作るのが理想です。

example.rb
def index
  @friends = Friend.all

  respond_to do |format|
    format.html # index.html.erb
    format.json { render json: @friends }
  end
end

要は究極的には、以下のような形が基本

@hoge = Hoge.new
@hoge.hoge
レスポンスを返す

コントローラーが膨らんだ場合は、まずはモデルへ!!

コントローラーでは、そのモデルに紐づくインスタンスを作り、それに対してメソッドを実行するだけのイメージが重要でした。なので、一旦、あらゆるビジネスロジックはモデルに寄せることを考るといいです。
ただ、何でもかんでも寄せるのは別の問題が起きるので、モデルに寄せるのは、主に永続化に関わるものや、単一モデルの操作で完結するビジネスロジックを優先的に寄せるイメージです。

モデルに実装するパターンは以下が一般的。

  • モデルに紐付いたテーブルのレコード取得(ActiveRecordの操作)
  • モデルに紐付いたテーブルをベースとした関連テーブルを含めたデータ取得
  • モデルに紐付いたテーブルのデータ更新
  • その他、単一モデルに紐づくビジネスロジック

単一テーブルの単純な更新など、シンプルな処理が主に該当し、それ以外は単一モデルで完結するビジネスロジックなどかなーと思います。

サービスクラスの活用

複数のモデル操作やファイル操作などの処理を、アトミックなビジネスロジックのひとまとめの単位としてサービス層として切り出します。

基本的には、以下のような形で、ActiveRecordにひもづかない(テーブルと1対1で紐づかない)通常のクラスを作ります。クラスを作り、既存のモデルから複数モデルに跨る複雑なロジックを分離する感じです。使い方は単純で、クラスのインスタンスを作り、それに対して生やしたメソッドを実行するだけです。

exmple.rb
class ExampleService
  def initialize
    ....
  end

  def example
    ....
  end
end

consernやnamespaceを切ってmodelsディレクトリ配下にクラスを作る

紹介した方法でも、モデル、サービスクラスがfatになった場合は、modelsディレクトリ配下に、namespaceを切って、テーブルと1対1になっていない単なるクラスを作り、そこにfatになったモデルやサービスクラス内の汎用的に使えそうなメソッドをこちらに移管させることで、モデル、サービスクラスがfatになるのを防ぐテクニックもあります。また、consernを使って、冗長なものを一つにまとめたりします。例えば、models/{table name}/{use case}.rbを作成して、処理を切り出すイメージです。見通しをよくするためにも、 インスタンス変数の定義はControllerにて行うようにします。

Controller/Service/Modelの分担まとめ

  • ControllerとService層は基本的に手続き処理※のみを行う。※手続き処理とは、関数の呼び出しや、CRUDにまつわる処理を行うこと
  • ControllerとService層は返って来たデータを使うだけでロジックやデータの加工には関知しない
  • Service層は、Controller内の処理が複数Modelにまたがる際に、複数のモデルに生えているメソッドをうまく活用して、サービスクラスにメソッドを作り、主にインスタンスに対して使用する。例えば、複数のモデルに跨る処理などでは、サービスクラス内で、元々、跨る想定の各モデルに生えているインスタンスメソッドを活用し、サービスクラス内でメソッドを生やし、コントローラーでは、サービスクラスのインスタンスを作って、それをレシーバーにしてメソッドを実行するような形をとる。
  • サービスクラスもできる限りfatにしたくないので、ビジネスロジックが嵩ばれば、consernやnamespaceを切ってさらに別のクラスをmodelsディレクトリ配下作るイメージ。models/{table name}/{use case}.rbを作成して、処理を切り出す。見通しをよくするためにも、 インスタンス変数の定義はControllerにて行うようにする。
  • ロジックやデータの加工は必ずModelで行うようにする
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Strong Parametersとは?

Strong Parametersとは

Strong ParametersはRails4系から追加されたセキュリティを向上させるための仕組みです。
指定した値以外は受け取らないようにして、攻撃者による意図しないコードの実行を防止するセキュリティ対策。

フォームからデータを送信するときは、「マスアサインメント脆弱性」というセキュリティ上の問題があります。
簡単に伝えると、データ送信時に不正なリクエストによって、予期しない値が変更されてしまう脆弱性です。
Railsでは、この脆弱性を防ぐ「Strong Parameters」の仕組みが用意されています。

こんな感じです。
Strong parametersは必ずprivateより下に記述します。

app/controller/user_controller.rb
class UsersController < ApplicationController
  def create
    user = User.new(user_params)
  end

  private

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

簡単に言うと、userに関する値(パラメーター)が送信されても「name」「email」しか許可しませんよということです。

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

【Rails】テストに使うダミーデータを用意する【Faker】

はじめに

RSpecなどでテストする際に、FactoryBotなどであらかじめデータを用意することがありますが、その際にランダムデータをいい感じに作ってくれるFakerの使い方について書いていきます。

準備

gemをインストールするだけです。

Gemfile
group :development, :test do
  # (略)
  gem 'faker'
end
ターミナル
$ bundle install

使い方

rbファイル内でFaker::[ジャンル].[タイトルなど]と入力すればOKです。
どんなものが用意されているかは公式リファレンスから確認してみてください。

READMEのとこにサンプルが並んでるので、使いたいものをクリックしてリンク先の表示どおりに使うだけです。
278199070c4abe565b7f1ecb13ca831c.png

使ってみないとわかりにくいので実際に使ってみます。
今回はMoviesを使ってみたいと思います。READMEのMoviesをクリックすると下のように同一ページのMovies欄に飛びます。
25cbc0c934fbfedd13009afd6e7fb9ff.png
今回はFaker::movieを使います。
Faker::movieをクリックして詳細ページに飛びます。
9c862c81313fa7018403ab0fb7212a8e.png
このページに書かれているとおりに記述すれば、ランダムにデータを取得してくれます。
試しにFaker::Movie.titleで映画のタイトルを取得してみましょう。

コンソールで確かめます。

ターミナル
$ rails c

95008ab8d5f596fb880f99867f2cab20.png

こんな感じで取得してくれます。

ポケモンやスターウォーズなんかのデータもあるので面白いです。
3b3af87aaeeec64d399f9f9819055435.png
b03d65bc4ae23c1a32f8c04b8bf6266e.png

FacrotyBotでの使い方

FactoryBotを使う時は下のように書けばOKです。

book.rb
FactoryBot.define do

  factory :book do
    title     { Faker::Book.title }
    author    { Faker::Book.author }
    publisher { Faker::Book.publisher }
  end

end

同様にseedファイルなんかでも使えば初期データをランダムにいろいろ作成できたりします。

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

RubyのHashのメモ

リファレンス
rubyのhashがわからなかったときの自分用のメモです。
間違え等あったらコメントしてくださると幸いです。

環境

ruby 2.7.1

定義

下記すべてで定義できる

訂正コメント下さりありがとうございます。」

#文字列 と =>
hash1={"first"=>"いち"}

#シンボル と =>
hash2={:first=>"いち"}

#キーがシンボルの場合の省略した書き方
#(:"first"→:first というシンボルができる)
hash3={"first":"いち"}

キーがシンボルの場合の省略した書き方
hash4={first:"いち"}

当然これはできない

#シンボル と :
hash5={:first:"いち"}
=>syntax error

中身は異なっている

  • hash1 → 文字列がキー
  • hash2,3,4 → シンボルがキー
#hash1
{"first"=>"いち"}

#hash2,3,4
 {:first=>"いち"}

呼び出すときは

hash1["first"]
hash2[:first] #hash2,3,4共通

付録

気をつけないと間違えそう

hoge="second"
hash5={hoge:2,hoge=>2}
hash5
=> {:hoge=>2, "second"=>2}

こんなこともできちゃう

hash={"first"=>1,:first=>"いち"}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】マイグレーションファイルを削除する

参考対象者

  • マイグレーションファイルの操作の仕方を知りたい方

環境

$ rails -v
Rails 6.0.3.1
$ ruby -v
ruby 2.7.0p0 (2019-12-25 revision 647ee6f091) [x86_64-darwin19]
$ mysql --version
mysql  Ver 14.14 Distrib 5.7.29, for osx10.15 (x86_64) using  EditLine wrapper

マイグレーションファイルを削除する

Add column to usersというファイルを削除したかったとします

  • 削除したいファイルのマイグレーションIDを確認する
$ rails db:migrate:status

 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20200618162841  Create tweetposts
   up     20200620004226  Change tweetposts to tweets
  down    20200621075518  Create posts
  down    20200623102444  Change posts to chats
  down    20200627042358  Create users
   up     20200627080839  Create users
   up     20200627083356  Add column to users
  down    20200627220915  Change datatype content of chats
  down    20200710035709  Add user id to tweets
  • ID指定して、downさせる
$ rails db:migrate:down VERSION=Add column to users
  • downさせたファイルをゴミ箱へ
$ rm db/migrate/20200703201452_add_column_to_users.rb

downさせる前に、マイグレーションファイルを削除してしまったとき

********** NO FILE **********というファイルで、up状態のファイルを削除したい

  • 削除したいファイルのマイグレーションIDを確認する
$ rails db:migrate:status

 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20200618162841  Create tweetposts
   up     20200620004226  Change tweetposts to tweets
  down    20200621075518  Create posts
  down    20200623102444  Change posts to chats
  down    20200627042358  Create users
   up     20200627080839  Create users
   up     20200627083356  Add column to users
  down    20200627220915  Change datatype content of chats
   up     20200703201452  ********** NO FILE **********
  down    20200710035709  Add user id to tweets
  • 削除したマイグレーションファイル名と同名のファイルを作成する
$ touch db/migrate/20200703201452_add_column_to_users.rb
20200703201452_add_column_to_users.rb
class AddColumnToUsers < ActiveRecord::Migration
  def change
  end
end
  • downさせて、作成したマイグレーションファイルを削除する
$ rails db:migrate:down VERSION=20200703201452
$ rm db/migrate/20200703201452_add_column_to_users.rb
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails初心者がエラーを解決して学んだこと

こんにちは、Shotaです!

現在、Railsでのポートフォリオを作成するうえで、エラーに躓きまくっています。

そして色々なエラーを解決して、改めて学んだことが3つあります。

1、エラー文の意味を知る
2、質問するときは、ただ単にどうすればよいかと聞かない
3、いったんコードから離れることも重要

では、初心者なりに1つずつさらっと解説していきます。

1つ目、エラー文の意味を知る
エラー文の意味が分かれば本当に変わります。
初心者で英語ができない僕は、見たことのない英語表記のエラー文を見たら、
「なんだこれ!難しい。。。」
と感じてしまいます。しかし、英語の意味やエラー文をググることで、解決にグッと近づきます。
ポイントは、「きちんとエラーの意味を知る」ということです。
初心者によくありがちな
「エラー文を打って、似たエラーの解決策がヒットしたとき、その意味を理解しないまま真似して解決する」
というのはあまり良くないことが分かりました。

2つ目、質問するときは、ただ「どうすればよいか」と聞かない
私を含め、初心者の方は特にこういった質問をしてしまうことがあります。
しかし、質問をする際は、「エラー文と、どうすればよいか」だけではなく、
「現状➜質問➜試したこと」を説明した方が良いです。
そうすることで、自分が何を解決してほしいをきちんと伝わりますし、
回答する側としても気持ちよく答えることができるはずです。

3つ目は、いったんコードから離れることも重要
一回リフレッシュしたり、寝たりして、次の日また再開したらサクッと解決できた!
なんてことも結構あります。
また、僕みたいな初心者のうちは、
「なんかよくわかんないけど、とりあえず動いたからまぁよしとしよう」
みたいな考えも全然アリだと思います!
完璧を求めてがんばったけど、意味わからなすぎて停滞するよりは、マシだと思いますし。

以上が、エラーを解決したうえで、改めて大事だと気付いたことです。

今後もこの3つ

1、エラー文の意味を知る
2、質問するときは、ただ単にどうすればよいかと聞かない
3、いったんコードから離れることも重要

を意識してエラーと戦っていきます!

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

resourcesでルーティングを設定する方法

resourcesでルーティングを設定する

ルーティングは、個別に設定も可能です。
ただし、railsでの基本的な7つのアクションは開発の際によく使われるので、
そのたびに設定するのは効率的とはいえません。
こんなときは、resourcesメソッドを利用すると、ルーティングを1行書くだけで自動設定されます。

Rails.application.routes.draw do
  resources :blogs
end

rails routesコマンドで確認。

$ rails routes

全てのurlが設定されていることを確認。

$ rails routes
                   Prefix Verb   URI Pattern                                                                              Controller#Action
                    blogs GET    /blogs(.:format)                                                                         blogs#index
                          POST   /blogs(.:format)                                                                         blogs#create
                 new_blog GET    /blogs/new(.:format)                                                                     blogs#new
                edit_blog GET    /blogs/:id/edit(.:format)                                                                blogs#edit
                     blog GET    /blogs/:id(.:format)                                                                     blogs#show
                          PATCH  /blogs/:id(.:format)                                                                     blogs#update
                          PUT    /blogs/:id(.:format)                                                                     blogs#update
                          DELETE /blogs/:id(.:format)                                                                     blogs#destroy
       rails_service_blob GET    /rails/active_storage/blobs/:signed_id/*filename(.:format)                               active_storage/blobs#show
rails_blob_representation GET    /rails/active_storage/representations/:signed_blob_id/:variation_key/*filename(.:format) active_storage/representations#show
       rails_disk_service GET    /rails/active_storage/disk/:encoded_key/*filename(.:format)                              active_storage/disk#show
update_rails_disk_service PUT    /rails/active_storage/disk/:encoded_token(.:format)                                      active_storage/disk#update
     rails_direct_uploads POST   /rails/active_storage/direct_uploads(.:format)                                           active_storage/direct_uploads#create

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