- 投稿日:2021-01-06T23:35:09+09:00
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
- 投稿日:2021-01-06T22:30:13+09:00
<投稿一発目> Rubyの勉強はじめました
前置き
初めてQiitaで記事を書いてみます。
自分の性格的に、出来ればQiitaの機能等について詳しく知り尽くした上で投稿を始めたいのですが、そんな調子だと石橋を100回叩いても一歩を踏み出せない気がするので、Rubyの勉強を開始したこのタイミングでとりあえずはじめてみます。
ひとまず学習内容の記録を備忘録的に残していく形で書いてみました。これからどのように記事を書いていったらいいかもまだ曖昧ですが、書き方・内容についても少しずつブラッシュアップしていければと思います。
自己紹介等はおいおい機会があるごとに少しずつ書いていけたらと思います。学習教材について
「Progate」の「Ruby学習コース」を活用して勉強をはじめます。
今回は「Ruby学習コースⅠ」を終わらせました。ちょっとした雑記・学習後の所感
プログラミングって学び始めて直ぐの段階から、「面倒なこと・重複作業をしないため、要らないミスをなるべく減らすために、ここはこういうふうにしましょう」ってことを考えさせ・勉強しますよね。
「だってそれがプログラミングの要でしょ?」って言われてしまうかもしれませんが、そんな当たり前なところにものぼくはものすごく魅了を感じます。以前勤めていた職場でも、空き時間等を使って様々な業務の簡素化・自動化にチャレンジしてました。
- アナログ且つマニュアルな業務をエクセルのフォーミュラ等を駆使して改善してみたり
- 毎回のように新しく作っていたエクセルシートやワードの資料をテンプレート化して都度使用するごとに改善を加えたり
- 人に業務手順とか作業方法聞かれたときに毎回手とり足取り教えるのが嫌になり業務マニュアル作ったり(自分も解決できない疑問点があると納得いくまで人に聞きまくるが、これを他人からされると辛い…)まあ、要は主な動機として単純作業に毎日多くの時間を費やすのをやめて、なるべく付加価値を付けたアウトプットを出したかったからですね。副次的にはいずれその努力から得られるメリットがチームや部署に普及してみんなで得をしていければいいなとの思いもありました。最初はExcelの独学に時間を費やしていましたが、いろいろ壁にぶち当たるうちに知ったのがプログラミングやRPA。特にある程度のプログラミングの知識とスキルがあれば、異なるソフトウェアを跨いで作業を自動化させたり、なんならお高いERPパッケージを買わなくても、チームや部署内で使える簡易webアプリケーションとかを組めることを知りました。
大学院でビジネスを学んでいたときも、アイデアはピッチするものの技術的なスキルや知識(ソフトウェアもハードウェアも)が圧倒的に不足していたので、机上の空論を並べるだけで抽象的なイメージを具現化することができず、いろいろと悔しい思いもしました。(当時思いついたアイディアはどれもデジタルやIoTがシステムに組み込まれてやっと完成するものばかりだったのです… 結局、課題選定時にはボツにされたアイディアが、後に海外でほとんど瓜二つのビジネスモデルとしてマーケットに出現してまあまあ利益を上げていることを知ったり…これはもうコロンブスのたまごですが。)
プログラミングでなにかを作るって、究極的に利便性や効率化を追求する手段・作業ですよね。自分は今でも普段から、「あーこういうことが出来ればいいのにな。こんなサービスがあれば世の中もっと便利にになるはずなのにね。」なんてことをぼーっと考えてます。そんなひらめきや思いをもっと簡易に実現する手段でもあるプログラミング・ソフトウェアを本腰を入れて学んでみることにしました。
このあたりの話はまたこれから機会あるごとに少しずつ書いてみようと思います。「Ruby学習コースⅠ」備忘録・気づき
なぜプログラミングにおいて変数を使うのか
- 同じ要素を繰り返し使える
- 後からの変更に対応しやすくなる
- なんの要素かわかりやすくなる
変数名のルール
- 英単語で記載する
- 2ワード以上は空白部分をアンダーバーで区切る
- 望ましくない変数名 => ローマ字表記、日本語表記等々…
- エラー発生する変数名 => 数字始まりの
文字列における変数展開
- 文字列内に「#{変数名}」で変数展開が可能
- 注意点:
- 変数展開はダブルクォーテーションの文字列内でのみ可能
- シングルクォーテーション文字列では文字列として出力されてしまう
- 変数になっている数値と文字列は足し算で連結不可のため(エラー発生する)
- 上記の理由から、変数を文字列に含めたい場合は、変数展開を使用すること
その他
- true or false をダイレクトにコンソールに表示するには, 変数定義後にputsで可能
- 2者が等しいかの式 「==」
- 2者が異なるかの式 「!=」
- 「且つ」の式は 「&&」
- 「又は」の式は 「||」
- インデントはTABキーで。パッと見たときの読みやすさを意識すること
- 投稿日:2021-01-06T21:45:52+09:00
docker-compose環境でRuby on Jetsの構築からデプロイまで<後編>
概要
以前の記事でRuby on Jetsのローカル環境を作成するところまで書きました。
docker-compose環境でRuby on Jetsの構築からデプロイまで<前編>
今回は実際にデプロイするところまでまとめてみたいと思います。
ユーザを準備
コンソールからIAMユーザを作成し、credentialを取得してください。
https://console.aws.amazon.com/iam/home#/users
今回デプロイするためだけのユーザということで「プログラムによるアクセス」にチェックを入れます。
ポリシーの作成では「JSON」というタブを押して以下に記述したjsonを貼り付けてください。
ポリシー設定用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ポリシーをアタッチできます。気が向いたらそちらも書く予定です。
好みの名前を入力してポリシーを作成します。
この後はお好みの設定でユーザを作成してください。
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 deploylambdaコンソールからアプリケーションがデプロイされているのを確認できれば完了です!
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 deletehttps://rubyonjets.com/reference/jets-delete/
まとめ
まだまだ書きたいことがたくさんあるのですが、とりあえずデプロイするところまで
行けました!!
引き続き気づいたことや詰まったことは発信していきたいと思います。
- 投稿日:2021-01-06T21:05:31+09:00
【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)まとめ
- バイナリーサーチとはソート済みのリストや配列に入ったデータを検索するときに使用する手法
- 二分割しながら値を絞り込む
参考文献
- 投稿日:2021-01-06T20:40:02+09:00
【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」
に当てはまるか確認しています。
他にこんなやり方があるよ!と教えてくださる方がいらっしゃいましたら、是非ご指摘いただけると幸いです!!
- 投稿日:2021-01-06T20:38:09+09:00
git push herokuし、herokuのURLを開くとMethod Not Allowedが出る問題
問題
git push herokuすると以下のような表示が出ますよね
ここの下から2行目を開くとMethod Not Allowedがでます。解決法
上の写真の下から2行目はgit用のファイルなので、remote:の後のURLを開きましょう。
リンクを確認せずに開くとこういうことになってしまいます。
気をつけましょう(戒め)ちなみに
このgitのリンクはデプロイ用のgit repositoryらしいです。
なんらかの問題があった場合の最終手段としてcloneしたりするのはいいらしいですが
正規の”オリジン”リポジトリとしては使用してはいけないそうです。
詳しくは以下のリンクを参照してください。参照
- 投稿日:2021-01-06T19:54:53+09:00
ニコニコ動画apiを使って埋もれてる面白い動画を発掘する
はじめに
- ニコニコが好きなので作ってみました。
背景
- ニコニコ動画のとりあえずマイリストの廃止で動画のマイリスト数が激減した
- マイリストは面白い動画を見分ける判断材料になっていたのでとても残念
- とりマイの代わりにできた「いいね」の数はなぜか非公開(意味がわからない)
- 良質な動画を発見する機会と材料がなくなった
概要
- ニコニコのスナップショットAPIを使って、動画のタグ検索を行い動画リストを作成する
- 埋もれている動画の基準として、"(コメント数+マイリスト数×100)/再生数"が60%以上で、かつ再生数が500以上の動画
- csvファイルにて出力
開発環境
- 言語
- ruby
検索例(一部)
"実況プレイ動画"タグで検索。
対象の投稿日時は、2020年1月から12月末まで。
全部で1053件の動画が抽出されました。
最後に
スナップショットapiは一度に取得できる動画の数が最大100でyoutubeDataAPIのようにnext_page_tokenがなく、大量のデータを取得するには指定した日付で1週間ごとのループ行ったが少し面倒だった。
とりあえずマイリストを消した運営の判断は本当に意味がわからないし、いいねも機能しているとは思えない。いいね数を開示するか、いいねとマイリストを合算した数を開示しないと、いいねをする理由にはならないと思う。(ユーザーがいいね機能を使う理由が今のところ存在しない。)
- 投稿日:2021-01-06T19:49:15+09:00
【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.ymlversion: 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について: circleCIDeveloperorbsorbs: 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について: circleCIDeveloperorbsorbs: 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も環境変数を参照するように設定
jobsdocker: - 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"?
step
でcommand
を実行
サービス起動まで待機:dockerize を使って他のコンテナ内サービス起動を待つstepssteps: - 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を指定して自動でテスト&コードチェックが実行される
workflowsworkflows: 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の部分を適宜コンテナ名に変更?コミットしてみて動くか検証
- 投稿日:2021-01-06T14:02:54+09:00
【Rails】シングルテーブル継承を使って、テーブルの数を削減する【STI】
シングルテーブル継承(単一テーブル継承、STI)とは
シングルテーブル継承(以下、STI)は、単一の継承階層に所属するクラス群を、ただひとつのテーブルを使って永続化する手法です。
言葉だけでは伝わリにくいので、下図を御覧ください。
Postsテーブル(スーパークラス)が、サブクラスに継承する形になります。
しかし、注意点が2点あります。
- Books,Clothes,Goodsテーブルは実際には存在しない。
- 個々のデータはすべてスーパークラスのテーブルに保存されます。この場合はPostsテーブル。
それでは、STIはどういう場面で使えばいいのでしょうか。
STI継承しないと中間テーブルが再生産が起きる
自分はSTIの存在を知らずにアプリを作っていったら下図のようになってしまいました。
・・・。
PostsテーブルとしてはBooksとClothesとGoodsの記事を作りたかったのですが。。。
それぞれのテーブルを作ってしまうことで、それぞれの中間テーブル(ここでは、Comments,Likes,Pickupテーブル)が再生産が起きてます。
機能自体はできましたが、ゴチャゴチャしすぎて保守的には最悪ですね・・・。
何より新機能をつける度に3つテーブルを用意する必要があり、骨が折れます?そこで!STIを使い、Postsクラスをサブクラスに継承させました!
以下の通りです。めっちゃスッキリしましたね!
(画像にはBooks,Clothes,Goodsはテーブルとして書いてありませんが、継承させています。)
これで保守がしやすく、新機能もつけやすくなりました!やり方(結論)
1. スーパークラスを作る
rails g model post
でマイグレーションを作成し、テーブルの設定をします。migrate/〇〇_create_posts.rbclass 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.rbclass Post < ApplicationRecord belongs_to :user #省略 endそれでは
rails g model book --parent=Post
でbookモデルを作成します。
--parent=PARENT
オプションを使うことで、マイグレーションファイルを生成せずに済みます。models/book.rbclass 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
- 投稿日:2021-01-06T12:32:44+09:00
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)よって、前述のコードでは
max
がnil
となる場合、無限ループとなる。じゃあどうしたら?
以下のように
#upto()
のループに置き換える0.upto(max) do |i| # 何か処理 end
max
にnil
が入る余地を無くすというのも手ですが、そもそも無限ループしない書き方にしたい。
upto
にnil
を渡すと例外が発生するので、少なくとも無限ループすることはあり得ない。
- 投稿日:2021-01-06T12:32:44+09:00
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)よって、前述のコードでは
max
がnil
となる場合、無限ループとなる。じゃあどうしたら?
以下のように
#upto()
のループに置き換える0.upto(max) do |i| # 何か処理 end
max
にnil
が入る余地を無くすというのも手ですが、そもそも無限ループしない書き方にしたい。
upto
にnil
を渡すと例外が発生するので、少なくとも無限ループすることはあり得ない。
- 投稿日:2021-01-06T09:48:16+09:00
[Gem不要!!HTML&CSSのみ]初心者が簡単にドロップダウンメニューを作成する方法
はじめに
ハンバーガーメニューやドロップダウンメニューの作成をしたいけど、Gem導入の方法がよくわからない・JavaScriptは思うようにいかない。
そんな初心者の方におすすめの記事なっております。開発環境
・Rails6.0.0
・MySQL5.6.50ドロップダウンメニューの実装
早速ドロップダウンメニューの実装の方法の流れを解説します。
ちなみにドロップダウンメニューとは以下のようなメニューのことです。「...」 を押すとメニューが表示されるものです。
よく見かけますが、JavaScriptでやるには面倒だし、Bootstrap導入のためにGemやjQueryを導入したりするのは初心者には中々ハードルが高めかなと思います。
それでは解説していきます。
1)application.html.erbで初期設定
まず
app/views/layouts/application.html.erb
でBootstrap
など必要なものを読み込みます。以下は僕がドロップダウンメニューを作成した際に使用した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のスキルの一部を見に付けてみてはいかがでしょうか。参考文献
- 投稿日:2021-01-06T09:19:27+09:00
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
と言われているのですが、特にどこにも書いていません。
また.zshrc
でexport 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が原因かも
- 投稿日:2021-01-06T03:16:11+09:00
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 君の存在を知ってしまった
もっといい方法あったら誰かがコメントしてくれると思った
- 投稿日:2021-01-06T01:40:44+09:00
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パターン
- Template Method
- Strategy オブジェクト
- Observer パターン
- Composite パターン
- Iterator パターン
- Command パターン
- Adapter パターン
- Proxy
- Decorator パターン
- Singleton
- Factory Method
- Abstract Factory
- Builder パターン
- Interpreter
Rubyの中のパターン
- 内部ドメイン特化言語
- メタプログラミング
- Convention over Configuration(CoC)
- 投稿日:2021-01-06T01:13:50+09:00
【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/×Gold)
Silver試験のみですが対策問題集を解くことができます。こちらは問題が決まっています。
Rexである程度解けるようになったら、補完できていなかった知識を埋めるのに役立ちます。
- CTC(×Silver/○Gold)
こちらはGold試験のみですが対策問題集を解くことができます。
ミニツク同様の使い方で大丈夫です。
- 公式Silver模擬問題集(○Silver/×Gold)
公式がSilverしか問題集を出していない。あまり納得できないがこればかりは仕方ない。
問題は易しめではあるが、非常に似た問題が試験に数問出ていたので、解くべき。
- ruby_silver_all.md(○Silver/×Gold)
m-haramoto(@HaramotoReo)さん作のSilver対策問題集
各classごとに分かれた問題で、非常に良問揃い。
こちらも試験2週間くらい前に手をつけて知識の抜けを埋めるのに非常に役立つ。
- Ruby Association Certified Ruby Programmer Examination(○Silver/○Gold)
問題が英語なので初見殺しだが、意外と意味もわかりつつ解ける。
こちらも知識の補完。本試験でここの問題を解いていなかったら落としていた問題も数問あったので、見つけて助かった。【その他】
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でプログラミングを始める人の何かの参考になれば嬉しい。
- 投稿日:2021-01-06T00:08:34+09:00
putsとprintの違い
Progateでpythonの勉強をし始めたら、「print」というのが出てきた。
python特有の物かと思ったら、Rubyでも普通にあるみたいで。。知らなかった・・!
自分用のメモとして記録しておく。■主な違い
・改行するかしないかputs→出力後改行
print→出力後改行しない
- 投稿日:2021-01-06T00:00:19+09:00
Ruby:クラスメソッドとインスタンスメソッド、クラス変数とインスタンス変数の違い
クラスメソッドとインスタンスメソッドの違い
まずRubyのクラスメソッドとインスタンスメソッドの違いを見ていきます。
クラスメソッドとは
クラスメソッドを定義したクラス自身が使用できます。クラスで共通の情報を使った処理に使用します。インスタンスがなくても呼び出すことができます。
クラスメソッドを定義する際は、
self.メソッド名
と記述します。以下のようにクラス名Fruits
から呼ぶことができます。また、インスタンスを生成するnew
メソッドは、代表的なクラスメソッドです。fruits.rubycalss Fruits def self.call #selfはクラス自身を指す puts "クラスメソッドを呼び出しました" end end Fruits.new #newメソッドもクラスメソッドの1つ。 Fruits.callターミナルで上記のrubyファイルを実行すると次のような結果になります。
ターミナルruby fruits.rb クラスメソッドを呼び出しましたFruits.callの実行結果が表示されます。
Fruits.newは空のインスタンスが生成されるだけなので実行結果には表示されません。インスタンスメソッドとは
インスタンスが使用できるメソッドで、クラス内に定義します。
「インスタンスメソッドを定義したクラス」から生成されるインスタンスが使用できます。fruits.rubycalss Fruits def call puts "インスタンスメソッドを呼び出しました" end end fruits = Fruits.new fruits.call #.でつなげて下記のように呼び出すこともできます。 Fruits.new.callターミナルruby fruits.rb インスタンスメソッドを呼び出しましたinitializeメソッド
initialize
メソッドは、new
メソッドによってインスタンスを生成したと同時に実行される処理を定義できるインスタンスメソッドです。
実は、クラスに記述しなくてもinitialize
メソッドは自動で実行されており、この場合は何も処理がされません。fruits.rbclass Fruits def initialize puts "インスタンスが生成されました" end end Fruits.newターミナルで上記のrubyファイルを実行すると次のような結果になります。
ターミナルruby fruits.rb インスタンスが生成されました
Fruits.new
でインスタンスを生成した後にinitialize
メソッドに定義した処理が実行されたことがわかります。クラス変数とインスタンス変数の違い
次にクラス変数とインスタンス変数の違いを見ていきます。
クラス変数とは
そのクラス内で定義される変数で、
@@変数名
と記述して定義します。クラス変数は、クラスとして共通の変数を定義したいときに使うのに適しています。fruits.rbclass Fruits @@fruit = "オレンジ" #initializeメソッド内で使用するために、インスタンス生成前に定義 def initialize puts "私は#{@@fruit}が好きです" end end Fruits.new実行結果
ターミナルruby fruits.rb 私はオレンジが好きですクラスメソッドの特徴として、一度定義すればクラス内のどこでも使用することができます。
fruits.rbclass 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.rbclass 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
メソッド で定義したインスタンス変数@fruit
がdislike
メソッドでも使用できているのが確認できます。参考資料