20210302のRubyに関する記事は21件です。

webpackとは?

webpackとは

  1. Webアプリケーションを作成する際に必要な、
    様々なJavaScriptをひとまとめに管理する為のツール
  2. モダンなWebアプリケーション開発では、
    様々なJavaScriptライブラリを用いる為、その依存関係を管理してくれる

以前取り上げた機械語と人間語とも関連しています。

webpackの公式ドキュメントこちらも参考として添付します。

webpackが行うこと

基本要素 読み 役割
Entry エントリー 依存関係を解決するために、
どのファイルを基準(エントリーポイント)とするかを決める
Output アウトプット エントリーポイントにされ、
webpackによってまとめられたファイルを、
どこへどのような名前で出力(アウトプット)するのか指定する
Loaders ローダー JavaScript以外のCSSやHTMLなどのファイルを
モジュールに変換する方法を読み込み(ロード)、指定した処理を行う
Plugins プラグイン 圧縮などの、ファイルをまとめる以外で
ローダーが実行できないタスクを導入し、拡張(プラグイン)する

webpackを用いることで、JavaScriptのライブラリとJavaScript以外の
さまざまな言語を、変換・圧縮した上で、好きな場所に配置することが可能

WebpackerというGem

Railsにもwebpackを導入してコマンドによる操作が可能だが、
設定ファイルの記述がやや難しくなっている
そのため、設定を簡易化してくれるWebpackerというGemを使用

Webpacker

webpackをRails仕様にし、専用の設定ファイルやヘルパーメソッドを用意してくれるGem

Railsバージョン6系以降からは、デフォルトでWebpackerが導入される

近年のフロントエンド技術の台頭により、
(主には、JavaScriptのライブラリが充実してきたこと)
Sprocketsからwebpackを利用する方針へ転換された

Webpackerの公式GitHub

Webpackerによって、
Sprocketsのアセットパイプラインと同じような静的ファイルのプリコンパイルに加え、
JavaScriptのパッケージが利用できるようになる

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

formのオプションを条件分岐する

ポートフォリオのテスト用アカウントやゲストアカウントなどで、アカウントデータを改変できないようにしたい場合があると思います。真っ先に思い浮かぶ記述方法は以下のようなものだと思います。

<%= f.text_area :nickname, readonly: "#{'readonly' if current_user.email == 'test@gmail.com'}" %>

しかし、これだとなぜかどちらでもreadonlyになってしまい、上手く条件分岐できません。おそらく、falseの処理が無いためだと思います。
逆に、trueかfalseになる処理にしてあげれば、上手くいくのではと考えました。

前提

・deviseを使ったユーザー認証を導入している。
・すでにテストアカウントを作成している。
※今回の場合は、「テストアカウントをすでに作成しており、そのデータを編集画面で表示はするが、編集はできないようにしたい。ただし、テストアカウントでは無い場合は編集でき、ビューに<% if ~ %>などで二度同じ様な記述を避けたい。」というものです。

text_areaなどの入力する系

text_area | Railsドキュメント
email_field | Railsドキュメント

<%= form_with model: @user, url: user_registration_path, local: true do |f| %>

  <%= f.text_area :nickname, readonly: current_user.email == "test@gmail.com" %>

  <%= f.email_field :email, readonly: current_user.email == "test@gmail.com" %>

<% end %>

この場合だと、readonly: truereadlonly: falseになるので、正しく条件分岐ができるようになります。
他のメソッドでも同じようにできます。

画像の選択

file_field | Railsドキュメント

<%= f.file_field :image, disabled: current_user.email == "test@gmail.com" %>

画像の場合は、readlonlyオプションが容易されていますが、readlonlyでは画像の選択ができてしまいます。ですので、無効化するdisabledオプションで指定します。

セキュリティ

上記の記述は、あくまでビュー側での条件分岐です。実際にデータを改変できないようにするには、サーバ側で弾く処理を加えてやる必要があると思います。

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

dockerでgemを追加したときにbundle installではなくbuildする

備忘録的な感じです

題名にある通りDockerでrails開発をしていてgemを追加した後

$ docker-compose run --rm (コンテナ名) bundle install

を試したらgemが更新されずエラーになる

$ docker-compose build

でエラーも出ず解決した。

色々調べていたらdockerfileの

Dokerfile
FROM ruby:2.6.6
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client
RUN mkdir /rails-qanda
WORKDIR /rails-qanda
COPY Gemfile /rails-qanda/Gemfile
COPY Gemfile.lock /rails-qanda/Gemfile.lock
RUN bundle install
COPY . /rails-qanda

のCOPY Gemfile /rails-qanda/Gemfileが
[COPY] ローカルのファイルをコンテナへコピー
という意味らしいのでgemを追加したらここの部分やり直すためにbuildし直すということなのかな。

また理解が深まり次第追記予定

docker難しい、、

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

あとからカラム属性にインデックスを追加する

インデックス(索引)

インデックスとは検索やソートを高速化するためのデータ構造の事です。
むやみにインデックスを貼るのはデータベースリソースを余分に使うため、性能が向上するかどうかを見極めてから作成する必要があります。

モデル作成とadd_indexを同時に試みるも、

PG::UndefinedTable: ERROR:  relation "care_recipitents" does not exist

エラーを吐かれてしまったので先にモデルを作成しました。

migrationファイルを作成します。

rails g migration add_index_to_carerexipidents
class AddIndexToCarerexipidents < ActiveRecord::Migration[6.0]
  def change
    add_index :care_recipitents, [ :family_name_kana, :given_name_kana ]
  end
end

複合インデックスを作成しています。

rails db:migrate

schema.rb

 t.index ["family_name_kana", "given_name_kana"], name: "index_care_recipitents_on_family_name_kana_and_given_name_kana"

ちゃんと貼られています。

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

【Ruby】初心者がるりまを読んで初めて知ったメソッドをまとめてみる

最近るりまを読んでいるので、学習したメソッドから有用そうなものをまとめていこうと思います(追加予定)
たのしいRubyを読み終わったあたりの初心者が対象の記事です

Arrayクラス

eql?(other) -> bool

selfotherを比較します
普段使うなら==で事足りますが、11.0を区別するといった場合に有用です

fetch(nth) -> object

idxの要素を返します
[]と違うのは、要素がなかった場合の挙動です
1. 第二引数を与えているとその値を返す
2. ブロックを与えているとnthをブロック変数としてブロックを評価  しその戻り値を返す
3. どちらもなければ例外発生

if文を書かなくも様々な対応ができる素晴らしいメソッド

dig(idx, ...) -> object | nil

ネストしたオブジェクトを参照して返します
[]を連続して使うのと結果は同じですが見栄えが良くなります

ary = [[1, [2, 3]]]

ary[0][1][1]     #=> 3
ary.dig(0, 1, 1) #=> 3

values_at(*selectors) -> Array

selectorsのインデックスに対応する要素を配列で返します
インデックスの指定方法は[]と似ています

ary = ["a", "b", "c", "d"]

ary.values_at(0, 1) #=> ["a, "b"]
ary.values_at(0..2) #=> ["a", "b", "c"]

assoc(key) -> Array | nil

selfを配列の配列と仮定して[0]keyと等しい最初の配列を返します
元々はハッシュのような配列のためのメソッドですが、特殊な形式の配列に使えそう

[[1, 10], [2, 20]].assoc(2) #=>[2, 20]

[1]を検索する rassoc というメソッドもあります

rindex(val) -> Integer | nil

valと等しい最後の要素を返します
index の逆バージョンですね

bsearch { |x| ... } -> object | nil

rubyで二分探索ができます
使えそう(希望的観測)

delete_at(pos) -> object | nil

インデックスでdelete出来ます

delete_if {|x| ... } -> self

ブロックの評価が真(nil, false以外)になった要素を削除します
reject! と違い、変化がなくてもselfを返すので中々便利

ブロックの評価が偽になった要素を削除する keep_if もあります

drop(n) -> Array

先頭からn個の要素を削除して残った配列を返します
削除した要素を返す shift と違い、残った要素を返すので使い分けができますね

ブロックで判定を行う drop_while もあります

dup -> Array

selfのコピーの配列を返します
レシーバと戻り値は別のオブジェクトですが、要素は同じオブジェクトを参照しているので、完全なコピーを作るには Marshalモジュール がオヌヌメです

*配列の要素がIntegerなどのイミュータブルなオブジェクトであればdupで大丈夫です

sample -> object | nil

selfからランダムな要素を一つ返します
引数を与えた場合(たとえ1でも)その個数のランダムな要素を配列で返します

reverse_each {|item| ... } -> self

selfを逆順にブロック変数に代入しブロックを実行します
見た目ではreverse.each {|item| ...}とほぼ変わりませんが、たぶん処理効率が良いです

zip(*lists) -> [[object]]

selflistsの各要素からなる配列の配列を生成して返します

ary1 = [1, 2, 3]
ary2 = [4, 5, 6]

ary1.zip(ary2) #=> [[1, 4], [2, 5], [3, 6]]

ブロックを与えるとzipした結果の配列でイテレーションします

rotate(cnt = 1) -> Array

cntの位置の要素を先頭とした配列を返します

ary.rotate    #=> [2, 3, 4, 1]
ary.rotate(2) #=> [3, 4, 1, 2]

破壊的なrotate!もあります

flatten(lv = nil) -> Array

selfを平坦化した配列を返します

有名なメソッドですが、実は引数を取れるようです
lvを与えるとその深さまで平坦化します

ary = [1, [2], [3, [4]]]

ary.flatten    #=> [1, 2, 3, 4]
ary.flatten(1) #=> [1, 2, 3, [4]]

uniq -> Array

selfから重複した要素を削除した配列を返します
ブロックを与えた場合、各要素をブロック変数としてブロックを評価し、その戻り値が重複した要素を削除します

["Alice", "alice", " Tony"].uniq(&:downcase) #=> ["Alice", " Tony"]

transpose -> Array

selfを行列と見立て、縦列と横列を入れ替えます

ary = [
  [1,2],
  [3,4],
  [5,6]
]

ary.transpose #=> [[1, 3, 5], [2, 4, 6]]

to_h -> Hash

self[key, value]のぺアの配列として解析した結果をHashにして返します

有名なメソッドですが、実はブロックを取れます
ブロックが与えられた場合、各要素をブロック引数としてブロックを評価し、その戻り値を[key, value]のペアの配列として解析します

[1, 2].to_h { |x| [x, x * 10] } #=> {1=>10, 2=>20}

each_with_objectなどでコーディングするよりもかなり文章量が減りますね

最後に

るりまをよむのはいいぞ。(るりまおじさん)
表現力が上がり、メソッドの詳しい挙動が知れることもあり、良い事づくめです
紹介してないメソッドも沢山あるのでぜひ

初心者は ruby style gide を読むのもオススメです

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

【Railsチュートリアル】第11章 アカウントの有効化②

11.3 アカウントを有効化する

AccountActivationsコントローラのeditアクションを書いていく。アクションへのテストを書き、しっかりとテストできていることが確認できたら、AccountActivationsコントローラからUserモデルにコードを移していく作業(リファクタリング)にも取り掛かかる。

11.3.1 authenticated?メソッドの抽象化

sendメソッドを使うと共通化できる。

sendメソッド とは?
渡されたオブジェクトに「メッセージを送る」ことによって、呼び出すメソッドを動的に決めることができるメソッド。

>> user = User.first

>> user.activation_digest
=> "$2a$10$4e6TFzEJAVNyjLv8Q5u22ensMt28qEkx0roaZvtRcp6UZKRM6N9Ae"

>> user.send(:activation_digest)
=> "$2a$10$4e6TFzEJAVNyjLv8Q5u22ensMt28qEkx0roaZvtRcp6UZKRM6N9Ae"

>> user.send("activation_digest")
=> "$2a$10$4e6TFzEJAVNyjLv8Q5u22ensMt28qEkx0roaZvtRcp6UZKRM6N9Ae"
  # 文字列も渡すことができる

>> attribute = :activation
  # シンボルを代入

>> user.send("#{attribute}_digest")
=> "$2a$10$4e6TFzEJAVNyjLv8Q5u22ensMt28qEkx0roaZvtRcp6UZKRM6N9Ae"
  # 式展開を使って渡す

演習 1

コンソール内で新しいユーザーを作成してみてください。新しいユーザーの記憶トークンと有効化トークンはどのような値になっているでしょうか? また、各トークンに対応するダイジェストの値はどうなっているでしょうか?

>> user = User.create(name: "sample", email: "sample@email.com", password: "sample", password_confirmation: "sample")
   (4.2ms)  SELECT sqlite_version(*)
   (0.1ms)  begin transaction
  User Exists? (1.8ms)  SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER(?) LIMIT ?  [["email", "sample@email.com"], ["LIMIT", 1]]
  User Create (8.4ms)  INSERT INTO "users" ("name", "email", "created_at", "updated_at", "password_digest", "activation_digest") VALUES (?, ?, ?, ?, ?, ?)  [["name", "sample"], ["email", "sample@email.com"], ["created_at", "2021-03-02 04:11:18.445221"], ["updated_at", "2021-03-02 04:11:18.445221"], ["password_digest", "$2a$12$.NT19iae7r0WhFR2OcikiemF5WD3QvT0aA4/LJUSZ9UHYOt4XB0T."], ["activation_digest", "$2a$12$jKN4cC3pqjMUIKs4/EvhIOOza0GueGUAKzsGgaMLixzoGHv/Moo5W"]]
   (5.5ms)  commit transaction
=> #<User id: 102, name: "sample", email: "sample@email.com", created_at: "2021-03-02 04:11:18", updated_at: "2021-03-02 04:11:18", password_digest: [FILTERED], remember_digest: nil, admin: nil, activation_digest: "$2a$12$jKN4cC3pqjMUIKs4/EvhIOOza0GueGUAKzsGgaMLixz...", activated: false, activated_at: nil>

演習 2

リスト 11.26で抽象化したauthenticated?メソッドを使って、先ほどの各トークン/ダイジェストの組み合わせで認証が成功することを確認してみましょう。

>> user.remember_token
=> nil
>> user.remember_digest
=> nil
>> user.activation_token
=> "DQKQr9KfehJzT6PzsjrEdQ"
>> user.activation_digest
=> "$2a$12$jKN4cC3pqjMUIKs4/EvhIOOza0GueGUAKzsGgaMLixzoGHv/Moo5W"

11.3.2 editアクションで有効化

editアクションを書いていく。

  # GET /account_acrivations/:id/edit
    user = User.find_by(email: params[:email])
      # emailを元にuserを探して変数userに代入
    if user && !user.activated? && user.authenticated?      (:activation, params[:id])
      # 左: nilかどうかを確認
      # 中: userがactivatedされていないかを確認
      # 右: :activation, params[:id]の2つで認証する
      user.update_attribute(:activated,    true)
      user.update_attribute(:activated_at, Time.zone.now)
      log_in user
        # ログイン
      flash[:success] = "Account activated!"
      redirect_to user
        # プロフィールページにアクセス
    else
      flash[:danger] = "Invalid activation link"
      redirect_to root_url
    end
  end

演習 1

コンソールから、11.2.4で生成したメールに含まれているURLを調べてみてください。URL内のどこに有効化トークンが含まれているでしょうか?

----==_mimepart_603dc222a8f1c_14022ad7ea9149d8402a2
Content-Type: text/plain;
 charset=UTF-8
Content-Transfer-Encoding: 7bit

Hi test,

Welcome to the Sample App! Click on the link below to activate your account:

http://localhost:3000/account_activations/exKxGElXRHOQ6VyC0ia4MA/edit?email=test%40example.com

この部分がトークン: account_activations/exKxGElXRHOQ6VyC0ia4MA/

演習 2

先ほど見つけたURLをブラウザに貼り付けて、そのユーザーの認証に成功し、有効化できることを確認してみましょう。また、有効化ステータスがtrueになっていることをコンソールから確認してみてください。

>> user = User.find_by(name: "test")
  User Load (3.3ms)  SELECT "users".* FROM "users" WHERE "users"."name" = ? LIMIT ?  [["name", "test"], ["LIMIT", 1]]
=> #<User id: 103, name: "test", email: "test@example.com", created_at: "2021-03-02 04:42:10", updated_at: "2021-03-02 04:45:05", password_digest: [FILTERED], remember_digest: nil, admin: nil, activation_digest: "$2a$12$MmJY.TpGghnO.LdaF6GSPO8xQUWDIPzzl0L3ISc5FYU...", activated: true, activated_at: "2021-03-02 04:45:05">

>> user.activated
=> true

11.3.3 有効化のテストとリファクタリング

アカウント有効化の統合テストを追加する。

test/integration/users_signup_test.rb
test "valid signup information with account activation" do
  get signup_path
    # signup_pathにアクセスする
  assert_difference 'User.count', 1 do
    # ユーザー数が1つ増えているか確認。増えたユーザーの情報は以下。
    post users_path, params: { user: { name:  "Example User", email: "user@example.com", password: "password",  password_confirmation: "password" } }
  end
  assert_equal 1, ActionMailer::Base.deliveries.size
    # メールを1つ送っているか確認
  user = assigns(:user)
    # バリデーションされていない@userにアクセスする
  assert_not user.activated?
    #  userが有効化されていないか確認
  log_in_as(user)
    # 有効化していない状態でログインしてみる
  assert_not is_logged_in?
    # ログインできなかったらtrue
  get edit_account_activation_path("invalid token", email: user.email)
    # edit_account_activation_pathにトークンとメールアドレスを渡してアクセス
  assert_not is_logged_in?
    # ログインできなかったらtrue
  get edit_account_activation_path(user.activation_token, email: 'wrong')
    # トークンは正しいが、メールアドレスが無効の場合でアクセス
  assert_not is_logged_in?
    # ログインできなかったらtrue
  get edit_account_activation_path(user.activation_token, email: user.email)
    # トークンもメールアドレスも有効の場合でアクセス
  assert user.reload.activated?
    # ユーザーが更新されたらtrue
  follow_redirect!
    # リダイレクトされる
  assert_template 'users/show'
    # users/showを描画しているか確認
  assert is_logged_in?
    # ログインできていたらtrue
  end

演習 1

リスト 11.35にあるactivateメソッドはupdate_attributeを2回呼び出していますが、これは各行で1回ずつデータベースへ問い合わせしていることになります。リスト 11.39に記したテンプレートを使って、update_attributeの呼び出しを1回のupdate_columns呼び出しにまとめてみましょう。これでデータベースへの問い合わせが1回で済むようになります(注意!update_columnsは、モデルのコールバックやバリデーションが実行されない点がupdate_attributeと異なります)。また、変更後にテストを実行し、 green になることも確認してください。

app/models/user.rb
# アカウントを有効にする
def activate
  update_columns(activated: true, activated_at: Time.zone.now)
end

演習 2

現在は、/usersのユーザーindexページを開くとすべてのユーザーが表示され、/users/:idのようにIDを指定すると個別のユーザーを表示できます。しかし考えてみれば、有効でないユーザーは表示する意味がありません。そこで、リスト 11.40のテンプレートを使って、この動作を変更してみましょう9 。なお、ここで使っているActive Recordのwhereメソッドについては、13.3.3でもう少し詳しく説明します。

app/controllers/users_controller.rb
def index
  @users = User.where(activated: true).paginate(page: params[:page])
end

def show
  @user = User.find(params[:id])
  redirect_to root_url and return unless @user.activated?
end

11.4 本番環境でのメール送信

サンプルアプリケーションの設定を変更し、production環境で実際にメールを送信できるようにする。

演習 1

演習 2

$ heroku push時にPrecompiling assets failed.が出て、解決できなかったので後に回します。

エラーメモ

たぶんここで引っかかってるけど、調べてもよくわからない。

$ git push heroku
.
.
.
remote:        SyntaxError: /tmp/build_bb915e0f/config/environments/production.rb:84: syntax error, unexpected '\n', expecting =>
.
.
.
remote:  !
remote:  !     Precompiling assets failed.
remote:  !
remote:  !     Push rejected, failed to compile Ruby app.
remote: 
remote:  !     Push failed
.
.
.

さいごに

メール認証難しかったです!

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

たけさん用

動的ソート方法

前提

全部で2パターン考えました。
1つ目は王道パターンですが、jQueryの知識が必要です。
2つ目は王道ではなく、見た目の自由度も少ないですが、Railsだけで完結するので、最初に聞いた「コントローラーに分岐が増えてしまう」「1書回1回通信が発生してしまう」という課題の部分は解決します。

パターン1:jQueryで見た目を操作する

実装手順

前提条件

  • ページの初期表示時はコントローラーから渡した@tasksが表示されている想定です。
  • @tasksは、デフォルトで表示したい順番でソートしたタスクを入れておいてください。
  • タスクが表示されているリストはdiv要素やtable要素などで囲んで、他とかぶらないクラス名をつけておいてください。(class= "tasks_list")
  • タスクのタスク名のカラムはnameと仮定して話をすすめます
  • 表示するのは、タスク名だけで進めます(優先度や日付を表示したい場合は、適宜真似して調べながらやってみてください)

以下に例示します。あくまでHTMLとしての例です。実際はERBで@tasksをループして書くことになります。

 <table>
    <tr>
      <th>タスク名</th>
    </tr>
    <tr>
      <td>タスク1</td>
    </tr>
    <tr>
      <td>タスク2</td>
    </tr>
    <tr>
      <td>タスク3</td>
    </tr>
  </table>


1. jQueryの導入

これはRails6を使っている場合は
https://qiita.com/tatsuhiko-nakayama/items/b2f0c77e794ca8c9bd74

Rails5を使っている場合は
https://qiita.com/Statham/items/372234e23749ff1f6bf8

等、調べながら入れてみてください。

2. ソート用ボタンの作成(見た目)

これは以下4つのボタン要素をご自分で作成してください。

  • 日次の古い順, class名: sort_asc_by_date_button
  • 日次の新しい順, class名: sort_desc_by_date_button
  • 優先度高い順, class名: sort_desc_by_priority_button
  • 優先度低い順, class名: sort_asc_by_priority_button

全ボタンにvalue属性で@tasksを渡す。
```

value=<%= @tasks %>
```

3. 2で作ったボタンに対して、jQueryのイベントを紐づける

ボタンを押したときに、jQueryで用意したソート用の関数が発火する仕組みにします。

app/assets/javascripts以下に、以下2つのファイルを作ります。

sort_by_priority.js
sort_by_date.js
優先度関連のコードはpriorityの方、日付関連の方はdateの方にまとめていきます。

では例として、優先度高い順ボタンを押したときのコードを例示します。
優先度関連なので、sort_by_priority.jsに追記していきます。

  // sort_desc_by_priority_buttonクラスがclickされたら, 中の関数が動く
  // '.sort_desc_by_priority_button' はセレクタといいます
  // clickはイベントと言います
  $('.sort_desc_by_priority_button').on('click', function(e){
    e.preventDefault();
    // クリックされた要素が持つvalue属性を取得
    const before_sort_tasks = $(this).val()
    // appendはセレクタの要素に対してHTMLを差し込むメソッドです
    const table = `<table class = '.tasks_list'>
                    <tr>
                      <th>タスク名</th>
                    </tr>
                   </table>`

    $('.tasks_list').append(table);

    // ソートされたタスクを順番に.tasks_listの中のHTMLに追加していっています。
    const sorted_tasks = before_sort_tasks.sort(function(a, b) {
       if (Object.keys(a) > Object.keys(b)) {
           return -1;
       } else {
           return 1;
       }
    }

    table.ready(function() {
     sorted_tasks.forEach(function(sorted_task){
       $('.tasks_list').add(`
         <tr>
           <td> ${sorted_task.name} </td>
         </tr>
       `)
      })
    })
  });
});

参考記事:
https://note.com/skipla/n/nb65a0bb4c24c
https://blog.toshimaru.net/jqueryhidden-inputjquery/
http://k-program.hatenablog.com/entry/2015/07/25/113110

パターン2:タブを4つ作り、それぞれのタブにすでにソートしたオブジェクトを入れておく

これは動的ソートではないですが、「動的ソートに見せかける」ことができます。
ページリロード無しでソート結果を表示するというゴールは達成できるかと思います。

こちらはRailsだけでできるので簡単です。

  1. Controllerは@tasksを返します(順番は日付が新しい順で良いと思います)
  2. ViewHelperで「日付が新しい順」「日付が古い順」「優先度高い順」「優先度低い順」 の4種類のソート用メソッドを用意します。(sortのやり方は調べればでてくると思います)
  3. https://bagelee.com/design/css/create_tabs_using_only_css/ を参考に「日付が新しい順」「日付が古い順」「優先度高い順」「優先度低い順」のタブを作成します
  4. それぞれのタブに、2で作ったメソッドを使った@tasksを配置すればタブごとにソートした結果が出るはずです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【個人学習振り返り】Ruby勉強 #2

■この記事の目的

自分の振り返り用としての投稿です。
Sierから卒業しWebエンジニアになるため、Rubyを1から習得中です。

■勉強に利用させていただいた動画

大変勉強になりました。投稿者様に感謝です。
本ページはこちらを参考に手でやった記録になります。

1.環境構築

自分はWindows環境で構築。

ruby・コマンドプロンプト・vscodeはあらかじめ入っていたため、
「SQLite」をインストールします。

ちなみに以下すべての記載で入力しているコマンドは、VScode経由での入力です。

1.1 SQlite

1.2 Railsのインストール

そもそも「gem」が何かが不明でしたが以下のページで説明されており、
rubyのパッケージ管理ツールのコマンドのようです。
linuxでいうところのyumのような存在でしょうか。

gem install rails -v "5.2.3"

1.3 パッケージ管理ツールのインストール

gem install bundler

Gemfileというファイルを作るためのコマンドを実行。
この時点でこのファイルの意義はまだ未理解です・・・

bundle init

このコマンドの後、Gemfileというファイルが実行フォルダの直下に作成されるので、
このファイルをテキストエディタで開き、以下を追記します。

gem "rails"

1.4.Railsのソースコードインストール

一つ上の手順でGemfileに"rails"という文字と定義したことで、
以下でrailsのソースコードがインストールできます。

bundle install --path vendor/bundle

2.Railsでアプリケーション作成

以下のコマンドでRailsのアプリケーションの基礎を作成します。

途中でオーバーライドするかと質問されたら、「A」を押して、オーバーライドします。

 rails new .

2.1Railsサーバー起動

rails s

http://localhost:3000/
Yay! You’re on Rails!
と表示されます。

ここまでのはまりポイント。すんなり、"rails s"ができた人はこの項目は飛ばしてください。

→rails s実行で返ってきた結果を抜粋。
サーバーが起動したとは思えないメッセージです。

rails\rails_tutorial> rails s
Usage:
rails new APP_PATH [options]...

同じ経験をされていた方の記事を発見し、こちらで対応してみました。
gitを入れていないことが原因のようです。
https://qiita.com/Leone/items/dc7f8ef2d5329d297e72

gitをインストールvscodeを閉じて開きなおして、再度以下のコマンドでアプリケーションの作成を行いました。

 rails new .

一回目のgitなしのアプリケーション作成と比べ、かなりファイルが増えました。

image.png

しかしまだ"rails s"コマンドは動きません。

bin/rails:3:in require_relative': cannot load such file -- C:/Users/****/Desktop/rails/rails_tutorial/config/boot (LoadError)
from bin/rails:3:in
'

これは調べてみたら、インストールしていたRubyのバージョンが原因で、boot.rbファイルが作られておりませんでした。
私の環境のRubyは以下のバージョンでした。

ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x64-mingw32]

以下のダウンロードページから、再度2.7台のRubyを入れなおしました。

https://rubyinstaller.org/downloads/
ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [x64-mingw32]

2.2Railsサーバー停止

ターミナルをctrl+cで閉じるとサーバーが停止され、このページに接続できなくなります。

3.TOPページ作成

Railsはファイルの命名規則が非常に厳しく、
コントローラーのファイル名「top_controller.rb」とした場合、
クラス名は必ず「TopController」にしないとエラーとなります。

例)ファイル名:小文字アンダーバーで繋ぐ
  クラス名:ファイル名のアンダーバーを消す。
       「最初の文字」と「アンダーバーの後のアルファベット」を大文字にする。

3.1 ルーティング設定

ルーティング設定とは、URLをサーバーが受け取ったときにコントローラーどういう処理をさせるかという意味らしいです。
(コントローラーというのはMVCモデルの中のコントローラーを指します)

Railsのルーターは受け取ったURLを認識し、適切なコントローラ内アクションやRackアプリケーションに割り当てます。ルーターは、ビューでこれらのパスやURLを直接ハードコードすることを避けるためにパスやURLを生成することもできます。

これまでのディレクトリの中に、「config」フォルダがあり、その中のrouter.rbを開きます。
このファイルのdoとendの間に以下を追記します。

get '/', to: 'top#index'

これの意味としては。
1要素目:getはHTTPメソッドの「get」
2要素目:トップページということで「/」
3要素目:コントローラーとアクションを定義する。この書き方だとTOPコントローラーのindexアクションとなる。

3.2 コントローラー設定

これまでのディレクトリの中に、「app」→「controller」がありので、そこにファイルを作ります。
作るファイルは「top_controller.rb」とします。

内容は以下の通りにします。
この「ActionController:Base」を継承しているのはコントローラーのルールのようで、絶対に書かないといけないもののようです。

class TopController < ActionController::Base
    def index
    end
end

3.3 ビュー設定

これまでのディレクトリの中に、「app」→「views」がありので、そこにフォルダを作ります。
作成するフォルダ名は、コントローラーを「TopController」というクラスで定義したため、「top」となるようです。

topの下にファイルを作ります。
ファイル名は、先のコントローラー設定の中のdefで「index」の名前で定義したため、
index.html.erb
とします。
erbという拡張子を始めた見ましたが、railsでは拡張子を「html.erb」とするようです。

index.html.erbの中身自体は何でもよいので、動画を参考にこんな感じにしました。

<h1>Hello world</h1>

現状でき上ったものまとめ

config\routes.rb
Rails.application.routes.draw do
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
  get '/', to: 'top#index'
end

app\controllers\top_controller.rb

class TopController < ActionController::Base
    def index
    end
end

app\views\top\index.html.erb

<h1>Hello world</h1>


サーバーを起動してどう動くか見てみます。

rails s

http://localhost:3000/にアクセスすると、
Hello world
が表示されました。

ただ初回実行時のエラーにありました。

以下のエラーが発生しました。

raise LoadError, "Unable to autoload constant

コントローラーが読み込めないというエラーのようです。
しかしファイル名の違いなどは何度確認してもなく困惑しました。

改善した方法としては、
top_controller.rbにおいて「ActionController::Base」の箇所を
「ApplicationController」に変えたところ改善しました。
この二つの差異が今のところ不明です。

ただ試した限り、以下の動作後にいずれのパターンでも動作し、原因は不明のままです。
1.ApplicationControllerに変更
2.Hello world表示可能
3.rails停止
4.ActionController::Base:切り替え
5.rails起動
6.Hello world表示


4.DB接続

config\database.ymlが設定に使用するファイルとなるが、現時点での変更は不要です。

4.1 modelファイル作成

下記のコマンドを実行することでmodelが、app\models\user.rbとして作成する。
意味としては、 rails g model 以降が「DB名」 「列名:データ型」になる

rails g model User name:string age:integer

以下のようなファイルが作成されました。
invoke active_record
create db/migrate/20210302043737_create_users.rb
create app/models/user.rb
invoke test_unit
create test/models/user_test.rb
create test/fixtures/users.yml

4.2 DB作成

rails db:create

4.3 ユーザーテーブルの作成

4.1で作成した中のmigrateファイル内のデータを使ってテーブルが作成されます。
migrateファイルというのはDBの定義が書いてあるファイルと覚えればよいです。

rails db:migrate

4.4 データベースへの接続

今回sqlite3を用いているため、以下のコマンドで接続する。

sqlite3 db/development.sqlite3

中身を見るにはこのコマンド。

.schema users

ただ、「rails g model User name:string age:integer」というコマンドでつくったので、userが正しいと思っていたが、
db/migrate/20210302043737_create_users.rbファイル内のcreate文を見ると確かに、
「create_table "users」の記載があり、この辺りはまだ理解が及びません。。

4.5データの挿入

まずrailsのコンソールを以下のコマンドで立ち上げます。
rails環境でrubyを使用できる環境となる。

rails c

・insert文

User.create!(name:"Aさん",age:19)

User.create!(name:"Bさん",age:20)

・select文
このコマンドは内部的には「SELECT "users".* FROM "users" LIMIT ?」と同じになるようです。

User.all

・select結果の変数格納
この場合、id:1ののユーザーに対するwhere文となり、その結果が変数格納されます。
「SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? 」

user=User.find(1)

この状態で変数「user」にはid1のユーザーの情報が格納されます。
変数.nameとして名前を見ることや、変数.ageとして年齢を見ることができます。
またそれを指定して内容を更新することができます。

user.name="改名A"

・update文

現在、変数userの内容を更新していて、id1のユーザーの名前が"改名A"となっています。
ただこの時点では変数しか書き換えていないため、以下のコマンドでDBに反映させます。
内部的には「UPDATE "users" SET "name" = ?, "updated_at" = ? WHERE "users"."id" = ?」になっているようです。

user.save

・select+where文
条件付きのselect文には、下記のコマンドがあります。
User.where(条件)

ageを条件とする場合は、以下となります。

User.where("age>=19")

5 新しいページの追加

新しいページを追加します。
今回の目的はユーザーの情報をDBから取得し、画面に出力させます。

流れは、「ルーティングの追記」⇒「コントローラーの追加」⇒「ビュー追加」となります。

5.1ルーティングファイルの更新

例により最初にルーティングのファイルを書き換えます。
「config」フォルダのrouter.rbを開きます。

それぞれの意味として、
「/users/:id」は、users/1やusers/2として、変数で受け取れるようになります。
「to: 'users#show'」は、usersコントローラーのshowメソッドを追加しています。
「as:"user"」はルーティングに対して、名前を付ける機能です。後でユーザー一覧作成の際に使用します。

  get '/users/:id', to: 'users#show', as: "user"

5.2コントローラーファイルの追加

「app」→「controller」があるので、そこに新しいファイルを作ります。
作るファイルは「users_controller.rb」とします。
内容はTOPページと同じ要領で、
1)ファイル名の大文字&アンダーバー削除
2)メソッドはルーティングで追加した「show」を入れる。

ここから新しい要素で、 @user=user.find(params["id"])があります。
これは
user.find()は、モデルからデータを抜き出す処理
params["id"]は、ルーティングから受け取るID
最後の変数に結果を格納しています。これに「@」がついているのは、ビューにファイルを渡せるようにするため。

class UsersController < ActionController::Base
    def show
        @user=user.find(params["id"])
    end
end

5.3ビューファイルの追加

「app」→「views」がありので、そこに新しいフォルダを作ります。
作成するフォルダ名は、コントローラーを「UsersController」というクラスで定義したため、「users」となるようです。

「users」フォルダの配下に、show.html.erbを作成します。
(メソッド名+html.erb)

ファイルの内容は以下です。
この<%~~~ %>タグの中がRubyのコードを書く領域になります。

<%=と<%の違いは以下の通りです。
<%=:画面表示あり
<%:画面表示なし

if文を書く時には、画面表示しないrubyを使いたいので、そういうときは<%を使うように使い分けができる。

<h1>ユーザー詳細</h1>

<%= @user.name %> <br>
<%= @user.age %> 才

再び「rails s」でサーバーを起動させ、以下URLにアクセスします。
http://localhost:3000/users/1

画面上で以下の結果が出力されました。
ユーザー詳細
改名A
19 才

5.4ユーザー一覧を作成する。

同じ流れで、「ルーティングの追記」⇒「コントローラーの追加」⇒「ビュー追加」となります。
「config」フォルダのrouter.rbに以下を追記。

  get '/users', to: 'users#index'

「app」→「controller」の「users_controller.rb」に追加します。
User.allはすべてのユーザーを取得するコマンドでした。

    def index
        @users=User.all
    end

「users」フォルダの配下に、index.html.erbを作成します。
(メソッド名+html.erb)

@usersを受け取って、eachで回しています。
2行目のlink_toはhtmlでいうタグにあたる内容です。
user_path(id: user.id)は、
タグ内のhrefにあたり、id:user.idへのリンクを自動生成します。
(まだしっかり理解できていません...)

<h1>ユーザーすべて</h1>

<% @users.each do|user| %> 
    <%= link_to user.name,user_path(id: user.id) %> <br>
<% end %>

この状態でいかにアクセスすると
http://localhost:3000/users/

画面上以下が表示されました。

ユーザーすべて
改名A
Aさん
Bさん
Bさん

ソースコードは以下のようになっていました。

    <a href="/users/1">改名A</a> <br>
    <a href="/users/2">Aさん</a> <br>
    <a href="/users/3">Bさん</a> <br>
    <a href="/users/4">Bさん</a> <br>

5.5 追加機能で、「戻る」ボタンを作ってみます。

ユーザーの詳細画面からへのボタン追加のため、ルーティング設定を行います。
行う設定はas名前の追加です。

「config」フォルダのrouter.rbを以下に変更。

  get '/users', to: 'users#index'
  ⇒  get '/users', to: 'users#index', as: "users"

show.html.erb へ以下を追記。

link_to でタグ化し、asで定義したusersという名前を書くことで、その画面へ遷移することができます。

<%= link_to "戻る" ,users_path %>

■また次回に続きます。

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

【超かんたん】ransackを使って検索機能を実装しよう!

ransackを利用して検索機能を実装します。
今回も初心者向けにレシピ投稿アプリを例に作成していきます。

また、検索機能の実装にActive Hashの値も利用するのでActive Hashがわからない方は前回記事にしておりますので、そちらをご覧頂けたらと思います。
【超かんたん】Active Hashで投稿ページにプルダウンメニューを作成しよう!

完成イメージ

19c0a417740b22b00dc7a7fcfe4ad268.gif

それでは、実装していきましょう!

ransackとは

ransackはRails用の検索機能を実装するためのGem。公式ドキュメント

導入方法

Gemfileに下記を記述しbundle installします。

Gemfile
gem 'ransack'
ターミナル
bundle install

デモデータを投入しよう!

seed.rbにデモデータ生成する記述をしていきます。
category_idとtime_required_idはActive Hashの値と紐付いているカラムになります。

また、time_required_idのFakerがわからない方は前回記事にしておりますので、そちらをご覧頂けたらと思います。
【超かんたん】Fakerを使ってダミーデータを作成しよう!

db/seed.rb
5.times do |n|
  Recipe.create!(
    title: "すし・魚料理#{n}",
    text: "作り方",
    category_id: 1,
    time_required_id: Faker::Number.within(range: 2..6)
  )
end

#中略

5.times do |n|
  Recipe.create!(
    title: "お菓子・スイーツ#{n}",
    text: "作り方",
    category_id: 10,
    time_required_id: Faker::Number.within(range: 2..6)
  )
end
ターミナル
rails db:seed

デモデータの作成完了。
r.jpg

簡易的にindexページに表示します。
in.png

検索機能の実装

ルーティングの設定

まずは検索ページ(search)のルーティングと検索結果を表示するページ(result)のルーティングの設定をしましょう。

7つのアクション以外のルーティングを設定するので、recipesにネストさせます。
今回は、URLにidがつかないのでcollectionを利用します。

config/routes.rb
Rails.application.routes.draw do
  root to: 'home#index'
  devise_for :users
  resources :users
  resources :recipes do
    collection do
      get :search
      get :result
    end
  end
end

コントローラーの編集

以下の記述は公式ドキュメントを参考にしております。

app/controllers/recipes_controller.rb
class RecipesController < ApplicationController
  before_action :search_recipes, only: [:search, :result]

  def index
    @recipes = Recipe.all
  end

  #中略

  def search
  end

  def result
    @results = @q.result
  end

  private
  def search_recipes
    @q = Recipe.ransack(params[:q])
  end
end

params[:q]のキー「:q」でrecipesテーブルからレシピ情報を探し「@q」に格納します。
この@qに対して「.result」とすることで検索結果を取得します。

次にビューファイルを作成していきましょう。

ビューの作成

ビューファイルの作成

ターミナル
touch app/views/recipes/{search.html.erb,result.html.erb}

ビューファイルの編集

今回はCSSの説明は省きます。

検索フォームにはsearch_form_forというメソッドを使います。
form_withのransack版というイメージです。
form_withでは「text_field」ですが、search_form_forだと「search_field」になります。

また、「:カラム名_マッチャ」とすることで条件にあった検索を行います。
_cont」だと「入力された値が含まれている」という意味になり、「_eq」は「入力された値と等しい」という意味のマッチャになります。
その他のマッチャについては公式ドキュメントを参照してください。

collection_selectメソッドについては前回の記事Railsドキュメントを参照してください。

以下のように編集していきます。

app/views/recipes/search.html.erb
<div class="recipe-form">
  <h1 class="text-center">検索する</h1>
  <%= search_form_for @q, url: result_recipes_path do |f| %>
    <div class="form-group">
      <label class="text-secondary">料理名</label><br />
      <%= f.search_field :title_cont, class: "form-control"%>
    </div>
    <div class="form-group">
       <label class="text-secondary">カテゴリー</label><br />
       <%= f.collection_select(:category_id_eq, Category.where.not(id: 0), :id, :name, include_blank: '指定なし') %>
    </div>
    <div class="form-group">
       <label class="text-secondary">所要時間</label><br />
       <%= f.collection_select(:time_required_id_eq, TimeRequired.where.not(id: 0), :id, :name, include_blank: '指定なし') %>
    </div>
    <div class="form-group">
       <label class="text-secondary">フリーワード</label><br />
       <%= f.search_field :text_cont, class: "form-control"%>
    </div>
    <div class="actions">
      <%= f.submit '検索', class: "btn btn-primary" %>
    </div>
  <% end %>
</div>

それでは表示してみましょう。
せ.png

次に検索結果ページを作成していきましょう。
以下のように編集していきます。

app/views/recipes/result.html.erb
<div class="recipes-index text-center">
  <h1 class="result-index">検索結果</h1>
  <% if @results.length != 0 %>
    <% @results.each do |recipe| %>
      <div class="recipe">
        <div class="recipe-title">
          <%= recipe.title %>
        </div>
        <div class="recipe-content">
          カテゴリー: <span class="recipe-category"><%= recipe.category.name %></span>
          所要時間: <span class="recipe-time"><%= recipe.time_required.name %></span>
        </div>
      </div>
    <% end %>
  <% else %>
    該当するレシピはありません
  <% end %>
</div>

if文で該当する検索結果がない場合は「該当するレシピはありません」と表示させるようにしています。
それでは実際に検索してみましょう。

該当する検索結果がある場合

19c0a417740b22b00dc7a7fcfe4ad268.gif

該当する検索結果がない場合

c8e6ad3cfc012c474e3c28ddb7be9cfe.gif

以上で完成です。

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

[Rails]slickを用いて投稿された画像をランダムに取得してスライドショーを実装する

スライドショーの実装

題名通りjQueryのslickを用いて投稿された画像をランダムにスライドショーで実装する方法の紹介です。
初投稿なので誤字や脱字など至らない点はあると思いますが、よろしくお願いいたします。

完成形

前提

Rails 6.0.3.5
slickはjQueryのプラグインなのでjQueryの導入をお願いいたします。

slickの導入

slick公式サイト
CDNを利用して導入します。
application.html.erb内の<head>

apprication.erb
<link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/slick-carousel@1.8.1/slick/slick.css"/>
<link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/slick-carousel@1.8.1/slick/slick-theme.css"/>
<script type="text/javascript" src="//cdn.jsdelivr.net/npm/slick-carousel@1.8.1/slick/slick.min.js"></script>

を付け加えましょう。
導入に関してはこれだけです。

slick.jsの作成

javascript下にslick.jsファイルを作りましょう。
コードの記載は下の通りです。

slick.js
$(function() {
  $('.slider').slick();
});

slickの読み込み

slickを読み込むためにapplication.jsに

application.js
require('slick')

の記載を追加しましょう。

投稿を取得してスライドショーにしよう

スライドショーを実地するための記載をしましょう。
今回の場合は@postsに画像つきの投稿の全てを取得させています。

html.erb
<div class="slider">
  <% @posts.each do |post| %>
     <%= link_to image_tag(post.image), post_path(post.id), method: :get, class: :slick_image %>
   <% end %>
</div>

これで投稿を取得して画像をスライドショーで表示できるようになったと思います。

取得する投稿をランダムにしよう

↑の場合だと投稿全てを取得して表示してしまうので、
コントローラー内で新たに@randamsを定義してランダムな投稿を取得しましょう。

controller.rb
randams = Post.order("RAND()").limit(5)  //limit(5)で5件を取得させている。

@randamsにランダムな投稿5件を取得させています。

ビューファイルも書き換えましょう。

.html.erb
<div class="slider">
  <% @randams.each do |randam| %>
    <%= link_to image_tag(randam.image), post_path(randam.id), method: :get %>
  <% end %>
</div>

@randamsにランダムな投稿5件を取得させてeachで表示させています。

スライドを自動にしてみよう

現状のスライドだと寂しいので色々オプションを付け加えてみましょう。

slick.js
$(function() {
  $('.slider').slick({
      centerMode: true, //スライド画面に次のスライドが表示される
      centerPadding: '10%', //次のスライドの幅
      dots: true, //スライドの下にドットのナビゲーションを表示
      autoplay: true, //自動再生オン
      autoplaySpeed: 2000, //再生スピード
      infinite: true //スライドが終了したら最初に戻る
  });
});

他にもさまざまなオプションがあるので気になった方は公式リファレンスをチェック!

最後に

初投稿と言うこともあり、色々不十分な点もあると思いますが、拙い文章にお付き合いいただきありがとうございました。

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

3桁の整数の百、十、一の位の和を出す

課題 3桁の整数がある時、百の位、十の位、一の位の和を求める

回答

doriru.rb
def total_num(num)
  total = (num/100 %10) + (num/10 %10) + (num %10)
   puts total
end

total_num(123) 

解説

ここから私なりの理解した内容を記述していきたいと思います。
まず百の位、十の位、一の位を取り出すやり方で共通しているのは%10する時は取り出したい位で割っていることだと思いました。
どういうことかと言いますと、例えば百の位のとき分母を100にして割ると

123/100 = 1.23
1.23 %10 = 1

となり、小数点以下は切り捨てられるので残った数字に%10すると百の位である1が取り出せました。
次に十の位のとき分母を10にして割ると

123/10 = 12.3
12.3 %10 = 2

となり、小数点以下は切り捨てられて残った数字で%10すると十の位である2が取り出せました。
最後に一の位ですが、分母は1になるのでそのまま%10します。

123 %10 = 3

最終的な余りが3なのでこちらが出力されます。
あとは出力した値を足していけば3桁の整数の百の位、十の位、一の位を足した結果が出力されます。

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

【Ruby on Rails】デバッグツール(pry-rails)

エラーの時にはデバッグツールを使ってバグを発見したり、処理を止めて動作を確認したりします。
私はpry-railsを利用しているのでその使い方をまとめます。

pry-rails

Railsにおけるデバッグ用のGemです。
私の主な使い方はコントローラー内で記述し、その処理を止めることでどんなデータが渡っているかなどを調べるのに使っています。
テストコードを書く際などにもエラー文を調べるために利用したりします。

準備

Gemfileの一番下に

Gemfile
gem 'pry-rails'

と記述します。

ターミナルで該当のプロジェクトのディレクトリで以下のコマンドを実行します。

ターミナル
bundle install

以上でGemの導入とGemfileの更新ができました。

使い方

①送られているデータの確認方法

例えばcreateアクションでどのデータが送られているか確認したい場合、コントローラー内の処理を確認したいところにbinding.pryを記述します。

コントローラー
def create
    binding.pry
    Sample.create(sample_params)
end

記述できたらローカルのサーバーから実際にcreateアクションの動作を行ってみます。
(例えばformからの投稿など)

この状態でターミナルを見てみるとコンソールが起動していると思います。
下記のような入力街の状態です。

ターミナル
pry(#<SampleController>)>

ここにparamsと入力すると送られているデータが配列で確認できます。
うまく保存ができない時に試すと原因が分かることがあります。

②テストコードでの使い方

※テストコードの書き方の詳細は省きます。
以下のように異常系のテストコードを書く際にbinding.pryで処理を止め、エラーメッセージがどういうものか確認します。

context '新規登録がうまくいかない時' do
  it "名前(name)が空だと登録できない" do
    @user.name = ''
    @user.valid?
    binding.pry
  end
end

上記の記述をしてテストコードを実行するとターミナルでコンソールが起動するので

ターミナル
user.errors.full_messages

と入力するとエラーメッセージを出力してくれます。

以上です。

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

【Railsチュートリアル】第11章 アカウントの有効化①

はじめに

アカウントを有効化するステップを新規登録の途中に差し込み、本当にそのメールアドレスの持ち主なのかどうかを確認できるようにする。

11.1 AccountActivationsリソース

セッション機能(8.1)を使って、アカウントの有効化という作業を「リソース」としてモデル化する。

11.1.1 AccountActivationsコントローラ

resources :account_activations, only: [:edit]

URL「/account_activation/トークン/edit」にGETがリクエストされたらeditアクションを呼び出す。

演習 1

現時点でテストスイートを実行すると green になることを確認してみましょう。
確認のみなので省略。

演習 2

表 11.2の名前付きルートでは、_pathではなく_urlを使うように記してあります。なぜでしょうか? 考えてみましょう。ヒント: 私達はこれからメールで名前付きルートを使います。
メール本文のURLからアクセスするから。

11.1.2 AccountActivationのデータモデル

仮想的な属性を使ってハッシュ化した文字列をデータベースに保存するようにする。

演習 1

本項での変更を加えた後、テストスイートが green のままになっていることを確認してみましょう。

GREEN

演習 2

コンソールからUserクラスのインスタンスを生成し、そのオブジェクトからcreate_activation_digestメソッドを呼び出そうとすると(Privateメソッドなので)NoMethodErrorが発生することを確認してみましょう。また、そのUserオブジェクトからダイジェストの値も確認してみましょう。

>> user = User.new
   (4.5ms)  SELECT sqlite_version(*)
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, password_digest: nil, remember_digest: nil, admin: nil, activation_digest: nil, activated: false, activated_at: nil>
>> user.create_activation_digest
Traceback (most recent call last):
        1: from (irb):2
NoMethodError (private method `create_activation_digest' called for #<User:0x00007f5eb1cd6088>)
Did you mean?  restore_activation_digest!

>> user.activation_digest
=> nil

演習 3

リスト 6.35で、メールアドレスの小文字化にはemail.downcase!という(代入せずに済む)メソッドがあることを知りました。このメソッドを使って、リスト 11.3のdowncase_emailメソッドを改良してみてください。また、うまく変更できれば、テストスイートは成功したままになっていることも確認してみてください。

app/models/user.rb
def downcase_email
  self.email.downcase!
end

GREEN

11.2 アカウント有効化のメール送信

Action Mailerライブラリを使ってUserのメイラーを追加する。

11.2.1 送信メールのテンプレート

Userメイラーの生成
$ rails generate mailer UserMailer account_activation password_reset

$ rails generate [メイラー名][アクション名][アクション名]

app/views/user_mailer/account_activation.text.erb
app/views/user_mailer/account_activation.html.erb
ブラウザと違って、メールボックスによってHTMLを描画できないものもあるので、textも用意している。

app/mailers/application_mailer.rb
class ApplicationMailer < ActionMailer::Base
  default from: 'from@example.com'
    # どこから送るか
  layout 'mailer'
    # デフォルトではどんなレイアウトを使うのか。
end

application_mailer.rbではメイラー全体の設定をする。

app/mailers/user_mailer.rb
class UserMailer < ApplicationMailer

  # Subject can be set in your I18n file at config/locales/en.yml
  # with the following lookup:
  #
  #   en.user_mailer.account_activation.subject
  #
  def account_activation
    @greeting = "Hi"
      # インスタンス変数を展開

    mail to: "to@example.org"
  end

  # Subject can be set in your I18n file at config/locales/en.yml
  # with the following lookup:
  #
  #   en.user_mailer.password_reset.subject
  #
  def password_reset
    @greeting = "Hi"
      # インスタンス変数を展開

    mail to: "to@example.org"
  end
end

user_mailer.rbではメイラーでは何をするのかを設定する。

演習 1

コンソールを開き、CGIモジュールのescapeメソッド(リスト 11.15)でメールアドレスの文字列をエスケープできることを確認してみましょう。このメソッドで"Don't panic!"をエスケープすると、どんな結果になりますか?

>> CGI.escape("Don't panic!")
=> "Don%27t+panic%21"

エスケープ:使えない文字列を使える文字列に変換する。

11.2.2 送信メールのプレビュー

メールのメッセージをその場でプレビューすることができるメールプレビューを設定する。

development.rb: 開発環境用 / test.rb: テスト環境用 / production.rb : 本番環境用

host = 'localhost:3000' # ローカル環境用
config.action_mailer.default_url_options = { host: host, protocol: 'http' }

cloud9を使っていないので、上記を選択。
host〜をコピペすると、自分が開発しているhost(ドメイン名)にGETリクエストが送れないためにエラーが起きます。

演習 1

Railsのプレビュー機能を使って、ブラウザから先ほどのメールを表示してみてください。「Date」の欄にはどんな内容が表示されているでしょうか?

アクセスした日時が表示される。

11.2.3 送信メールのテスト

メールプレビューのテストも作成して、プレビューをダブルチェックできるようする。

リスト 11.21: テストのドメインホストを設定する

test/mailers/user_mailer_test.rb
require 'test_helper'

class UserMailerTest < ActionMailer::TestCase

  test "account_activation" do
    user = users(:Michael)
      # users(:Michael)をuserに代入
    user.activation_token = User.new_token
      # トークン情報を生成してuser.activation_tokenに代入
    mail = UserMailer.account_activation(user)
      # UserMailer.account_activation(user)をmail変数に代入

    # ここから確認のテスト
    assert_equal "Account activation", mail.subject
      # mail.subject(件名)を確認
    assert_equal [user.email], mail.to
      # mail.to(送り先)を確認
    assert_equal ["noreply@example.com"], mail.from
      # mail.from(送り元)を確認
    assert_match user.name,               mail.body.encoded
      # mail.body(本文)にuser.name(名前)が入っているか確認
    assert_match user.activation_token,   mail.body.encoded
      # mail.body(本文)にuser.activation_token(トークン)が入っているか確認
    assert_match CGI.escape(user.email),  mail.body.encoded
      # mail.body(本文)にuser.emailの「@」が
      # CGI.escape(エスケープ処理)されているものが入っているか確認
  end
end

演習 1

この時点で、テストスイートが green になっていることを確認してみましょう。
動作確認のみなので省略。

演習 2

リスト 11.20で使ったCGI.escapeの部分を削除すると、テストが red に変わることを確認してみましょう。
動作確認のみなので省略。

11.2.4 ユーザーのcreateアクションを更新

ユーザー登録を行うcreateアクションにコードを追加し、メイラーをアプリケーションで実際に使えるようにする。
signup直後のログインの廃止(本人確認前にログインできないようにする)して、メールチェックしてもらえるように促す。

app/controllers/users_controller.rb
class UsersController < ApplicationController
  .
  .
  .
  def create
    @user = User.new(user_params)
      # app/models/user.rb
      # attr_accessor :remember_token, :activation_token
      # before_save   :downcase_email

      # def create_activation_digest
      #  self.activation_token  = User.new_token
      #   self.activation_digest = User.digest(activation_token)
      # end

    if @user.save

      # app/models/user.rb
      # before_create :create_activation_digest

      UserMailer.account_activation(@user).deliver_now
      flash[:info] = "Please check your email to activate your account."
      redirect_to root_url
    else
      render 'new'
    end
  end
  .
  .
  .
end

演習 1

新しいユーザーを登録したとき、リダイレクト先が適切なURLに変わったことを確認してみましょう。その後、Railsサーバーのログから送信メールの内容を確認してみてください。有効化トークンの値はどうなっていますか?

適切なURL: root_url

----==_mimepart_603da2dfbacd4_11ed2af75249ad6c294cd
Content-Type: text/plain;
 charset=UTF-8
Content-Transfer-Encoding: 7bit

Hi moutoon,

Welcome to the Sample App! Click on the link below to activate your account:

http://localhost:3000/account_activations/iXav_kpcTA4krSc-3LR3DA/edit?email=moutoonm342%40gamil.com

演習 2

コンソールを開き、データベース上にユーザーが作成されたことを確認してみましょう。また、このユーザーはデータベース上にはいますが、有効化のステータスがfalseのままになっていることを確認してください。

>> user = User.find_by(name: "moutoon")
   (0.1ms)  begin transaction
  User Load (5.8ms)  SELECT "users".* FROM "users" WHERE "users"."name" = ? LIMIT ?  [["name", "moutoon"], ["LIMIT", 1]]
=> #<User id: 101, name: "moutoon", email: "moutoonm342@gamil.com", created_at: "2021-03-02 02:28:47", updated_at: "2021-03-02 02:28:47", password_digest: [FILTERED], remember_digest: nil, admin: nil, activation_digest: "$2a$12$9y5elJ64pu1EC1COuJfdU.95jcOd0TdqpDyHz7W5m1M...", activated: false, activated_at: nil>

activated: falseになっている。

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

Railsポートフォリオ作成 #5 基本機能バックエンド開発

こんにちは:smiley:
今回は基本機能のバックエンド開発を行いました。
(前回記事(#4 herokuデプロイ))

私は、前職(ホテルの料飲部)における、コミュニケーションの課題を解決するアプリを作っているのですが、今回は、

基本機能のバックエンド開発を行いました

具体的には、「レストランで使うものの数を管理する機能」です。

しかし、肝心の数を管理するやり方が正直いまいちいいのが出てこなくて、一旦プルダウンの選択式しました。

ただこれはUXとしてはいまいちなのでは?
という気がするので、最終的には何かもっといい方法でできるといいんだけど、、、と思っています。

感じたこと

  • Railsでバックエンドやるのは少し慣れてきた。
    楽しみながらできるようになってきたし、基本部分は1日で終わらせることができました。
    少し成長を感じました。(やっぱり前回のAWSはキツかった、、、)

  • プログラミングはつくづく巨大な岩を小さなトンカチで少しずつ少しずつ削ってるみたいだってこと。
    やらないといけないこと、実装しないといけないこと、勉強しないといけないことがありすぎて、押しつぶされそうになって正直諦めそうになります、、、

    でもそれを一個一個少しずつ解決していくしかないわけで。
    水の呼吸で一刀両断とかできたらいいのに、、、
    もくもく会とか参加しながら自分をやらないといけない状況において、仕組みを使って解決していこうと思います。

最後に

モデルの単体テストまで書き終わったので、次はフロントエンドをやっていこうと思います。:fist:
フロントエンドは経験値が少ないので、復習しながら時間をかけてやっていくことになると思います。

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

Ajaxでお気に入り機能を実装する

自己紹介

9月から独学でプログラミング学習を開始し、
11月からスクールを使って学習をしています。
現在はポートフォリオの作成し転職活動中です。
知識を定着させるために、学びをアウトプットしています。
また、これから学び始める方の参考になることを願っています。


開発環境

  • Ruby 3.0
  • Ruby on Rails 6.0.3.4
  • jQuery 3.5.1

Ajaxでお気に入り機能を実装する

前回、Railsでお気に入り機能を実装するという記事を投稿しました。
今回は、この記事の非同期化を行います。
同時にお気に入り数のカウントも行ってみましょう!

1.マイグレーションファイルを作成する

まずはターミナルで下記のコマンドを実行して下さい。
rails g migration AddLikersCountToMoives
そして、生成されたマイグレーションファイルを編集します。

class AddLikersCountToMovies < ActiveRecord::Migration[6.0]
  def change
    add_column :movies, :likers_count, :integer, default: 0
  end
end

これでlikees_countというメソッドが使用できるようになりました。

公式のGithubも合わせて参照下さい。

☆ポイント
ここでrails db:migrateを実行しますが、
その前に、もしお気に入りの登録を行っている場合は全て解除して下さい。
default: 0としているため、現在の状態が0になってしまいます。
このまま、お気に入り解除をすると-1のような表示になってしまいます。

2.ビューファイルを追加する

まずは、views/movie配下に_favorite.html.erbというビューファイルを新しく追加します。

<% if current_user.likes?(movie) %>
  お気に入り解除
<% else %>
  お気に入り登録
<% end %>
<%= movie.likers_count %>

これは以前に作成したビューファイルを切り出したものに、likers_countを追加したものになります。
それでは、以前に作成したビューファイルを編集しましょう

3.ビューファイルの編集をする

<%= link_to favorite_movie_path(movie), remote: true do %>
  <div id="favorite-movie">
    <%= render partial: "movies/favorite", locals: {movie: movie}
  </div>
<% end %>

まず、作成した_favorite.html.erbrender partial: "movies/favorite"で読み込んでいます。
locals: {movie: movie}favorite.html.erb内のmovieにビューで使っているmovieを渡しています。

renderについてはRailsガイドを参照ください。

link_toのオプションにremote: trueを指定しています。
これによりviews/movies/favorite.js.erbが呼び出されるようになります。
指定したid="favorite-moviefavorite.js.erbで使用します。

4.JavaScriptファイルを作成する。

views/movies配下にfavorite.js.erbを作成して下さい。
内部は下記の1行だけです。

$("#favorite-movie").html("<%= j(render partial: "movies/favorite", locals: {movie: @movie}) %>");

先程のidを指定し、内部のhtmlを_favorite.html.erbに書き換えています。
今回、jQueryを使用していますが、導入については、省略致します。


以上で機能の実装は終了です。
前回記事、Railsでお気に入り機能を実装すると合わせてご覧下さい。
また、至らない点があれば、お手数ですがご指摘下さい。


補足①

非同期でお気に入りを行った際に、お気に入り数のカウントが、遅れてしまう可能性があります。
そのような場合、controllers/movies_controller.rbに下記を追加して下さい。

  def favorite
    @movie = Movie.find(params[:id])
    current_user.toggle_like!(@movie)
    + @movie.reload    #この1行を追加

reloadでお気に入り処理後に再読み込みを行っています。

補足②

お気に入り処理をeachなど繰り返し処理内で行いたいこともあると思います。
その場合は、指定したid="favorite-movieを下記のように変更して下さい。

<%= @movies.each do |movie| %>
  <div id="favorite-movie-<%= movie.id %>">
    <%= render partial: "movie/favorite", locals: {movie: movie} %>
  </div>
<% end %>

views/movies/favorite.js.erb

$("#favorite-movie-<%= @movie.id %>").html("<%= j(render partial: "movies/favorite", locals: {movie: @movie}) %>");

id属性にid値を指定することで、繰り返し処理内でもお気に入りの処理を行うことができます。

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

マジックナンバーとrailsにおける定数管理gem "config"

この記事の目的

開発中に「マジックナンバー」と言う聞き慣れない(恥ずかしながら)言葉を耳にし、その意味と問題点を調べたのでまとめました。また、Railsにおける「マジックナンバー」への対応策の一つを紹介したいと思います。

この記事で以下のことが分かると思います。

  • マジックナンバーとは何か
  • 開発におけるマジックナンバーの問題点
  • その解決策の一つであるrailsのgem "config"の扱い方

1. マジックナンバーとは

マジックナンバーとは、ハードコーディングされた数値のことです。

ハードコーディングとは、固有名詞・固有値をソースコード内に直接埋め込んだコードのことです。
ソースコードとは、開発者がコーディングしているファイルの内容のことです(index.html, stylesheet.cssなど大体そうかと)。

ハードコードの中でも数値のことを、プログラミングにおいて「マジックナンバー」と呼びます。

index.html.erb
# ハードコードの例
<li>
  <p>山田太郎<p>
  <p><span>23</span>歳です</p> # 23がマジックナンバー
</li>
<li>
  <p>田中花子</p>
  <p><span>73</span>歳です</p> # 73がマジックナンバー
</li>
:

上記はSNSにおけるユーザー一覧の例です。恐らく、こんな直接的な書き方はしないと思います。
一般にマジックナンバーはNGとされています(そもそもハードコードがNGなのかな...)。
その理由を次に説明します。

2. マジックナンバーが何故いけないのか

一般にマジックナンバーは、コーディングの際に避けるべきだ、と言われています。その主な理由は3つだと思われます。

  1. 数字だけ見ても何を意味しているか分からない[可読性が低い]
  2. 変更する場合は全てのマジックナンバーが利用されている場所を変更する必要がある [保守性が低い]
  3. セキュリティの安全性が下がる[脆弱性を生む]

3つの理由の説明はその他のサイトでも説明されていると思います。ここでは、少し具体的なマジックナンバーを使ってしまいそうな例を提示してみます(実体験)。

products_controller.rb
def show
  @product = Spree::Product.find(params[:id])
  @related_products = @product.related_products(4) # マジックナンバー
end

この4という数値が何を意味しているか、このコードを見ただけでは分かりません。
これは下の画像における表示個数の個数を表します。このように、実際の機能に対してコードの意味が伝わりにくくなってしまうのがマジックナンバーの良くない点です。
これ以降では、Railsにおけるマジックナンバーに関する対応策であるconfigと言うgemの扱いを簡単に紹介したいと思います。

[画像挿入]

3. Railsにおける定数管理のgem "config"

以下で具体的な使い方は説明しますが、このgemのいいところは以下の2つだと思います

  • 定数の意味をソースコード内で表現できる
  • 一箇所で定数を管理できる

これがリソースです。
rubyconfig/config

gem "config"は、定数管理を指定のYAMLファイルを用いて一箇所で行う為のgemです。場合によっては環境毎に(development, production, test)定数の値を変更することもできます。
ここでは、簡単な方法を一つ紹介し、先程の例を解決したいと思います。

4. gem "config"の使い方

ここでは最も簡単だと考えられる、一つのファイルで定数を管理する方法を示します。
その場合config/settings.ymlのみ書き込むことで定数管理を実現します。

(1) gem "config"の準備

Gemfile
gem "config"
Terminal
$ bundle install
$ rails g config:install
            create  config/initializers/config.rb
      create  config/settings.yml
      create  config/settings.local.yml
      create  config/settings
      create  config/settings/development.yml
      create  config/settings/production.yml
      create  config/settings/test.yml
      append  .gitignore

以下のようにファイルが追加されます(自動的に.gitignoreに追加されていました)。

(2) 定数を管理する

configでは、木構造のように定数を管理します。
今回は「商品の個数」の中で、「上限の数値」「テストの際の数値」といった定数を定義します。(このように記載することで、先程の例を解決します)

config/settings.yml
products_count:
  max_count: 4
  test_count: 10

このファイルにて定数の管理を、一括で扱います。また、定数への意味付けも可能になります
[可読性上がる]。

(3) - 1 定数を取り出す

定数は以下のように記載することで取り出すことができます。

Terminal
$ rails c
[1] pry(main)> Settings.products_count.max_count
=> 4
[2] pry(main)> Settings.products_count.test_count
=> 10

設定に応じてSetteings. ~ .~の~部分を置き換えることで、定数を取り出すことが可能になります。

(3) - 2 定数を取り出す(ファイル内で)

以上を参考に先程の例を、このように解決することができます。

products_controller.rb
def show
  @product = Spree::Product.find(params[:id])
  @related_products = @product.related_products(Settings.products_count[:max_count])
end

マジックナンバーを比べていた時に比べ、可読性が少しは上がります(恐らく)。

以上です。この記事が少しでも参考になるといいな、と思います。

余談

マジックナンバーには、エンジニアの方にコードレビューして頂いた際に出会いました。「実装要件を満たした」と思った自分に対して、予想のできない指摘が飛んできました。実務の世界では当たり前のことができていない、本当にまだまだなのだな、という実感を沸いた経験でした。

リソース

以下を参考にさせて頂きました

https://wa3.i-3-i.info/word12868.html

https://qiita.com/RyoheiHashimoto/items/38ec132bd2852238295e

https://it-biz.online/it-skills/hard-coding/

また、gem "config"に関しましてはその他多くの説明が存在しますので、詳細はそちらを参考にすると実装が捗るかと思います。

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

Ruby SilverとGoldの合格体験記(2020/12〜2021/03)

はじめに

約2ヶ月間(2020年12月末〜2021年3月頭)でRuby Silver試験(2.1)とRuby Gold試験(2.1)に合格しました。点数的にはどちらもギリギリだったので、もう少しなんとかなったかな、と思っており、これを読んでいていただいた方の少しでもためになればと思って書き始めてます。主にGold中心に書いてますが、見ておけば+2~4点くらいできるようになれれば幸いです。

目次

・そもそもRuby Silver とRuby Goldって?
・勉強していてなんだかなと思ったポイント
・当日苦戦した問題(Gold)
・直前で学んだ内容で、出てきた問題(Gold)
・最後に

そもそもRuby Silver とRuby Goldって?

こちらの公式サイトをご参照ください。また、とある出典によると、Goldが基本情報技術者試験と同じくらいの難易度だとか。基本情報の方が範囲が広い分大変だった記憶があるんですけどね…。

勉強していてなんだかなと思ったポイント

その1 問題の答えだけを暗記してしまう。

どちらかというとGoldの方がそうだったなと思っているんですが、内容を理解する前に、なんとなく答えだけ分かってしまう問題はなかなか困りました。定期的に、色んな方のブログや合格体験記を見て、「あ〜この辺まだちゃんと覚えてられてないな」って思った部分を復習して学習を進めていきました。

あとは、Goldでいうと、RExでの問題でinstance_evalmodule_evalなどのeval系の問題が頻繁出てきたのですが、試験ではほとんど出なかったのが地味にしんどかったですね。

その2 学習の後半から視力検査になってくる。

特にSilverはその傾向が強かったのですが、問題を解いていると、「あ、これ解いたことある問題じゃん!」と思って回答すると、実はすこーーーしだけコードが違っていて、不正解になるパターン。勝手にこういう問題を"視力検査"と呼んでます(笑) 確かにちゃんとコードを見ず、先入観だけで解こうとした自分が良くないのはわかるけど、なんだか"試験に受かるための試験勉強"になってしまうところが本質的ではないのかな、と感じたところです。

資格試験全般に言える話だと思いますが、あくまで試験に合格することが目的ではなく(中にはそういう資格試験もあるかもだけど)、何か技術やスキルを磨くためのものだと思うので、そこは少々もやっとしたポイントでした。まあレビューする時とかに、そういう微妙な間違い等を見分けられないといけないのかな…。

当日苦戦した問題(Gold)

Silverはどんな問題出たか忘れてしまったので、一旦Goldの問題で苦しんだ問題例。

コマンドラインの動作

Q. -rの正しい動きを選びなさい。(1つ選択)
A. スクリプト実行前に、指定されたファイルを実行する。

良くあるのが、「Rubyの中で存在しないコマンドラインはどれか」というものは良く解いたけど、中身まではきちんと覚えられてなかったですね…。

catch/throwによる大域脱出

catch/throwだと、どちらにもタグがつくけど、catch/return、catch/next、catch/breakだとcatch側だけにタグがついて、もう片方には付けなくてOK。この中から動作するものを選べ系の問題が出た記憶。

Comparable

昇順になるのか降順になるのかわからなくなるので、paiza.ioとかで納得行くまで動きを見ておいた方が良いです。(問題出てきてテンパった)

privateとsuper

一瞬、これ参照できるんだっけ…?ってなった問題例。

Q. 下記コードを実行すると、どうなるか?(1つ選択)

class A
    private
    def a_method
        p "test!!!"
    end
end
class B < A
    def a_method
        super
    end
end
B.new.a_method

A. "test!!!"

ブロックとdo...end

合格教本にも似たような問題出てきたけど、完全にど忘れした問題。後から復習したら、しっかり間違えていたため、戒めに書き残します。

Q. 次の中から文法として正しい物を選びなさい。(3つ選択)
 1. 1.upto 3 do p "No.1" end
 2. 1.upto (3) do p "No.2" end
 3. 1.upto 3 { p "No.3"}
 4. 1.upto (3) { p "No.4"}

A. 1,2,4

分かっていれば、そこまで難しくない問題のはず。ブロックで引数がある時は( )をつける!!

正規表現

言語関係ないですが、突然出てくると忘れてしまう問題。全然Rubyのサイトでもなんでもないですが、前日にこのサイトを一読しておくだけでも1問解けるのではないかと思います。
試験では+?が出てきて、完全に記憶の彼方へ飛んでたので、ヤマカンで答えました。

直前で学んだ内容で、出てきた問題(Gold)

直前にどこかで見てたので、解けた問題。

cloneメソッド

確か合格教本にも載っていた問題。

Q. cloneメソッドについて適切な記述を選びなさい。(2つ選択)
A. freeseの内容も含めてコピーする。
  参照先のオブジェクトはコピーされない。

dupと併せて覚えると、より正解できるはず。

socketライブラリ

中身はちゃんと覚えてなかったけど、「〜Server」とつくのが「TCPServer」と「UNIXServer」だけ覚えていたら、点数取れました。もしかしたら、他パターンも出るかもしれないけど。

参考にしたサイト、記事

特に参考にした記事を載せておきます。この方々がいなかったら、まず自分は合格できてなかったです。本当に感謝しております…!
あとは探すと色んな方が記事を投稿しているので、同じような問題解いてて飽きてきたら、Qiita内の記事や各種ブログを読み漁るのも一つ勉強としては良いかもしれないです。

Silver

Ruby Silverに合格したので、勉強方法をまとめてみた(2019年2月版)

Ruby Silver試験前に見直すと幸せになれるメモ

Gold

Ruby Goldに合格したので、勉強方法をまとめてみた(2020年11月版)

1ヶ月後「Ruby Association Certified Ruby Programmer Gold version 2.1」に合格する方法

Ruby Gold 試験範囲を一気に見直す

最後に

なんやかんや言ってましたが、結局のところやってみて良かったかなと思ってます。個人的にあまりRubyを使えてなかったので、体系的に学ぶことにより、幅広い知識が付けられたのは確かだったかなと。
ただ、試験費用もなかなか高いので、受ける方は一発で取れるよう頑張ってください…!何かの拍子で思い出せたら、記事も書き足していこうと思ってます。

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

Ruby Gold試験前に読むとほんの少しだけ点数が上がる記事(2020/12〜2021/03)

はじめに

約2ヶ月間(2020年12月末〜2021年3月頭)でRuby Silver試験(2.1)とRuby Gold試験(2.1)に合格しました。点数的にはどちらもギリギリだったので、もう少しなんとかなったかな、と思っており、これを読んでいていただいた方の少しでもためになればと思って書き始めてます。主にGold中心に書いてますが、見ておけば+2~4点くらいできるようになれれば幸いです。

目次

・そもそもRuby Silver とRuby Goldって?
・当日苦戦した問題(Gold)
・直前で学んだ内容で、出てきた問題(Gold)
・参考にしたサイト、記事(Silver/Gold)
・勉強していてなんだかなと思ったポイント(Silver/Gold)
・最後に

そもそもRuby Silver とRuby Goldって?

こちらの公式サイトをご参照ください。また、とある出典によると、Goldが基本情報技術者試験と同じくらいの難易度だとか。基本情報の方が範囲が広い分大変だった記憶があるんですけどね…。

当日苦戦した問題(Gold)

Silverはどんな問題出たか忘れてしまったので、Goldの問題で苦しんだ問題例。

コマンドラインの動作

Q. -rの正しい動きを選びなさい。(1つ選択)
A. スクリプト実行前に、指定されたファイルを実行する。

良くあるのが、「Rubyの中で存在しないコマンドラインはどれか」というものは良く解いたけど、中身まではきちんと覚えられてなかったですね…。日常的にRubyを使っている人であれば、もしかしたらそこまで難しくはないのかも…?

catch/throwによる大域脱出

catch/throwだと、どちらにもタグがつくけど、catch/return、catch/next、catch/breakだとcatch側だけにタグがついて、もう片方には付けなくてOK。この中から動作するものを選べ系の問題が出た記憶。

Comparable

昇順になるのか降順になるのかわからなくなるので、paiza.ioとかで納得行くまで動きを見ておいた方が良いです。(問題出てきてテンパった)

privateとsuper

一瞬、これ参照できるんだっけ…?ってなった問題例。

Q. 下記コードを実行すると、どうなるか?(1つ選択)

class A
    private
    def a_method
        p "test!!!"
    end
end
class B < A
    def a_method
        super
    end
end
B.new.a_method

A. "test!!!"

ブロックとdo...end

合格教本にも似たような問題出てきたけど、完全にど忘れした問題。後から復習したら、しっかり間違えていたため、戒めに書き残します。

Q. 次の中から文法として正しい物を選びなさい。(3つ選択)
 1. 1.upto 3 do p "No.1" end
 2. 1.upto (3) do p "No.2" end
 3. 1.upto 3 { p "No.3"}
 4. 1.upto (3) { p "No.4"}

A. 1,2,4

ブロックで引数がある時は( )をつける!!

正規表現

言語関係ないですが、突然出てくると忘れてしまう問題。全然Rubyのサイトでもなんでもないですが、前日にこのサイトを一読しておくだけでも1問解けるのではないかと思います。
試験では+?が出てきて、完全に記憶の彼方へ飛んでたので、ヤマカンで答えました。

直前で学んだ内容で、出てきた問題(Gold)

直前にどこかで見てたので、解けた問題。

cloneメソッド

確か合格教本にも載っていた問題。

Q. cloneメソッドについて適切な記述を選びなさい。(2つ選択)
A. freeseの内容も含めてコピーする。
  参照先のオブジェクトはコピーされない。

dupと併せて覚えると、より正解できるはず。

socketライブラリ

中身はちゃんと覚えてなかったけど、「〜Server」とつくのが「TCPServer」と「UNIXServer」だけ覚えていたら、点数取れました。もしかしたら、他パターンも出るかもしれないけど。

参考にしたサイト、記事(Silver/Gold)

特に参考にした記事を載せておきます。この方々がいなかったら、まず自分は合格できてなかったです。本当に感謝しております…!
あとは探すと色んな方が記事を投稿しているので、同じような問題解いてて飽きてきたら、Qiita内の記事や各種ブログを読み漁るのも一つ勉強としては良いかもしれないです。

Silver

Ruby Silverに合格したので、勉強方法をまとめてみた(2019年2月版)

Ruby Silver試験前に見直すと幸せになれるメモ

Gold

Ruby Goldに合格したので、勉強方法をまとめてみた(2020年11月版)

1ヶ月後「Ruby Association Certified Ruby Programmer Gold version 2.1」に合格する方法

Ruby Gold 試験範囲を一気に見直す

勉強していてなんだかなと思ったポイント(Silver/Gold)

その1 問題の答えだけを暗記してしまう。

どちらかというとGoldの方がそうだったなと思っているんですが、内容を理解する前に、なんとなく答えだけ分かってしまう問題はなかなか困りました。先ほども記載した通り、定期的に色んな方のブログや合格体験記を見て、「あ〜この辺まだちゃんと覚えてられてないな」って思った部分を復習して学習を進めていきました。

あとは、Goldでいうと、RExでの問題でinstance_evalmodule_evalなどのeval系の問題が頻繁出てきたのですが、試験ではほとんど出なかったのが地味にしんどかったですね。

その2 学習の後半から視力検査になってくる。

特にSilverはその傾向が強かったのですが、問題を解いていると、「あ、これ解いたことある問題じゃん!」と思って回答すると、実はすこーーーしだけコードが違っていて、不正解になるパターン。勝手にこういう問題を"視力検査"と呼んでます(笑) 確かにちゃんとコードを見ず、先入観だけで解こうとした自分が良くないのはわかるけど、なんだか"試験に受かるための試験勉強"になってしまうところが本質的ではないのかな、と感じたところです。

資格試験全般に言える話だと思いますが、あくまで試験に合格することが目的ではなく(中にはそういう資格試験もあるかもだけど)、何か技術やスキルを磨くためのものだと思うので、そこは少々もやっとしたポイントでした。まあレビューする時とかに、そういう微妙な間違い等を見分けられないといけないのかな…。

最後に

なんやかんや言ってますが、結局のところやってみて良かったかなと思ってます。個人的にあまりRubyを使えてなかったので、体系的に学ぶことにより、幅広い知識が付けられたのは確かだったかなと。
ただ、試験費用もなかなか高いので、受ける方は一発で取れるよう頑張ってください…!何かの拍子で思い出せたら、記事も書き足していこうと思ってます。

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

Rubyのincludeを理解したい①

書くこと

Rubyのincludeについて、メソッド探索について学んだ結果見えた事実
こちらの記事を参考にさせていただきました。ありがとうございました。

【ruby】 メソッド探索から見る、モジュール・特異メソッド・特異クラス

自分なりに、こちらの記事を設計図と車で喩え直してみました。

(こちらの記事は、2部構成になっているうちの、第一部です。)
次の記事はこちら→

クラスとインスタンス

本題は、Rubyのincludeについてですが、この記事では後に理解がしやすくなるようにクラスとインスタンス、それに伴う変数とメソッドについて掘り下げていきます。

Rubyには、クラスとインスタンスと言う概念があります。
車を作る時で考えてみましょう。

- クラスは、設計図です。

- インスタンスは、その設計図をもとに作られた実際の車です。

もう少し理解してみましょう。クラスとインスタンスには、それぞれメソッドなるものが存在します。

- クラスメソッドは、設計図全体に適応される共通オプションです。

手引書のルールみたいなもんですね

- インスタンスメソッドは、それぞれの車の特徴・動作などをそれぞれに付け加えます。

車は「走る」、あの車は「赤い」などと言ったことを表します。

example.rb
class Car   #クラス
  def color   #インスタンスメソッド
    @color = red   #@colorはインスタンス変数と呼ばれます。@colorには、redが代入されています。
  end
end

model_car = Car.new   #Carクラスのインスタンスを生成し、model_carに代入しています。
model_car.color   #Carクラスで定義されているcolorと言うインスタンスメソッドを、直前で生成したmodel_carインスタンスにかけています。

はい、ここまでは、多少Rubyについて勉強している方であれば、理解いただけたと思います。
わからない人も、ふーんと思いながら聞き進めてください。

本当に設計図と車の関係?

さて、ここから少しずつ、僕がなるほどなるほどと納得し直した部分に入っていきます。

まずは、先ほどのクラスとメソッドの関係性について
おさらいすると

クラスは、設計図です。

インスタンスは、その設計図をもとに作られた実際の車です。

と端的に書きました。

設計図と車の関係であれば
「設計図通りの色や大きさ、エンジンなどの特徴・部品で車が作られる」
つまり、設計図に書いてある内容を、それぞれの車が持つことになります。

しかし、クラスとインスタンスの関係は、少し違うようなのです。
どのように違うのでしょうか?

実は常に「参照」している

結論から述べると
特徴や動作を「持つ」のではなく、一回一回、設計図を「参照しながら」車は、動いているのです。

ちょっとイメージが湧きにくいかと思いますので、先ほどのコードをもとに考えてみましょう。

example.rb
class Car #Carクラスという設計図には、
  def color #colorでredを呼び出せるインスタンスメソッドが存在します。
    @color = red                           
  end
end

model_car = Car.new                        #1
model_car.color #ここで、colorを呼び出しています。 #2

ここからが、最も大切な部分ですので、注意して読んでみてください。

まず、ここで何が起きているか順を追って説明します。

  1. model_car変数に、Carクラスのインスタンスが代入されます
  2. model_carインスタンスに、colorインスタンスメソッドを呼び出します。その結果、model_carオブジェクトはインスタンス変数の@colorを持つことになります。

今の説明から、model_carと言う箱の中に、@colorがあるということをイメージできるでしょうか。
しかし、その箱の中には、colorというインスタンスメソッドは存在しません。

つまり、オブジェクトは@colorと言うインスタンス変数を持つことができるけど、colorというメソッドを持つことができない。という結論になります。

そうすると、クラスがインスタンスメソッドを持つことになり、インスタンスはクラスのメソッドを常に参照することになりそうです。

まとめると

オブジェクトは インスタンス変数 と クラスへの参照 を持つ
クラスは インスタンスメソッド を持つ

と言うことができます。

No Method Errorが起きてしまうわけ

もう少しだけ話を膨らませます。
もし、このクラス(設計図)に、言及がないメソッドが呼び出されたらどうでしょうか?

example.rb
class Car             #Carクラスには、wheelメソッドは存在しません。
  def color 
    @color = red                           
  end
end

model_car = Car.new                        
model_car.wheel        #wheelを参照しようとしています
#→No Method Error

このような状態で、No Method Errorが発生します。
このエラーが意味するところは

「そんな特徴は、設計図に書いてねーよ!」
ということです。次につながる話ですので、もう少し補足すると

「この設計図には書いてないから、この設計図の元になったものを追ってみよう。」
と判断させることもできます。

このことについては、次の記事で触れたいと思います。

最後に

最後まで読んでいただき、ありがとうございます。
ソースコード、記事の書き方について「もっとこうしたほうがいいよ!」というご意見、「そこどうなっているの?」というご質問など、お待ちしております。

参考文献

【ruby】 メソッド探索から見る、モジュール・特異メソッド・特異クラス

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

【Rails】世界一簡単なcreated.at(updated.at)日本語表記

はじめに

railsではロンドン?の時刻表示がデフォになっていますが、簡単に日本語表記で表すことができます。

本記事では簡単にやる方法を簡潔に書きます。

開発環境

  • Ruby2.6.6

実際のコード

まずは、application.rbに以下を記述します。

config/application.rb
config.i18n.default_locale = :ja

次に、config/locateの中にja.ymlのファイルを作り、以下を記述します。

config/locate/ja.yml
ja:
  datetime:
    distance_in_words:

      less_than_x_minutes:
        one:  "1秒"
        other: "%{count}秒"
      x_minutes:
        one:   "1分"
        other: "%{count}分"
      about_x_hours:
        one:   "約1時間"
        other: "約%{count}時間"
      x_days:
        one:   "1日"
        other: "%{count}日"
      about_x_months:
        one:   "約1ヶ月"
        other: "約%{count}ヶ月"
      x_months:
        one:   "1ヶ月"
        other: "%{count}ヶ月"
      about_x_years:
        one:   "約1年"
        other: "約%{count}年"
      over_x_years:
        one:   "1年以上"
        other: "%{count}年以上"

あとは、表示させたいviewに追記部分を加えるだけ!

index.html.erb
<h1>sample</h1>
<h3>Tweet一覧</h3>
<%= link_to "新規投稿へ", tweets_new_path %>
<div class="tweets-container">
  <% @tweets.each do |t| %>
    <div class="tweet">
      <%= t.body %>
         #ここから
      <time datetime="<%= t.created_at %>">
      <%= time_ago_in_words(t.created_at) %>前
      </time>  
     #ここまで
    </div>
  <% end %>
</div>

最後に

世界一簡単にRailsでcreated.atやupdated.atをTwitterのように(〇分前、〇日前)日本語表記する方法についてご紹介しました。

簡単に実装可能なのでぜひ試してみてみてくださいね!

参考記事:https://qiita.com/bellx2/items/30906a7832ef4ff4c886

最後まで読んでいただき、ありがとうございました。

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

[Ruby on Rails] No template for interactive request

なんか色々と長い内容のエラーに出くわした。
備忘録と言うよりは打つ間違いに気をつけろ!ってことで
自身への反省をこめて書きます。

No template

なら、いつもの記述間違いか?ってなる所、
今回のエラーはいつもより長かった...

  

エラー内容↓

No template for interactive request

CatsController#show is missing a template for request formats: text/html
NOTE!


(インタラクティブリクエスト用のテンプレートはありません
CatsController#showにリクエスト形式のテンプレートがありません:text / html
注意!)
 

解決方法?

なのかは、分からないがshow.htmlのファイルを作った時にコンマが一個多かったorz
show..html.erb となっていた。
ただそれだけ。
 

まとめ

たまたま早期発見できたものの、今後templateエラーが出たら
コードとファイルの両方を細かくチェックするべきだと実感しました。

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