プログラミング学習

Rubyやrailsについて学んだことをアウトプットしています。

【Ruby】FizzBuzzアプリを作ってみる

今回はプログラミングを学ぶ上で多くの人が経験するであろうFizzBuzzアプリの作り方について学んでいきます。

FizzBuzzアプリとは

FizzBuzzアプリのコードを書いてみる

FizzBuzzアプリとは FizzBuzzアプリとは一般的に以下の要件を満たすアプリだといわれています。

① 1~任意の数を順番に表示する。
② 3の倍数の時は"Fizz"を表示する。
③ 5の倍数の時は"Buzz"を表示する。
④ 両方で割り切れる数の時は”FizzBuzz”と表示する。

これらすべての条件を満たすために条件分岐をうまく活用しながらロジックを考えていきます。
FizzBuzzアプリのコードを書いてみる
まず、最初のステップとして要件①の任意の数字を受け取るようにしましょう。
ユーザーから数字を受け取るためにはgetsメソッドを使います。コードで書くと以下のようになります。

number = gets.to_i

(1..number).each do |x|

end

getsメソッドで受け取った数値をnumber変数に代入しています。
この時、注意が必要なのはgetsメソッドはデータを文字列として受け取るということです。
なので、受け取った文字列データをto_iメソッドを使って数値データへと変更しています。
数値に変更することで(1..number)の部分で任意の数字それぞれにアクションを行うよう指示が出せます。

次はeach分の中身を考えていきましょう。
今回は条件分岐のif文を使用します。
まず、条件④の3と5両方の倍数であるかを確認します。
この時には%を使うと便利です。%は対象の数字に対して割り算を行った結果、余りの値を教えてくれます。
if文と組み合わせると以下のようにコードが書けます。

number = gets.to_i

(1..number).each do |x|
  if x % 15 == 0
    puts "FizzBuzz"
  end
end

これで15の倍数の時に"FizzBuzz"を出力するプログラムができました。
同じ要領で"Fizz"と"Buzz"も作っていきます。

number = gets.to_i

(1..number).each do |x|
  if  x % 15 == 0
    puts "FizzBuzz"
  elsif  x % 5 == 0
    puts "Buzz"
  elsif x % 3 ==0
    puts "Fizz"
  else
    puts x
  end
end

以上のコードで条件をすべて満たすことができました。

ちなみに、要件④を一番最初に書いたのはプログラミングでは上から順番にコードが読まれるという特徴があるからです。
なので、先に要件③や②を書いてしまうと"FizzBuzz"にたどり着く前に他の文字列が表示されるという問題が発生してしまうのです。

以上でFizzBuzzアプリについての説明を終わります。
プログラミングを勉強する上で大切な要素がたくさん含まれていたと思うのでしっかり身に着けていきたいです。

【rails エラー】エラーから学ぶlink_toメソッド

先日redirect_toメソッドから生成される遷移先の理解不足によってエラーが発生してしまいました。

【Rails】エラーメッセージから学ぶredirect_toメソッドについて - プログラミング学習

今回はredirect_toメソッドと似ているlink_toメソッドについて学ぶことでrailsの遷移に対する理解をより深めていきたいと思います!

  • link_toメソッドとは
  • link_toメソッドの使い方


・link_toメソッドとは
link_toメソッドとは
「リンクを作成するためのメソッドのこと」
を指します。
詳しく説明するとlink_toメソッドを使用することによってHTMLのリンクタグであるaタグを簡単に生成することができるのです。
それでは詳しい使用方法について見ていきましょう。

・基本の書き方
link_toメソッドは以下のようにリンク元になる文字とリンク先のパスで構成されています。

<%= link_to '表示したい文字', パス %>

このコードを書くことによって

<a href="パス">表示したい文字</a>

リンク先で指定できるものは大きく2つに分けられます。
・内部リンク…作成中のアプリ内のページを表示するリンク
・外部リンク…それ以外のリンク

  • 内部リンクの作成方法 内部リンクの具体的な例としては以下のようなコードが挙げられます。
<%= link_to 'New Fruit', new_fruit_path %>

ここで「new_fruit_path」の部分について詳しく見ていきましょう。
このpathはURLヘルパーメソッドと言い、URLを作成することを簡単にしてくれています。
今回のnew_fruit_pathからはfruit/newというURLを作成してくれています。
また、このpathはターミナルでrails routesコマンドを実行すると確認することができます。
f:id:yusuke_learning:20211027231008p:plain 写真の左側のPrefixの部分に_pathを付け加えてあげることで指定したいURLのヘルパーメソッドを作ることができます。
ただし、URI Pattern欄に「:id」と表示されている場合は、内部リンクのパスで「fruit」のようにパラメータを指定する必要があるので注意が必要です。
パラメーターを指定することによって編集や削除を行うためのリンクを作成することができます。
例えば、以下のようにviewページ上でfruitオブジェクトを作成したうえでそのパラメーターを取得したURLを作成すると

<% @fruits.each do |fruit| %>
<%= link_to 'Edit', edit_fruit_path(fruit) %>

下のようにそれぞれのオブジェクトに対応したリンクを作成することができます。

<a href="/fruits/1/edit">Edit</a>

また、削除に関しても以下のようにオブジェクトを指定することでそれぞれを削除することができます。

<%= link_to '削除', fruit, method: :delete %>

ここでのmethod: :delete とはHTTPメソッドの種類を表しています。link_toメソッドではデフォルトがGETメソッドに設定されているのでdeleteに変更してあげることで削除の指示を指すことができます。

・外部リンクの作成方法

外部リンクとはウィキペディアなど自分のアプリ以外のシステムで動いているサイトへのリンクのことを指します。
書き方としては以下のようになります。

<%= link_to '果物 - Wikipedia', "https://ja.wikipedia.org/wiki/果物" %>


以上でlink_toメソッドについての説明を終わります。
railsでよく見るlink_toに対する理解を深めることが今後の勉強にも役立つと思うので基礎を忘れずに勉強続けていきます!!


参考記事:


【Rails入門】link_toの使い方とオプションをわかりやすく解説! | 侍エンジニアブログ

【初学者向け】_urlや_pathといったヘルパーメソッドの使い方 - Qiita

【Rails エラー】No route matchesの原因と解決方法

今回もオリジナルアプリを開発している過程でエラーに遭遇しました。
このエラーはSessionモデルを使用してログイン機能を実装している過程で発生しました。
今回はこのエラーの原因と対処法、それに関連したルーティングに関して考えていきます! f:id:yusuke_learning:20211026184659p:plain

・エラーコードから原因を読み解く

・ルーティングについて


・エラーコードから原因を読み解く


今回のエラーコードについて読み解いていきます。
まず、エラーの発生はログイン機能においてメールアドレスとパスワードを入力し、ログインボタンを押したときに発生しました。f:id:yusuke_learning:20211026185237p:plain

以下のエラーコードによるとRoutingに関して問題が発生していることがわかります。
さらに詳しく見ると
・POSTメソッドで/session/newに該当するルーティングが見つからない。
ことが原因であることがわかります。
よって、今回のエラーはRoutingに関する記載があるroutes.rbファイルと原因となるリクエストを送信したログインページを見れば解決できると考えられます。 f:id:yusuke_learning:20211026184659p:plain

・該当箇所を確認する f:id:yusuke_learning:20211026190537p:plain 該当箇所のログインページを見ていきます。
ここではメールアドレスとパスワードを入力することでsessionコントローラーのcreateアクションに遷移するように設定されています。
コードを見たところ特に問題はなさそうに思えます。
次にroutes.rbのファイルを確認しましょう。
f:id:yusuke_learning:20211026185745p:plain routes.rbではsession#createに繋がるアクションは"/login"に繋がれていました。ルーティングの方でURL先を変更していたのにログインフォームで変更を加えていなかったことがルーティングエラー発生の原因でした。
そこでログインフォームを以下のように変更します。

<%= form_with  url: login_url, scope: :session, local: true do |f| %>

これによってurl先は/loginにしてすることができました。
この状態でログインを行うと f:id:yusuke_learning:20211026191846p:plain 今度は別のエラーが発生してしまいました…
しかし、URLの部分を見てみると
f:id:yusuke_learning:20211026191928p:plain "/login"となっており指定したかったURL先に変更しています。エラーの内容も変わったことから先ほどのエラーはとりあえず解決できたと考えられます。

そこで今回のエラーコードを読み解いてみると Sessionコントローラーが単数形で登録されているが複数形ではないか?といった内容でした。
ここでもう一度routes.rbを確認してみると
f:id:yusuke_learning:20211026192154p:plain "session#create"の部分が単数形になってしまっていました! この部分を修正すると無事にログインアクションが行えました!

・エラーコードから原因を読み解く


最後に今回のエラーの原因となったルーティングについて学習しましょう。
ルーティングとはRailsアプリケーションのコントローラへ指示を出すための道筋のことでです。
その設定方法は基本的に以下の形になります。 f:id:yusuke_learning:20211026192824p:plain HTTPリクエストのメソッドを指定し、URL(パス)とコントローラー名#アクション名で定義します。
ルーティングファイルを確認するときにちゃんとこの基礎の形に沿っているかを確認することで今回のようなエラーを防ぐことができたと思います!

同じエラーを起こさないように今後も頑張ります!!
参考資料:


Rails ルーティング 基礎 まとめ - Qiita

【Rails エラー】RecordNotFoundとredirect_toメソッドについて

先日オリジナルアプリの開発を行っていたところ以下のようなエラーが発生しました。f:id:yusuke_learning:20211025213106p:plain

なので、今回はこのエラーの解決方法と深くかかわっていたredirect_toメソッドについて以下の順で学んでいきます。

・エラーコードから原因を読み解く

・redirect_toメソッドとは



・エラーコードから原因を読み解く


今回のエラーはユーザー登録を行うためにUserモデルを作成し、CRUD機能の実装を行い登録したユーザーを削除したときに発生しました。f:id:yusuke_learning:20211025213106p:plain エラーコードの内容を確認すると
①エラーが発生しているのはUserコントローラーのshowアクション内であること。

②エラーの原因は"id"=13(今回削除テストを行ったユーザーのid)を持ったユーザーが見つからないため詳細を表示することができないというものであること。

ということがわかりました。
つまり、今回の原因はユーザーを削除する機能ではなく削除した後の指示に問題があることがわかりました。
さらに詳しく考えると
showアクションでエラーが発生してしまっているため削除後にユーザー一覧に返したいはずが詳細ページに移動するように指示してしまっていることが原因だと考えられます。

このようにエラーコードを読み解くことで原因の特定が容易になるためエラーが出たときはしっかりと向き合うことが大切になることを実感しました。
それでは該当箇所であると思われるUserコントローラーのdestroyアクションを見ていきましょう。


Userコントローラーのshowアクションには以下のコードが書かれていました。

  def destroy
    @user = User.find(params[:id])
    @user.destroy
    redirect_to admin_user_path
  end

今回のエラーの原因となっているのはredirect_toの部分です。この部分を

redirect_to admin_users_path

に変更することで削除後に正しくユーザー一覧ページに飛ぶことができ、エラーの問題を解決することができました。 次にエラーの原因となったrenderメソッドについて学んで同じエラーを起こさないようにしていきましょう。




・redirect_toメソッドとは


redirect_toメソッドは指定されたURLに遷移を行ってくれるメソッドです。よって書き方は以下のようになります

redirect_to "リダイレクト先"

URL以外にも様々な方法でリダイレクト先を指定することができます。いくつか紹介していきます。

redirect_to Prefix名
# pathによって遷移先を指定
<br>
redirect_to action: :アクション名
# 同一コントローラーのアクションを指定
<br>
redirect_to  controller: :コントローラー名, action: :アクション名
# アクションだけでなくコントローラーも指定
<br>
redirect_to  controller: :users, action: :show, id: 1
# usersコントローラーのshowアクションにid=1を渡す

今回のエラーに関してはpathを使用して遷移先を指定しており、それが誤ってshowアクションになってしまっていました。
ちなみに、pathの確認はrails routesを行うことで確認できるので皆さんもredirect_toメソッドに関係するエラーが出たときは一度確認してみてください。



参考サイト


【Rails】 | Pikawaka - ピカ1わかりやすいプログラミング用語サイト

【Rails】form_withとは

今回はRailsで入力フォームを作成するときに登場するform_withメソッドについて見ていきます。

  • form_withヘルパーとは

  • そもそもフォームとは

  • form_withヘルパーの使い方



form_withヘルパーとは
まず初めにform_withヘルパーとはどのようなものなのかについて見ていきます。

form_withとは、railsで情報を送信するためのヘルパーメソッドです。 form_withを使うことにより、簡単に入力フォームに必要なHTMLを作成することができます。
引用元:【Rails】 form_withの使い方を徹底解説! | Pikawaka - ピカ1わかりやすいプログラミング用語サイト

こちらのサイトによるとform_withとは簡単に入力フォームに必要なHTMLを作成することができるヘルパーメソッドのことのようです。
つまりform_withを理解するためにはHTMLの入力フォームについての理解が必須となります。
なので、HTMLの入力フォームについて見ていきましょう。


ウェブフォームとは
ウェブフォームとはユーザーが ウェブサイトへデータを送るためのものです。
送信されたデータは ウェブサーバーに送られて処理、保存されるなどして扱われます。
このウェブフォームには以下のHTML要素が使用されます。それぞれ詳しく見ていきましょう。


  • formについて 全てのフォームはこの
    タグから始まります。このタグでフォームを構成する部品を囲います。
<form action="/my-handling-form-page" method="post">
</form>

このフォーム内でフォーム動作を設定するための属性をサポートすることができます。
属性の中でも特に大切よなるのは以下の2つです。

  • action属性…フォーム内で収集したデータを送信する場所のURLを定義する。

  • method属性…データを送信するために使用するHTTP メソッドを定義する。
    その他にもたくさんの属性がありますがとりあえず上記の2つを押さえておきましょう。


  • labelについて このタグはフォームの部品に対して名前を付けることができます。
    以下のコードのようにlabel forの形で名前を指定することによって入力部分との紐づけをすることが可能になります。
<form action="/form.php" method="post">
        <div>
            <label for="name">名前</label>
        </div>
</form>
  • inputについて このタグは実際に入力を行うためのフィールドを設置する役割も持ちます。
    inputタグではinput = "text"などの形で属性を指定することができ、この属性によって入浴される値の種類(メールアドレス、テキストなど)を決めることができる。
    また、inputタグ内のidがlabelのfor属性と日もずいている。
    さらにname="name"の部分ではそれぞれの入力した値に対して名前を付けているので複数のデータが送信された場合でも値の識別を行うことができます。
 <form action="/form.php" method="post">
        <div>
            <label for="name">名前</label>
            <input type="text" id="name" name="name">
        </div>

  • textareaについて このタグではinputタグのtext属性と同じような外観を作ることができ、複数のテキストを入力することができます。
<label for="message">内容</label>
            <textarea id="message" name="message"></textarea>

  • buttonについて 最後のタグのbuttonはユーザーがフォームに記入したらデータを"送信"するためのボタンを追加します。
    buttonタグはsubmit属性を受けることでボタンをクリックするとフォームのデータを、 要素の action 属性で定義した ウェブページへ送信してくれます。
<li class="button">
  <button type="submit">メッセージを送信</button>
</li>

ここまででウェブフォームがどのようにして構成されているかを学ぶことができました。
次に本題であるform_withヘルパーメソッドによってウェブフォームを書くことがどのように簡略化されるのかについて見ていきましょう。



form_withの使い方
form_withヘルパーでは以下のようにコードを記述することで先ほど紹介したウェブフォームに必要なHTMLを生成してくれます。

<%= form_with model: @user do |f| %>
  <%= f.label :name %>
 <%= f.text_field :name, id = "task_name" %>
  <%= f.submit '登録' %>

また、データの送信先については、:urlオプションを追加することによっても指定できますが、
渡されたモデルの状態(①新規②既存)によって自動推定をしてくれるます。
新規の場合であればcreateアクションに既存の場合であればupdateアクションに送信されます。


以上でform_withに関する説明を終わります。
長くなってしまいましたがフォームに対する理解を深めることでform_withヘルパーに対する理解も深まったと思います!

参考記事: https://qiita.com/hakusai_it/items/234d10c97c380294c285

初めてのフォーム - ウェブ開発を学ぶ | MDN

【HTML入門】formタグを使ってフォームを作る方法を1から解説 | 侍エンジニアブログ

【Paizaラーニング】RubyのC問題を攻略する

私は現在PaizaアプリでRuby言語を勉強しており、Bランクを目指しています。

今回はCランクレベルアップ問題集の「文字列FINAL問題」を解いていきます!




問題について

パイザ君の家の前では毎週日曜日に工事が行われます。この先 N 週間、工事が日曜日の何時に始まり、どれくらいの時間続くのかは分かっています。パイザ君は工事の間は家を離れようと思っているので、それぞれの日に工事が何時に終わるのかを知りたいと思いました。
工事が N 週間続くとして、各週日曜日の工事が始まる時刻と、工事が何時間何分続くのかに関する情報が与えられるので、工事が終わる時刻を 00:00 から 23:59 までの 24 時間表記で出力してください(ここで「工事が終わる時刻」とは、工事が h 時間 m 分続くとした場合、工事が始まった時刻の h 時間 m 分後を指します)。

上記が今回の問題文になります。 入力・出力例としては

1
13:00 1 30

が入力されると

14:30

が出力されます。現在時間(13:00)と工事にかかる時間(1:30)が入力されて工事終了後の時刻が表示されていることがわかりますね。
それでは次にコードを書くために問題文をかみ砕いていきましょう。

回答のポイント

この問題で重要となる点は以下の3点です。

  • 入力された値の受け取り方

  • 時間の繰り上げについて

  • 出力時に00:00のにすること

それぞれ見ていきましょう。

まず、入力された値の受け取り方について今回受け取る数値は以下のように分けられます。

  • n…工事が何週間続くのかを表す。

  • h…現在時刻の時間部分を表す。

  • m…現在時刻の分部分を表す。

  • h_a…追加される時間数を表す。

  • m_a…追加される分数を表す。 これらを踏まえて入力された値を受け取るコードを書いてみましょう。

n = gets.to_i
# 工事が続く回数だけ終了時刻を求めるのでn以下の値はeachメソッドを使用して繰り返し処理を行います。
n.times do
    h_m, h_a, m_a = gets.split(" ")
# ここではsplitメソッドを使用し、入力された値をスペース区切りで配列に格納します。
# 配列の長さと同じ変数を並べて代入すると配列の要素が先頭からそれぞれの変数に代入されます。
    h, m = h_m.split(":").map(&:to_i)
# h_mには現在時刻が13:46といった形で入っているのでそれぞれ時間と分数に分けてあげます。
# mapメソッドを使用すると配列の各要素に指定したメソッドの処理を受け取ることができます。今回は文字列で受け取った入力値を数値へと変換しています。
    h_a = h_a.to_i
    m_a = m_a.to_i
# ここでも同様に文字列の値を数値に変換しています。それぞれの値を数値に変換しないと足し算が行えないからです。
end

次に受け取った時刻に工事の終了時刻を追加してあげましょう。

h_t = h + h_a
m_t = m + m_a

これでh_tが終了時刻をm_tが終了時刻の分数を表すようになりました。

次に時間の繰り上げについて考えていきます。
前回のままのコードだと時刻が24時を過ぎた場合や分数が59分を超えた場合は27:67のように表示されてしまいます。
この問題を解決するために条件分岐のif文を使用していきます。

if m_t > 59
  m_t = m_t - 60
 m_h = m_h + 1
end
# 分数が59を超えた場合は時刻に1繰り上げ、分数からは60を引きます。
if m_h > 23
  m_h = m_h - 24
end
# 時刻に関しても23時を超えた場合は24を引き、24時間表示にします。



最後に出力時に00:00のにすることについて考えていきます。
今のままのコードでは24:3や8:22のように指定された24:03や08:22の形での出力が行えません。
そこでh_tとh_mそれぞれに値が一桁の場合は先頭に0を付け足すようにコードを加えます。

 h_t = h_t.to_s
 m_t = h_m.to_s
# 合計値が一桁かどうかを確かめるために数値を文字列に変更します。
if h_t.length == 1
  h_t = "0" + h_t
end
if h_m.length == 1
  h_m = "0" + h_m
end
# lengthメソッドによって桁数を確認し、1桁の場合は先頭に0を追加しています。

最後に合計時刻を出力するコードを追加すると完成です。

puts h_t + ":" + h_m
綺麗なコードを書くには

ここまでで以下のようなコードが完成しました。
このコードでも問題をクリアすることはできるのですが少しごちゃごちゃしていて読みにくさがあります。
そこで今回は①if文を1行で書く②+=を活用するの方法でより整理されたコードにしていきます。
①if文の省略について
if文は以下のように複数行のものを1行にまとめることができます。

  if h_t > 23
    h_t = h_t - 24
  end
h_t = h_t - 24 if h_t > 23


②+=の記号を使うと以下のような文章を省略して書くことができます。
h_tにh_tから24を引いた数値を代入する場合は重複が発生するので-=で引いた数がh_tであるということを示しています。

h_t = h_t - 24 if h_t > 23
h_t -= 24 if h_t > 23

これら2つの方法を使うと

n = gets.to_i
n.times do
  h_m, h_a, m_a = gets.split(" ")
  h, m = h_m.split(":").map(&:to_i)
  h_a = h_a.to_i
  m_a = m_a.to_i
  h_t = h + h_a
  m_t = m + m_a
  if m_t > 59
    m_t = m_t - 60
    h_t = h_t + 1
  end
h_t -= 24 if h_t > 23
    h_t = h_t.to_s
    m_t = m_t.to_s
m_h = "0" + m_h if m_h.length == 1
m_t = "0" + m_t if m_t.length == 1

      puts h_t + ":" + m_t
end

このようにコードを整理することができました。
問題に正解することはもちろん大切ですがプログラミングを仕事にするとなると整理されてわかりやすいコードを書くこともとても大切になってくると思うので常により良いコードを追い求めていきたいですね!

今回は以上となります。お疲れさまでした!


参考記事: Cランクレベルアップメニュー(言語選択) | レベルアップ問題集 | プログラミング学習サービス【paizaラーニング】