20210501のRubyに関する記事は27件です。

【結論】Live serverはHAMLを表示できません

タイトルで結論が出てますが、一応解説します。 前提 ・Live severを起動してもファイル画面が表示される。 ・Setting.jsonの記述は完璧 config.json "liveServer.settings.port": 5000, "liveServer.settings.CustomBrowser": "chrome", "liveServer.settings.ChromeDebuggingAttachment": false, "liveServer.settings.fullReload": true, "liveServer.settings.donotShowInfoMsg": true, 原因 HAML は、Brackets がアクセスできないサーバーサイドの状態を参照できるテンプレート言語なので、サーバーサイドの HAML ページをリアルタイムで Live Preview 更新しながら編集するのは複雑です。 あと自分が英語のイシューを避けてたことも原因でした。 日本語でぱっと見記事がなさそうな時は英文のソースも積極的に見ていきたいと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

初心者のためのRuby on Rails環境構築

Ruby on Rails 環境構築 この記事の対象者 ローカル環境でRailsで環境構築を初めてする人 mac 使っている人 Railsチュートリアルや入門レベルで環境構築したことがある人 環境 mac Big Sur Version 11.3 Ruby 2.5.1 Rails 5.2.5 ターミナル bash zshになっている場合は(%で始まる)ターミナル設定からbash($で始まる)に切り替えてください ここからターミナルで行う作業は最初のほうはホームディレクトリで進めてください。 参考書籍 現場で使える Ruby on Rails5 速習実践ガイド(5.2対応) Command Line Tools for Xcodeをインストール $ xcode-select --install - これはHomebrewを使うためにインストールします。かなり重たいのでストレージを気にしてください。 インストールできたら $ xcodebuild -version で確認。 ここで僕はエラーが起きたのですが どうやらXcodeのインストールが必要だったみたいなのでお忘れなく。 Homebrewのインストール Homebrewとは ではHomebrewをインストールしていきます https://brew.sh/index_ja のページに行って/bin/bash....という文字が並んでいるところがあるのでこれをコピペしてターミナルで実行してください。 $ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" インストールできたら $ brew doctor でインストールが正常にできているか確認。 Your system is ready to brew.みたいなことがレスポンスとして返ってきたら問題なしです。 rbenvをインストール $ brew install rbenv rbenvコマンドを利用できるようにする パス設定と初期化処理を.bash_profileに追加。 $ echo 'export PATH="$HOME/.rbenv/bin:$PATH"'>> ~/.bash_profile $ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile これをやる理由 https://qiita.com/1000ch/items/a61e65fe82d8bdea840e Rubyのインストール $ rbenv install 2.5.1 インストールが終わったら、システム全体で使用するRubyのバージョンをrbenvに変更する。 $ rbenv global 2.5.1 最後に正しくrbenvでインストールしたバージョンのRubyが利用できるか確認する。 $ ruby -v $ which ruby ここでうまく行かなかったので、以下の記事を参考にしたら解決できました! Rubyのパッケージ管理ツール「RubyGems」をアップデート Ruby本体だけでも動作するが、公開されているライブラリを使うことでより、生産的にプログラムを書いていくことができる。 最新版のシステムにアップデートしておきます $ gem update --system Bundlerのインストール Bundlerとはgem(ライブラリ)を束ねてどのgemのどのバージョンが必要なのか明示してくれる仕組み。 $ gem install bundler Railsのインストール $ gem install rails -v 5.2.5 Node.jsのインストール WebアプリケーションのフロントエンドにJavaScriptを使う場合、効率よく配信するためにJavaScriptを圧縮するのが一般的。 Railsにもその機能は備わっているが、JavaScriptランタイムが必要なのでNode.jsをインストールする。 $ brew install node データベースのインストールとセットアップ postgresqlのインストール $ brew install postgresql 正しくインストールされているか確認 $ postgres -V(Vは大文字なので注意!) PostgreSQLを起動する $ brew services start postgresql PostgreSQLサーバを立ち上げたらコンソールに入って動作確認 $ psql postgres control + Dで脱出できます PostgreSQLを停止する $ brew services stop postgresql Gemfile編集 https://bamboo-note.tokyo/Ruby/rails-new-error-messages/ この記事をみてGemfileを編集してください アプリケーションを新規作成 rails newでアプリの雛形を作成。データベースをpostgresqlに指定 $ rails new アプリ名 -d postgresql これでアプリフォルダが自動生成されるので、アプリフォルダに移動 $ cd アプリ名 データベース作成 PostgreSQLを起動した状態でデータベース作成コマンドを実行 $ bin/rails db:create railsコマンドではなく、bin/railsにしている理由は、アプリのルートディレクトリ直下のbinディレクトリにある railsというスクリプトを呼び出している。このスクリプトを使うと「bundle exec rails」として実行した時と同様に Gemfile通りのgemを使える環境上でコマンドを実行できるようになります。 サーバ立ち上げ $ bin/rails s ここからアプリの開発を進めてください! おつかれさまでした!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

webサービスを個人で開発・運営するときに知ってほしい6つのこと【個人開発】

初めに 自分が今まで個人開発をしてきて学んだこと、考えたことをまとめます。 筆者について webアプリを作るのが好きでここ一年間、公開したものだけで15個はあります 最近作ったもの(宣伝も兼ねて) AmmotというSNSで、コンセプトは「制限の少ない自由な投稿を」です。 「ツイッターは文字数制限がきつい、ただfacebookは実名制だしデザインがごちゃごちゃでいや」 という声を聴いたので作ってみました。 文字数制限が6000字まで、画像・動画・音声は同時に10個まで投稿可能です。 詳しくはこちらも見てください 1.アイデアを出す方法 一番いいのは自分が困った経験を思い出すことです。 「○○あったらいいのになぁ」「○○がなくなればいいのになぁ」など 特に「このサービス使いにくいなぁ」とか結構いいかもしれません。 そのサービスを使ってる人はある程度自分が作ったサービスに興味を持つだろうし、使う人(ペルソナ)が絞られているので。 ただし急にそんなことを思い出そうとしてもなかなか出ないので、日ごろからメモをしたり 付箋に適当なことを書きまくってそれをグループ分けして要らないものをそぎ落とし、残ったものを順序よく並べて整理するという方法もあります。(KJ法と言われています。) ↓自分の日ごろのメモ まともなアイディアがありませんね。はい アイディア出しの注意 めちゃ個人的意見ですが 基本的には悩みを解決するタイプ以外のwebアプリは使われにくいです。 理由は二つ。 1.検索されないから。 「なんかおもろいwebサービスないかなぁ」で検索されることはほぼないです。 ユーザーがwebサービスを探す理由は基本的に困ったことがあるからです。 2.実際に使ってくれる人が少ない 緊急でもないので 「面白そうだな」とは思ってもそこから実際に使ってくれる人は非常に少ないと思います。 そう考えるとBoketeってすごい 2.開発する前のアイディアの確認 開発する前に確認するべきことは大体こんな感じ 自分はそのサービスを使うか。 なぜそのサービスを作りたいのか。 悩みをどうやって解決することができるサービスでしょうか。 最初は日本語だけで運営可能か 個人で管理できるか ほぼコンテンツがいらない or 自分で初期コンテンツが作れる 1~2年は運用できそうか 差別化はできそうか ユーザーにどんな体験を与えるか 一番重要なのは「自分はそのサービスを使うか」です。 自分が使うサービスは成功しやすいです。 開発してる時もユーザーの気持ちなどをいちいち考えず「自分がどうしたら使いやすいか」という主観的な目線で作れるからです。 ただ注意してほしいのは「これは自分も使う!」と思って開発したが結局自分は使わなかったというパターンです。 これを防ぐのは結構難しいですが、いったん休憩をしてみて落ち着いた状態でもう一回そのアイディアを見つめなおすと良いかもしれません。 3.開発中 意識してるのは2つ デザインを重視する これは結構意見が分かれがちですが僕はデザインはかなり重要だと思ってます。 最初はデザインなんて適当でいいやと思っていましたが トップページのデザインは、ユーザーがどのくらい登録してくれるかに大きく左右します。 動作速度を見る railsは素の状態で使うと結構遅いので工夫が必要です。 僕がやってるは countメソッドを使わない キャッシュを使う scriptにはasync属性を付ける turbolinksは絶対に外さない render collectionを使う くらいですかね。 それでもAmmotはそこそこ遅いので困ってます。 4.リリースしたら qiita service-safari zenn note つくログ twitter 最低でもこのくらいは宣伝したほうがいいです。 無料で宣伝できるところがあったらなんでもやるくらいの心がけで挑みましょう。 名言: 宣伝はやりすぎるくらいがちょうどいい 5.少し過疎ってきたら... 内容を変えて再度、qiitaやnoteに宣伝してみる。 ログインをしないとコンテンツが見えないようにする 投稿時刻などを見せない など ツイッターやQiitaではスパム報告をされない程度に全力でやりましょう。 過疎ったということは一度は人を寄せ付けたということですから。 6.諦めるタイミング 何度も宣伝したが無理... 完璧に過疎った...PV数0 某掲示板製作者のひ○ゆきという方が言っていました 「口コミで広がらないサービスは伸びない」 宣伝をしたら最低でも100人くらいの人が作ったwebアプリを見てくれると思います。それを何度かやって無理なら、あきらめましょう。 期間でいえば大体1月くらい公開・宣伝して全く無反応だったらやめましょう。 愛着があるサービス程、閉鎖は悲しいと思いますがあなたの中でその失敗の原因を探して今後に生かせば失敗しても「作ってよかった」といえる日がくるはずです。 まとめ 一番重要なのは 自分が使うサービスを作ろう ただそれでも失敗することはあるので webアプリを当てるのは結構難しいのでへこまず前へ進もう。 数を作ろう(そのためにスピードを上げよう) 最後に僕の作ったAmmotもぜひ使ってみてください! AmmotのURL https://ammot.net/ 僕のAmmotのアカウント https://ammot.net/user/yamada(%E9%96%8B%E7%99%BA%E8%80%85) 僕のツイッターアカウント https://twitter.com/yamada1531
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】実務未経験の介護士が共同開発に参加して学んだこと

0. はじめに はじめまして! この記事では、「実務未経験の介護士の私が Rails 共同開発に挑戦し、そこで学んだことや躓いたこと、反省した点」などについてまとめています。 チームでの開発現場経験を積むことで、「コミュニケーションの適切な取り方」や「わからない部分の質問の仕方」、「コンフリクトの解消の仕方」など、一人での学習では決して学ぶことのできない貴重な経験を積ませていただくことができました。 今回はそのような共同開発の現場で実際に学んだことをまとめて、今後の自分の成長につなげることができたらなと考えております! 1. 自己紹介 まずは簡単な自己紹介からさせて頂きます! スペック 27歳 介護士 → エンジニアを目指している駆け出しエンジニア 学習中の言語:Ruby, Ruby on Rails 今後学習予定の言語や知識:Javascrict, AWS 趣味 カラオケ(高音域が出ないことが悩みなので、いつかボイストレーニングを習いたい) 野球(球速は遅いが、コントロールには安定感がある) 筋トレ・運動全般(毎日頑張っています?) メンタリストDaiGoさんの動画を視聴しながら、実用的な技術を生活に取り入れる 性格 介護士として忍耐強く働いてきたということもあり、衝動的な性格から理性的に行動するように。 比較的、温厚な性格だと思う。 2. 今回の共同開発に参加しようと思った動機 まず、「なぜ今回の共同開発に参加しようと思ったのか?」の根本的な動機の部分を述べさせて頂きます。端的に言うと、以下のものを「得たい!」と思ったので、共同開発に参加させて頂きました。 コミュニケーションスキルの向上 チームでの開発経験 問題にぶち当たった時に自分で原因を特定し、解決を図るための「自走力」 試行錯誤した上でどうしてもわからない場合、素直に質問できる柔軟性 これらのものを「共同開発」に参加することを通して獲得したいなと思いました。 結果的に、特に「コミュニケーション」の部分に関してはスキルの向上ができたのと、以前よりもより自信を持つことができた気がします。 ここについての具体的なやり取りに関しては後述させて頂きます! 3. Rails 共同開発で取り組んだ内容 共同開発で取り組んだ内容を簡単にご説明していきます! 成果物 今回の共同開発では「ECサイト」の購入者視点の画面の実装に取り組みました。 概要 開発期間:3/1 ~ 4/30(2ヶ月間) 週1回のチームミーティングを行い、進捗状況の確認を行う 週2~3回の作業会を行い、それぞれわからないところを質問し合う 構成メンバー 講師・TA:現役エンジニア2名 共同開発メンバー:現役インフラエンジニア1名、未経験2名 使用した言語・技術 バックエンド Ruby(バージョン:2.7.1) Ruby on Rails(バージョン:6.0.3.5) フロントエンド HTML5 CSS3 Bootstrap(5.0.0.beta2) インフラ Docker docker-compose データベース MySQL2(0.5.3) 使用したツール・環境 Slack:レビュー依頼、進捗状況の確認、日報の共有などをしました。 GitHub:タスク管理・確認、プルリクエストを出す、コードレビューを受ける、受けた指摘に対応し、コミットを出すなどをしました。 Googleドライブ:モックアップ、基本設計(ER図/画面遷移図)、画面定義書などのファイルを管理・共有のために使用しました。 Git / Sourcetree:コミットやプッシュなどの git 操作をするために利用しました。 Sequel Pro:DB を視覚的に管理できるツール Boost Note:「1タスク1メモ」といった感じで、学んで点や躓いた点を随時メモしました。 DeepL:英語対策のための翻訳アプリ 使用したエディター:Visual Studio Code 使用したPC:Mac ER図 実装した機能 新規ユーザ登録機能 ログイン / ログアウト処理 商品検索 商品詳細へ カートへ カートを開く 購入確定 Top画面に戻る 履歴を開く 注文検索 注文キャンセル ユーザ情報を開く ユーザ情報修正 / 退会処理 修正確定 GitHub https://github.com/quest-academia/qa-rails-ec-training-violet 4. Rails 共同開発で私が担当した箇所 ①ユーザー登録ページ 「お客様情報登録」にお客様(ユーザー)が登録に必要な情報を入力するためのページを作成しました。 ②商品詳細画面 ■ 商品が存在する場合 ■ 商品が存在しない場合 「商品詳細画面」を商品が存在する場合と存在しない場合の二つに分けて、それぞれの画面が表示されるようなページを作成しました。 ③商品検索画面 ■ 検索結果にヒットする商品が存在する場合 ■ 検索結果にヒットする商品が存在しない場合 「商品検索画面」に検索フォームや商品の一覧、ページネーション機能などを入れて、お客様(ユーザー)が商品を検索できるようなページを作成しました。 5. 【必ず身に付けておきたい】 講師に学んだプルリクエストの出し方 共同開発では、開発業務以外にも Git や GitHub の操作方法がとても学びになりましたが、その中でも特に「 Pull Request(プルリクエスト )の出し方」が個人的には参考になりました! 今後の開発を進めていく上での基礎として、必ず身に付けておきたいと思いました。 ▼ プルリクエストを出す際の雛形となるテンプレート 以下は講師が提供してくださったテンプレートを元に僕が作成したプルリクエストの一例です。 プルリクエスト出す際は、以下のようなフォーマットをもとに作成しました。 プルリクエストの最終的な確認項目 このプルリクエストで実行したこと(概要) 対象 issue 重点的に見て欲しいところ(不安なところ) 実装できなくて後回しにしたところ チェックリスト(動作確認・ rubocop の実行など) その他の参考情報(参考にした記事のリンクなど) このようなフォーマットを元に書くことによって、レビュアーの方にとってわかりやすいプルリクエストの作成に繋がると感じました。 特に「重点的に見て欲しいところ(不安なところ)」の項目では、「問題に躓いた時にうまく人に頼れるスキル」も大事になって来ると思うので、不安だったことについては小さなことであっても、必ず書くようにしました。 また、予想完了時間や実質完了時間、作業内容、納期などもタスクに取り組む前に予測・設定しました。実務では「担当するタスクを細かい作業項目に分解して、一つずつ取り組んでいくスキル」が必要になってくると思うので、思いつく限りのことはなるべく言語化して書くようにしました。 作業内容は、最初は全ての作業項目を洗い出すことはできず、取り組みながら後から修正を加えたりしました。 ただ、プルリクエストを出してマージされるまでにかかった時間が、予想完了時間を大幅に超えてしまっていたり、納期が遅れてしまったりしたことは反省点です? はじめから無理な目標を設定しすぎない方が良いと思いました。 ▼ 1指摘1コミット また、コードレビューを受ける際は「1指摘1コミット」でやり取りをするようにしました。つまり、複数の指摘を同時に受けたとしても、対応する際は一つずつコミットを出して個別に対応していくということ。 これは講師の方から「意外と知らない人が多いけど、大事なこと」として教わりました。 以下のような感じです↓ 基本的なことかもしれませんが、こう言った基礎的なことが個人的にはとても大事になってくると思うので、今後も実践を通して身に付けていきたいです。 6. Rails 共同開発で躓いた点・大変だったこと 共同開発において躓いたことや大変だったこと、またそれに対する僕の対応です! 主に、以下の2点でつまずきました。 ① コンフリクトの発生 ② if文を用いた View ファイルの条件分岐 ① コンフリクトの発生 コンフリクト発生に関しては、共同開発が始まった初っ端から躓いてしまい、かなり焦りました? まだ始まったばかりなのにいきなり難しい問題に出くわして「自分にはやっぱり向いてないんじゃないかな・・・」と勘違いしてしまった記憶があります? その時はなんとか解決したいと思い、検索を繰り返し問題への対処に当たりました。 とりあえず問題の理解と解決策がなんとなく理解できたので、それを実行しようと思う意思とそれが今後の開発にあたり問題のない対処法かどうかを確認をしたかったので、講師の方に質問してみました。 以下が僕が講師の方に質問させていただいた際のやり取りの記録になります。 僕からの講師への質問 (Slack より引用)文字が小さくてすいません? この質問への講師からの回答は1往復で済み、なんとか「コンフリクトの解消」にまで至りました! とても嬉しかったですし、次回以降同じような問題に出くわしたとしても、以前のように無駄に焦ったりはしなくなりました。 ② if文を用いた View ファイルの条件分岐 「if文を用いた商品に関しての条件分岐」については、 html.erb 内で if 文を使って「商品が存在するページ」と「商品が存在しないページ」に分岐することができるようにするタスクだったのですが、メソッドの書き方が間違っており、苦戦しました。 苦戦したコードの内容:商品テーブルから指定されたIDの商品の詳細を取得する 本来はコントローラー内で以下のように記載しなければなりませんでした。 def show @product = Product.find_by(id: params[:id]) end しかし僕は、以下の二つの間違いをずっと繰り返していました。 def show @product = Product.find(params[:id]) # ← find_by を使ってない end def show @product = Product.find_by(params[:id]) # ← find_by の引数にカラム指定をしていない end 最終的には講師の方に記述ミスを指摘してもらい、解決に至りましたが、「find_by メソッドを使う時はカラムを指定する」というところがすっかり抜けていました。 このようにコードの記述ミス然り、アルファベットの記述ミスやファイル名の命名違い、全角スペースでのインデントなど、細かいミスがまだまだ目立つなと思いました。 今後はこのようなミスをできるだけ少なくできるよう、必ず独自の「メモ」を取るようにして、同じ間違いを繰り返さない工夫をしたいと思います。 7. Rails 共同開発に参加して良かったこと 2021年3月頃までは僕は主に一人でプログラミング学習に取り組んでいました。 しかし、将来的にもしエンジニアになることができたら、一人での開発ではなくチーム単位での開発となり、お互いの進捗状況を確認しあったり、わからないことを相談しあったりするなどと言った「協調性」が必ず必要になってくると思いました。 そのため、早めにそのスキルを身につけておくことによって、「技術面でのサポート」はどうしても頂かなければならない時が多々あるかと思いますが、そのような技術的なサポートをして頂く際の「質問力」であったり、互いにスムーズで円滑なやりとりを行うための「コミュニケーション能力」の面においては、なるべく一緒に仕事をさせていただく方々の負担にならないようにしたいなと思いました。 また、個人的に「チーム単位での活動」や「誰かと協力すること」、「コミュニケーション能力」にいささかの不安があったため、実際の現場に近い環境で現役のエンジニアさんやチーム開発参加者たちと共に「テキストベース」や「 ZOOM などでお互いに顔を合わせた状態でのコミュニケーション」に積極的に参加して場数を踏むことによって、苦手分野を克服したいなと思いました。 たとえここで失敗したとしても、苦手分野の克服に挑戦したことによって自分なりの改善策や解決策などのデータが得られると思ったので、積極的に挑戦して行くべきだと判断しました。 ありがたいことに今回の共同開発では、みなさん向上心があり親切な方々ばかりだったので支えて頂いたことの方が多かった印象があるのですが? 、それでも僕なりに役に立ちそうな情報は共有するようにしたり、読み手に負担をかけないわかりやすい文章を作成することにとても神経を使いました。 この経験によって、コミュニケーションのスキルが今までよりも段違いに向上したのではないかと思います。 8. さいごに【まとめ】 今回この「共同開発」というものに参加させてもらうことによって、 コンフリクトの解消 GitHub の見方・操作・やりとりの仕方 Git の操作やプルリクエストの出し方 開発するものに対する意思の疎通や進捗状況の確認 タスクへの取り組み方や管理の仕方 などの個人での開発・学習では決して学ぶことのできない多くのことを学び、経験させていただきました。 また、現役のRailsエンジニアの方からは「技術力は正直まだまだ足りてないですが、コミュニケーションの取り方はハイレベルですね」といった評価をして頂けたのはとても嬉しかったです! 今後はこれらのことをよりスムーズにできるようにブラッシュアップさせて、実務に入った時に周りの方々に「この人との仕事は余計なストレスがないし、スムーズでやりやすいな」と思ってもらえるように、備えて行きたいと思います。 拙い文章でしたが、最後までご覧頂き、ありがとうございました! Twitter :@kunikuni2992
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails] Rspecでテストコードの実装①

はじめに 本日より何回かに分けて、テストコードに関しての知識をこちらでアウトプットできればと思います テストの必要性 絶対に壊れない機械がないように、絶対に不具合のないシステムはありません。しかし、サービスの一時停止や不具合は、サービスへの信頼度を著しく下げ、ユーザ離れを引き起こします。(もっといろいろな問題はありますが) こうした問題を起こさないように、ちょっとでも防ぐためにテストを行います。例えば、何か新しい機能を追加した時に他の機能との競合を確認しないままリリースしてしまえば、メイン機能が止まる可能性もあるわけです。とはいえ、毎回機能実装のたびに手動で確認するのは非効率でミスが起こりやすいです。そこで活躍するのが、テストコードです。 テストコードとは。 テストコードとは、動作を確認するためのコードを書くことで、自動で挙動確認するという方法です。こうしたコードをテストコードと言います。Railsにおいては、今回、テストコードの実装にはRspecを使います。 基本的に、境界値分析など様々なテストケースの考え方があります。この記事では、特にわかりやすい正常系と異常系のテスト行います。 正常系 「ユーザーが開発者の意図する操作を行った時の挙動」をテストするもの 異常系 「ユーザーが開発者の意図しない操作を行った時の挙動」をテストするもの テストの種類 テストは大きく分けて単体テストと結合テストの2つがあります。 単体テスト モデルやコントローラーといった機能ごとのテスト。例えば、バリデーションが本当に機能しているかなどを調べます 結合テスト ユーザーがブラウザで操作する一連の流れを再現して、問題がないか確かめます。例えば、「ユーザはログイン情報を入力し、送信ボタンを押したら、成功した旨が表示されマイページにと遷移するかどうか」を確認したりします。 テストコード実装準備① テストコードの実装には、Rspecというgemを使用します。早速インストールしましょう。 Gemfileに以下を記載しましょう group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] gem 'rspec-rails', '~> 4.0.0' end ターミナルでbundle installを忘れないように!!!! 次に、Rspecの設定をします。 以下のように、コマンドを打ってください。 rails g rspec:install このコマンドで生成されたファイルのうち.rspecファイルを開き、以下のように記述します。 テストコードの結果をターミナル上に可視化するための記述です。 --require spec_helper --format documentation テストコード実装準備 ここからはUserモデルのテストコードを書く準備を行います。 rails g rspec:model user これを行うと、以下のファイルが生成されます。 spec/models/user_spec.rb require 'rails_helper' RSpec.describe User, type: :model do pending "add some examples to (or delete) #{__FILE__}" end これからはこのファイルにテストコードを記述していくこととなります。 ちなみに、一行目のrails_helperはRspecを用いてRailsの機能をテストするときに、共通の設定を書いておくファイルです。各テスト用ファイルでspec/rails_helper.rbを読み込むことで、共通の設定やメソッドを適用します。 rails gコマンドでテストファイルを生成すると、rails_helperを読み込む記述が、自動的追加されます。 おわりに 今回は一旦概念の理解と準備までを完了しました! 次回は実際にテストコードを実装していきましょう!!!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails & PostgreSQL]rails db:createをするとPG::InsufficientPrivilege: ERROR: permission denied to create databaseが発生

Postgres初心者です。エラーを解決した備忘録として残しておきます。 環境 Amazon Linux2 Rails 6.0.3 Posgres 11.5 起きていること 本番環境でrails db:createを入力したところ以下のようなエラーが発生した $ rails db:create RAILS_ENV=production PG::InsufficientPrivilege: ERROR: permission denied to create database Couldn't create 'travelour_production' database. Please check your configuration. rails aborted! ActiveRecord::StatementInvalid: PG::InsufficientPrivilege: ERROR: permission denied to create database bin/rails:4:in `<main>' Caused by: PG::InsufficientPrivilege: ERROR: permission denied to create database bin/rails:4:in `<main>' Tasks: TOP => db:create (See full trace by running task with --trace) 解決方法 どうやらデータベースの作成権限がないらしい。そこでpostgresにログインして、権限を付与していく #ログイン $ psql -U postgres ALTER ROLEコマンドでデータベース作成権限を与える postgres=# ALTER ROLE {ユーザ名} WITH CREATEDB; ALTER ROLE その後serviseコマンドで再起動 sudo service postgresql restart これでrails db:createコマンドができるようになります。 rails db:create RAILS_ENV=production Created database `travelour_production`
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CRUDについてのまとめ

CRUD アプリケーションのデータ取り扱いに関して、基本的な処理の頭文字を並べたものです。 アプリケーションの機能は、この4つの処理を組み合わせながら実装します。 C(Create) R(Read) U(Update) D(Delete) 生成 読み取り 更新 削除 Railsでは、CRUDを7つのアクションに分割して、処理を実現します。 7つのアクション CRUDを実現するためには、それぞれの処理を記述する必要があります。 Ruby on Railsには、それらのアクションの設定が慣習的に決められており、下記の表のようなアクションが存在します。 アクション名 内容 index 一覧表示 show 詳細表示 new 生成 create 保存 edit 編集 update 更新 destroy 削除 これを本カリキュラムでは、「7つのアクション」と呼んでいます。 これらの7つのアクションのルーティングは、resourcesメソッドを使用することで一度に設定が可能です。 resourcesメソッド resourcesは、7つのアクションへのルーティングを自動生成するメソッドです。 resourcesの引数に、:tweets というシンボルを指定すると/tweetsのパスに対応するルーティングが生成されます。 例】resourcesメソッドの使用例 Rails.application.routes.draw do resources :tweets end 上記のように記載すると、以下のような7つのアクションすべてのルーティングを設定したことになります。 例】resourcesメソッドで自動生成されるルーティング GET /tweets(.:format) tweets#index POST /tweets(.:format) tweets#create GET /tweets/new(.:format) tweets#new GET /tweets/:id/edit(.:format) tweets#edit GET /tweets/:id(.:format) tweets#show PATCH /tweets/:id(.:format) tweets#update PUT /tweets/:id(.:format) tweets#update DELETE /tweets/:id(.:format) tweets#destroy
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby on Rails】途中でカラムを追加・削除する

概要 アプリ作成途中に「追加でこの情報もテーブルに保存したい!」「このカラムはいらん!」と思う時は多々ありますよね、、、 そんな時のために「カラムを追加・削除する方法」を記載しておきます!! (環境構築とモデルの作成はできている状態です) 環境 ruby 2.6.5 Rails 6.0.3.5 【カラムを追加する】 追加するカラム Usersテーブルにnameカラムを追加する ①追加するカラムのマイグレーションを生成 % rails g migration Add[カラム名]To[テーブル名][カラム名:型]  (見本) % rails g migration AddNameToUsers name:string (実行するコマンド) 以下のマイグレーションファイルが自動で作成されます。 db>migrate>〇〇〇〇〇〇_add_name_to_users.b class AddNameToUsers < ActiveRecord::Migration def change add_column :users, :name, :string end end ②追加したマイグレーションファイルをテーブルに反映 % rails db:migrate これでテーブルに新しくカラムが追加されます。 【カラムを削除する】 削除するカラム Usersテーブルのnameカラムを削除する ①削除するカラムのマイグレーションを生成 % rails g migration Remove[カラム名]To[テーブル名][カラム名:型]  (見本) % rails g migration RemoveNameToUsers name:string (実行するコマンド) 以下のマイグレーションファイルが自動で作成されます。 db>migrate>〇〇〇〇〇〇_remove_name_to_users.b class RemoveNameToUsers < ActiveRecord::Migration def change remove_column :users, :name, :string end end ②作成されたマイグレーションファイルをテーブルに反映 % rails db:migrate これでUsersテーブルのnameカラムが削除されます。 参考リンク Railsのデータベースでカラムを追加する方法 -Qiita Ruby on Rails カラムの追加と削除 -Qiita
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsで手軽に静的ページを作る方法

手軽に静的ページを作りたい 個人開発をしていると必要になる「利用規約」「プライバシーポリシー」などの静的ページ そのためにcontrollerを作成してroutesをいじるっていうのは結構手間ですよね? その問題を解決できる「high_voltage」というgemが存在します! gemの導入 gemfile gem 'high_voltage' gemfileに追加する ターミナル $ bundle install コマンドを打ち込むことで「high_voltage」を使える準備が整いました! 使用方法 1.app/viewsのディレクトリの中にpagesというディレクトリを作成 2.app/views/pagesのディレクトリの中にpolicy.html.erbを作成 「policy」には好きな文字列を! 作成したpolicy.html.erbに何か書いておきましょう 以下のURLにアクセスすることでpolicyページが表示されます! http://localhost:3000/pages/policy RoutingErrorになる場合はサーバーの再起動を行ってみてください。 ページのリンクを作成する <%= link_to 'policy', page_path('policy') %> リンクはこのような書き方になります
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ActionView::Template::Error (ActiveStorage::InvariableError)の対処法

エラー概要 記事投稿画面から、画像を選択し投稿した際に起こったエラー。データベースには登録されていたが、ブラウザにはエラー画面が出ていた。 原因 拡張子がHEIC形式のものを投稿した際に、エラーが出ていた。jpgやpngの場合は投稿できた。 解決方法 rais db:migrate:resetをして、データベースにあるものをリセットすると、エラー画面はなくなる。HEIC形式以外の画像を添付すると、エラーは解決された。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

devise機能にカラムを追加する方法

diviseにカラムを追加する方法 deviseの実装後にnicknameカラムを追加したくなったので今回は追加の手順をメモする。まずはDBにあるdeviseのマイグレーションファイルにnicknameカラムを追加する。今回はnicknameなのでstring型で追加する データベースを変更するためにターミナル上でロールバックを行う まずは編集したいdbが何番目にあるか確認する! % rails db:migrate:status database: アプリ名_development Status Migration ID Migration Name -------------------------------------------------- up 20210428012237 Devise create users 今回はまだdeviseのマイグレーションファイルしか存在しないので1つのみUPになっている。❗️ちなみに下から何番目か数える❗️ 次にロールバックのコマンドを記入する % rails db:rollback STEP=○ 今回は1番目なのでSTEP以降の記述はいらない。 その後にもう一度マイグレーションファイルの現状を確認するために先ほどと同様に以下のコマンドを入力 % rails db:migrate:status database: アプリ名_development Status Migration ID Migration Name -------------------------------------------------- down 20210428012237 Devise create users 上記のようにdownになっていれば変更可能の状態になっている。 今回はdeviseのマイグレーションにnicknameカラムを追加したいので以下のコードを記載する # frozen_string_literal: true class DeviseCreateUsers < ActiveRecord::Migration[6.0] def change create_table :users do |t| ## Database authenticatable ここから追加 t.string :nickname, null: false     ここまで追加 t.string :email, null: false, default: "" t.string :encrypted_password, null: false, default: "" 変更が終了できたら、ターミナルでdbをマイグレートする % rails db:migrate これで問題なければ反映されている? 最後に確認でDBのschema.rbに追加したカラムのコードがあれば成功! 感想 4月は学校の新生活やコロナウイルスの騒動であまりプログラミングをできていなかったがGWから時間を確保できるので再開していこうと思う? 今回は初心に帰ってdbの変更方法をQiitaに書いてみた? dbの変更の手順はいつになっても使うことなのでこの記事の手順は絶対に忘れないようにしよう!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

rails -sでサーバの起動ができない

rails -sでサーバを起動しようとするも、 boot.rbファイルがないためエラーが発生 ターミナルには下記のようなエラーが表示されている。 wrong number of arguments (given 2, expected 1) (ArgumentError)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails LINEbot 入門

Rails×LINEbotの実装方法と一連の処理の流れを説明しています。 ※Railsに関しては一通り学習を終えていることが前提 まず一連の処理の流れ ※WEBサーバは何でも問題ないですが、以下の例ではHerokuを使用している想定です。 ①LINEアプリで自分が作成したチャネルを友達登録し、メッセージを送信します。 ②LINEのサーバではそのメッセージを受信し、チャネルに設定したWebhook URLにリクエストを送信します。 ③リクエストを受信したRailsサーバは受信した内容を参照し、色々と処理をした結果、最終的にレスポンスとなるメッセージを作成します。 ④レスポンスメッセージをLINEサーバに返します。 ⑤LINEサーバがレスポンスメッセージをLINEアプリに返します。 一つずつ解説 ①LINEアプリで自分が作成したチャネルを友達登録し、メッセージを送信します。 まずLINEbotを作るにはLINE Developersに登録する必要があります。 こちらから登録しましょう。 LINEアカウントがあればすぐに登録できます。 登録が終わったらまずしなければいけないことは プロバイダーの作成 チャネルの作成 になります。 プロバイダーとは今回の場合、開発者(=自分)のことを指します。 チャネルは要するにメッセージを受け取るための公式アカウントです。 こちらのドキュメントにプロバイダーの作成、チャネルの作成の説明がありますので、確認しながら作成してください。 ※作成するチャネルの種類は「Messaging API」になります。 ②LINEのサーバではそのメッセージを受信し、チャネルに設定したWebhook URLにリクエストを送信します。 さてチャネルを作成したので、LINEアプリから友達登録をしてみましょう。 LINE Developersコンソールから トップ > プロバイダー名 > チャネル名 > Messaging API設定 > ボット情報 を表示すると ボットのベーシックID というのがあり、このIDをLINEアプリで検索することで友達追加することが可能です。 応答メッセージの無効化 現時点でメッセージを送信すると このようなメッセージが返ってくると思います。 今回のLINEbot作成では不要な機能なので、設定を変更します。 LINE Developersコンソールから トップ > プロバイダー名 > チャネル名 > Messaging API設定 > LINE公式アカウント機能 応答メッセージを無効にします。 Webhook設定 LINEサーバから自分が開発したWEBアプリにリクエストを送信するための設定をします。 LINE Developersコンソールから トップ > プロバイダー名 > チャネル名 > Messaging API設定 > Webhook設定 Webhook URLの設定とWebhookの利用をONにします。 ※「www.example.com」は自分が作成したアプリのURLを設定してください。 ※この例ではcallbackアクションがLINEbotのリクエストの受付先となります。 ③リクエストを受信したRailsサーバは受信した内容を参照し、色々と処理をした結果、最終的にレスポンスとなるメッセージを作成します。 次にRails側の実装をしていきたいところですが、先にLINEサーバに接続するためのアクセストークンを発行しましょう。 LINE Developersコンソールから トップ > プロバイダー名 > チャネル名 > チャネル基本設定 > チャネルシークレット チャネルシークレットを発行します。 LINE Developersコンソールから トップ > プロバイダー名 > チャネル名 > Messaging API設定 > チャネルアクセストークン チャネルアクセストークンを発行します。 上記の チャネルシークレット チャネルアクセストークン がLINEサーバに接続するために必要な情報になります。 こちらが漏洩すると自分が作成したチャネルを悪用されてしまうので、注意しましょう。 今度こそRailsの実装をしていきたいと思います。 公式の説明はこちらです。 まず、Gemfileに gem 'line-bot-api' を追加してbundle installをしましょう。 最初にルーティングの設定をします。 Rails.application.routes.draw do post '/callback', to: 'linebot#callback' end そしてコントローラを作成します。 class LinebotController < ApplicationController # LINEbotを使用するための設定を読み込み require 'line/bot' # CSRFトークン認証を無効 protect_from_forgery :except => [:callback] def client # LINE APIクライアントのインスタンスをアクセストークンなどを使用して生成 @client ||= Line::Bot::Client.new { |config| # アクセストークンは環境変数に設定 # トップ > プロバイダー名 > チャネル名 > チャネル基本設定 > チャネルシークレット config.channel_secret = ENV["LINE_CHANNEL_SECRET"] # トップ > プロバイダー名 > チャネル名 > Messaging API設定 > チャネルアクセストークン config.channel_token = ENV["LINE_CHANNEL_TOKEN"] } end def callback body = request.body.read signature = request.env['HTTP_X_LINE_SIGNATURE'] # 開発環境でやると認証が通らないことがあったため、本番環境でのみ署名の認証を行う # (LINEアプリからの送信ということを示すための署名) if Rails.env.production? unless client.validate_signature(body, signature) head :bad_request return end end # LINEサーバから送信されてきたメッセージ、各種情報を取得 events = client.parse_events_from(body) events.each { |event| case event when Line::Bot::Event::Message case event.type when Line::Bot::Event::MessageType::Text # 送信されてきたメッセージを取得 received_msg = event.message['text'] # 今回はオウム返し message = [ { type: "text", text: received_msg } ] # ④レスポンスメッセージをLINEサーバに返します。 client.reply_message(event['replyToken'], message) end end } head :ok end end あとはデプロイをして動作確認をしましょう。 ※環境変数の設定を忘れずに! ⑤LINEサーバがレスポンスメッセージをLINEアプリに返します。 ここまでできたらアプリの完成です。 うまくできたでしょうか。 今回はただのオウム返しアプリになりますが、受信したメッセージの内容によって処理を分岐すれば色々なことができると思います。 私の場合は、毎日出社したときにあるものを提出しなければならず、非常に面倒だったので、LINEbotから送信して提出できるようにしました。 LINEであれば毎日開くのでついでにルーチンワークができるようになれば楽ですよね。 テキストメッセージ以外の受信 前述のコントローラでは case event when Line::Bot::Event::Message case event.type when Line::Bot::Event::MessageType::Text このように受信した情報がどいうものなのかを判断しています。 公式情報の例を覗いてみると events.each do |event| case event when Line::Bot::Event::Message handle_message(event) when Line::Bot::Event::Follow reply_text(event, "[FOLLOW]\nThank you for following") when Line::Bot::Event::Unfollow logger.info "[UNFOLLOW]\n#{body}" when Line::Bot::Event::Join reply_text(event, "[JOIN]\n#{event['source']['type']}") when Line::Bot::Event::Leave logger.info "[LEAVE]\n#{body}" when Line::Bot::Event::Postback message = "[POSTBACK]\n#{event['postback']['data']} (#{JSON.generate(event['postback']['params'])})" reply_text(event, message) when Line::Bot::Event::Beacon reply_text(event, "[BEACON]\n#{JSON.generate(event['beacon'])}") when Line::Bot::Event::Things reply_text(event, "[THINGS]\n#{JSON.generate(event['things'])}") when Line::Bot::Event::VideoPlayComplete reply_text(event, "[VIDEOPLAYCOMPLETE]\n#{JSON.generate(event['videoPlayComplete'])}") when Line::Bot::Event::Unsend handle_unsend(event) else reply_text(event, "Unknown event type: #{event}") end 色々あるようですね。 友達追加したとき ブロックしたとき グループに追加したとき グループから削除したとき ファイルが送信されたとき etc... 友達追加のタイミングでユーザー登録処理などを実装することも可能です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MVCその1.ルーティングについて

“初学者向け基礎知識”MVCにおけるルーティングについて ここではルーティングの意味と、MVC各機能の詳細について触れます。 大まかな概要部分については、下記の記事でまとめました。 https://qiita.com/TechOtome/items/bb7886fa9fcb7e0a5c18 MVCの処理の流れ 図1.リクエストからレスポンスまでの処理の流れ 説明の前に ここでは、Ruby on Railsを用いたMVCの記述を紹介しています。 ・Ruby: プログラミング言語の一つ。記述がシンプルで分かりやすいことから人気。大きなWEBアプリーケーションにも小さなプログラムにも対応できる。 ・Ruby on Rails: Rubyで作られた”フレームワーク”のこと。 ・フレームワーク:WEBアプリを作成する上で必要なツールを準備する必要があるが、 フレームワークは既に”必要となる作業やリソース”を用意している。簡潔に言えば、フレームワークを使って開発した方が作業が減って楽。 ルーティングについて 一言で書くと ”クライアントからのリクエストの処理を振り分ける。” 仮にユーザーが”A.com”というURLをクリックしたら、”A”というページを表示する(レスポンスとして返す)ように処理を振り分けます。 Twitterであれば「新しいツイートをする」「プロフィール画面を表示する」「フォロワー一覧を見る」「フォロワーのツイート一覧を見る」などなど。さまざまな処理がありますが、これらは全て一度ルーティングにリクエストが送られて、どのような処理をするのか振り分けてから、コントローラーからレスポンスが送られてユーザーが受け取ることができます。 実例)ルーティングでトップページを見るには? リクエストと言っても、具体的な中身がイメージしにくいと思います。 例えば”Tweet”というアプリがあって、そのトップページを見たいというリクエストがあった場合のルーティングは下記の記述になります。 get ’/tweets’, to: ’tweets#index’ 上記の記述は3つに分けることができます。 またそれぞれの意味も一緒に記述します。 ・get →HTTPメソッドの”GET” ・/tweets →URIパターン(URIとURLは別のものですが、WEBページのアドレスではURIもURLも同じ意味を指します。) (※URI解説参照: https://webtan.impress.co.jp/e/2010/03/09/7539) ・tweets#index →リクエストの行き先=tweetsというコントローラ名のindexアクション ルーティングでは、リクエストで”HTTPメソッド”と”URI”パターンを受け取りリクエストの行き先を記述します。 HTTPメソッド ‘URIパターン’, to ‘コントローラー名#アクション名’ HTTPメソッドとアクションとは? ここで、MVCの記述における重要な2つの用語を簡潔にまとめます。 1.HTTPメソッド HTTPメソッド:HTTP通信の中で行いたい処理の種類のこと。HTTPリクエストメソッドとも言う。8つ存在する。 HTTP通信:WEBアプリはインターネットを通じて利用することができる。その時のデータの送受信の通信方法をHTTP通信と呼ぶ。 図2.代表的なHTTPメソッド4つ 2.アクション アクション:MVCにおけるコントローラー内の処理の種類のことを言う。コントローラーではルーティングから受け取ったリクエストに対応する処理をする。 図3.MVCのコントローラーアクション 終わりに MVCのメリットの一つに「処理の記述が整理されている」点がありますが、このようにアクション名でどんな処理をするのかが理解できます。 MVCを使ったアプリ開発では、HTTPメソッドとアクション名を理解することがとても重要です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby】0から9までのカウンタ (paizaランク D 相当)【解答】

はじめに 問題文は上記からご参照ください。 この問題のミソは10以上の数値になったときの対処法を考えてあげればOK! 解答 #入力値を変数nに代入する n = gets.to_i #10回繰り返す for n in n..n+9 #1~9までの時はそのまま表示させる if n < 10 puts n else #10以上の時は、10で割った時の余りを表示させる puts n % 10 end end
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ZONe mad_hacker にデザインされたプログラムをRubyで書いてみた

ZONe mad_hacker 2021/04/27 に発売されたエナジードリンクで、缶には何やらプログラムが書かれています。 ⚠️hacked⚠️hacked⚠️究極の没入マッドネスを体感せよ? ZONe mad_hacker; 登場⚠️hacked⚠️hacked⚠️#ZONeエナジー #madhacker pic.twitter.com/QnK53WoII0— ZONe Energy (@zone_energy_jp) April 26, 2021 何が書かれているのか? どうやら JavaScript で書かれているようです。 気になったのでRubyに翻訳してみました!12 binarySearch bubbleSort dpFib GCD linearSearch bfs mergeSort まだ全て書けたわけではないですが、ゴールデンウィークなのでどんどん書いていきたいです。 binarySearch (二分探索) 図書館で本を探したことがあるでしょうか。 また、家の本棚から本を探したことがありますか? 図書館では本は著者名の順に並んでいます。あなたの家の本棚ではどうでしょうか。 本が何かの順番に並んでいれば、適当な本を取り出したとき、 それが探している本よりも右にあるならそれより左だけを探せばいい それが探している本よりも左にあるならそれより右だけを探せばいい というふうに探すと効率的です。 二分探索では、「適当な本」として探す範囲の中央を取ります。 これにより、探す範囲は半分、半分、また半分とどんどん狭くなっていきます。 例えば、探す範囲の長さが $64$ なら、 $64, 32, 16, 8, 4, 1$ となります。 このようにどんどん狭めることで、莫大な長さの配列(例えば、長さが $10^9 = 1,000,000,000$ )からも、少ない回数(この例では最大 $30$ 回)の探索で $val$ を見つけることができます。 関数 binary_search は、配列 $arr$ の $[min, max]$ の範囲から $val$ という値を探します。 配列 $arr$ はソートされている(順番に並んでいる)必要があります。 $val$ が $arr$ の中にあるなら、その位置を返します。 もし $val$ が $arr$ の中になければ、 nil (「ない」という意味)を返します。 def binary_search(arr, val, min = 0, max = arr.size - 1) return nil if max < min # もはや探すべき範囲はない half = min + (max - min) / 2 # max と min の中間の点 return half if arr[half] == val # 見つけた (val < arr[half]) ? # 中間の点が val よりも右側か? binary_search(arr, val, min, half - 1) : # そうなら、中間よりも左側を探す binary_search(arr, val, half + 1, max) # そうでなければ、中間よりも右側を探す end bubbleSort (バブルソート) 書類がバラバラな順番で積まれていて、これを通し番号の順に並べ替える必要があるとします。 あなたならどのように並べ替えますか? 書類を並べ替える(ソートする)一つの方法は、「バブルソート」です。 バブルソートでは、隣り合う $2$ 枚の書類を選び、それが逆順に並んでいたら入れ替えます。 残念ながらバブルソートはあまり効率的なアルゴリズムではなく、要素数の $2$ 乗に比例した回数の比較が必要です。例えば、 $1,000$ 枚の紙があれば、およそ $1,000,000$ 回近くの比較が必要になります。 さらに効率的なマージソートを後で紹介します。 関数 bubble_sort(arr) は配列 $arr$ を昇順に並び替えた後の配列を返します。 def bubble_sort(arr) new_arr = arr.dup # arr を複製する len = new_arr.size # 配列の長さ (0 ... len).each do |i| # len 回繰り返す (0 ... len - 1).each do |j| # len - 1 回繰り返す # 隣り合う 2 要素が逆順になっていたら入れ替える new_arr[j], new_arr[j + 1] = new_arr[j + 1], new_arr[j] if new_arr[j] > new_arr[j + 1] end end new_arr # 新しい配列を返す end dpFib (フィボナッチ数列) フィボナッチ数列を知っていますか?僕は知っています。 ……という冗談はさておき、フィボナッチ数列は $0, 1, 1, 2, 3, 5, \ldots$ という数列で、自然界のいたるところに現れます。 例えば、花びらの枚数など3。 フィボナッチ数の一般項は以下のように求められます4。 $$F_n = \frac{\phi^n - (1 - \phi)^n}{\sqrt5}$$ 式の中に黄金比 $\phi = \frac{1 + \sqrt5}{2}$ が現れているのがわかりますね。 フィボナッチ数は以下のような漸化式を使っても求めることができます。 $$\begin{aligned} F_0 &= 0 \\ F_1 &= 1 \\ F_n &= F_{n - 2} + F_{n - 1} \quad (n \ge 2) \end{aligned}$$ 下に示すプログラムでは、この漸化式をそのまま使ってフィボナッチ数を計算しています。 ナイーブなプログラム def fib(n) return 0 if n == 0 return 1 if n == 1 fib(n - 2) + fib(n - 1) end しかしこのプログラムでは、困ったことに、計算回数が $\phi^{n-1}$ に比例する回数になってしまいます。 たとえば fib(10) は $177$ 回、 fib(20) は $21,891$ 回、 fib(30) は $2,692,537$ 回です。 この調子で計算していては、 fib(100) の計算など、どれだけ時間がかかるか分かったものではありません。 そこで使われるプログラミング的テクニックが動的計画法 (DP: Dynamic Programming)です。 動的計画法では、フィボナッチ数の計算において、それぞれの fib(n) の値を覚えておきます。 このようにすることで、 $n$ 番目のフィボナッチ数の計算に必要な計算回数を $n$ に比例する回数にできます。 ZONe mad_hacker の缶に書かれているコードには動的計画法の書き方の一つ、メモ化再帰と呼ばれる手法が使われています。 関数 dp_fib(n) は $n$ 番目のフィボナッチ数を計算して返します。 def dp_fib(n, memo = {}) return memo[n] if memo[n] # メモがあればそれを返す return 0 if n == 0 # fib(0) = 0 return 1 if n == 1 # fib(1) = 1 (memo[n] = dp_fib(n - 1, memo) + dp_fib(n - 2, memo)) # fib(n - 1) と fib(n - 2) を計算し、メモに入れ、返す end 因みに、この方法を使っても $n = 10^{18}$ のような場合は流石に時間がかかりすぎます。 そういう場合は行列表現とバイナリー法を組み合わせたり(行列累乗と呼ばれます)、きたまさ法という方法を使って $n$ の対数に比例する時間で計算します。 競技プログラミングでは行列累乗を使う問題もよく出題されることがあります。 GCD (最大公約数) 最大公約数が何かについては小学校で習ったと思うので、詳細には立ち入りません。 ユークリッドの互除法は、 $2$ つの数の最大公約数を計算するシンプルかつ効率的なアルゴリズムで、内容は以下のとおりです。 片方が $0$ なら他方が最大公約数である 片方をもう片方で割ったあまりと置き換え、 1. に戻る 例として、 $10$ と $14$ の最大公約数を計算してみたいと思います。 $$(10, 14) \to (10, 4) \to (2, 4) \to (2, 0) \to 2$$ このように、 $a$ と $b$ の大きい方の対数に比例する計算回数で計算を終えることができます。 「片方をもう片方で割ったあまりと置き換える」という操作において注意するべきは、大きい方で小さい方を割ることを続けるなら、計算が終了しないということです。 そこで以下のコードでは、毎回 2 つの数を入れ替えることで、そうならないようにしています。 関数 gcd(a, b) は $a$ と $b$ の最大公約数を求め、それを返します。 def gcd(a, b) return a if b == 0 gcd(b, a % b) end linearSearch (線形探索) 先に説明した二分探索はとても高速ですが、探索する対象がソート済でなければ使えません。 順番に並んでいないものの中から何かを探したいときは線形探索を使うことになります。 たとえば、書類の中から「Z」という文字を探したいとします。 どこに「Z」があるかはわからないので、書類を 1 枚 1 枚めくって探すと思います。 線形探索はそのように、 1 つ 1 つ確かめる探索です。 長さが $n$ の対象から探すとき、計算回数は、名前のとおり最大で $n$ に比例する回数となります。 関数 linear_search(arr, val) は配列 $arr$ から $val$ を探します。 $arr$ の中に $val$ があるなら、一番左の位置を返します。 もしなければ、 nil を返します。 def linear_search(arr, val) len = arr.size # arr の長さ len.times do |i| # i = 0 から len - 1 まで繰り返す return i if arr[i] == val # arr[i] が val だったら i を返す end nil # false を返す end bfs (幅優先探索) HTML に触ったことがある人ならおそらくわかるでしょうが、 HTML 文書は要素の木構造で表すことができます。この構造は DOM (Document Object Model) と呼ばれ、これによりプログラムから文書を操作するのが容易になります。 HTML 構造 表示 幅優先探索は、そのような木構造を、根(一番左)に近い順に調べていく探索です。 下の図は <ul> を根とする木に対して、 <span style="color:red">400</span> を探す幅優先探索を行った図です。 JavaScript には DOM を直接扱う機能が標準で付いていますが、 Ruby はコマンドラインで動くのが主であるため、デフォルトではその機能はありません。 Ruby で DOM を扱うには、 Nokogiri というライブラリなどがあります。 関数 bfs(root, val) は $root$ を根とする木から $val$ を探し、あれば true 、なければ false を返します。 def bfs(root, val) queue = [root] # root が入ったキュー queue を作る until queue.empty? # queue が空になるまで繰り返す current = queue.shift # queue の先頭の要素を取り出す return true if current == val # val を見つけた current.children.each do |child| # current のそれぞれの子に対して繰り返す queue << child # queue の末尾に child を追加 end end false # 見つからなかった end 余談ですが、 Ruby の実装の一つである CRuby では、配列は Deque として実装されているため、 push (<<), pop だけでなく shift, unshift も定数時間で行うことができます。 しかし、 JavaScript では Array#shift の計算回数は配列の長さに比例するはずですが……。 ZONeエナジー プログラミングコンテスト “HELLO SPACE” mad_hacker の発売を記念してプログラミングコンテストが開かれました。なんと開催は今夜(5/1 21:00)です! 賞金総額は30万円! これは楽しそうですね! プログラミングをあまりやったことがない方、または普段プログラミングコンテストなどに出たことがない方などもこの機会に一度参加してみてはいかがでしょう? 参加にはAtCoderへの登録が必要となるため、早めに登録しておいた方がよさそうです! / ⚠️明日21:00よりSTART⚠️ \賞金総額100万円!プログラミングコンテスト #HELLOSPACE 1st ROUNDは @atcoder にて明日開催! ?️5/1(Sat) 21:00 START▼参加はこちらから▼https://t.co/ezgmC5xHG3#madhacker #AtCoder pic.twitter.com/E21CzmDo67— ZONe Energy (@zone_energy_jp) April 30, 2021 著作権があるので、そのまま掲載はできません ↩ 隠れている場所は想像で補いました。コーディング規約にあわせて適宜書き換えた場所もあります。また、不要となったため省略した変数もあります ↩ https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A3%E3%83%9C%E3%83%8A%E3%83%83%E3%83%81%E6%95%B0#%E3%81%9D%E3%81%AE%E4%BB%96%E3%81%AE%E8%A9%B1%E9%A1%8C ↩ https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A3%E3%83%9C%E3%83%8A%E3%83%83%E3%83%81%E6%95%B0#%E4%B8%80%E8%88%AC%E9%A0%85 ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ZONe mad_hacker にデザインされたプログラムを翻訳してみた

ZONe mad_hacker 2021/04/27 に発売されたエナジードリンクで、缶には何やらプログラムが書かれています。 ⚠️hacked⚠️hacked⚠️究極の没入マッドネスを体感せよ? ZONe mad_hacker; 登場⚠️hacked⚠️hacked⚠️#ZONeエナジー #madhacker pic.twitter.com/QnK53WoII0— ZONe Energy (@zone_energy_jp) April 26, 2021 何が書かれているのか? どうやら JavaScript で書かれているようです。 気になったのでRubyに翻訳してみました!12 binarySearch bubbleSort dpFib GCD linearSearch bfs mergeSort まだ全て書けたわけではないですが、ゴールデンウィークなのでどんどん書いていきたいです。 binarySearch (二分探索) 図書館で本を探したことがあるでしょうか。 また、家の本棚から本を探したことがありますか? 図書館では本は著者名の順に並んでいます。あなたの家の本棚ではどうでしょうか。 本が何かの順番に並んでいれば、適当な本を取り出したとき、 それが探している本よりも右にあるならそれより左だけを探せばいい それが探している本よりも左にあるならそれより右だけを探せばいい というふうに探すと効率的です。 二分探索では、「適当な本」として探す範囲の中央を取ります。 これにより、探す範囲は半分、半分、また半分とどんどん狭くなっていきます。 例えば、探す範囲の長さが $64$ なら、 $64, 32, 16, 8, 4, 1$ となります。 このようにどんどん狭めることで、莫大な長さの配列(例えば、長さが $10^9 = 1,000,000,000$ )からも、少ない回数(この例では最大 $30$ 回)の探索で $val$ を見つけることができます。 関数 binary_search は、配列 $arr$ の $[min, max]$ の範囲から $val$ という値を探します。 配列 $arr$ はソートされている(順番に並んでいる)必要があります。 $val$ が $arr$ の中にあるなら、その位置を返します。 もし $val$ が $arr$ の中になければ、 nil (「ない」という意味)を返します。 def binary_search(arr, val, min = 0, max = arr.size - 1) return nil if max < min # もはや探すべき範囲はない half = min + (max - min) / 2 # max と min の中間の点 return half if arr[half] == val # 見つけた (val < arr[half]) ? # 中間の点が val よりも右側か? binary_search(arr, val, min, half - 1) : # そうなら、中間よりも左側を探す binary_search(arr, val, half + 1, max) # そうでなければ、中間よりも右側を探す end bubbleSort (バブルソート) 書類がバラバラな順番で積まれていて、これを通し番号の順に並べ替える必要があるとします。 あなたならどのように並べ替えますか? 書類を並べ替える(ソートする)一つの方法は、「バブルソート」です。 バブルソートでは、隣り合う $2$ 枚の書類を選び、それが逆順に並んでいたら入れ替えます。 残念ながらバブルソートはあまり効率的なアルゴリズムではなく、要素数の $2$ 乗に比例した回数の比較が必要です。例えば、 $1,000$ 枚の紙があれば、およそ $1,000,000$ 回近くの比較が必要になります。 さらに効率的なマージソートを後で紹介します。 関数 bubble_sort(arr) は配列 $arr$ を昇順に並び替えた後の配列を返します。 def bubble_sort(arr) new_arr = arr.dup # arr を複製する len = new_arr.size # 配列の長さ (0 ... len).each do |i| # len 回繰り返す (0 ... len - 1).each do |j| # len - 1 回繰り返す # 隣り合う 2 要素が逆順になっていたら入れ替える new_arr[j], new_arr[j + 1] = new_arr[j + 1], new_arr[j] if new_arr[j] > new_arr[j + 1] end end new_arr # 新しい配列を返す end dpFib (フィボナッチ数列) フィボナッチ数列を知っていますか?僕は知っています。 ……という冗談はさておき、フィボナッチ数列は $0, 1, 1, 2, 3, 5, \ldots$ という数列で、自然界のいたるところに現れます。 例えば、花びらの枚数など3。 フィボナッチ数の一般項は以下のように求められます4。 $$F_n = \frac{\phi^n - (1 - \phi)^n}{\sqrt5}$$ 式の中に黄金比 $\phi = \frac{1 + \sqrt5}{2}$ が現れているのがわかりますね。 フィボナッチ数は以下のような漸化式を使っても求めることができます。 $$\begin{aligned} F_0 &= 0 \\ F_1 &= 1 \\ F_n &= F_{n - 2} + F_{n - 1} \quad (n \ge 2) \end{aligned}$$ 下に示すプログラムでは、この漸化式をそのまま使ってフィボナッチ数を計算しています。 ナイーブなプログラム def fib(n) return 0 if n == 0 return 1 if n == 1 fib(n - 2) + fib(n - 1) end しかしこのプログラムでは、困ったことに、計算回数が $\phi^{n-1}$ に比例する回数になってしまいます。 たとえば fib(10) は $177$ 回、 fib(20) は $21,891$ 回、 fib(30) は $2,692,537$ 回です。 この調子で計算していては、 fib(100) の計算など、どれだけ時間がかかるか分かったものではありません。 そこで使われるプログラミング的テクニックが動的計画法 (DP: Dynamic Programming)です。 動的計画法では、フィボナッチ数の計算において、それぞれの fib(n) の値を覚えておきます。 このようにすることで、 $n$ 番目のフィボナッチ数の計算に必要な計算回数を $n$ に比例する回数にできます。 ZONe mad_hacker の缶に書かれているコードには動的計画法の書き方の一つ、メモ化再帰と呼ばれる手法が使われています。 関数 dp_fib(n) は $n$ 番目のフィボナッチ数を計算して返します。 def dp_fib(n, memo = {}) return memo[n] if memo[n] # メモがあればそれを返す return 0 if n == 0 # fib(0) = 0 return 1 if n == 1 # fib(1) = 1 (memo[n] = dp_fib(n - 1, memo) + dp_fib(n - 2, memo)) # fib(n - 1) と fib(n - 2) を計算し、メモに入れ、返す end 因みに、この方法を使っても $n = 10^{18}$ のような場合は流石に時間がかかりすぎます。 そういう場合は行列表現とバイナリー法を組み合わせたり(行列累乗と呼ばれます)、きたまさ法という方法を使って $n$ の対数に比例する時間で計算します。 競技プログラミングでは行列累乗を使う問題もよく出題されることがあります。 GCD (最大公約数) 最大公約数が何かについては小学校で習ったと思うので、詳細には立ち入りません。 ユークリッドの互除法は、 $2$ つの数の最大公約数を計算するシンプルかつ効率的なアルゴリズムで、内容は以下のとおりです。 片方が $0$ なら他方が最大公約数である 片方をもう片方で割ったあまりと置き換え、 1. に戻る 例として、 $10$ と $14$ の最大公約数を計算してみたいと思います。 $$(10, 14) \to (10, 4) \to (2, 4) \to (2, 0) \to 2$$ このように、 $a$ と $b$ の大きい方の対数に比例する計算回数で計算を終えることができます。 「片方をもう片方で割ったあまりと置き換える」という操作において注意するべきは、大きい方で小さい方を割ることを続けるなら、計算が終了しないということです。 そこで以下のコードでは、毎回 2 つの数を入れ替えることで、そうならないようにしています。 関数 gcd(a, b) は $a$ と $b$ の最大公約数を求め、それを返します。 def gcd(a, b) return a if b == 0 gcd(b, a % b) end linearSearch (線形探索) 先に説明した二分探索はとても高速ですが、探索する対象がソート済でなければ使えません。 順番に並んでいないものの中から何かを探したいときは線形探索を使うことになります。 たとえば、本から、「う」で終わる二字熟語が最初に現れるのはどこか探したいとします。 どこにその単語があるかは予測できないので、ページを 1 枚 1 枚めくり、すべての行を見て探すと思います。 線形探索はそのように、 1 つ 1 つ確かめる探索です。 長さが $n$ の対象から探すとき、計算回数は、名前のとおり最大で $n$ に比例する回数となります。 関数 linear_search(arr, val) は配列 $arr$ から $val$ を探します。 $arr$ の中に $val$ があるなら、一番左の位置を返します。 もしなければ、 nil を返します。 def linear_search(arr, val) len = arr.size # arr の長さ len.times do |i| # i = 0 から len - 1 まで繰り返す return i if arr[i] == val # arr[i] が val だったら i を返す end nil # false を返す end bfs (幅優先探索) HTML に触ったことがある人ならおそらくわかるでしょうが、 HTML 文書は要素の木構造で表すことができます。この構造は DOM (Document Object Model) と呼ばれ、これによりプログラムから文書を操作するのが容易になります。 HTML 構造 表示 幅優先探索は、そのような木構造を、根(一番左)に近い順に調べていく探索です。 下の図は <ul> を根とする木に対して、 <span style="color:red">400</span> を探す幅優先探索を行った図です。 JavaScript には DOM を直接扱う機能が標準で付いていますが、 Ruby はコマンドラインで動くのが主であるため、デフォルトではその機能はありません。 Ruby で DOM を扱うには、 Nokogiri というライブラリなどがあります。 関数 bfs(root, val) は $root$ を根とする木から $val$ を探し、あれば true 、なければ false を返します。 def bfs(root, val) queue = [root] # root が入ったキュー queue を作る until queue.empty? # queue が空になるまで繰り返す current = queue.shift # queue の先頭の要素を取り出す return true if current == val # val を見つけた current.children.each do |child| # current のそれぞれの子に対して繰り返す queue << child # queue の末尾に child を追加 end end false # 見つからなかった end 余談ですが、 Ruby の実装の一つである CRuby では、配列は Deque として実装されているため、 push (<<), pop だけでなく shift, unshift も定数時間で行うことができます。 しかし、 JavaScript では Array#shift の計算回数は配列の長さに比例するはずですが……。 ZONeエナジー プログラミングコンテスト “HELLO SPACE” mad_hacker の発売を記念してプログラミングコンテストが開かれました。なんと開催は今夜(5/1 21:00)です! 賞金総額は30万円! これは楽しそうですね! プログラミングをあまりやったことがない方、または普段プログラミングコンテストなどに出たことがない方などもこの機会に一度参加してみてはいかがでしょう? 参加にはAtCoderへの登録が必要となるため、早めに登録しておいた方がよさそうです! / ⚠️明日21:00よりSTART⚠️ \賞金総額100万円!プログラミングコンテスト #HELLOSPACE 1st ROUNDは @atcoder にて明日開催! ?️5/1(Sat) 21:00 START▼参加はこちらから▼https://t.co/ezgmC5xHG3#madhacker #AtCoder pic.twitter.com/E21CzmDo67— ZONe Energy (@zone_energy_jp) April 30, 2021 著作権があるので、そのまま掲載はできません ↩ 隠れている場所は想像で補いました。コーディング規約にあわせて適宜書き換えた場所もあります。また、不要となったため省略した変数もあります ↩ https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A3%E3%83%9C%E3%83%8A%E3%83%83%E3%83%81%E6%95%B0#%E3%81%9D%E3%81%AE%E4%BB%96%E3%81%AE%E8%A9%B1%E9%A1%8C ↩ https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A3%E3%83%9C%E3%83%8A%E3%83%83%E3%83%81%E6%95%B0#%E4%B8%80%E8%88%AC%E9%A0%85 ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ZONe mad_hacker にデザインされたプログラムを解説してみた

ZONe mad_hacker 2021/04/27 に発売されたエナジードリンクで、缶には何やらプログラムが書かれています。 ⚠️hacked⚠️hacked⚠️究極の没入マッドネスを体感せよ? ZONe mad_hacker; 登場⚠️hacked⚠️hacked⚠️#ZONeエナジー #madhacker pic.twitter.com/QnK53WoII0— ZONe Energy (@zone_energy_jp) April 26, 2021 何が書かれているのか? どうやら JavaScript で書かれているようです。 気になったのでRubyに翻訳してみました!12 binarySearch bubbleSort dpFib GCD linearSearch bfs mergeSort まだ全て書けたわけではないですが、ゴールデンウィークなのでどんどん書いていきたいです。 binarySearch (二分探索) 図書館で本を探したことがあるでしょうか。 また、家の本棚から本を探したことがありますか? 図書館では本は著者名の順に並んでいます。あなたの家の本棚ではどうでしょうか。 本が何かの順番に並んでいれば、適当な本を取り出したとき、 それが探している本よりも右にあるならそれより左だけを探せばいい それが探している本よりも左にあるならそれより右だけを探せばいい というふうに探すと効率的です。 二分探索では、「適当な本」として探す範囲の中央を取ります。 これにより、探す範囲は半分、半分、また半分とどんどん狭くなっていきます。 例えば、探す範囲の長さが $64$ なら、 $64, 32, 16, 8, 4, 1$ となります。 このようにどんどん狭めることで、莫大な長さの配列(例えば、長さが $10^9 = 1,000,000,000$ )からも、少ない回数(この例では最大 $30$ 回)の探索で $val$ を見つけることができます。 関数 binary_search は、配列 $arr$ の $[min, max]$ の範囲から $val$ という値を探します。 配列 $arr$ はソートされている(順番に並んでいる)必要があります。 $val$ が $arr$ の中にあるなら、その位置を返します。 もし $val$ が $arr$ の中になければ、 nil (「ない」という意味)を返します。 def binary_search(arr, val, min = 0, max = arr.size - 1) return nil if max < min # もはや探すべき範囲はない half = min + (max - min) / 2 # max と min の中間の点 return half if arr[half] == val # 見つけた (val < arr[half]) ? # 中間の点が val よりも右側か? binary_search(arr, val, min, half - 1) : # そうなら、中間よりも左側を探す binary_search(arr, val, half + 1, max) # そうでなければ、中間よりも右側を探す end bubbleSort (バブルソート) 書類がバラバラな順番で積まれていて、これを通し番号の順に並べ替える必要があるとします。 あなたならどのように並べ替えますか? 書類を並べ替える(ソートする)一つの方法は、「バブルソート」です。 バブルソートでは、隣り合う $2$ 枚の書類を選び、それが逆順に並んでいたら入れ替えます。 残念ながらバブルソートはあまり効率的なアルゴリズムではなく、要素数の $2$ 乗に比例した回数の比較が必要です。例えば、 $1,000$ 枚の紙があれば、およそ $1,000,000$ 回近くの比較が必要になります。 さらに効率的なマージソートを後で紹介します。 関数 bubble_sort(arr) は配列 $arr$ を昇順に並び替えた後の配列を返します。 def bubble_sort(arr) new_arr = arr.dup # arr を複製する len = new_arr.size # 配列の長さ (0 ... len).each do |i| # len 回繰り返す (0 ... len - 1).each do |j| # len - 1 回繰り返す # 隣り合う 2 要素が逆順になっていたら入れ替える new_arr[j], new_arr[j + 1] = new_arr[j + 1], new_arr[j] if new_arr[j] > new_arr[j + 1] end end new_arr # 新しい配列を返す end ちなみに、ある配列に対する、バブルソートをしたときの交換回数を転倒数と呼びます。 競技プログラミングでは転倒数に関する問題が出ることもあります。 dpFib (フィボナッチ数列) フィボナッチ数列を知っていますか?僕は知っています。 ……という冗談はさておき、フィボナッチ数列は $0, 1, 1, 2, 3, 5, \ldots$ という数列で、自然界のいたるところに現れます。 例えば、花びらの枚数など3。 フィボナッチ数の一般項は以下のように求められます4。 $$F_n = \frac{\phi^n - (1 - \phi)^n}{\sqrt5}$$ 式の中に黄金比 $\phi = \frac{1 + \sqrt5}{2}$ が現れているのがわかりますね。 フィボナッチ数は以下のような漸化式を使っても求めることができます。 $$\begin{aligned} F_0 &= 0 \\ F_1 &= 1 \\ F_n &= F_{n - 2} + F_{n - 1} \quad (n \ge 2) \end{aligned}$$ 下に示すプログラムでは、この漸化式をそのまま使ってフィボナッチ数を計算しています。 ナイーブなプログラム def fib(n) return 0 if n == 0 return 1 if n == 1 fib(n - 2) + fib(n - 1) end しかしこのプログラムでは、困ったことに、計算回数が $\phi^{n-1}$ に比例する回数になってしまいます。 たとえば fib(10) は $177$ 回、 fib(20) は $21,891$ 回、 fib(30) は $2,692,537$ 回です。 この調子で計算していては、 fib(100) の計算など、どれだけ時間がかかるか分かったものではありません。 そこで使われるプログラミング的テクニックが動的計画法 (DP: Dynamic Programming)です。 動的計画法では、フィボナッチ数の計算において、それぞれの fib(n) の値を覚えておきます。 このようにすることで、 $n$ 番目のフィボナッチ数の計算に必要な計算回数を $n$ に比例する回数にできます。 ZONe mad_hacker の缶に書かれているコードには動的計画法の書き方の一つ、メモ化再帰と呼ばれる手法が使われています。 関数 dp_fib(n) は $n$ 番目のフィボナッチ数を計算して返します。 def dp_fib(n, memo = {}) return memo[n] if memo[n] # メモがあればそれを返す return 0 if n == 0 # fib(0) = 0 return 1 if n == 1 # fib(1) = 1 (memo[n] = dp_fib(n - 1, memo) + dp_fib(n - 2, memo)) # fib(n - 1) と fib(n - 2) を計算し、メモに入れ、返す end 因みに、この方法を使っても $n = 10^{18}$ のような場合は流石に時間がかかりすぎます。 そういう場合は行列表現とバイナリー法を組み合わせたり(行列累乗と呼ばれます)、きたまさ法という方法を使って $n$ の対数に比例する時間で計算します。 競技プログラミングでは行列累乗を使う問題もよく出題されることがあります。 GCD (最大公約数) 最大公約数が何かについては小学校で習ったと思うので、詳細には立ち入りません。 ユークリッドの互除法は、 $2$ つの数の最大公約数を計算するシンプルかつ効率的なアルゴリズムで、内容は以下のとおりです。 片方が $0$ なら他方が最大公約数である 片方をもう片方で割ったあまりと置き換え、 1. に戻る 例として、 $10$ と $14$ の最大公約数を計算してみたいと思います。 $$(10, 14) \to (10, 4) \to (2, 4) \to (2, 0) \to 2$$ このように、 $a$ と $b$ の大きい方の対数に比例する計算回数で計算を終えることができます。 「片方をもう片方で割ったあまりと置き換える」という操作において注意するべきは、大きい方で小さい方を割ることを続けるなら、計算が終了しないということです。 そこで以下のコードでは、毎回 2 つの数を入れ替えることで、そうならないようにしています。 関数 gcd(a, b) は $a$ と $b$ の最大公約数を求め、それを返します。 def gcd(a, b) return a if b == 0 gcd(b, a % b) end linearSearch (線形探索) 先に説明した二分探索はとても高速ですが、探索する対象がソート済でなければ使えません。 順番に並んでいないものの中から何かを探したいときは線形探索を使うことになります。 たとえば、本から、「う」で終わる二字熟語が最初に現れるのはどこか探したいとします。 どこにその単語があるかは予測できないので、ページを 1 枚 1 枚めくり、すべての行を見て探すと思います。 線形探索はそのように、 1 つ 1 つ確かめる探索です。 長さが $n$ の対象から探すとき、計算回数は、名前のとおり最大で $n$ に比例する回数となります。 関数 linear_search(arr, val) は配列 $arr$ から $val$ を探します。 $arr$ の中に $val$ があるなら、一番左の位置を返します。 もしなければ、 nil を返します。 def linear_search(arr, val) len = arr.size # arr の長さ len.times do |i| # i = 0 から len - 1 まで繰り返す return i if arr[i] == val # arr[i] が val だったら i を返す end nil # false を返す end bfs (幅優先探索) 木構造と呼ばれるデータ構造があります。 木構造では、一つのオブジェクトが一つの値を持ち、また、 0 個以上の「子供」のオブジェクトを持ちます。 木構造においてこのようなオブジェクトはノードと呼ばれます。 木構造の例として、 DOM があります。 HTML に触ったことがある人ならおそらくわかるでしょうが、 HTML 文書は要素の木構造で表すことができます。この構造は DOM (Document Object Model) と呼ばれ、これによりプログラムから文書を操作するのが容易になります。 HTML 構造 表示 幅優先探索は、そのような木構造を、根(一番左)に近い順に調べていく探索です。 下の図は <ul> を根とする木に対して、 <span style="color:red">400</span> を探す幅優先探索を行った図です。 関数 bfs(root, val) は $root$ を根とする木から、値が $val$ であるようなノードを探し、あればそのノード、なければ nil を返します。 def bfs(root, val) queue = [root] # root が入ったキュー queue を作る until queue.empty? # queue が空になるまで繰り返す current = queue.shift # queue の先頭の要素を取り出す return current if current.val == val # 見つけた current.children.each do |child| # current のそれぞれの子に対して繰り返す queue << child # queue の末尾に child を追加 end end nil # 見つからなかった end 余談ですが、 Ruby の実装の一つである CRuby では、配列は Deque として実装されているため、 push (<<), pop だけでなく shift, unshift も定数時間で行うことができます。 しかし、 JavaScript では Array#shift の計算回数は配列の長さに比例するはずですが……。 ZONeエナジー プログラミングコンテスト “HELLO SPACE” mad_hacker の発売を記念してプログラミングコンテストが開かれました。 05/17まで開催されています。 賞金総額は70万円! これは楽しそうですね! プログラミングをあまりやったことがない方、または普段プログラミングコンテストなどに出たことがない方などもこの機会に一度参加してみてはいかがでしょう? 著作権があるので、そのまま掲載はできません ↩ 隠れている場所は想像で補いました。コーディング規約にあわせて適宜書き換えた場所もあります。また、不要となったため省略した変数もあります ↩ https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A3%E3%83%9C%E3%83%8A%E3%83%83%E3%83%81%E6%95%B0#%E3%81%9D%E3%81%AE%E4%BB%96%E3%81%AE%E8%A9%B1%E9%A1%8C ↩ https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A3%E3%83%9C%E3%83%8A%E3%83%83%E3%83%81%E6%95%B0#%E4%B8%80%E8%88%AC%E9%A0%85 ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

全角・半角カタカナのバリデーションルール設定方法(正規表現)

はじめに ユーザー登録機能等を実装する際のバリデーションルールに、例えば 氏名のフリガナには全角カタカナを、 口座名義には半角カタカナのみを入力させるようにしたい時があると思います。 そんな時に、どのような正規表現を使えば良いのかをご紹介します。 全角カタカナのバリデーションルール 全角カタカナのバリデーションルールを設定するときは、以下のように正規表現を使うと、 全角カタカナと、全角カタカナ小文字、長音記号(ー)のみを許容するようにできます。 /^[ァ-ヴー]+$/u キモとなる部分は[ァ-ヴー]の部分ですが、この部分の意味としては ァ-ヴは、文字コードの「ァ」から「ヴ」までの全角カタカナを意味し、ーはまんま長音記号「ー」を意味しています。 なお、全角カタカナの文字コードの順番としては、以下のようになっています。 ァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶ このうち、小文字の「ァ」から始まって、最後は「ヴ」までの範囲の全角カタカナが対象となっています。 カタカナの並び順って、綺麗に「アイウエオ」や「ァィゥェォ」、「カキクケコ」等となってはいないのですね。 ちゃんとマッチしてるかチェック↓ Rubularというサイトで正規表現がマッチしているかを簡単に確認できるので便利です? なお、最後の「ヵ」、「ヶ」については、 「3カ所」や「1ヶ月」などに使われる文字なのですが、フリガナ等のカタカナとして含めたくないことの方が多いのではないかなと思います。 もし含めたい場合は、正規表現を /^[ァ-ヶー]+$/u とします。 ちなみに、全角カタカナの正規表現として [ァ-ン]というものも見かけますが、この場合「ヴ」が含まれなくなってしまいます。 半角カタカナのバリデーションルール 半角カタカナのバリデーションルールを設定するときは、以下のように正規表現を使うと、 半角カタカナと、半角カタカナ小文字、半角の長音記号(-)のみを許容するようにできます。 /^[ヲ-゚-]+$/u キモとなる部分は[ヲ-゚-]の部分ですが、この部分の意味としては ヲ-゚は、文字コードの「ヲ」から「゜」までの半角カタカナを意味し、最後の-はまんま半角の長音記号「-」を意味しています。 ※似ていて紛らわしいですが、ハイフン「-」ではありません (濁点「゛」、半濁点「゜」の半角カタカナも含む) なお、半角カタカナの文字コードの順番としては、以下のようになっています。 ヲァィゥェォャュョッアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘノマミムメモヤユヨラリルレヒロワン゙゚ ちゃんとマッチしてるかチェック↓ 正規表現についてとても参考になる記事 そもそも正規表現のルールがよくわからん!基礎から学びたい! という場合は、こちらのQiita記事が初心者向けにかなり丁寧に解説されていて、参考になりました。 初心者歓迎!手と目で覚える正規表現入門・その1「さまざまな形式の電話番号を検索しよう」
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby】二次元配列とはなんぞや

二次元配列とは 配列の中に配列が入っている配列。 配列とは a = ["hoge1", "hoge2", "hoge3"] puts a hoge1 hoge2 hoge3 1つの箱の中に情報が入っているデータ集合。 上記の場合"変数a"に、"hoge1", "hoge2", "hoge3"の3つの情報が入っています。 (※今回のhoge1のことを要素といいます) また、要素にインデックス番号が自動で振り当てられ、左から0,1,2...となっていきます。 hoge1 → インデックス番号0 hoge2 → インデックス番号1 hoge3 → インデックス番号2 2次元配列 a = ["ぐみ", "ちょこ", "ドーナッツ"] b = ["納豆", "佃煮", "漬物"] all = [a, b] p all [["ぐみ", "ちょこ", "ドーナッツ"], ["納豆", "佃煮", "漬物"]] #こんな感じで2次元配列は、配列の中に配列がある puts all[0][1] ちょこ #変数allのインデックス番号0の要素である"変数a"の、変数aのインデックス番号1の要素である"ちょこ"を呼び出した mapメソッドで2次元配列を作ってみる num = Array.new(3).map{Array.new(2, "a")} p num [["a", "a"], ["a", "a"], ["a", "a"]] puts num.length 3 ・Array.new()で()内の数だけ配列の要素を作ってくれる。(今回は3つ) ・map{}で{}ないの処理をしてくれるので、今回はArray.new(3)で作った配列の中に、要素"a"を2つ配列として作る。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rangeクラスのオブジェクトの指定

Rangeクラスのオブジェクトの指定にはリテラル記法を用います。 n..m n以上m以下の範囲 n...m n上m未満の範囲 公式リファレンスも役に立ちます:class Range (Ruby 3.0.0 リファレンスマニュアル) https://docs.ruby-lang.org/ja/3.0.0/class/Range.html
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

sketchupでruby その18

概要 sketchupでrubyやってみた。 練習問題やってみた。 練習問題 面だけで、球を作れ。 写真 サンプルコード def tama p1 = Geom::Point3d.new 0, 0, 0 p2 = Geom::Point3d.new 10, 10, 10 entities = Sketchup.active_model.entities radius = p2.distance(p1) dtheta = dphi = 360.0 / 16 -90.step(90, dtheta) do |theta| 0.step(360, dphi) do |phi| group = entities.add_group pts = [] x = radius * Math::cos(theta.degrees) * Math::cos(phi.degrees) y = radius * Math::cos(theta.degrees) * Math::sin(phi.degrees) z = radius * Math::sin(theta.degrees) pts << (p1 + [x, y, z]) x = radius * Math::cos((theta + dtheta).degrees) * Math::cos(phi.degrees) y = radius * Math::cos((theta + dtheta).degrees) * Math::sin(phi.degrees) z = radius * Math::sin((theta + dtheta).degrees) pts << (p1 + [x, y, z]) x = radius * Math::cos((theta + dtheta).degrees) * Math::cos((phi + dphi).degrees) y = radius * Math::cos((theta + dtheta).degrees) * Math::sin((phi + dphi).degrees) z = radius * Math::sin((theta + dtheta).degrees) pts << (p1 + [x, y, z]) if theta > -90 && theta < 90 x = radius * Math::cos(theta.degrees) * Math::cos((phi + dphi).degrees) y = radius * Math::cos(theta.degrees) * Math::sin((phi + dphi).degrees) z = radius * Math::sin(theta.degrees) pts << (p1 + [x, y, z]) end begin group.entities.add_face pts rescue end end end end 以上。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

加算と連結

加算 irb(main):0.330o> 1 + 3 => 4 連結 irb(main):0.330o> "1" + "3" => "13"
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rubyで利用できる型

型名 リテラル表記名 意味 integer 234 整数 Float 3.14159 浮動小数点 String "Hello World!" 文字列 Array [1,2,3,4] 配列 Hash {"Lemon" => 100, "Orange" => 150} ハッシュ Range 1..10 範囲 Symbol data[:name] シンボル Regexp /\A[ぁ-んァ-ン一-龥]/ 正規表現 NilClass nil 何もない TrueClass true 真 FalseClass false 疑
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails]bulletを使ってN + 1問題を解消

N + 1問題とは 要約するとSQLが沢山発行して動作が重くなってしまう問題 詳しくは以下の記事をご確認ください私も参考にさせていただきました。 bulletとは N + 1クエリを自動で検出するgemですうっかりN+1問題が起こってもすぐに見つけることができます。 ただbulletが検出できないようなN + 1クエリがあるケースがあるので頼りすぎるのもよくないです。↓以下参考記事 bulletを使う前 自作のアプリケーションでSQLを発行し確認してみたところ以下のようになった Processing by QuestionsController#index as HTML User Load (0.7ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 18], ["LIMIT", 1]] Rendering questions/index.html.erb within layouts/application Question Load (1.3ms) SELECT DISTINCT "questions".* FROM "questions" WHERE "questions"."best_answer_id" IS NULL ORDER BY "questions"."created_at" DESC LIMIT $1 OFFSET $2 [["LIMIT", 10], ["OFFSET", 0]] ↳ app/views/questions/index.html.erb:51 User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 18], ["LIMIT", 1]] ↳ app/views/questions/index.html.erb:52 これが100行ぐらい続くのである。。 bulletをインストール Gemfileに以下を追加します。 Gemfile group :development gem 'bullet' end bundle installを実行します。 $ bundle install そしてSQLを発行しているページにいく(筆者の場合indexページ)と以下のように表示された。 表示の通りコントローラーにincludes[:user])に書き換える - @questions = @q.result(distinct: true) + @questions = @q.result.includes(:user) こうするとポップアップが表示されなくなりSQLがどう発行されているか確認してみた。 Processing by QuestionsController#index as HTML User Load (1.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 18], ["LIMIT", 1]] Rendering questions/index.html.erb within layouts/application Question Load (0.7ms) SELECT "questions".* FROM "questions" WHERE "questions"."best_answer_id" IS NULL ORDER BY "questions"."created_at" DESC LIMIT $1 OFFSET $2 [["LIMIT", 10], ["OFFSET", 0]] ↳ app/views/questions/index.html.erb:51 User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."id" IN ($1, $2, $3, $4, $5, $6, $7, $8) [["id", 18], ["id", 17], ["id", 14], ["id", 19], ["id", 13], ["id", 9], ["id", 11], ["id", 3]] ↳ app/views/questions/index.html.erb:51 70行ぐらいに減っていた! includesを指定することで関連をまとめて取得し、最小限のクエリ回数で読み込みます。 以上です
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails]ransackでキーワード検索をする

はじめに 自作のQ&Aアプリケーションでキーワード検索を実装したのでメモとして残します。 ransackは複数テーブルを検索できるので例えばquestionテーブルに紐付いているtagテーブル のカラムに対しても検索をかけることができます。ransackのインストール方法は以下をご覧ください [Rails]ransackインストール テーブルの関係 questionテーブルの子テーブルとしてtagテーブルを設定している model/question.rb has_many :tags model/tag.rb belongs_to :question コントローラー コントローラー以下のようになっている def index @q = Question.ransack(params[:q]) @question = @q.result(distinct: true) end 実装方法 以下のビューファイルのように記述します。 index.html.erb <%= search_form_for @q do |f| %>   <%=f.search_field:title_or_body_or_tags_name_or_country_name_cont,class:"form-control", placeholder: "キーワード検索"%> <%= f.submit class: "input-group-text"%> <% end %> 自身のテーブルのカラムを検索したいときはtitleのようにカラムを一つ指定して記述する しかし子テーブルtagのnameカラムを指定したいときはtag_nameのようにスネークケースで繋げて記述する。 上記を見ても分かるとおり複数のカラムを検索したい場合は_or_で繋げることで実装できる。 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

草野球の出欠確認Webアプリを作ろう! part.5

これから作っていく簡単なWebアプリの作成メモ(自分の備忘)です。 自分用なのであまり凝りすぎないように書いていきたい。 <<前回の記事 今回やったこと Rspecの導入 ようやく重い腰を上げてRspecを導入する。 以下の記事を参考にした(基本的に記事の通りにした)。 RailsアプリへのRspecとFactory_botの導入手順 Gemfile group :development, :test do gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] (既存のgem) gem "rspec-rails" gem "factory_bot_rails" end $ bundle $ bundle exec rails generate rspec:install config/application.rb config.generators do |g| g.test_framework :rspec, view_specs: false, helper_specs: false, routing_specs: false end spec/rails_helper.rb RSpec.configure do |config| config.include FactoryBot::Syntax::Methods (略) end spec/rails_helper.rb Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f } ↑rails_helper.rbの記述は私の環境ではコメントアウトを解除すればよかった(最初に生成した時からコメントアウトで書いてあった)。 Rspecの動作確認 まず参考記事の内容をなぞって、FactoryBotに新規フォルダ・ファイルを作成して定義をする。 $ mkdir ./spec/factories/ $ touch ./spec/factories/users.rb spec/factories/users.rb FactoryBot.define do factory :user do sequence(:name) { |n| "TEST_NAME#{n}"} sequence(:email) { |n| "TEST#{n}@example.com"} sequence(:password) { |n| "TESTpassword"} sequence(:password_confirmation) { |n| "TESTpassword"} end end FactoryBotのほうを整えたら、テストコードを作成する。 $ mkdir ./spec/models/ $ touch ./spec/models/users_spec.rb /spec/models/users_spec.rb require 'rails_helper' RSpec.describe User, type: :model do before do @user = build(:user) end describe 'バリデーション' do it 'nameが空だとNG' do @user.name = '' expect(@user.valid?).to eq(false) end it 'emailが空だとNG' do @user.email = '' expect(@user.valid?).to eq(false) end it 'password_digestがfalseだとNG' do @user.password_confirmation = '' expect(@user.valid?).to eq(false) end it 'nameとemailどちらも値が設定されていれば、OK' do expect(@user.valid?).to eq(true) end end end テストコードを実行する。 $ bundle exec rspec spec/models/users_spec.rb きちんと動作したのでハッピー。 実行結果 .... Finished in 0.07136 seconds (files took 1.74 seconds to load) 4 examples, 0 failures 短いけど今回はここまで。 次回からようやくTDDの真似事ができるようになる(つもりでいますが、挫折する可能性も...)。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む