20210125のRubyに関する記事は16件です。

rails newするときのoptionなにしたらええんやっけ?となったとき

$ bundle exec rails help
Usage:
  rails new APP_PATH [options]

Options:
      [--skip-namespace], [--no-skip-namespace]              # Skip namespace (affects only isolated applications)
  -r, [--ruby=PATH]                                          # Path to the Ruby binary of your choice
                                                             # Default: /Users/shoutaro/.rbenv/versions/2.7.2/bin/ruby
  -m, [--template=TEMPLATE]                                  # Path to some application template (can be a filesystem path or URL)
  -d, [--database=DATABASE]                                  # Preconfigure for selected database (options: mysql/postgresql/sqlite3/oracle/frontbase/ibm_db/sqlserver/jdbcmysql/jdbcsqlite3/jdbcpostgresql/jdbc)
                                                             # Default: sqlite3
      [--skip-gemfile], [--no-skip-gemfile]                  # Don't create a Gemfile
  -G, [--skip-git], [--no-skip-git]                          # Skip .gitignore file
      [--skip-keeps], [--no-skip-keeps]                      # Skip source control .keep files
  -M, [--skip-action-mailer], [--no-skip-action-mailer]      # Skip Action Mailer files
      [--skip-action-mailbox], [--no-skip-action-mailbox]    # Skip Action Mailbox gem
      [--skip-action-text], [--no-skip-action-text]          # Skip Action Text gem
  -O, [--skip-active-record], [--no-skip-active-record]      # Skip Active Record files
      [--skip-active-storage], [--no-skip-active-storage]    # Skip Active Storage files
  -P, [--skip-puma], [--no-skip-puma]                        # Skip Puma related files
  -C, [--skip-action-cable], [--no-skip-action-cable]        # Skip Action Cable files
  -S, [--skip-sprockets], [--no-skip-sprockets]              # Skip Sprockets files
      [--skip-spring], [--no-skip-spring]                    # Don't install Spring application preloader
      [--skip-listen], [--no-skip-listen]                    # Don't generate configuration that depends on the listen gem
  -J, [--skip-javascript], [--no-skip-javascript]            # Skip JavaScript files
      [--skip-turbolinks], [--no-skip-turbolinks]            # Skip turbolinks gem
  -T, [--skip-test], [--no-skip-test]                        # Skip test files
      [--skip-system-test], [--no-skip-system-test]          # Skip system test files
      [--skip-bootsnap], [--no-skip-bootsnap]                # Skip bootsnap gem
      [--dev], [--no-dev]                                    # Setup the application with Gemfile pointing to your Rails checkout
      [--edge], [--no-edge]                                  # Setup the application with Gemfile pointing to Rails repository
      [--rc=RC]                                              # Path to file containing extra configuration options for rails command
      [--no-rc], [--no-no-rc]                                # Skip loading of extra configuration options from .railsrc file
      [--api], [--no-api]                                    # Preconfigure smaller stack for API only apps
  -B, [--skip-bundle], [--no-skip-bundle]                    # Don't run bundle install
  --webpacker, [--webpack=WEBPACK]                           # Preconfigure Webpack with a particular framework (options: react, vue, angular, elm, stimulus)
      [--skip-webpack-install], [--no-skip-webpack-install]  # Don't run Webpack install

helpを見ましょう

$ bundle exec rails new . -B -d mysql --skip-turbolinks --skip-test --no-skip-webpack-install -J

こんな感じでつくりました。

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

railsのバリデーション

バリデーションとは

正当性を実証(確認)すること。
例えば、新規登録フォームでユーザー名が入力されていなかったら登録できない、
メールアドレスが正規の型でない等を検知する。

新規登録時に名前、メールアドレスが入力されているか検証する

app/models/user.rbファイルに記入する。
validatesメソッドに presence:trueという引数を与えて使うことで検証できます。

app/models/user.rb
class User < ApplicationRecord
  validates :name, presence: true
  validates :email, presence: true
end

長さを検証する

上記のコードにlenghtを追加します。
今回は名前を50文字、メールアドレスを255文字を制限とします。

app/models/user.rb
class User < ApplicationRecord
  validates :name,  presence: true, length: { maximum: 50 }
  validates :email, presence: true, length: { maximum: 255 }
end

フォーマットを検証する

メールアドレスにおなじみのパターンuser@example.comに合っているかを検証します。
無効なメールアドレスにはマッチしない正規表現を組み立てる必要があります。
正規表現とは、一定の規則に従って特定の文字列(群)を集合の要素として表す表記法。
コンピューターで,テキスト処理に使われる。
正規表現がこちら。
/\A[\w+-.]+@[a-z\d-.]+.[a-z]+\z/i

暗号みたいでわかりずらいので表を置いときます。

正規表現 意味
/\A[\w+-.]+@[a-z\d-.]+.[a-z]+\z/i (完全な正規表現)
/ 正規表現の開始を示す
\A 文字列の先頭
[\w+-.]+ 英数字、アンダースコア(_)、プラス(+)、ハイフン(-)、ドット(.)のいずれかを少なくとも1文字以上繰り返す
@ アットマーク
[a-z\d-.]+ 英小文字、数字、ハイフン、ドットのいずれかを少なくとも1文字以上繰り返す
. ドット
[a-z]+ 英小文字を少なくとも1文字以上繰り返す
\z 文字列の末尾
/ 正規表現の終わりを示す
i 大文字小文字を無視するオプション
app/models/user.rb
class User < ApplicationRecord
  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 }
end

一意性を強制

メールアドレスの一意性を強制するために、validatesメソッドの:uniquenessオプションを使います。
uniquenessは登録されているメールアドレスは登録できないことを検証します。

pp/models/user.rb
class User < ApplicationRecord
  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:true
end

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

emailを小文字に変換はemail.downcaseを使います。
今回の場合は、オブジェクトが保存される時点で処理を実行したいので、before_saveというコールバックを使います。
ユーザーがデータベースに保存する前にemail属性を強制的に小文字に変換します

app/models/user.rb
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: true
end
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

モデルとテーブルについて

目次

①モデルとは
②テーブルとは
②モデルの作成方法
④テーブルの作成・編集方法

①モデルとは

MVCモデルの役割の一つ。データベースにアクセスすることができ、あらゆる情報に関する処理をすることができる。モデルがあることによって、データベースにあるテーブルも管理ができるようになる。各テーブルは各モデルに対応しており、モデルとにテーブルを管理できる。

②テーブルとは

データベース内に作成されるデータを表形式で収納するもの。データベースに各用途におうじてテーブルが存在して、必要となればそのテーブルからデータを抽出することができる。

③モデルの作成方法

rails g model person
#モデルの作成、モデルは単数形

④テーブルの作成・編集方法

モデルを作成後、それに対応するテーブルは出来上がる。ただ、まっさらなテーブルの状態で、どのような情報を入れたいかなどの設計がなされていない状態である。それを設計するために、マイグレーションファイルに以下のように記述し、コマンドを実行するとテーブルに反映される

class CreateHumans < ActiveRecord::Migration
 def change
  create_table :humans do |t|
    t.integer :age ←記述
    t.name :name ←記述
    t.timestamps
   end
 end
end

上記のマイグレーションをテーブルに反映させるには以下のコマンドを実行する

rails db:migrate
#マイグレーションをテーブルに反映

もしテーブルの使用を変更したいときは、

rails db:rollback

をすると前の状態に戻るので、マイグレーションファイルを正しい情報に書き換えたのちにrails db:migrate
をするとまたテーブルに反映される。

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

コントローラについて

目次

①コントローラとは
②コントローラの作成方法
③コントローラの削除方法
④コントローラの処理のカテゴリー

①コントローラとは

MVCモデルの役割の一つ。リクエストに対する処理をまとめて用意しておき、ルーティングからリクエストを受け取って処理を行った後、クライアントにレスポンスを返す。またレスポンスに必要となるデータがあれば、他の役割と連携してデータを取得したり受け渡しを行い、レスポンスを完成させる。

②コントローラの作成方法

rails g controller コントローラ名
#コントローラを作成、コントローラは複数形

③コントローラの削除方法

rails d controller コントローラ名
#コントローラを削除、コントローラは複数形

④コントローラの処理のカテゴリー

コントローラはリクエストに対応する処理を記述する場所。リクエストの処理はアクションと呼ばれ、主に7つのアクションがある。

アクション名 何に対応するか
index 一覧表示ページを表示するリクエストに対応
new 新規投稿のページを表示するリクエストに対応
create データの投稿を行うリクエストに対応
show 詳細ページを表示するリクエストに対応
edit 編集ページを表示するリクエストに対応
update データの更新をおこなうリクエストに対応
destory データの削除をおこなうリクエストに対応
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

テーブルの内容を修正する方法

rails db:rollbackの手順

マイグレーションを差し戻して、テーブルの内容を修正する。

必要な手順は以下の3ステップ

ステップ1 ロールバック

ステップ2 migrationファイルの修正

ステップ3 再度migrationを実行

ステップ1

rails db:rollbackコマンド

ターミナル
% rails db:rollback

rails db:rollback
カラム名を誤ってしまった場合などに、モデルに紐づくテーブルを作り直したいときに用いられるターミナルコマンド

例: nameをnemeにしてしまった等

「差し戻す」と表現される

実行すると以下のような表示が出て差し戻される。

ターミナル
== 20200315054113 CreatePosts: reverting ======================================
-- drop_table(:posts)
   -> 0.1939s
== 20200315054113 CreatePosts: reverted (0.2332s) =============================

rails db:migrate:statusコマンドとは?

補足情報として
rails db:migrate:statusというコマンドで状態を確認出来る。

ターミナル
% rails db:migrate:status
  • マイグレーションファイルの状況
    • up = 実行済み
    • down = 適応されていない
ターミナル
database: first_app_development

 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20190820071210  Create posts

downの表記がされていれば差し戻されている

ターミナル
database: first_app_development

 Status   Migration ID    Migration Name
--------------------------------------------------
  down    20190820071210  Create posts

ステップ2

migrationファイルの修正

db/migrate/20XXXXXXXXXXXX_create_変更前.rb
class CreatePosts < ActiveRecord::Migration[6.0]
  def change
    create_table :posts do |t|
      t.text :memo
      t.timestamps
    end
  end
end

t.text :memot.text :contentへ変更

db/migrate/20XXXXXXXXXXXX_create_変更後.rb
class CreatePosts < ActiveRecord::Migration[6.0]
  def change
    create_table :posts do |t|
      t.text :content
      t.timestamps
    end
  end
end

カラム名と型とは?

補足情報として、カラム名と型とは何のことなのか解説

カラム名と型
t.text :memo

t.に続くのがカラムの型
その右側にシンボルで記載されるものがカラム名

ステップ3

再度migrationを実行

修正したマイグレーションを実行します。

ターミナル
% rails db:migrate

以上の修正が反映されているか確認して終了です

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

アプリケーションの作成〜立ち上げ

アプリケーション作成の流れ

①アプリケーションを保存するためのディレクトリを作成
②新規のrailsアプリケーションを作成
③データベースを作成
④アプリのケーションの立ち上げ

①アプリケーションを保存するためのディレクトリを作成

ホームディレクトリから新規フォルダで適当な名前のディレクトリを作成する

②新規のrailsアプリケーションを作成

cd ①のディレクトリ
#①のディレクトリに移動する

rails railsのバージョン new Career_up -d mysql
#railsのバージョンを指定して、Career_upを作成

cd Career_up
#Career_upのディレクトリに移動する

pwd
#現在のディレクトリに移動

③データベースを作成

rails db:create
#データベースを作成する

④アプリのケーションの立ち上げ

cd Career_up
#Career_upのディレクトリに移動する

rails s
#Career_upのディレクトリ上記のコマンドを打つ

以上です

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

pramasについて

目次

①paramsとは何か
②値はどのように送られてくるのか?
③どのように取り出すのか
④まとめ

①paramsとは何か

送られてきた値を受け取るためのメソッドのこと

②値はどのように送られてくるのか?

以下のコードはブラウザから入力されたデータを受け取るためのコードです。

  def create
    Peroson.create(human_params)
  end

  def human_params
    params.require(:human).permit(:text).merge(user_id:current_user.id)
  end

投稿作業を行った後、ターミナルを見てみると

 Parameters: {"authenticity_token"=>"MgJJR92h/eFO7aQ+4YMt4y2tY6kPAxD1KaiVccrRxcuK4342o8v7bNpMV0SQgmmIZW8WZA4ik/UwxLVLyT5NSA==", "human"=>{ "text"=>"おはよう"}, "commit"=>"SEND", "id"=>"14"}

といったものが表示されています。
Parametersにハッシュの形でいろいろ格納されてデータが送られてきます。

どのように受け取るのか

②の"human"=>{ "text"=>"おはよう"}, "commit"=>"SEND", "id"=>"14"}の「おはよう」を取り出すときは

human(params[:text])

というように記述するとParametersのハッシュから「おはよう」を取り出すことができる。

④まとめ

クライアントサイドから送られてきた値はParametersというハッシュに格納されたデータが送られてくる。その送られてきたデータをハッシュから取り出してデータを受け取るメソッドがparamsです。

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

Model.human_attribute_name(:カラム名)について(Rails)

経緯

普段viewでよく見かけるタイトルについて自分の学習用のメモ的な感じです。

Model.human_attribute_name(:カラム名)とは?

ActiveRecord::Base のクラスメソッドで内部的にI18nモジュールを
利用してくれるというものです
参照先は config/locales/ja.ymlです。

ja.yml
---
ja:
  activerecord:
    errors:
      messages:
        record_invalid: 'バリデーションに失敗しました: %{errors}'
        restrict_dependent_destroy:
          has_one: "%{record}が存在しているので削除できません"
          has_many: "%{record}が存在しているので削除できません"
    models:
      task: タスク
    attributes:
      task:
        id: ID
        name: 名称
        description: 詳しい説明
        created_at: 登録日時
        updated_at: 更新日時
      user:
        name: 名前
        email: メールアドレス
        admin: 管理者権限
        password: パスワード
        password_confirmation: パスワード(確認)
        created_at: 登録日時
        updated_at: 更新日時

viewではこんな感じで使います。

 th= Task.human_attribute_name(:name)

この場合ですと「名称」ですね!

最後に

ymlの書き方は特徴があって毎回躓きます。。

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

Docker開発環境

はじめに

現在開発中のアプリにDockerを導入したのでアウトプットします。

環境

Ruby on Rails '6.0.0'
Ruby '2.6.5'
MySQL '5.6.47'

Dockerfile

開発中アプリのルートディレクトリにDockerfileを作成します。

Dockerfile
FROM ruby:2.6.5

RUN apt-get update -qq && \
    apt-get install -y build-essential \
                       libpq-dev \
                       nodejs

RUN mkdir /アプリ名
WORKDIR /アプリ名

ADD ./Gemfile /アプリ名/Gemfile
ADD ./Gemfile.lock /live_search/Gemfile.lock

RUN gem install bundler
RUN bundle install
ADD . /アプリ名

docker-compose.yml

docker-compose.yml
version: '3'
services:
  db:
    image: mysql:5.6.47
    environment:
      MYSQL_ROOT_PASSWORD: 'password'
    ports:
      - "4306:3306"
    volumes:
      - ./db/mysql-data:/var/lib/mysql

  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/アプリ名
    ports:
      - "3000:3000"
    depends_on:
      - db

entrypoint.sh

entrypoint.sh
set -e

rm -f /myapp/tmp/pids/server.pid

exec "$@"

database.yml

database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: password
  host: db
  socket: /tmp/mysql.sock

password: password
host: db
を追加

コンテナを作成

ターミナル
% docker-compose build

DB作成、migrationの実行

ターミナル
% docker-compose run web bundle exec rake db:create
% docker-compose run web bundle exec rake db:migrate

コンテナを起動

ターミナル
% docker-compose up 
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby】レシーバのないメソッド

Rubyにおいてレシーバのないメソッドでは、暗にselfをレシーバとしているらしい。

puts "hello"
# => hello

は下の文と等しい。

self.puts "hello"
# => hello

トップレベルでのselfmainという名前のObjectクラスのインスタンスであり、
ObjectクラスはKernelモジュールをincludeしている。
Kernelモジュールにputsメソッドが定義されているため、トップレベルでputsが使えるということらしい。

参考

【Ruby】メソッドの前のレシーバがない(ように見える)場合の考え方)

プロを目指す人のためのRuby入門
p.300

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

Ruby初心者向けプログラミング問題10選を解いてみた(下)

Ruby初心者向けプログラミング問題10選を解いてみた(上)の続きです
引き続き自分の回答を貼っていきますが、2問解けてないです(へなちょこ)

素晴らしき元サイト様

アウトプットのネタに困ったらこれ!?Ruby初心者向けのプログラミング問題を集めてみた(全10問)

国民の祝日.csv パースプログラム (回答無し)

問題文

問題文(折りたたみ)

その昔、「国民の祝日.csv」という扱いづらいCSVが話題になっていました。
具体的にはこんなCSVファイルです↓

平成28年(2016年),,平成29年(2017年),,平成30年(2018年),
名称,月日,名称,月日,名称,月日
元日,2016/1/1,元日,2017/1/1,元日,2018/1/1
成人の日,2016/1/11,成人の日,2017/1/9,成人の日,2018/1/8
建国記念の日,2016/2/11,建国記念の日,2017/2/11,建国記念の日,2018/2/11
春分の日,2016/3/20,春分の日,2017/3/20,春分の日,2018/3/21
昭和の日,2016/4/29,昭和の日,2017/4/29,昭和の日,2018/4/29
憲法記念日,2016/5/3,憲法記念日,2017/5/3,憲法記念日,2018/5/3
みどりの日,2016/5/4,みどりの日,2017/5/4,みどりの日,2018/5/4
こどもの日,2016/5/5,こどもの日,2017/5/5,こどもの日,2018/5/5
海の日,2016/7/18,海の日,2017/7/17,海の日,2018/7/16
山の日,2016/8/11,山の日,2017/8/11,山の日,2018/8/11
敬老の日,2016/9/19,敬老の日,2017/9/18,敬老の日,2018/9/17
秋分の日,2016/9/22,秋分の日,2017/9/23,秋分の日,2018/9/23
体育の日,2016/10/10,体育の日,2017/10/9,体育の日,2018/10/8
文化の日,2016/11/3,文化の日,2017/11/3,文化の日,2018/11/3
勤労感謝の日,2016/11/23,勤労感謝の日,2017/11/23,勤労感謝の日,2018/11/23
天皇誕生日,2016/12/23,天皇誕生日,2017/12/23,天皇誕生日,2018/12/23
,,,,,
月日は表示するアプリケーションによって形式が異なる場合があります。,,,,,

(中略)
これをいい感じにパースして、以下のようなデータ構造(Rubyのハッシュオブジェクト)に変換しよう、というプログラミング問題です。

{
  2016 => {
    # 実際のキーは文字列ではなくDateオブジェクト
    '2016/01/01' => '元日',
    '2016/01/11' => '成人の日',
    # ...
    '2016/11/23' => '勤労感謝の日',
    '2016/12/23' => '天皇誕生日',
  },
  2017 => {
    '2017/01/01' => '元日',
    '2017/01/09' => '成人の日',
    # ...
    '2017/11/23' => '勤労感謝の日',
    '2017/12/23' => '天皇誕生日',
  },
  2018 => {
    '2018/01/01' => '元日',
    '2018/01/08' => '成人の日',
    # ...
    '2018/11/23' => '勤労感謝の日',
    '2018/12/23' => '天皇誕生日',
  },
}

コード

csvの扱い方が全くわからなかったので解けなかったです…
代わりと言ってはなんですが本家の模範解答のURLを貼っておきます
【短命に終わった】国民の祝日.csvをパースして変換するRubyプログラムとコード解説動画

要点解説

解説動画です
【短命に終わった】国民の祝日.csvをパースして変換するRubyプログラムとコード解説

「Rubyで英語記事に含まれてる英単語を数えて出現数順にソートする」問題

問題文

問題文(折りたたみ)

テキストファイルの中から英熟語や英単語を抜き出してカウントする、という問題です。

入力に使うテキストファイルはこんな感じです。

Interior design and decorating resource Houzz is the overall best Android app of the year, according to Google, which this evening announced the results of the first-ever Google Play Awards at its developer conference, Google I/O. 
(略)

出力結果はこんな感じになります。

単語数(熟語以外):331
英熟語?------------------------------------------------------------------
  2 Google I/O
  2 Google Play Awards
  1 And Google
  1 Best App
  1 Best Game
  1 Best of
  1 Best Standout Startup
  1 Best Use of Google Play Game Services
  1 Best Use of Material Design
  (略)
英単語------------------------------------------------------------------
 22 the
 11 and
 11 of
  8 a
  6 apps
  5 app
  5 best
  5 for
  5 Google
  5 to
  4 that
  4 this
  (略)

コード

*かなりゴチャゴチャしてます
*熟語の判定がガバガバなので本家と出力結果が違います

file_pass = # 任意のパス
words_hash = Hash.new(0)
words = []
idioms_hash = Hash.new(0)
idioms = []
sentence = File.read(file_pass)

# 英熟語を抜き出す
while (idiom = sentence.slice!(/[A-Z][\w]*(?:[\/\s-]+[A-Z][\w]*)+/))
  idioms << idiom
end
idioms.sort.each { |idiom| idioms_hash[idiom] += 1 }

# 記号系を消す
while (s = sentence.slice!("’s"))
  words << s
end
sentence.gsub!(/[,.“”?!;:ー"–]/, " ")

# 単語を抜き出す
words << sentence.split
words.flatten!
wods.sort.each { |word| words_hash[word.downcase] += 1 }

# ソート
i = 0
words_hash = words_hash.sort_by { |_, v| [v, i -= 1] }.reverse.to_h
idioms_hash = idioms_hash.sort_by { |_, v| [v, i -= 1] }.reverse.to_h

# 出力
puts "単語数 : #{words.count + idioms.count}"
puts "英熟語?-----------------------------------------------------------------"
idioms_hash.each { |word, num| puts "#{num} #{word}" }
puts "英単語------------------------------------------------------------------"
words_hash.each { |word, num| puts "#{num} #{word}" }

要点解説

while (idiom = sentence.slice!(/[A-Z][\w]*(?:[\/\s-]+[A-Z][\w]*)+/))
  idioms << idiom
end

(idiom = sentence.slice!(/[A-Z][\w]*(?:[\/\s-]+[A-Z][\w]*)+/))は条件式の中で警告を出さずに変数代入を行う書き方です(カッコを外すと警告が出ます)

i = 0
words_hash = words_hash.sort_by { |_, v| [v, i -= 1] }.reverse.to_h
idioms_hash = idioms_hash.sort_by { |_, v| [v, i -= 1] }.reverse.to_h

るりまのsort_byのページを参考に安定なソート(比較結果が同じ要素は元の順序通りに並ぶソート)を作りました
原理は全くわかりません()

sortの結果は配列になっているのでto_hでハッシュに戻します(執筆中に気づきましたがここは配列のままでも動作するみたいです)

行単位、列単位で合計値を求めるプログラム

問題文

問題文(折りたたみ)

行単位、列単位で合計値を出しましょう、という問題です。

たとえばこういうインプットであれば、

- col1 col2 col3 col4
row1 9 85 92 20
row2 68 25 80 55
row3 43 96 71 73
row4 43 19 20 87
row5 95 66 73 62

こういう結果になります。

- col1 col2 col3 col4 sum
row1 9 85 92 20 206
row2 68 25 80 55 228
row3 43 96 71 73 283
row4 43 19 20 87 169
row5 95 66 73 62 296
sum 258 291 336 297 1182

ただし、出題元のブログでは以下のような仕様になっていました。

  • ランダムに数字を出力する
  • 計算結果は以下のようなフォーマットで出力する
   9|  75|  83|  74| 241
   0|  27|  32|  48| 107
  51|  66|  76|   3| 196
   2|  37|  69|  85| 193
  55|  40|  25|  88| 208
 117| 245| 285| 298| 945

コード

class SumMatrix
  class << self
    def sum
      matrix = generete_matrix
      matrix = sum_matrix(matrix)
      format_matrix(matrix)
    end

    def generete_matrix
      matrix = Array.new(5) { [] }
      5.times { |i| 4.times { matrix[i] << rand(0..99) } }
      matrix
    end

    def sum_matrix(matrix)
      2.times do
        matrix.each { |ary| ary << ary.sum }
        matrix = matrix.transpose
      end
      matrix
    end

    def format_matrix(matrix)
      matrix.each { |elem| elem.map! { |x| x.to_s.rjust(4) } }
      matrix.map! { |elem| elem.join("|") }
      matrix.join("\n")
    end
  end
end

要点解説

class << self

endまでで定義したメソッドがクラスメソッドとして定義されます
ネストは増えるけど便利

      matrix = Array.new(5) { [] }

Array.newは第1引数に要素数、第2引数に中身を指定してデフォルト値(?)を作れます
しかし、出来上がった配列の中身はすべて同じオブジェクトを参照しているのでうまく動きません
なので別々のオブジェクトを与えるためブロックを使っています

      5.times { |i| 4.times { matrix[i] << rand(0..99) } }

同じ列に重複する値が入るのもいいかなと思ってこんな書き方になりました
最初は5.times { |i| matrix[i] = [*(0..99)].sample(4) }としていましたが、中途半端ですしね

      matrix.each { |elem| elem.map! { |x| x.to_s.rjust(4) } }

[1,2], [3, 4][[" 1", " 2"], [" 3", " 4"]]にします
ここはもうちょっといい書き方があった気がします

ガラケー文字入力問題

問題文

問題文(折りたたみ)

英語のガラケーでは「2」キーを2回押すと「b」になり、「3」キーを3回押すと「f」になります。
ただし、この問題では特別ルールとして「0」で文字を確定させます。

たとえば、このプログラムに対して"440330555055506660"を入力すると、"hello"が返ってきます。

コード

*keitai_messageの引数はStringとして取っていますが、これはIntegerとするとメソッド呼び出しのとき8進法の数と解釈されてエラーを起こすことがるからです
*入力を10進法のリテラルにするのも違うかな、と考えこうしました

CHARSES = {
  "1" => %w(. , ! ? \ ),
  "2" => %w(a b c),
  "3" => %w(d e f),
  "4" => %w(g h i),
  "5" => %w(j k l),
  "6" => %w(m n o),
  "7" => %w(p q r s),
  "8" => %w(t u v),
  "9" => %w(w x y z)
}.freeze

def keitai_message(message)
  nums = message.scan(/([123456789]+)0/).flatten
  return if nums.empty?

  nums.map! do |num|
    chars = CHARSES[num.chr]
    index = (num.size % chars.size) - 1
    chars[index]
  end
  nums.join
end

要点解説

nums = message.scan(/([123456789]+)0/).flatten

scanの引数の正規表現にカッコが含まれる場合、カッコの内側にマッチした文字列が配列になって返ります
つまり、"01022"は[["1"], ["22"]]になるわけですね

値札分割問題 (回答無し)

問題文

問題文(折りたたみ)

「値段らしき文字列」を「数字部分」と「単位部分」に分割する、split_priceメソッドを作ってください、というプログラミング問題です。

split_price '110.0万円'     #=> ['110.0', '万円']
split_price '2015円'        #=> ['2015', '円']
split_price '1,123,456円'   #=> ['1,123,456', '円']
split_price '110 - 120万円' #=> ['110 - 120', '万円']
split_price '2015円'    #=> ['2015', '円']
split_price '価格未定'      #=> ['価格未定', '']
split_price nil             #=> ['', '']

コード

全然わかりませんでした…!
なので本家の模範解答のURLを貼っておきます
【Rubyプログラミング問題】値札分割メソッド(split_price)を作成してください:解答編

おわり

以上、「Ruby初心者向けプログラミング問題10選を解いてみた」でした
ここまで読んでいただき本当にありがとうございました!

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

Sinatraでデータを修正、更新する(CRUDのUpdate機能)

Rubyでシステムを構築する際に、Railsだとちょっとボリュームが多いので、そんな場合は軽量フレームワークとしてSinatra(PythonのFlaskみたいなもの)というものがあります。

そして、色々と使い方を解説したページや記事もあるのですが、なぜかデータの修正、更新機能については触れていないことが多く、それではどうやって作るのかをひたすら調べ、ようやく解決したので、備忘録として置いておきます。

まずは、この記事(自分とは別人です)のように登録機能と削除機能を作ってみてください。自分の記事はそこから補足説明となります。

なぜ、データ修正機能の記事が少ないのか?

日本語サイトでもほとんど見つからなかった上に、MVCの観点を鑑みて、全ての機能を懇切丁寧に解説しているものは皆無だったので、英語サイトも隈なく探してみたのですが、そういったサイトは見つかりませんでした(この記事を作ろうとしたきっかけです)。

その理由は明白で、SinatraはRailsとは異なりコントローラの自動生成が簡単にできない上にRailsと記述が若干異なります。その上、公式ページの解説がかなり不親切なので、実際に機能作成を行った事例が少なく、またそのような例もコントローラ部分の解説にとどまっていることが多く、テンプレート周りの記述事例がほとんどありませんでした。

また、普通にサーバ起動してからデータ更新処理を行うと、処理がもたつきます。したがってRackサーバを使って立ち上げる方が能率的なのですが、そもそもSinatraは軽量が売りでありそこまで大掛かりなものは作らないので、利用目的としては矛盾している(実用的価値が少ない)のもありそうです。このへんも踏まえて解説できたらと思います。

ツリー構造

最低限のデータ構造はこうなっています。Rackを使うので、そのためにはconfig.ruが必要となります。config.ruは自動生成されないので、適宜作成します。

- 任意のプロジェクト名
    - db
    - public
    - vendor
    - views
        edit.erb  #編集用
        index.erb #リスト
    config.ru #Ruckの設定ファイル
    app.rb #コントローラ

Rackの設定

Rackサーバの設定はconfig.ruで行います。色々記事がありますが、最低限これだけ必要です。

config.ru
require './app' #コントローラ
run Sinatra::Application

また、Rackサーバの起動コマンドは以下の通りとなります(ローカルサーバ接続)。また、rackのデフォルトポートは9292となるので、sinatraと同じように4567にしています(bashを使ってbundle execを省略した場合、rackコマンドで起動可能)。

# bundle exec rackup -o 0.0.0.0 -p 4567

コントローラのメソッド記述

データの更新作業は以下のプロセスを経由します。

一覧画面から修正ボタンを押下 → 編集画面に遷移 → 編集画面でデータの編集 
→ 編集画面から更新ボタンを押下 →更新処理 → 一覧画面に遷移

このうち、編集画面に遷移するにはgetメソッドを使用し、データの編集を反映させるにはpatchメソッドを使用します。また、今回はレコード名がuserとなっているので、以下のディレクトリで処理が行われます。

app.rb
#編集データを編集画面(edit.erb)に遷移
get '/users/:id/edit' do
    @user = User.find_by_id(params[:id]) #該当IDのデータ取得
    erb :edit #編集画面の呼び出し
end

#編集画面での更新処理を反映
patch '/users/:id' do
    @user = User.find_by_id(params[:id]) #該当IDのデータ情報取得
    @user.name = params[:name] #更新データの代入
    @user.save #データ更新の反映
    redirect to "/" #一覧画面へ
end

参考にしたサイト

コントローラの全容はこのようになっています。csrf対策のために任意のトークンを発行する必要があります。

app.rb
require 'sinatra' 
require 'active_record' #モデルからレコード取得
require 'rack/csrf' #csrf制御に不可欠

use Rack::Session::Cookie, secret: "xxxxxxxxxxxxxxxxxxxxxxxxxxx" #任意のトークン
use Rack::Csrf, rise:true

ActiveRecord::Base.establish_connection(
    adapter: 'sqlite3',
    database: './db/sindb.db'
)

class User < ActiveRecord::Base
    validates :name, presence: true
end

get '/' do
    @title = "User List"
    @users = User.all
    erb:index
end

#新規作成
post '/create' do
    User.create(name: params[:name])
    redirect to('/')
end

get '/users/:id/edit' do
    @user = User.find_by_id(params[:id])
    erb :edit
end

patch '/users/:id' do
    @user = User.find_by_id(params[:id])
    @user.name = params[:name]
    @user.save
    #redirect to 
    redirect to "/"
end

#削除
post '/destroy' do
    User.find(params[:id]).destroy
end

テンプレートの作成

テンプレートの注意点としてはcsrf対策を行わないと403エラーに悩まされることになります(一覧、編集双方で対応が必要です)。

一覧

一覧画面はそこまで難しく考える必要ないですが、actionプロパティの値に変数を埋め込む必要があります。

index.erb
<body>
<h1><%= @title %></h1>
<% @users.each do |user| %>
    <form method="get" action="/users/<%= user.id %>/edit">
    <ul>
        <li data-id="<%= user.id %>" data-token="<%= Rack::Csrf.csrf_token(env) %>">
            <%= Rack::Utils.escape_html(user.name) %>
            <button type="submit" >修正</button>
            <button class="delete">削除</button>
        </li>
    </ul>
    </form>
<% end %>

<form action="/create" method="post">
  <%= Rack::Csrf.csrf_tag(env) %> 
  <input type="text" name="name">
  <input type="submit" value="追加">
</form>
</body>

編集画面

編集画面は以下の通りとなります。大事なポイントはpatch処理が必要なので、メソッドをhiddenで埋め込む必要があります。

edit.erb
<form action="/users/<%= @user.id %>" method="post">
    <%= Rack::Csrf.csrf_tag(env) %> 
    <input id="hidden" type="hidden" name="_method" value="patch">
    <input type="text" name="name" value="<%= @user.name %>">
    <button type="submit">更新</button>
</form>

実際の動き

一覧画面(更新前)

ここではshoujiというデータを編集するので、修正ボタンを押します。

list.jpg

編集処理

shoujiをshinjiに変更します。

edit.jpg

一覧画面(更新後)

データが反映されます。

index2.jpg

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

[個人メモ] Ruby on Rails 時間計測

      p "start : #{Time.now.iso8601(6)}"
      p "end   : #{Time.now.iso8601(6)}"
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails RSpecテストを導入しよう!

経緯

Railsチュートリアルなどではminitestが使われているが
実際の現場ではRSpecを用いたテストを行っているため
今回はRailsにRSpecを導入するまでの手順を乗せていこうと思います。

利用するテスト用ライブラリ

1 RSpec
2 Capybara
3 FactoryBot

RSpecのインストールと初期準備

group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'rspec-rails', '~>3.7'
end

次に以下のgenereteコマンドを実行します。

bundle
bin/rails g rspec:install
=>Running via Spring preloader in process 4359
      create  .rspec
      create  spec
      create  spec/spec_helper.rb
      create  spec/rails_helper.rb

最後にminitest用のtestディレクトリを削除します。

rm -r ./test

Capybaraの初期準備

spec/spec.helper.rbを以下のように編集します。

spec.helper.rb
require 'capybara/rspec'

RSpec.configure do |config|
  config.before(:each, type: :system) do
    driven_by :selenium_chrome_headless
  end

FactoryBotのインストール

テストデータを作成支援してくれるFactoryBotを導入します。
Gemfileに以下のように追記します。

group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'factory_bot_rails', '~> 4.11'
end

導入に向けての手順は以上となります。

最後に

ここまで見てくれてありがとうございました!
具体的な書き方については別の機会で解説していこうかなと思います!

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

Rubyスクリプトにもmainメソッドを定義するといいかも、という話

はじめに

Ruby(Railsではない、単純なRubyスクリプト)では、以下のようにトップレベルで変数を宣言したり、様々な処理を記述したりすることができます。

require 'date'

def play
  puts 'あそぶよー'
end

def study
  puts '勉強するよー'
end

# トップレベルで変数宣言
today = Date.today

# トップレベルで条件分岐とメソッド呼び出し
if today.sunday?
  play
else
  study
end

上のコードの問題点

もちろんこれでもよいと言えばよいのですが、以下のような問題点もあります。

コードリーディング時に下から上に進まないといけない

プログラムとしてのロジックが開始されるのは today = Date.today の行からですが、プログラムの構造上、どうしてもメソッド定義(def playdef study)の方を先に書かざるを得なくなります。

よって、コードリーディング時(またはコードレビュー時)は先にファイルの下に進んでから、メソッドの内容を確認するために上スクロールしなければならなくなります。

Screen Shot 2021-01-24 at 17.28.24.png

できれば実行の起点となるコードはできればスクリプトの先頭に書いて、上から下へ文章っぽく自然に読みたいところです。

可読性の低いコードを書いてもRubocopに指摘されない

コードレビューを自動化するためにRubocopを導入している人も多いと思います。

しかし、トップレベルに書いたロジックはいくらダラダラと何行に渡って書いても、Rubocopに「長すぎる」と怒られることがありません。
その結果、他の人にとって理解しづらいメソッドを書いてしまう恐れがあります。

Screen Shot 2021-01-24 at 17.31.13.png

これがメソッドになっていれば、メソッドの長さをRubocopがチェックしてくれるはずです。

そこでmainメソッドを導入してみる

こういった問題を避けるため、僕は明示的な main メソッドを導入することが多いです。

require 'date'

# トップレベルに書いていたロジックをmainメソッドに移動させる
def main
  today = Date.today
  if today.sunday?
    play
  else
    study
  end
end

def play
  puts 'あそぶよー'
end

def study
  puts '勉強するよー'
end

# トップレベルではmainメソッドの呼び出しを最後に書くだけ
main

mainメソッドを導入するメリット

main メソッドを導入すると、実行の起点となるコードをスクリプトの先頭に書くことができるので、コードを上から下へ順に読み下しやすくなります。
また、 main メソッドが無駄に長くなるとRubocopのチェックで「メソッド長すぎ!」と指摘されるようになります。

なぜmainという名前なのか

main というメソッド名は任意です。 start でも execute でも何でも構いません。
ただ、C言語やJavaなどでは main メソッド( main 関数)から処理を開始するようになっています。

#include <stdio.h>

// C言語
int main(void)
{
    puts("Hello, world!");
    return 0;
}
// Java
public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello, world!");
    }
}

そのため、 main という名前にしておけば他の開発者も「あ、ここから処理が始まるんだな」と推測しやすくなると思い、この名前を付けるようにしています。

まとめ

というわけで、この記事ではRubyスクリプトにmainメソッドを導入する理由やメリットについて書いてみました。

メソッド定義がいくつかあって、1画面に収まらないぐらいの長さのRubyスクリプトを書く場合は、 main メソッドを導入して可読性を上げることを検討してみてください?

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

【M1チップ】Homebrew経由でのRubyインストールに苦戦した

概要

プログラミング勉強真っ只中の私ですが、先日M1チップ搭載のMacbook Proを購入しました。
そこでRuby on Railsの環境構築をしようとしたところ苦戦しましたが、初心者の私でもなんとか出来たのでやったことを残しておきます。
(最初はHomebrewって何?美味しいの?ってレベルでした)

参考にさせていただいた記事
https://qiita.com/aiorange19/items/5ffaefc85f912f60c2fa

動作環境

・Macbook Pro (13-inch, M1, 2020)
・macOS Big Sur (ver11.0.1)

Xcodeをインストールして無い人は予めインストールしておくと幸せになれるかもしれません。
(App StoreからDL出来ます)
容量約12GBなのでめっちゃ時間かかった。

Homebrewのインストール

Homebrewをインストールします。
https://brew.sh/index_ja

公式ドキュメントにも記載があるように、M1チップのMacでは「/opt/homebrew」にインストールすることが推奨されているので、そうしましょう。
自分の場合は何も考えずに公式サイトのコードをコピペして自動的に「/opt/homebrew」にインストールされましたが...。

(訳)
ただし、macOSIntelでは/ usr / local、macOSARMでは/ opt / homebrew、Linuxでは/home/linuxbrew/.linuxbrewにインストールしてください。

予めディレクトリを作っておいて、インストール先を指定した方が良いかもしれません。

% cd /opt
/opt % sudo mkdir homebrew
/opt % curl -L https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C homebrew

brewコマンドが打てない

しかし、このままだとbrewコマンドが打てなかった

% brew -v
zsh: command not found: brew

で、ここで最初の壁にぶち当たりましたが、どうやらPATHというものを通さなければならないらしい。
PATHを通すためには「.zshrc」というファイルにその旨のコードを記述する必要があるっぽいんですけど...

% ls -a
.               Documents           Music               Public              Downloads
..              Dropbox             .DS_Store           Movies              Pictures
Library         Desktop             .adobe              .zsh_history        .cups
.zsh_sessions   .dropbox            .Trash              Creative Cloud Files
.local

そのファイルが無い\(^o^)/

無くて焦りましたが、なかったら作れば良いということで作りました。
作成したら、PATHを通すコードを記述します。

% touch .zshrc
% open ~/.zshrc

# .zshrcに下記を記述
export PATH=/opt/homebrew/bin:$PATH

# またはコマンドラインで下記を実行
% echo 'export PATH=/opt/homebrew/bin:$PATH' >> .zshrc

# .zshrcが編集できたら設定を反映させるために下記を実行
% source .zshrc

brewコマンドが使えるか確認してみる。

% brew -v
Homebrew 2.7.5  # Homebrewのバージョンが表示されればOK

無事PATHを通せました。

rbenvでRubyのインストール

Homebrewがインストール出来たら、Rubyのバージョン管理ができるようにrbenvをインストールします。

% brew install rbenv

これも先ほどと同じようにPATHを通す必要があるので、.zshrcに追記します。

% open ~/.zshrc
# 下記を記述
export PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)"

# またはコマンドラインで下記を実行
% echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> .zshrc
% echo 'eval "$(rbenv init -)"' >> .zshrc

# 設定を反映
% source .zshrc

これでRubyインストールの準備完了です。

Rubyのインストール

# 公開されている(DL可能な)Rubyのバージョン一覧を確認
% rbenv install -l
2.5.8
2.6.6
2.7.2
3.0.0
jruby-9.2.14.0
mruby-2.1.2
rbx-5.0
truffleruby-21.0.0
truffleruby+graalvm-21.0.0

2020年12月25日にRuby 3.0.0が公開されましたが、ここでは2.7.2
をインストールしました。
Ruby 3.0.0はなんか動作が早くなったとか...。
もうちょっと勉強したらアップデートしようと思います。

ということでRubyをインストール

% rbenv install 2.7.2

、、、しようとしましたがなぜか上手くいかない。

いろいろ調べると、openssl関連で上手くいっていないようでした。
とりあえずインストールを試みましたが...

% brew install openssl
Error: /opt/homebrew/opt/openssl@1.1 is not a valid keg

なんやこれ...
このエラー解消に結構時間がかかってしまいました。

結果、/opt/homebrew/Cellarに作られてたopenssl@1.1というフォルダが空だったので、一度削除したらインストール出来ました。
スクリーンショット 2021-01-25 0.48.52.png

インストール出来ましたが、また.zshrcを編集してPATHを通します。

% which openssl
/usr/bin/opensl  # homebrewへPATHを通しましょう

# .zshrcに下記を追記
export PATH="/opt/homebrew/opt/openssl@1.1/bin:$PATH"
export LDFLAGS="-L/opt/homebrew/opt/openssl@1.1/lib"
export CPPFLAGS="-I/opt/homebrew/opt/openssl@1.1/include"
export PKG_CONFIG_PATH="/opt/homebrew/opt/openssl@1.1/lib/pkgconfig"
export RUBY_CONFIGURE_OPTS="--with-openssl-dir=/opt/homebrew/opt/openssl@1.1"

# 設定を反映
% source .zshrc

# 再度opensslの場所を確認
% which openssl
/opt/homebrew/opt/openssl@1.1/bin/openssl

% openssl version
OpenSSL 1.1.1i  8 Dec 2020  # ちゃんとインストール出来てる

# homebrewへリンクを通す
% brew link openssl

これでようやくRubyをインストールできるはず!

% rbenv install 2.7.2
Downloading ruby-2.7.2.tar.bz2...
-> https://cache.ruby-lang.org/pub/ruby/2.7/ruby-2.7.2.tar.bz2
Installing ruby-2.7.2...
ruby-build: using readline from homebrew

BUILD FAILED (macOS 11.0.1 using ruby-build 20210119)

Inspect or clean up the working tree at /var/folders/p8/krxwz5vn6ld7l4_bc2g1xnbr0000gn/T/ruby-build.20210124030531.27274.KLMWnZ
Results logged to /var/folders/p8/krxwz5vn6ld7l4_bc2g1xnbr0000gn/T/ruby-build.20210124030531.27274.log

Last 10 log lines:
checking for off_t... yes
checking char bit... 8
checking size of int... 4
checking size of short... 0
checking size of long... 0
checking size of long long... configure: error: in `/var/folders/p8/krxwz5vn6ld7l4_bc2g1xnbr0000gn/T/ruby-build.20210124030531.27274.KLMWnZ/ruby-2.7.2':
configure: error: cannot compute sizeof (long long)
See `config.log' for more details

You have not agreed to the Xcode license agreements, please run 'sudo xcodebuild -license' from within a Terminal window to review and agree to the Xcode license agreements.

...あれ?
最後を見ると、Xcodeインストールしとけや!って書いてありますね。
はい。自分は最初にインストールしてなかったのでここでまた無駄なダウンロード待ち時間が発生しました。

3度目の正直

Xcodeをインストールし、再度実行。さすがに頼む。

% rbenv install 2.7.2
Downloading ruby-2.7.2.tar.bz2...
-> https://cache.ruby-lang.org/pub/ruby/2.7/ruby-2.7.2.tar.bz2
Installing ruby-2.7.2...
ruby-build: using readline from homebrew
Installed ruby-2.7.2 to /opt/homebrew/opt/rebind/versions/2.7.2

出来たーーー!!

あとは下記の流れに沿って...

% rbenv versions
* system (set by /opt/homebrew/opt/rebind/version)
  2.7.2

% rbenv rehash

% rbenv global 2.7.2

% rbenv versions
  system
* 2.7.2 (set by /opt/homebrew/opt/rebind/version)

% ruby -v
ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [arm64-darwin20]

これでRubyのバージョン切り替えができるようになりました!

Ruby on Railsのインストール

Railsもインストールしておきましょう。

% gem install rails
# バージョン指定しなければ最新版がインストールされる...と思います。

# 最後に一通り更新しておく
% rbenv rehash
% source ~./zshrc

# Railsのバージョン確認
% rails -v
Rails 6.1.1

これでRuby on Railの環境も整いました!

ここまで長かった...

環境構築って大変

プログラミングを挫折する人が多い理由の一つに環境構築が大変、というのをよく目にしますが、よく分かった気がします。笑
しかし、色々根気強く調べながらやっていけばなんとかなる!とも思いました。
先輩エンジニアの方々の情報にはとても感謝です。

まだまだ駆け出しの駆け出しですが、もっと頑張るぞ〜

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