20210106のRubyに関する記事は18件です。

RubyでValueObjectを作るベストなやり方を考えてみた

結論

以下のようにするのがベストではないかと思ってますが、もっと良いやり方あったらコメントください。

module ValueObjectable
  def initialize(args)
    super(args)
    freeze
  end
end

class Location < Struct.new(:country, :city, keyword_init: true)
  include ValueObjectable
end

## 特徴 ##
# 1. OpenStructのように Hash で初期化できる
tokyo = Location.new(country: 'Japan', city: 'Tokyo')
=> #<struct Location country="Japan", city="Tokyo">

# 2. 比較演算ロジックを自前で定義しないでいい
fukuoka = Location.new(country: 'Japan', city: 'Fukuoka')
tokyo == fukuoka
=> false

# 3. 値は不変
tokyo.country = 'U.S'
FrozenError: can't modify frozen Location
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

<投稿一発目> Rubyの勉強はじめました

前置き

初めてQiitaで記事を書いてみます。
自分の性格的に、出来ればQiitaの機能等について詳しく知り尽くした上で投稿を始めたいのですが、そんな調子だと石橋を100回叩いても一歩を踏み出せない気がするので、Rubyの勉強を開始したこのタイミングでとりあえずはじめてみます。
ひとまず学習内容の記録を備忘録的に残していく形で書いてみました。これからどのように記事を書いていったらいいかもまだ曖昧ですが、書き方・内容についても少しずつブラッシュアップしていければと思います。
自己紹介等はおいおい機会があるごとに少しずつ書いていけたらと思います。

学習教材について

「Progate」の「Ruby学習コース」を活用して勉強をはじめます。
今回は「Ruby学習コースⅠ」を終わらせました。

ちょっとした雑記・学習後の所感

プログラミングって学び始めて直ぐの段階から、「面倒なこと・重複作業をしないため、要らないミスをなるべく減らすために、ここはこういうふうにしましょう」ってことを考えさせ・勉強しますよね。
「だってそれがプログラミングの要でしょ?」って言われてしまうかもしれませんが、そんな当たり前なところにものぼくはものすごく魅了を感じます。

以前勤めていた職場でも、空き時間等を使って様々な業務の簡素化・自動化にチャレンジしてました。
- アナログ且つマニュアルな業務をエクセルのフォーミュラ等を駆使して改善してみたり
- 毎回のように新しく作っていたエクセルシートやワードの資料をテンプレート化して都度使用するごとに改善を加えたり
- 人に業務手順とか作業方法聞かれたときに毎回手とり足取り教えるのが嫌になり業務マニュアル作ったり(自分も解決できない疑問点があると納得いくまで人に聞きまくるが、これを他人からされると辛い…)

まあ、要は主な動機として単純作業に毎日多くの時間を費やすのをやめて、なるべく付加価値を付けたアウトプットを出したかったからですね。副次的にはいずれその努力から得られるメリットがチームや部署に普及してみんなで得をしていければいいなとの思いもありました。最初はExcelの独学に時間を費やしていましたが、いろいろ壁にぶち当たるうちに知ったのがプログラミングやRPA。特にある程度のプログラミングの知識とスキルがあれば、異なるソフトウェアを跨いで作業を自動化させたり、なんならお高いERPパッケージを買わなくても、チームや部署内で使える簡易webアプリケーションとかを組めることを知りました。

大学院でビジネスを学んでいたときも、アイデアはピッチするものの技術的なスキルや知識(ソフトウェアもハードウェアも)が圧倒的に不足していたので、机上の空論を並べるだけで抽象的なイメージを具現化することができず、いろいろと悔しい思いもしました。(当時思いついたアイディアはどれもデジタルやIoTがシステムに組み込まれてやっと完成するものばかりだったのです… 結局、課題選定時にはボツにされたアイディアが、後に海外でほとんど瓜二つのビジネスモデルとしてマーケットに出現してまあまあ利益を上げていることを知ったり…これはもうコロンブスのたまごですが。)

プログラミングでなにかを作るって、究極的に利便性や効率化を追求する手段・作業ですよね。自分は今でも普段から、「あーこういうことが出来ればいいのにな。こんなサービスがあれば世の中もっと便利にになるはずなのにね。」なんてことをぼーっと考えてます。そんなひらめきや思いをもっと簡易に実現する手段でもあるプログラミング・ソフトウェアを本腰を入れて学んでみることにしました。
このあたりの話はまたこれから機会あるごとに少しずつ書いてみようと思います。

「Ruby学習コースⅠ」備忘録・気づき

  • なぜプログラミングにおいて変数を使うのか

    • 同じ要素を繰り返し使える
    • 後からの変更に対応しやすくなる
    • なんの要素かわかりやすくなる
  • 変数名のルール

    • 英単語で記載する
    • 2ワード以上は空白部分をアンダーバーで区切る
    • 望ましくない変数名 => ローマ字表記、日本語表記等々…
    • エラー発生する変数名 => 数字始まりの
  • 文字列における変数展開

    • 文字列内に「#{変数名}」で変数展開が可能
    • 注意点:
      • 変数展開はダブルクォーテーションの文字列内でのみ可能
      • シングルクォーテーション文字列では文字列として出力されてしまう
      • 変数になっている数値と文字列は足し算で連結不可のため(エラー発生する)
      • 上記の理由から、変数を文字列に含めたい場合は、変数展開を使用すること
  • その他

    • true or false をダイレクトにコンソールに表示するには, 変数定義後にputsで可能
    • 2者が等しいかの式 「==」
    • 2者が異なるかの式 「!=」
    • 「且つ」の式は 「&&」
    • 「又は」の式は 「||」
    • インデントはTABキーで。パッと見たときの読みやすさを意識すること
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

docker-compose環境でRuby on Jetsの構築からデプロイまで<後編>

概要

以前の記事でRuby on Jetsのローカル環境を作成するところまで書きました。

docker-compose環境でRuby on Jetsの構築からデプロイまで<前編>

今回は実際にデプロイするところまでまとめてみたいと思います。

ユーザを準備

コンソールからIAMユーザを作成し、credentialを取得してください。

https://console.aws.amazon.com/iam/home#/users

今回デプロイするためだけのユーザということで「プログラムによるアクセス」にチェックを入れます。

Untitled.png

ポリシーの作成では「JSON」というタブを押して以下に記述したjsonを貼り付けてください。

Untitled (1).png

ポリシー設定用json

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "apigateway:*",
                "cloudformation:*",
                "dynamodb:*",
                "events:*",
                "iam:*",
                "lambda:*",
                "logs:*",
                "route53:*",
                "s3:*"
             ],
            "Resource": [
                "*"
            ]
        }
    ]
}

便宜上フルでアクションを許可しました。

もしセキュリティ視点でIAMポリシーを最小限にしたい場合は

以下のページを参考にデプロイ用IAMユーザにポリシーを設定してください。

(自分は最小限で設定しました。)

https://rubyonjets.com/docs/extras/minimal-deploy-iam/

公式ドキュメントには現時点では載っていなかったのですがVPCを設定するためには以下のような記述を追加する必要があると思います(というより記述しないとapplication.rbに書いたVPCの設定でデプロイが落ちました。。)

# Statementに追加
{
    "Version": "2012-10-17",
  "Statement": [
        中略
        },
        {
        "Effect": "Allow",
        "Action": [
        "ec2:DescribeSecurityGroups",
        "ec2:DescribeSubnets",
        "ec2:DescribeVpcs"
        ],
        "Resource": [
        "*"
        ]
        }
    ]
}

ここでは説明を省きますが、注意点としてはこのIAMポリシーは関数ロールに設定するIAMポリシーとは異なるという点です。config/application.rbの方で関数ロールへIAMポリシーをアタッチできます。気が向いたらそちらも書く予定です。

好みの名前を入力してポリシーを作成します。

Untitled (2).png

この後はお好みの設定でユーザを作成してください。

credentialをローカルに設定

IAMコンソールで作成したIAMユーザの画面へ行き、「認証情報」タブからアクセスキーとシークレットキーを作成してください。

取得した2つのキーを、以下を参考に~/.aws/credentialsと~/.aws/configに設定します。

https://rubyonjets.com/docs/deploy/

~/.aws/credentials:

[default]
aws_access_key_id=<アクセスキー>
aws_secret_access_key=<シークレットキー>

~/.aws/config:

[default]
region=<リージョン>
output=json

デプロイ実行

デプロイにはjets deployというコマンドを使います。ちなみに裏ではcloud formationが動いています。

dockerコンテナからそのままデプロイします。

ちなみに①で記述したDockerfileでaws-cliがコンテナに入っている状態になっています。

(①の方でDockerfileやdocker-compose.ymlの設定を載せています)

.env.containerでコンテナの環境変数を管理しているのでここにENVを記述します。

# .env.container
JETS_ENV = production

次に.env.production.remoteにDB情報などの、関数で使うための環境変数を記述します

(.env.developmentはローカル用、.env.development.remoteはリモート用でstagingとprodも同様)

# .env.production.remote
# DB情報などを記述

後はdeployするだけです!

$ docker-compose run --rm app bundle exec jets deploy

lambdaコンソールからアプリケーションがデプロイされているのを確認できれば完了です!

https://ap-northeast-1.console.aws.amazon.com/lambda/home?region=ap-northeast-1#/applications

staging環境を作成する

jetsでは先ほど記述したJETS_ENVという環境変数によって別の環境を簡単に作れます

以下のように.envなどに設定してみます

# .env.container
JETS_ENV=staging

先程と同様にdeployします

この時関数の環境変数は.env.staging.remoteに記述しましょう

$ docker-compose run --rm app bundle exec jets deploy

環境を入れ替えたいときはJETS_ENVの値を変えるだけでいいのでCI/CDの構築も

環境変数を切り替えてあげるだけで大丈夫です!

アプリケーションの削除

以下のコマンドでアプリケーションに依存しているリソース全てを消すことができます

扱いには注意が必要です

$ docker-compose run --rm app bundle exec jets delete

https://rubyonjets.com/reference/jets-delete/

まとめ

まだまだ書きたいことがたくさんあるのですが、とりあえずデプロイするところまで

行けました!!

引き続き気づいたことや詰まったことは発信していきたいと思います。

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

【Ruby】バイナリーサーチを使用して配列内の要素の検索

概要

少々複雑に感じることも言語化することで理解をを深くできると思いまとめました。もっと良い表現や間違えなどご指摘いただけたら幸いです。

目次

  • バイナリーサーチとは

    • 検索プロセス
  • 実践

    • 問題
    • 解答
  • まとめ

  • 参考文献

バイナリーサーチとは

ソート済みのリストや配列に入ったデータを検索するときに使用する手法です。対象のデータを半分に絞り込むことで検索していきます。

検索プロセス

  • 二分割したときの値検索したいデータが一致するまで繰り返し検索するように while を使用

    • 検索したいデータが半分より右にあるか? 左にあるか?
    • もしくは配列内に存在しないのか?

実践

問題

配列に任意の値が存在するかどうか、そして何番目に存在するのか、検索してください。

解答

def binary_search(ary, target)

  left = 0                # 配列は0番目スタート
  right = ary.length - 1  # 配列の最後尾(番目)

  while left <= right           # 目的の値を見つけるまで
    center = (left + right) / 2 # 配列の真ん中を取得

    if ary[center] == target                              # 配列の添字と検索したい数字が揃ったら
      return "#{target}は配列の#{center + 1}番目に存在します"  # returnで結果を返す

    elsif ary[center] < target # 検索したい数字が半分より右側にあったら
      left = center + 1        # 半分より右側を検索するように添え字に1を足す

    else                       # 検索したい数字が半分より左側にあったら
      right = center - 1       # 半分より左側を検索するように添え字に1を足す
    end
  end

  return "#{target}は配列内に存在しません" # whileの条件を外れ、検索に引っかからなかった時
end

# 配列
ary = [1, 3, 5, 6, 9, 14, 24, 33, 45, 53]

# ターミナルで検索したい数字を入力する
p '検索したい数字を入力してください'

# 数字なのでto_iを使用
target = gets.to_i

# ソート済みの配列と検索したい数字をbinary_searchメソッドに渡す。
p binary_search(ary, target) 

まとめ

  • バイナリーサーチとはソート済みのリストや配列に入ったデータを検索するときに使用する手法
  • 二分割しながら値を絞り込む

参考文献

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

【Ruby】if文 条件式の考え方

論理的思考強化の為、ドリルの復習をしています。
初学者のため、何かお気づきの点がありましたらご教示いただけますと幸いです。

問題

入力した整数が10の倍数からの差が2以内であるときはTrue、
それ以外はFalseと出力するメソッドを作りましょう。

模範解答

def near_ten(num)
  first_place = num % 10
  if first_place <= 2 || first_place >= 8
    puts "True"
  else
    puts "False"
  end
end

解説

一の位の値に着目します。
「10の倍数からの差が2以内」とは、一の位が「0,1,2,8,9」のどれかである、ということです。
そのため、四則演算の剰余算%を使い一の位を出し、それをfirst_placeに代入、
そしてfirst_place <= 2 || first_place >= 8「0,1,2,8,9」に当てはまるか確認しています。




他にこんなやり方があるよ!と教えてくださる方がいらっしゃいましたら、是非ご指摘いただけると幸いです!!

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

git push herokuし、herokuのURLを開くとMethod Not Allowedが出る問題

問題

git push herokuすると以下のような表示が出ますよね
ここの下から2行目を開くとMethod Not Allowedがでます。

スクリーンショット 2021-01-06 20.13.12.png

解決法

上の写真の下から2行目はgit用のファイルなので、remote:の後のURLを開きましょう。

リンクを確認せずに開くとこういうことになってしまいます。
気をつけましょう(戒め)

ちなみに

このgitのリンクはデプロイ用のgit repositoryらしいです。
なんらかの問題があった場合の最終手段としてcloneしたりするのはいいらしいですが
正規の”オリジン”リポジトリとしては使用してはいけないそうです。
詳しくは以下のリンクを参照してください。

参照

herokuにgit pushしたURLを開くと、Method Not Allowed と表示されてしまう

Git での既存の Heroku アプリケーションの複製

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

ニコニコ動画apiを使って埋もれてる面白い動画を発掘する

はじめに

  • ニコニコが好きなので作ってみました。

背景

  • ニコニコ動画のとりあえずマイリストの廃止で動画のマイリスト数が激減した
  • マイリストは面白い動画を見分ける判断材料になっていたのでとても残念
  • とりマイの代わりにできた「いいね」の数はなぜか非公開(意味がわからない)
  • 良質な動画を発見する機会と材料がなくなった

概要

  • ニコニコのスナップショットAPIを使って、動画のタグ検索を行い動画リストを作成する
  • 埋もれている動画の基準として、"(コメント数+マイリスト数×100)/再生数"が60%以上で、かつ再生数が500以上の動画
  • csvファイルにて出力

開発環境

  • 言語
    • ruby

検索例(一部)

"実況プレイ動画"タグで検索。
対象の投稿日時は、2020年1月から12月末まで。
全部で1053件の動画が抽出されました。
niconico.png

最後に

スナップショットapiは一度に取得できる動画の数が最大100でyoutubeDataAPIのようにnext_page_tokenがなく、大量のデータを取得するには指定した日付で1週間ごとのループ行ったが少し面倒だった。
とりあえずマイリストを消した運営の判断は本当に意味がわからないし、いいねも機能しているとは思えない。いいね数を開示するか、いいねとマイリストを合算した数を開示しないと、いいねをする理由にはならないと思う。(ユーザーがいいね機能を使う理由が今のところ存在しない。)

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

【circleCI】Rails6/mysql8のProjectを自動テスト&自動コードチェック

はじめに

久しぶりにyml職人していたら、circleCIの書き方を忘れてしまったので、備忘録として残します
折角なので冗長なymlをCircleCI Orbsでスッキリさせてみました
CircleCIで設定する環境と、実際にアプリを運用する環境をできるだけ合わせることがポイント
GithubでPull Requetを作成したら、masterにマージする前に自動でビルドされてテストやリンターが走ったら便利。

前提

  • Githubのアカウントをもっていること、既にRailsのプロジェクトがあること
  • Rspec & Rubocopが設定済みであること
  • Mysqlをつかった例を説明します

開発環境

  • Rails6
  • Mysql8
  • Docker
  • AWS ecs

config.ymlの設定

?全体はこんな感じ
・commitした時とmergeした時にRspec&RUbocopが走る
・mergeしたらecsに自動デプロイ

.circleci/config.yml
version: 2.1

orbs:
  ruby: circleci/ruby@1.1.2
  aws-ecr: circleci/aws-ecr@6.7.0
  aws-ecs: circleci/aws-ecs@1.1.0

jobs:
  test:
    docker:
      - image: circleci/ruby:2.6.3
        environment:
          RAILS_ENV: test
          RAILS_MASTER_KEY: ${RAILS_MASTER_KEY}
          DB_HOST: 127.0.0.1
          DB_USERNAME: 'test_user'
          DB_PASSWORD: 'password'
      - image: circleci/mysql:8.0
        command: --default-authentication-plugin=mysql_native_password
        environment:
          MYSQL_DATABASE: app_test
          MYSQL_USER: test_user
          MYSQL_PASSWORD: password
          MYSQL_HOST: 127.0.0.1
          TZ: "Asia/Tokyo"
    steps:
      - checkout
      - ruby/install-deps
      - run:
          name: Wait for DB
          command: dockerize -wait tcp://127.0.0.1:3306 -timeout 1m
      - run:
          name: Database setup
          command: bundle exec rails db:schema:load --trace
      - ruby/rubocop-check
      - ruby/rspec-test

workflows:
  test:
    jobs:
      - test
  deploy:
    jobs:
      - aws-ecr/build-and-push-image:
          account-url: AWS_ECR_ACCOUNT_URL
          region: AWS_REGION
          aws-access-key-id: AWS_ACCESS_KEY_ID
          aws-secret-access-key: AWS_SECRET_ACCESS_KEY
          create-repo: true
          dockerfile: ./docker/api/Dockerfile
          repo: sample-repo
          tag: "${CIRCLE_SHA1}"
          filters:
            branches:
              only: master
      - aws-ecs/deploy-service-update:
          requires:
            - aws-ecr/build-and-push-image
          family: 'sample-task'
          cluster-name: '${ECS_ARN}'
          service-name: 'sample-api'
          container-image-name-updates: "container=sample-container,tag=${CIRCLE_SHA1}"

circleci/ruby@1.1.2を使って諸々設定

?公式に詳しいことが載ってます
circleci/ruby@1.1.2について: circleCIDeveloper

orbs
orbs:
  ruby: circleci/ruby@1.1.2
今回使っているコマンド
# gemのインストール
- ruby/install-deps # Install gems with Bundler.
# rubocopのcommand
- ruby/rubocop-check # Check the code by Rubocop. You have to add `gem 'rubocop'` to your Gemfile. Enable parallelism on CircleCI for faster checking.
# rspecのcommand
- ruby/rspec-test # Test with RSpec. You have to add `gem 'rspec_junit_formatter'` to your Gemfile. Enable parallelism on CircleCI for faster testing.

circleci/aws-ecr@6.7.0 circleci/aws-ecs@1.1.0を使って諸々設定

?公式に詳しいことが載ってます
circleci/aws-ecrについて: circleCIDeveloper
circleci/aws-ecsについて: circleCIDeveloper

orbs
orbs:
  aws-ecr: circleci/aws-ecr@6.7.0
  aws-ecs: circleci/aws-ecs@1.1.0
今回使っているコマンド&ジョブ
# 必要に応じてAWS CLIをインストールし、設定を行う。Amazon ECRにログインし、イメージをリポジトリにプッシュする。AWS_ACCESS_KEY_IDとAWS_SECRET_ACCESS_KEYの環境変数が必要です
- aws-ecr/build-and-push-image: # Install AWS CLI, if needed, and configure. Log into Amazon ECR and push image to repository. Requires environment variables for AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY. We recommend these be saved in a Project 
# プロジェクトのデプロイ&ローリングアップデート
- aws-ecs/deploy-service-update: # Update an ECS service.

? jobsはtestだけ記述(今回はtest stepのみ記述下が、必要に応じてbuild stepも追加)

  • プロジェクトに合わせてimageを選択
  • それぞれ環境変数を設定
  • database.ymlも環境変数を参照するように設定
jobs
docker:
    - image: circleci/ruby:2.6.3 # projectに合わせる
      environment:
        RAILS_ENV: test
        RAILS_MASTER_KEY: ${RAILS_MASTER_KEY} # circleCIのEnvironment Variablesにmaster.keyを追加しておく
        DB_HOST: 127.0.0.1 # defaultでlocalhostなのでmysqlに合わせる
        DB_USERNAME: 'test_user'
        DB_PASSWORD: 'password'
    - image: circleci/mysql:8.0 # projectに合わせる
      command: --default-authentication-plugin=mysql_native_password # v8から認証の方法が変わった為 commandで認証する
      environment:
        MYSQL_DATABASE: app_test
        MYSQL_USER: test_user # rootでは作成できない為、適当に定義する
        MYSQL_PASSWORD: password
        MYSQL_HOST: 127.0.0.1 # containerのhostを指定
        TZ: "Asia/Tokyo"

?stepcommandを実行
サービス起動まで待機:dockerize を使って他のコンテナ内サービス起動を待つ

steps
steps:
  - checkout
  - ruby/install-deps
  - run:
    name: Wait for DB
    command: dockerize -wait tcp://127.0.0.1:3306 -timeout 1m # dockerize を使って他のコンテナ内サービス起動を待つ
  - run:
    name: Database setup
    command: bundle exec rails db:schema:load --trace # migration
  - ruby/rubocop-check
  - ruby/rspec-test

あとはtestのjobsに先ほど設定したtestを指定して自動でテスト&コードチェックが実行される

workflows
workflows:
  test:
    jobs:
      - test

? masterにmergeされたらDockerイメージをECRにpushする

  • circleCIにAWSの環境変数をそれぞれ設定
deploy:
  jobs:
    - aws-ecr/build-and-push-image:
         account-url: AWS_ECR_ACCOUNT_URL
         region: AWS_REGION
         aws-access-key-id: AWS_ACCESS_KEY_ID
         aws-secret-access-key: AWS_SECRET_ACCESS_KEY
         create-repo: true
         dockerfile: ./docker/api/Dockerfile # pushしたいDockerfileを選択
         repo: sample-repo # ecrのリポジトリ名を選択
         tag: "${CIRCLE_SHA1}"
         filters:
           branches:
             only: master

? masterにmergeされたらデプロイ&ローリングアップデート

  • circleCIにAWSの環境変数をそれぞれ設定
deploy
- aws-ecs/deploy-service-update:
    requires:
      - aws-ecr/build-and-push-image
    family: 'sample-task' # ecsのタスク名
    cluster-name: '${ECS_ARN}' # ecsのクラスター名
    service-name: 'sample-api' # ecsのサービス名
    container-image-name-updates: "container=sample-container,tag=${CIRCLE_SHA1}" # sample-containerの部分を適宜コンテナ名に変更

?コミットしてみて動くか検証


?マージしてしてみて動くか検証

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

【Rails】シングルテーブル継承を使って、テーブルの数を削減する【STI】

シングルテーブル継承(単一テーブル継承、STI)とは

シングルテーブル継承(以下、STI)は、単一の継承階層に所属するクラス群を、ただひとつのテーブルを使って永続化する手法です。

言葉だけでは伝わリにくいので、下図を御覧ください。

スクリーンショット 2021-01-05 18.49.31.png

Postsテーブル(スーパークラス)が、サブクラスに継承する形になります。
しかし、注意点が2点あります。

  • Books,Clothes,Goodsテーブルは実際には存在しない。
  • 個々のデータはすべてスーパークラスのテーブルに保存されます。この場合はPostsテーブル。

それでは、STIはどういう場面で使えばいいのでしょうか。

STI継承しないと中間テーブルが再生産が起きる

自分はSTIの存在を知らずにアプリを作っていったら下図のようになってしまいました。

スクリーンショット 2021-01-05 18.34.01.png

・・・。

PostsテーブルとしてはBooksとClothesとGoodsの記事を作りたかったのですが。。。

それぞれのテーブルを作ってしまうことで、それぞれの中間テーブル(ここでは、Comments,Likes,Pickupテーブル)が再生産が起きてます。

機能自体はできましたが、ゴチャゴチャしすぎて保守的には最悪ですね・・・。
何より新機能をつける度に3つテーブルを用意する必要があり、骨が折れます?

そこで!STIを使い、Postsクラスをサブクラスに継承させました!
以下の通りです。

スクリーンショット 2021-01-06 13.40.38.png

めっちゃスッキリしましたね!
(画像にはBooks,Clothes,Goodsはテーブルとして書いてありませんが、継承させています。)
これで保守がしやすく、新機能もつけやすくなりました!

やり方(結論)

1. スーパークラスを作る

rails g model postでマイグレーションを作成し、テーブルの設定をします。

migrate/〇〇_create_posts.rb
class CreatePosts < ActiveRecord::Migration[6.0]
  def change
    create_table :posts do |t|
      t.references :user,foreign_key: true

      #省略

      t.string :type #typeカラムを作成します!
      t.timestamps
    end
  end
end

ここで注意したいことは、typeカラムを作成することです。
この中に継承先のクラス名が入り、管理されます。

2. それぞれのクラスを作成し、スーパークラスを継承させる

先程のファイルをマイグレーションしてできたモデルファイルを編集したものです。

models/post.rb
class Post < ApplicationRecord
  belongs_to :user

  #省略

end

それではrails g model book --parent=Postでbookモデルを作成します。
--parent=PARENTオプションを使うことで、マイグレーションファイルを生成せずに済みます。

models/book.rb
class Book < Post
  #こうすることでスーパークラスのアソシエーションやバリデーションが引き継がれます。
end

完成です!

ちなみに!
この状態でBookモデルを保存すると、Postsテーブルのtypeカラムに"Book"が代入された状態で,Postsテーブルに保存されます。

Book.create(title: "本です",.......)

以上でSTIのやり方は終わりです。
最後まで読んで頂きありがとうございました!

参考

Railsガイド
https://railsguides.jp/association_basics.html

[Rails] STI(単一テーブル継承)とメタプログラミングでDRY
https://qiita.com/kidach1/items/789c2e7aebbcfbd2583e

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

Range でループする場合に気をつけること

なんか特定の条件でサーバが重くなるなぁ、と思ったら無限ループでした。

注意すべきコード

以下のようなループは無限ループとなる可能性があるので注意

(0..max).each do |i|
  # 何か処理
end

なぜ?

Range クラスの仕様で終端が省略されている or nil の場合の Range オブジェクトは「終端なしのRangeオブジェクト」となる。

An “endless range” represents a semi-infinite range. Literal notation for an endless range is:

(1..)
# or similarly
(1...)

Which is equivalent to

(1..nil)  # or similarly (1...nil)
Range.new(1, nil) # or Range.new(1, nil, true)

https://docs.ruby-lang.org/en/2.6.0/Range.html

よって、前述のコードでは maxnil となる場合、無限ループとなる。

じゃあどうしたら?

以下のように #upto() のループに置き換える

0.upto(max) do |i|
  # 何か処理
end

maxnil が入る余地を無くすというのも手ですが、そもそも無限ループしない書き方にしたい。

uptonil を渡すと例外が発生するので、少なくとも無限ループすることはあり得ない。

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

Range オブジェクトを #each や #map で回すときは無限ループに注意する

なんか特定の条件でサーバが重くなるなぁ、と思ったら無限ループでした。

注意すべきコード

以下のようなループは無限ループとなる可能性があるので注意

(0..max).each do |i|
  # 何か処理
end

なぜ?

Range クラスの仕様で終端が省略されている or nil の場合の Range オブジェクトは「終端なしのRangeオブジェクト」となる。

An “endless range” represents a semi-infinite range. Literal notation for an endless range is:

(1..)
# or similarly
(1...)

Which is equivalent to

(1..nil)  # or similarly (1...nil)
Range.new(1, nil) # or Range.new(1, nil, true)

https://docs.ruby-lang.org/en/2.6.0/Range.html

よって、前述のコードでは maxnil となる場合、無限ループとなる。

じゃあどうしたら?

以下のように #upto() のループに置き換える

0.upto(max) do |i|
  # 何か処理
end

maxnil が入る余地を無くすというのも手ですが、そもそも無限ループしない書き方にしたい。

uptonil を渡すと例外が発生するので、少なくとも無限ループすることはあり得ない。

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

[Gem不要!!HTML&CSSのみ]初心者が簡単にドロップダウンメニューを作成する方法

はじめに

ハンバーガーメニューやドロップダウンメニューの作成をしたいけど、Gem導入の方法がよくわからない・JavaScriptは思うようにいかない。
そんな初心者の方におすすめの記事なっております。

開発環境

・Rails6.0.0
・MySQL5.6.50

ドロップダウンメニューの実装

早速ドロップダウンメニューの実装の方法の流れを解説します。
ちなみにドロップダウンメニューとは以下のようなメニューのことです。

f15d1dda5826200510a6a8d6eabad639.png

「...」 を押すとメニューが表示されるものです。

よく見かけますが、JavaScriptでやるには面倒だし、Bootstrap導入のためにGemやjQueryを導入したりするのは初心者には中々ハードルが高めかなと思います。

それでは解説していきます。

1)application.html.erbで初期設定

まず app/views/layouts/application.html.erbBootstrapなど必要なものを読み込みます。

以下は僕がドロップダウンメニューを作成した際に使用したHTMLコードです。

views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>PlansApp</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>
    <link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/3.18.1/build/cssreset/cssreset-min.css">
    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
    <link href="https://use.fontawesome.com/releases/v5.6.1/css/all.css" rel="stylesheet">

    # ここでbootstrapを読み込んでいます
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
  </head>

  <body>
    <%= yield %>
  # 以下の3行のscriptタグを追記しHTMLで使用できるようにしています
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
  </body>
</html>

初期設定はこれで終了です。

2)HTMLを書く

初期設定ができたら、早速ドロップダウンメニューのHTMLを記述していきます。
具体的には公式を見てもらってアレンジしてもらうのがベストですが、参考にした記事のものと、僕が作成したものを紹介しておきます。

参考記事の例
<nav class="navbar navbar-expand-lg navbar-light bg-light">
  <a class="navbar-brand" href="#">Navbar</a>
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>

  <div class="collapse navbar-collapse" id="navbarSupportedContent">
    <ul class="navbar-nav mr-auto">
      <li class="nav-item active">
        <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">Link</a>
      </li>
      <li class="nav-item dropdown">
        <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
          Dropdown
        </a>
        <div class="dropdown-menu" aria-labelledby="navbarDropdown">
          <a class="dropdown-item" href="#">Action</a>
          <a class="dropdown-item" href="#">Another action</a>
          <div class="dropdown-divider"></div>
          <a class="dropdown-item" href="#">Something else here</a>
        </div>
      </li>
      <li class="nav-item">
        <a class="nav-link disabled" href="#">Disabled</a>
      </li>
    </ul>
    <form class="form-inline my-2 my-lg-0">
      <input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">
      <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
    </form>
  </div>
</nav>

僕の場合だとlistタグがあるためレイアウトが崩れるなどの問題がありました。
そこで以下のようにアレンジいました。

アレンジ例
<a class="nav-link" href="#" id="navbarDropdown" role="button" datatoggle="dropdown" aria-haspopup="true" aria-expanded="false">
   <i class="fas fa-ellipsis-h"></i>
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
   <a class="dropdown-item" href="#">コメント履歴</a>
   <div class="dropdown-divider"></div>
   <a class="dropdown-item" href="#">フォローしているユーザー</a>
   <div class="dropdown-divider"></div>
  <%= link_to 'ログアウト', destroy_user_session_path, method: :delete, class: "dropdown-item" %>
</div>

僕の場合はfontAwesomeでアイコンなどを使用したり、開発中のアプリのためパス指定があるところ・無いところがまばらですが、こんな感じでアレンジしました。

公式ドキュメント

3)CSSの適用させる

ここまでくれば、後はお好みでCSSを記述していくだけです。
参考までに以下に参考記事の記述例を紹介しておきます。

参考記事のHTML7行目の以下のクラスに適用させていきます。

 <div class="collapse navbar-collapse" id="navbarSupportedContent">

なぜ、このクラスに適用させるのかの詳しい解説は参考記事をご覧いただけるとわかりやすいので、ぜひ見てみてください。

【初心者】ハンバーガーメニューの詳細表示後のバーを装飾してみた

参考記事の例
@media screen and (max-width: 992px) {
.collapse.navbar-collapse{
    padding: 10%;
    border-radius: 10px 10px 10px 10px;
    background: linear-gradient(white, #cccccc) !important;
    margin: 15%;
    font-size: 1.7rem;
  }
}

@media screen and (max-width: 992px) {
  // スマホ用
  .collapsing.navbar-collapse{
    padding: 10%;
    border-radius: 10px 10px 10px 10px;
    background: linear-gradient(white, #cccccc) !important;
    margin: 15%;
    font-size: 1.7rem;

  }
}

以上でドロップダウンメニューの実装は終了です。
これを期に、UI/UXのスキルの一部を見に付けてみてはいかがでしょうか。

参考文献

公式ドキュメント

【初心者】ハンバーガーメニューの詳細表示後のバーを装飾してみた

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

rbenvでRubyのバージョンが切り替わらないときの対応

rbenvでRubyのバージョンが切り替わらなかったので、それのメモです。

事象

rbenvでバージョンを切り替えても変わりません

$ rbenv versions
  system
  2.6.6 
* 2.7.1 (set by RBENV_VERSION environment variable)
$ rbenv global 2.6.6
$ rbenv versions
  system
  2.6.6 
* 2.7.1 (set by RBENV_VERSION environment variable)

やったこと

set by RBENV_VERSION environment variableと言われているのですが、特にどこにも書いていません。
また.zshrcexport RBENV_VERSION=2.6.6をすると、rbenvのversionはうまく変更されますが、
rubyのバージョンを確認しようとするとエラーになります。

$ rbenv versions
  system
* 2.6.6 (set by RBENV_VERSION environment variable) 
  2.7.1
$ ruby -v
/Users/naoto.koyama/.rbenv/versions/2.7.1/bin/ruby: invalid option -:  (-h will show valid options) (RuntimeError)

原因

Ruby 2.7の警告を抑制するために.zshrcに書いているRUBYOPTの設定を書いていることが原因でした

$ cat ~/.zshrc
...
export RUBYOPT='-W:no-deprecated -W:no-experimental' # <- これが原因

上記を削除してから以下のコマンドを打てばOKです

$ unset RUBYOPT
$ rbenv global 2.6.6
$ rbenv versions
  system
* 2.6.6 (set by /Users/naoto.koyama/workspace/portal/.ruby-version)
  2.7.1
$ ruby -v
ruby 2.6.6p146 (2020-03-31 revision 67876) [x86_64-darwin20]

参考

rbenvのrubyコマンドがすべて「invalid option -: (-h will show valid options) (RuntimeError)」それRUBYOPTが原因かも

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

ssh先 & dirを指定→pecoで選んだfileをscpする

動作環境

  • pecoが入ってる
  • rubyが入ってる
  • 他にもあるかも
function scp_file {
    ssh -qt $1 "QUOTING_STYLE=literal ls -1 $2" > /tmp/lsfiles

    # peco で選択した文字列をrubyに渡してshell safeにする
    valid_file_name=$(cat /tmp/lsfiles | peco | ruby -rshellwords -e "print(Shellwords.escape(gets.chomp))")

    scp "$1":"$2/$valid_file_name" $3
}

scp_file remove_host_name remote_host_path client_path
で実行可能。

背景

色々エスケープしないとscpできないファイル名(記号とかスペースとか)のものをscpしたいことが多かった
Shellwords.escape 君の存在を知ってしまった
もっといい方法あったら誰かがコメントしてくれると思った

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

Rubyによるデザインパターンを読んでいく

第1章 よいプログラムとパターン

パターンのためのパターン

Gofのデザインパターンのアイデアを要約すると、次の4つのポイントになる。

1. 変わるものより変わらないものから分離する

ソフトウェア開発における全ての変更は局所的なので、全てのコードをくまなく調べる必要がないようにすべき。

2. インターフェイスに対してプログラムし、実装に対して行わない

ここでのインターフェイスとは、JavaやC#における抽象インターフェイスではなく、可能な限り一般的な型のことを指す。

例) 飛行機、電車、自動車 に対する 「乗り物」

インターフェイスに対するプログラミングの結果、
結合度が下がり、少しのクラスの変更だけで済む、変更に対して強いコードになる。

3. 継承より集約

  • 継承(is-a-kind-of)
    • サブクラスとスーパークラスの結合度が高いという問題がある。
  • 集約(has-a)
    • 各クラスの再利用性が高められる。
    • カプセル化ができる。

4. 委譲、委譲、委譲

集約されたオブジェクトに責任転嫁させるメソッドを書く。
継承よりも柔軟で副作用がなくなる。

サンプルコード

継承を使ったコードの例

class Vehicle
  # ...
  def start_engine
    # エンジンをスタート
  end

  def stop_engine
    # エンジンをストップ
  end
end

class Car < Vehicle
  def sunday_drive
    start_engine
    # 地方に出かけ、戻ってきます。
    stop_engine
  end
end

集約と委譲を使ったコードの例

class Engine
  def start
    # エンジンをスタート
  end
  def stop
    # エンジンをストップ
  end
end

class Car
  def initialize
    @engine = Engine.new
  end

  def sunday_drive
    @engine.start
    # 地方に出かけ、戻ってきます。
    @engine.stop
  end

  def start_engine
    @engine.start
  end

  def stop_engine
    @engine.stop
  end
end

必要になるまで作るな

YAGNI = You Ain't Gonna Need It

  • 将来必要とされるものを前もって作った場合、使われなかった場合はすべて無駄になり、増やしてしまった複雑さを抱え続けなければならなくなる。
  • 本当に必要になるまで待てれば、何が必要で、どのようにすべきかのよりよい理解を持ちやすくなる。

本書で扱うGofの14パターン

  1. Template Method
  2. Strategy オブジェクト
  3. Observer パターン
  4. Composite パターン
  5. Iterator パターン
  6. Command パターン
  7. Adapter パターン
  8. Proxy
  9. Decorator パターン
  10. Singleton
  11. Factory Method
  12. Abstract Factory
  13. Builder パターン
  14. Interpreter

Rubyの中のパターン

  1. 内部ドメイン特化言語
  2. メタプログラミング
  3. Convention over Configuration(CoC)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby初学者に向けた】 Ruby 技術者認定試験 Silver/Gold 受験記

初版公開:2021/01/05

概要

先日Ruby 技術者認定試験を受験し、Silver/Gold共に合格しました。(Silver:84点/Gold:94点)
合格にあたり、先人たちのQiita記事に大変お世話になったので、私も誰かの参考になればという気持ちから記事にまとめておきます。

著者の受験背景

現在私は社会人ではありますが、Ruby更にはプログラミングの仕事にはついてはおりません。
(仕事でプログラムを書くことはほぼありません。)
また、Rubyに初めて触れたのも2020年8月ごろです。(2021年1月本記事執筆)
個人的には将来的な(転職を含めた)キャリアアップに繋がればと思い受験しました。

以上の背景から、本記事はRuby初学者の方へ向けての受験記としています。
初学習から技術者認定試験を受験しSilver/Goldの資格を取得するための参考にしていただければ幸いです。

Rubyの初学習

【準備するもの】

Ruby:技術者認定試験の対象verが2.1です。最新のRubyのDLで問題ありません。
テキストエディタ:なんでも良いですが、著者はVScodeを利用しています。
githubアカウント:試験勉強に使用します。また持っておくと今後必ず使います。

※上記は書籍や記事にDLの方法が多く載っていると思いますので、方法は割愛します。

【使用した勉強書籍】

  • たのしいRuby(著:高橋征義、後藤裕蔵 / 出版:SB Creative)

どの先人の記事でも紹介されている「たのしいRuby」です。
基本的にこれ1冊あれば基礎を固めるには充分です。

私は第2部までを一通り目を通し、第3部で各章の末尾の問題を自力で回答しながら理解を深めました。
読み終えたら、後述のRails超入門を一度触ります。その後この本にもう一度戻ってくると、実戦でよく使いそうなメソッドが目につき非常に勉強になります。

  • Ruby on Rails6 超入門(著:掌田 津耶乃 / 出版:秀和システム)

いきなり本筋から逸れますが、Railsについての書籍です。
ここで紹介するのはそれなりの理由があります。
それは初学者に陥りやすい現象に、最終的なアウトプットが見えず勉強に限界を感じることです。
特に言語解説系の書籍は、実戦でよく使用される重要な部分が不透明です。
これでは出てくる全てが重要な構文・メソッド・技法に見えてしまいます。
ですので、Rubyに触れる人十中八九がこの先触れるであろう「Ruby on Rails」を軽く触っておくのは非常にメリットになるかと思います。

技術者認定試験へ向けた勉強

【試験に必要な準備】

プロメトリックID:受験に必要です。発効は無料。
試験予約:iPhone/iPadのSafariでは私はエラーで予約できませんでした。PC推奨のようです。

【使用した勉強書籍】

  • Ruby技術者認定試験合格教本(○Silver/○Gold)
    (著:増井雄一郎,小川伸一郎,株式会社日立ソリューションズ 牧俊男 / 出版:技術評論社)

こちらもどの先人の記事でも紹介されている合格教本です。
ある程度基礎が固まっている人が読むべきだと思います。目安は「たのしいRuby」読破後です。
Marshall/Thread等「たのしいRuby」でも触れられていない部分は、新しい知識として吸収します。
また、第5章までの範囲がとても難しく感じたのならば「たのしいRuby」に戻るべきです。

この本はメソッドや理論が淡々と並べられている詰め込み羅列型の本です。
一つ一つ挙動を組んで確認するのは当たり前ですが、出てくるメソッドやclass/moduleに対して、ただ模写するのではなく自分なりに工夫してプログラムを書いてみるべきです。

例えば自分なりにclass/moduleを作成してinclude/prependしたものは、自分が考えていた継承の通りでしょうか?
include/prependで2つ以上ののmoduleを一度に継承関係に置いた場合どうなりますか?

意外と細かいところまで気を配っておく必要があります。

  • メタプログラミングRuby(×Silver/◎Gold)
    (著:Paolo Perrotta 訳:角 征典/ 出版:オライリー・ジャパン)

メタプログラミングの真髄に触れることができる良書です。
試験だけならば読まなくても良いという記事を数件見かけましたが、個人的には読むべきです。
Silver試験ではこの内容までは不要なので、Silver受験後に購入して読破するのが良いでしょう。

この本を読む前と後でruby内の包括関係の理解は格段に上がりました。
最初はdefine_methodなどでメタプログラミングしていく内容で、なんでこの知識が必要なんだと理解に苦しむのですが、3,4章あたりが真髄です。

初見では試験勉強ではみたことがない内容が多く、ついていくのがやっとだと思います。
個人的には1周目をとりあえず模写して理解し、日をおいて2周目をするべきです。
2周目は模写ではなく、内容から真意を汲み取って自分なりのコーディングをするのが良いでしょう。

【試験対策】

  • Rex (◎Silver/◎Gold)

Silver/Gold両方の試験対策問題を無料で公開しているサイトです。
毎回ランダムで問題を出題してくるため、非常に有用。試験勉強として一番利用しました。
試験前の時点で毎回100点が取れるくらいやり込むべきです。
ただし、一部問題が間違っています。特にGoldで数個見かけました。
勉強していれば違和感を覚える回答です。気になったら自分でコードを書いて確認してください。

Silver試験のみですが対策問題集を解くことができます。こちらは問題が決まっています。
Rexである程度解けるようになったら、補完できていなかった知識を埋めるのに役立ちます。

  • CTC(×Silver/○Gold)

こちらはGold試験のみですが対策問題集を解くことができます。
ミニツク同様の使い方で大丈夫です。

公式がSilverしか問題集を出していない。あまり納得できないがこればかりは仕方ない。
問題は易しめではあるが、非常に似た問題が試験に数問出ていたので、解くべき。

m-haramoto(@HaramotoReo)さん作のSilver対策問題集
各classごとに分かれた問題で、非常に良問揃い。
こちらも試験2週間くらい前に手をつけて知識の抜けを埋めるのに非常に役立つ。

問題が英語なので初見殺しだが、意外と意味もわかりつつ解ける。
こちらも知識の補完。本試験でここの問題を解いていなかったら落としていた問題も数問あったので、見つけて助かった。

【その他】

2,3年前の記事を見ていると、ITメトレで勉強しましたという意見も多いが、サービスは終了。
問題も閲覧できなくなっているので、注意。

本試験

試験会場では、ペーパーと筆記用具が事前に用意されているので、問題を紙にメモしながら回答可能。
ただし、用紙は持ち帰れない。

【Silver】

とにかくメソッドを覚える。これに尽きる。
破壊的メソッドは!がつくが一部には付かないとか、色々一筋縄ではいかない。難儀だ。
あとは演算子の優先順位等少し細かいところを覚えておくとよい。

【Gold】

まずはsingletonを含めたclass/moduleの関係を頭に入れないと絶対に合格できない。
探索がどのように進むのか頭に描けるようになるまで、メタプログラミングRubyや問題を解く。
あとはクラスインスタンス変数(クラス変数、インスタンス変数どちらでもない)や、public,protected,privateの仕様。定数探索。rubyオプション。

一番難儀だったのが添付ライブラリについて。
試験教本でもページ数があり、かつどこまで覚えていいのか非常に難しい。
自分は1,2週間前までにざっと教本に目を通し、重要な部分だけピックアップしてノートにまとめた。
(他のファイルを用意して実行する時間があるなら、勉強に使ったほうがいいと判断した。)
本試験では添付ライブラリの問題は3,4問。
結局そこまで触れてなかった部分が出た気もするが、消去法で回答。(真相は闇の中)

【所感】

上記を見るとGoldの方が覚えることが多そうだが、実はSilverの方が覚えることが多い。
メソッドは無限にあるので、一問一答が得意な人は簡単かもしれない。
理論体系を覚えるのが得意な人はGoldの方が間違いなく簡単。

最後に

Rubyに触れて半年でGoldまで取得できるとは思っていなかったが、個人的に勉強してよかった。
この資格は必要なのか疑問視されることも多いが、特に初学者は目標になるし、その点では難易度は丁度良い。
金額が16500円するので、できれば1度で合格したいところだ。
(どちらも1度で受かってよかったと思える最大のポイントかもしれない。)

Rubyでプログラミングを始める人の何かの参考になれば嬉しい。

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

putsとprintの違い

Progateでpythonの勉強をし始めたら、「print」というのが出てきた。
python特有の物かと思ったら、Rubyでも普通にあるみたいで。。知らなかった・・!
自分用のメモとして記録しておく。

■主な違い
・改行するかしないか

puts→出力後改行
print→出力後改行しない

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

Ruby:クラスメソッドとインスタンスメソッド、クラス変数とインスタンス変数の違い

クラスメソッドとインスタンスメソッドの違い

まずRubyのクラスメソッドとインスタンスメソッドの違いを見ていきます。

クラスメソッドとは

クラスメソッドを定義したクラス自身が使用できます。クラスで共通の情報を使った処理に使用します。インスタンスがなくても呼び出すことができます。

クラスメソッドを定義する際は、self.メソッド名と記述します。以下のようにクラス名Fruitsから呼ぶことができます。また、インスタンスを生成するnewメソッドは、代表的なクラスメソッドです。

fruits.ruby
calss Fruits
  def self.call #selfはクラス自身を指す
    puts "クラスメソッドを呼び出しました"
  end
end

Fruits.new #newメソッドもクラスメソッドの1つ。
Fruits.call

ターミナルで上記のrubyファイルを実行すると次のような結果になります。

ターミナル
ruby fruits.rb

クラスメソッドを呼び出しました

Fruits.callの実行結果が表示されます。
Fruits.newは空のインスタンスが生成されるだけなので実行結果には表示されません。

インスタンスメソッドとは

インスタンスが使用できるメソッドで、クラス内に定義します。
「インスタンスメソッドを定義したクラス」から生成されるインスタンスが使用できます。

fruits.ruby
calss Fruits
  def call
     puts "インスタンスメソッドを呼び出しました"
  end
end

fruits = Fruits.new
fruits.call
#.でつなげて下記のように呼び出すこともできます。
Fruits.new.call
ターミナル
ruby fruits.rb

インスタンスメソッドを呼び出しました

initializeメソッド

initializeメソッドは、newメソッドによってインスタンスを生成したと同時に実行される処理を定義できるインスタンスメソッドです。
実は、クラスに記述しなくてもinitializeメソッドは自動で実行されており、この場合は何も処理がされません。

fruits.rb
class Fruits
  def initialize
    puts "インスタンスが生成されました"
  end
end

Fruits.new

ターミナルで上記のrubyファイルを実行すると次のような結果になります。

ターミナル
ruby fruits.rb

インスタンスが生成されました

Fruits.newでインスタンスを生成した後にinitializeメソッドに定義した処理が実行されたことがわかります。

クラス変数とインスタンス変数の違い

次にクラス変数とインスタンス変数の違いを見ていきます。

クラス変数とは

そのクラス内で定義される変数で、@@変数名と記述して定義します。クラス変数は、クラスとして共通の変数を定義したいときに使うのに適しています。

fruits.rb
class Fruits

  @@fruit = "オレンジ" #initializeメソッド内で使用するために、インスタンス生成前に定義

  def initialize
    puts "私は#{@@fruit}が好きです"
  end

end

Fruits.new

実行結果

ターミナル
ruby fruits.rb

私はオレンジが好きです

クラスメソッドの特徴として、一度定義すればクラス内のどこでも使用することができます。

fruits.rb
class Fruits

  @@price = 0 

  def initialize(fruit, price)
    @fruit = fruit
    @@price += price
  end

  def self.sum
    puts "合計金額は#{@@price}円です" 
  end

end

Fruits.new("オレンジ", 200)
Fruits.new("リンゴ", 300)
Fruits.new("ぶどう", 500)

Fruits.sum
ターミナル
ruby fruits.rb

合計金額は1000円です

オレンジ、リンゴ、ぶどうのインスタンスを生成するたびにクラス変数@@priceに各フルーツの価格が合算され、sumメソッドで合計金額を出力しました。

インスタンス変数とは

個別のインスタンスに定義できる変数で、@変数名と記述して定義します。インスタンス変数は定義したインスタンスメソッドとは別のインスタンスメソッドの中でも使用することができます。

fruits.rb
class Fruits

  def initialize(fruit)
    @fruit = fruit
    puts "私は#{@fruit}が好きです"
  end

  def dislike
    puts "私は#{@fruit}が苦手です"
  end
end

Fruits.new("オレンジ")
Fruits.new("リンゴ")
fruit = Fruits.new("ぶどう")
fruit.dislike
ターミナル
ruby fruits.rb

私はオレンジが好きです
私はリンゴが好きです
私はぶどうが好きです
私はぶどうが苦手です

initializeメソッドで、生成したインスタンスごとにインスタンス変数@fruitの値が代入され、putsで出力しています。

また、initializeメソッド で定義したインスタンス変数@fruitdislikeメソッドでも使用できているのが確認できます。

参考資料

Rubyのクラス変数の使い方を現役エンジニアが解説【初心者向け】(TechAcademyマガジン)

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