20201016のRubyに関する記事は23件です。

【Rails物語】デルメルの法則〜知りすぎてはいけない〜

概要

とある街に駆け出しのエンジニアのY君がいました

彼にとってプログラミングは難しいものでした

しかし彼はつよつよエンジニアになりたいと願い、数ヶ月前から毎日プログラミングの勉強をしてました

そんなある日、彼はより実践的な経験値を得るため共同開発チームに入るのでした

与えられたミッション(タスク)をこなし報告(プルリク)を出した時、それは起こりました、、、

デルメルの怒り

Y君はこんなコードを書いていました

<%= "#{message.user.name}さん : " %>
<!-- messageの中身はこんな感じ{"user_id"=>1, "content"=>"やっほー"} -->

、、、これがデルメルの怒りに触れてしまったのです。

デルメル「知りすぎじゃーーーーーー!!」

デルメル曰く、プログラミングの世界では「知りすぎている」のは罪なのです

この場合messageuser_idは知っていて紐づいている。だけどuser自体の事は知らないし、そのnameなんて事は知らないはずなのです

ギャングがボスの存在は知っていても本当の名前を知ってはならないように、、、(ディア○ロ思考)

これをデルメルの法則と言います

参考
https://qiita.com/br_branch/items/37cf71dd5865cae21401

Y君は絶望の淵に立たされました

賢者の救援

どうすれば良いのかわからず途方にくれていたY君

そこへ仲間の賢者(つよつよエンジニア)がやってきてこう言いました(レビュー)

賢者「delegate使えばええんやで、スッ」

参考
https://qiita.com/TT-nasu/items/13fb0617435a960407ec

Y君「!!」

必殺delegate

delegateマクロを使うとメソッドを簡単に委譲できる

Y君は上記記事を参考に下記のようにコードを書き加えました

class User < ApplicationRecord  
  has_many :messages

  def user_name
    "#{name}さん : "
  end
end

class Message < ApplicationRecord
  belongs_to :user

  delegate :user_name, to: :user
end

すると先ほどのデルメルぷんぷんコードはこうなりました、、、

<%= message.user_name %>

これを見たデルメルは「まぁよかろう」とだけ言って去って行きました

罪の晴れたY君は、デルメルの法則を肝に命じて、新たな開発を進めていくのでした。

この物語は半フィクションです、あと本当にこれでデルメルの法則を守れてるのか微妙かもです、この方がいいよというやり方あったら是非教えてください!

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

【Rails物語】デメテルの法則〜知りすぎてはいけない〜

概要

とある街に駆け出しのエンジニアのY君がいました

彼にとってプログラミングは難しいものでした

しかし彼はつよつよエンジニアになりたいと願い、数ヶ月前から毎日プログラミングの勉強をしてました

そんなある日、彼はより実践的な経験値を得るため共同開発チームに入るのでした

与えられたミッション(タスク)をこなし報告(プルリク)を出した時、それは起こりました、、、

デメテルの怒り

Y君はこんなコードを書いていました

<%= "#{message.user.name}さん : " %>
<!-- messageの中身はこんな感じ{"user_id"=>1, "content"=>"やっほー"} -->

、、、これがデメテルの怒りに触れてしまったのです。

デメテル「知りすぎじゃーーーーーー!!」

デメテル曰く、プログラミングの世界では「知りすぎている」のは罪なのです

この場合messageuser_idは知っていて紐づいている。だけどuser自体の事は知らないし、そのnameなんて事は知らないはずなのです

ギャングがボスの存在は知っていても本当の名前を知ってはならないように、、、(ディア○ロ思考)

これをデメテルの法則と言います

参考
https://qiita.com/br_branch/items/37cf71dd5865cae21401

Y君は絶望の淵に立たされました

賢者の救援

どうすれば良いのかわからず途方にくれていたY君

そこへ仲間の賢者(つよつよエンジニア)がやってきてこう言いました(レビュー)

賢者「delegate使えばええんやで、スッ」

参考
https://qiita.com/TT-nasu/items/13fb0617435a960407ec

Y君「!!」

必殺delegate

delegateマクロを使うとメソッドを簡単に委譲できる

Y君は上記記事を参考に下記のようにコードを書き加えました

class User < ApplicationRecord  
  has_many :messages

  def user_name
    "#{name}さん : "
  end
end

class Message < ApplicationRecord
  belongs_to :user

  delegate :user_name, to: :user
end

すると先ほどのデメテルぷんぷんコードはこうなりました、、、

<%= message.user_name %>

これを見たデメテルは「まぁよかろう」とだけ言って去って行きました

罪の晴れたY君は、デメテルの法則を肝に命じて、新たな開発を進めていくのでした。

この物語は半フィクションです、あと本当にこれでデメテルの法則を守れてるのか微妙かもです、この方がいいよというやり方あったら是非教えてください!

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

【図解】硬貨の和を再帰関数で求める【Ruby】

はじめに

ProjectEulerのProbem31についてです。
再帰関数での他の人の解答を参考にして、再帰関数初心者が解説してみました。
下で図解もしているので、そちらもぜひ見てください。

問題

Problem 31 「硬貨の和」
イギリスでは硬貨はポンド£とペンスpがあり,一般的に流通している硬貨は以下の8種類である.
1p, 2p, 5p, 10p, 20p, 50p, £1 (100p) and £2 (200p).
以下の方法で£2を作ることが可能である.
1×£1 + 1×50p + 2×20p + 1×5p + 1×2p + 3×1p
これらの硬貨を使って£2を作る方法は何通りあるか?

日本語版
英語版公式

方針

coins = [1,2,5,10,20,50,100,200]の中から任意の一枚ずつ取り出していく作業を、200になるまで繰り返す。
人間の手で行ってたらとてもじゃないけど、数えきれないのでこういう時は「再帰関数」!

再帰関数とは?

def ~ endで定義した関数内で自分自身を呼び出す関数のことをいいます。
有名なものだとフィボナッチ関数などはよく再帰関数の入門として扱われたりします。
初めて聞いたよという方は検索してみてください。

別の解説記事:【図解】階乗の再帰関数【Ruby】

解答

def coin_count(coins, goal, last = 0)
  if goal == 0
    return 1
  end

  total = 0
  coins.each do |c|
    if c < last
      next
    end
    if goal >= c
      total += coin_count(coins, goal - c, c)
    end
  end

  total
end

coins = [1,2,5,10,20,50,100,200]
puts coin_count(coins,200)

恥ずかしながら自力では解けなかったのでこちらを元に作成しました。
この解法を日本語で解説しようと思います。

解説

今回作りたいのは200という数値。
そこでgoal = 200と設定して、硬貨一つの値

まず関数内のeach文内から説明を始めます。

if c < last
  next
end

これは直近で足した数lastを超える数は足さないようにしています。
50 + 50 + 10050 + 100 + 50は今回の問題では同じなので、昇順に足していくパターンのみを採用するようにします。
nextはブロック内のnext以降の処理をスキップするという処理になります。

次に、再帰関数を用いている関数内の3つ目のif文内です。

if goal >= c
  total += coin_count(coins, goal - c, c)
end

今回、ccoins = [1,2,5,10,20,50,100,200]の要素のいずれかなので1 <= cです。
ですのでcoin_count(coins, goal, last)の引数として渡されるgoalgoal - cは0に向かって減っていきます。

仮にc = 50、 goal = 200の時は下のようになります。

例)
再帰関数で goal - c が繰り返されていくと、引数の goal は
1回目: 150     ※coin_count(coins, 150, 50)で呼び出し
2回目: 100     ※coin_count(coins, 100, 50)
3回目: 50      ※coin_count(coins, 50, 50)
4回目: 0       ※coin_count(coins, 0, 50)

4回目にcoin_count(coins, 0, 50)で関数が呼び出されたとき、

if goal == 0
  return 1
end

になるので、ここまできてようやく、

total += coin_count(coins, goal - c, c)

coin_count関数戻り値 1 を持つことになります。
そこででようやくtotal += 1となり、1プラスされます。

  • goal > 0の時
  • goal < 0の時

この場合は、total = 0が0のまま戻り値に渡されます。
最終的に組み合わせの総数がtotalの値として得られます。

図解

この、関数が繰り返し呼び出されていく状態を図にしてみました。
projecteuler31解説.001.jpeg

終わりに

説明の足りない点や、間違っている点、よりわかりやすい説明があればどしどし教えてください。
読んでいただきありがとうございました。

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

【図解】階乗の再帰関数【Ruby】

はじめに

自分が初めて再帰関数を知ったときに、理解するのに苦労しました。
その際に紙に書いたことで理解できたので、それを今回図解しました。

再帰関数とは?

def ~ endで定義した関数内で自分自身を呼び出す関数のことをいいます。
有名なものだとフィボナッチ関数などがよく再帰関数の入門として扱われたりします。
初めて聞いた方は検索してみてください。

階乗とは

1からnまでの連続するn個の自然数の積をnの階乗という。
n!と書き、例えば4!=1×2×3×4=24と表す。
ただし、0の階乗は1とする。

引用元:goo辞書

再帰関数を用いたコード

def factorial(num)
  if num == 1 || num == 0
    return 1
  end
  return num * factorial(num - 1)
end

num < 0が渡されてしまった場合は今回は考慮していません。

非常にシンプルなコードですが、脳内で考えていると意外と混乱します。

図解

スクリーンショット 2020-10-16 22.45.16.png

終わりに

まだまだ再帰関数初心者なので複雑なものは私もまだ混乱します。
ただ、今回図解したコードなどが基本になっていると思うので迷った時は初心に戻ろうと思います。

この記事がどなたかの再帰関数理解の一助になれば幸いです。

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

Qiita に J 言語のシンタックスハイライトがないので自分で実装した

はじめに

最近 J 言語 にハマっているのですが、残念なことに Qiita のシンタックスハイライトは J をサポートしてくれていません :qiitan-cry:J は特に見た目がアレな言語なので、 記事を書く側も読む側もシンタックスハイライトがあるとモチベーションが上がると思います。

ということで、自分で実装することにしました。その記録を、ここに残しておこうと思います。

他の言語のシンタックスハイライトを実装する時に参考になるかもしれませんし、J 言語が他の言語と違いすぎてあまり参考にならないかもしれません。

大まかな手順

Qiita のシンタックスハイライトには現在 Rouge という Ruby 製のライブラリが使われています。このライブラリにプルリクエストを送ることで、J のハイライトを追加しようと考えました。

Rouge をフォークしたら、lexer 開発のガイド を見ながら始めます。

最初に、lexer を定義するファイルと、spec を追加します。

lib/rouge/lexers/j.rb
# -*- coding: utf-8 -*- #
# frozen_string_literal: true

module Rouge
  module Lexers
    class J < RegexLexer
      title 'J'
      desc "The J programming language (www.jsoftware.com)"
      tag 'j'
      filenames '*.ijs', '*.ijt'

      # ここに lexer の実装を書く
    end
  end
end
spec/lexers/j_spec.rb
# -*- coding: utf-8 -*- #
# frozen_string_literal: true

describe Rouge::Lexers::J do
  let(:subject) { Rouge::Lexers::J.new }

  describe 'guessing' do
    include Support::Guessing

    it 'guesses by filename' do
      assert_guess :filename => 'foo.ijs'
      assert_guess :filename => 'foo.ijt'
    end
  end

  describe 'lexing' do
    include Support::Lexing

    # ここにテストを書く
  end
end

この他に lib/rouge/demos/jspec/visual/samples/j が必要ですが、始めは空のファイルで構いません。

あとは、以下の手順を並行して行います。言葉で解説するより実際のコードを見た方が早いので、細かい説明は省きます。知っている/よく使う言語の lexer を見れば大体分かると思います。

spec を書く

RSpec の書き方を知っていれば、特に困ることはないと思います 1

テストには assert_tokens_equal を使います。

assert_tokens_equal "コード", トークン1, トークン2, ...

トークンは、[名前, テキスト] の組で表します。トークンの名前については、一覧 を参照してください。

実際のところ spec がほとんど書かれていない言語も多いようなので、あまり詳細に書く必要はないのかもしれません

lexer を書く

lexer の記述にも、DSL(EDSL) が使われています。

state シンボル do
  rule 正規表現, トークン
  ...
end

詳しいことはここでは説明しません。分からないときは他の言語の lexer を見ると参考になると思います 2

visual sample / demo を書く

visual sample (spec/visual/samples/j) は、正しくハイライトされるかを、目で見てチェックするためのテキストファイルです。ある程度の大きさのプログラムでも、単なるトークンの羅列でも構いません。

demo (lib/rouge/demos/j) は、rouge.jneen.net に表示される短いコードです。

テスト

README に書いてありますが、spec は rake を使ってテストします。visual sample は、rackup を実行してチェックします。(localhost:9292 で demo が、localhost:9292/j で visual sample が表示されます。)

こだわった点

※ ここに書いてある内容は、J 言語を知らない人には全く通じないと思われます。

J のコードをハイライトする上で、一番大切なのは、全ての記号を演算子として扱ってはいけないという点です。記号を色分けできなければ、シンタックスハイライトの意味が半減してしまいます。

そこで、verb を関数 (Name.Function) 、adverb/conjunction を演算子 (Operator) として扱うことにしました。これによって、>:@i. のような式が読みやすくなります。

可読性のための工夫点はもう一つあります。explicit definition の定義部分が文字列リテラルの場合 (例: dyad : 'x + y')、リテラルの内部を式としてハイライトするようにしました。

おわりに

実は Ruby をまともに書いたのは、これが初めてなのですが、案外簡単に書けたように思います 3。視覚的にデバッグできるのが楽でした。

Rouge にプルリクエストを送ったところ、無事マージされました :tada: 。先日リリースされた v3.24.0 に含まれています (デモ)。

あとは Qiita が対応してくれるのを待つばかりです。 :qiitan:

余談

Rouge v3.24.0 リリースのコメントより抜粋:

This release has two new lexers: one for e-mails (中略) and one for J (why not another language starting with J?).

やっぱり J ってネタ言語扱いなんでしょうか……


  1. 実際には Minitest が使われていますが、基本的な書き方は共通しています。 

  2. 当たり前ですが、コピペはダメです。 

  3. Ruby というよりも、Ruby 上の EDSL を書いただけのような気がしますが。 

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

【NuxtJS×RailsAPI】折角0からプログラミングを勉強したので、推しキャラの誕生日アプリを作ってみた。

自己紹介

Webエンジニアをしたり、マジシャンをしたり、オンライン家庭教師をしたり、イベントを企画したり、色々なことをしておりますyukiと申します。
今年の1月からプログラミングを学習し、DMMWEBCAMP入学を経てエンジニアとして勤務、約4ヶ月ほどが経過しました。

過去学習してきたことなどは、こちらの記事にまとめてありますので、良ければご覧ください。
【卒業生】DMMWEBCAMPに通おうか迷っている人に伝えたい事

成果物

NuxtJS/RailsAPI/AWS/Firebase
【Webアプリ】https://tokidosaya.com
【GitHub】https://github.com/yuki-snow1823/project-saya
コードはお世話になっているエンジニアの方にレビューをしていただき、現在リファクタリング中です。ご容赦くださいませ。

この記事を読んで得られるもの、わかること

【技術面】

  • NuxtJS×RailsAPIのWebアプリ作成の時につまづいた部分と対応策の例
  • TwitterAPI使用の申請をした話
  • その他学びになったtips

【余談】

  • プログラミング未経験から、推しの誕生日をお祝いするに至るまでの流れ
  • 「発想とプログラミング」に関する自分のポエム

もし、読み進めてくださる方がいらしたら、よろしくお願いします。

その前に推しキャラと協力してくださった神の紹介

今回、自分の突拍子もないプロジェクトに賛同してくださった二人をご紹介します。
イラストレーターのKrarisとWebデザイナーのももりんごさんです。

お二人は素敵な絵を描いてくださったり、パーツのデザインを考えてくださったり、サイズを調整する案を出してくださったり、色彩のアドバイスをくださったり…とにかく全面的に協力してくださいました。

関係的には、Krarisは私の元バイト先の後輩で、ももりんごさんはDWCの先輩です。
改めて、お二人に感謝申し上げます。

推し:リトルバスターズEXより 朱鷺戸沙耶

    
Illustration by Kraris

この金髪の子です。お誕生日おめでとう。(10/21)詳しいシナリオはここには書きませんが、ちょっと個人的に思うことには報われなさすぎるキャラクターなので、なんとか幸せになって欲しいなと思い、このアプリを作るに至りました。ちなみに、男の子は理樹君という主人公です。
是非、リトルバスターズとリトルバスターズEX、アニメやゲームで体験してみてください。

技術の話 - NuxtJS×RailsAPIのアプリ作成の時につまづいた部分と対応策の例

こちらでは作成の際にぶつかったエラーと対策に関して、TwitterAPI以外のものをまとめます。

[Rails]gem 'active_model_serializers'がインストールできない

jsonをrailsAPI側から返すにあたり、gem serializersを使用しようと思いました。しかし、一向にbundle installが通らず、以下のエラーが出ていました。

Could not find case_transform-0.2 in any of the sources
Run `bundle install` to install missing gems.

こちらの件に関しては、spring stopを実行したのちに、bundle installを再度実行で解決しました。

bundle install周りって結構エラーが起きがちですが、これまでの経験上パスの指定が間違っていることが多い印象です。which bundleして一旦削除するとかも手だと思います。

[Rails]ミス:クラスメソッド名とカラム名を同じにしてしまった

これはもう自分がアホとしか言いようがないのですが、Counterテーブルというテーブルを作成したのち、カラム名の指定をcountというものにしました。よくよく考えたらrubyには元々そんなメソッドがありました…。

counter_controller.rb
    counter = Counter.find(1)
    counter.count = counter.count + 1

こんなみるも無残なコードを書いてしまいましたが、無事に動きました。リファクタリングやより良い実装ができるように精進します。この件は対策とかはなく、命名を注意してくださいということをお伝えできればと思います。

[Nuxt]Vuetifyでrowやcolの指定が効かないと思ったら…

Vuetifyというライブラリでデザインをしていたのですが、どうしてもグリッドシステムが思うように適用されないことがありました。しばし悩んだのち調べてみたところ、こんな記事を見つけました。

https://dev83.com/vue-vuetify-basic/

(引用させていただいております。)

v-appはVeutifyを使うために必須の要素です。Vuetifyのコンポーネントは必ずv-app要素の内側に書く必要があります。v-appで囲まないでVuetifyのコンポーネントを使うと予期しない動作や表示になってしまいます。下記のようにVuetifyのコンポーネントをv-appで囲みます。

( ω) ^ ^
案の定<v-app>で囲んでいないだけでした。しっかりとガイド読んでから使えよと戒めになりました。

TwitterAPI使用の申請、実装をした話

これが今回のプロジェクト1の衝撃だったのですが、「ハッシュタグのツイート収集」に関して私は公式から提供されているウィジェットを使えばいいやと思っていました。
ところが、調べてみると2018年にそのサポートは切れており、TwitterのDeveloperとして登録をして、自分でその機能を作らなければいけないことがわかりました。

ただ、どうしても実装したい機能だったので、1から調べて申請することにしました。

【参考にさせていただいた記事】
https://qiita.com/kngsym2018/items/2524d21455aac111cdee

ありがとうございました。Twitter側のUIは変わっていましたが、ほとんどこの通りに行いました。英語に関しては、急いでいたこともあったので、全部日本語で入力したのちにGoogle翻訳(最近の精度にびっくりしました。)、流石に変な部分を修正して申請しました。

3日くらいで通ったのですが趣味で使用すること(金銭が絡まない)危険な行為を一切しないことを強調した文章にしたところ、自分の場合はスムーズに通ったような気がします。

技術の話は次で終わりですが、gem twitterを使ってハッシュタグツイートを収集する方法に関しては、また別途記事でまとめたいと思います!チュートリアルでも作りたいですね!

その他学びになったtips

ツイートする時にカード?みたいなのを出したい。

リンクをツイートする時とかにふわっと出てくるアレ、名前も知らなかったのですが実装に成功しました。
名前は、Twitter Cardというらしいです。NuxtのSPAモードでの実装はどうやるんだろう…と悩んでいたところ、こちらの素晴らしい記事に救っていただきました。

Nuxt(SPAモード) + FirebaseでTwitterシェア用にOGP画像の設定をしたい。

そして、こちらのサイトを使うとリアルタイムでチェックができます。

スクリーンショット 2020-10-16 1.25.17.png

イラストの登場にふわっとアニメーションをつけたい

イラストがふわっと出ればいいなーと思っていたところ、友人がAnimate.cssなるものを教えてくれました。今回はガッツリコードを書いてアニメーションをつけるつもりもなかったので、CDNで導入してクラス名をつけるだけで、ふわっとしたアニメーションがつきました。感謝!

余談

ここからは、未経験からエンジニアになった自分が完全に自分が作りたいものを作るに至った考えやポエムをまとめたいと思います。自己満足なので、イラっとしない寛大な方だけお進みください。

プログラミング未経験から、推しの誕生日をお祝いするに至るまでの流れ(withWEBデザイナーさん、イラストレーターさん)

キャラクターの誕生日アプリを作りたい!と思ってから以下の順序で完成に至りました。

①キャラクターの誕生日とは、どんなことをするものなのか調べる

こちらの結論は、イラストを投稿したり、お祝いメッセージを書いたりすることでした。ですから、ハッシュタグをつけたツイートの収集+投稿機能は必須で入れたいと思いました。

②イラストが必要なため、イラストレーターを探して依頼する

私は絵が描けませんし、可愛い沙耶と理樹君の絵が見たかったので、昔から仕事を依頼していたKrarisに依頼をしました。

③アイテムの配置を考えた時に、Krarisや自分よりも知見の人を探す必要があった

Krarisもアイテムの配置や色彩に知見はありましたが、本人とも話した結果、Webデザイナーとして活動している人からもアドバイスをもらおうという結論に至り、DWCの先輩であるももりんごさんに参加いただきました。

④ハッシュタグツイートの収集にTwitter Developerの申請が必要と知る

不慣れな英語で申請をし、英語のドキュメントを読んでgem twitterを駆使してなんとか実装しました
ここでも、一度エンジニアの先輩にお世話になりました。

⑤せっかくならフロントとバックを分けたいのでNuxtJSを引っ張り出す

これはもう何度も出していますが、こちらのチュートリアルのおかげです。
https://qiita.com/saongtx7/items/d97ef5aec393e704fd3f

全て、何か必要がある→行動する、勉強するというプロセスでした。今回の実装にあたり、何個も何個も勉強になった部分があるので、これからもアウトプットとして個人開発は行っていきたいなと思います。

「発想とプログラミング」に関する自分のポエム

自分の強みは発想力だと思っています。これまでも、あまり人が思いつかないことや、思いついてもめんどくさくてやらないことを、色々やってきた自負が少しだけあります。ただ、形にしたくても、どうしてもできなくて挫折した経験もあります。

今、プログラミングを学び始めて半年くらいが経ち、改めて「発想を形にする力」を貸してもらっていると感じています。それと同時に、プログラミングだけじゃ駄目だという思いが強くなっています。

デザイナーさんがいるからアプリの見た目が良くなるし、イラストレーターさんがいるから絵を通じて想いを伝えられるし、営業さんがいるから作ったものが売れるし、マネージャーさんやディレクターさんがいるから作ることに専念できるし…いろんな人がいろんな発想を使って頑張っているから、素敵なアプリやプロダクトができていると今回改めて勉強になりました。

本当に、周りの方には感謝するばかりです。ありがとうございます。

さいごに

リトルバスターズというゲームをやって、この朱鷺戸沙耶と主人公の理樹君ががたどった結末を見た時に、私は大きなショックを受けました。当然現実には存在しませんが「この二人に幸せになって欲しい」「流石にキャラクターの誕生日に向けたアプリを作る人は少ないのではないか→やってやろう!」という思いで完成に至りました。

作りたいものを形にできるって、ありがたいことだなと思います。

これからも好きなものを作っていこうと思います!
もし、プログラミングはできないけど…推しの誕生日はお祝いしたい!みたいな人がいらしたら、是非連絡ください。
作りたいものを形にしたい方も、応援したいなと思います。

そして、もしも、、、万が一、、、朱鷺戸沙耶と理樹君が好きでここまで読み切った猛者がいたとしたら…いつか沙耶アフターを作りましょう!!ご連絡待ってます!

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

RSpec導入後、モデルの単体テストコードを書き始めるまで

はじめに

RSpecの導入までの流れは、こちらからどうぞ

流れ

  1. FactoryBotの準備
  2. テストコードを記述するファイルの生成
  3. 記述の型

1. FactoryBotの準備

ディレクトリとファイルを用意する。
ex)userモデルのFactoryBotなら、spec/factories/users.rb

spec/factories/users.rb
FactoryBot.define do
  factory :user do
    email {Faker::Internet.free_email} #例
    #以下、同じように必要なFakerを記述
  end
end

:userの部分が、spec/models/user_spec.rbでFakerを呼び出すときに使う。

Fakerの細かい使い方は、FakerのGitHubへ

2. テストコードを記述するファイルの生成

ターミナルで、

rails g rspec:model モデル名

このコマンドにより、
spec/models/モデル名_spec.rb
のファイルが生成される。

ファイルの中に初めから、

spec/models/user_spec.rb
RSpec.describe User, type: :model do
  pending "add some examples to (or delete) #{__FILE__}" #この行は削除
end

このようなコードが入っている。2行目のコードは削除して構わない。
(上の例は、モデル名にuserを指定したもの)

3. 記述の型

spec/models/user_spec.rb
RSpec.describe User, type: :model do
  describe '何をテストするのか(例)ユーザー新規登録' do
    before do
      @user = FactoryBot.build(:user) #userモデルを例にすると、userのFactoryBotを呼び出し
    end
    it "具体的なテスト項目(例)メールアドレスが必須であること" do 
    end
  end
end

(同じく上の例は、モデル名にuserを指定したもの。)

 .build(:user)←:userがFactoryBotから呼び出されている。

itdoの間にexampleを入れる。
do~endの間に、コードを記述する。

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

特定のテーブルのデータをすべて消去する方法

前提

db/seedにデータを入れていた。
データを変更したいので一旦消去することにした。

csvファイルのデータ
image.png

方法

rsils c

Food.all.destroy_all

解説

複数のデータを削除するときにはdestroy_allを使う。

結果

image.png

参考にしたサイト

https://www.sejuku.net/blog/63480

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

【個人開発】全ての食べ物を0kcalにするカロリー管理アプリ「Zerorie」をリリースしました

はじめに

こんにちは。

個人開発の醍醐味とは「技術の無駄遣い」だと私は思います。

そんな私も個人開発でクソアプリを作成しましたので、以下に色々記録しておこうと思います。

サービス概要

今回私は、「ゼロカロリー理論」を使って、全ての食べ物を0kcalにしてくれるカロリー管理アプリ「Zerorie」を作りました。
iOS の画像 (9).jpg

「ゼロカロリー理論」とは、サンドウィッチマンの伊達さんが考案したネタで、「寿司は握ることでカロリーが潰されるから0kcal」みたいな、食べ物のカロリーを0kcalにしてくれるトンデモ理論のことです。

つまりこのアプリを使えば、食事した食べ物をすべてゼロカロリーにしてくれるため、「カロリーを気にして食事を我慢する」「高カロリーの食べ物を食べたことで罪悪感を覚える」といったカロリーに関わる悩みを一切気にすること無く、食事を楽しむことができるという訳です。

アプリのURL

https://zerorie.com/

Githubのリポジトリ

https://github.com/ryota1116/zero_calorie

コンテストに出場!!

複数のプログラミングスクール生がポートフォリオを発表する合同コンテスト"editch"に、このアプリをもって、出場しました!
下記にイベントの様子をレポートしましたので、良かったらご覧になってください。

プログラミングスクール合同コンテスト「editch」に出場しました - note

アプリの使い方

トップページです。
まるでクソアプリとは思えないような 綺麗なデザインに仕上がっていますね。
スクリーンショット 2020-10-13 22.02.35.png

このアプリは食事した食べ物を検索するところから始まります。
食事した食べ物を、食べ物の「名前」や「画像」で検索することができます。
スクリーンショット 2020-10-16 15.28.25.png

検索結果として「食べ物のデータ」「食べ物が0kcalである理由」が表示されます。
スクリーンショット 2020-10-16 15.35.12.png

検索結果から食べ物を選択すると、「食事記録登録ページ」が表示されます。
画像検索を行った場合は、検索に使用した画像がプレビューで表示され、画像も一緒に登録できます。
スクリーンショット 2020-10-16 15.30.47.png

食べ物の検索時に、該当する検索結果を得られなかった場合は、「ちょっと何言ってるか分かりません」と怒られます。
その場合は、「検索条件を変更する」か、「新しく食べ物の登録」をしてみましょう。
スクリーンショット 2020-10-16 15.54.16.png

食べ物の登録ページでは、画像検索で使用した画像も表示されます。
スクリーンショット 2020-10-16 15.58.16.png

食べ物の登録ページで、カロリーを0以外で入力するとバリデーションエラーが発生し、「この食べ物のカロリーは0kcalです。0と入力してください。」と怒られます。ちゃんと0と入力しましょう。
スクリーンショット 2020-10-16 16.03.17.png

ざっとメイン機能はこんなところです。

個人的に好きなカロリー理論トップ3

僕の好きなカロリー理論トップ3を勝手ながら発表します。
他にもいっぱいカロリー理論があるので、正直トップ3を決めるのは心苦しい決断でした。

1位: 「なんくるないさ」=「カロリーゼロさ」(沖縄料理のカロリー理論)

沖縄に行くと街中で「なんくるないさ」の文字をよく見かけますが、そういう意味だったんですね。ますます沖縄のことが好きになりました。

2位: 野菜がカロリーを無効化してくれる。常連が野菜増し増しを注文する訳はコレである。(二郎のカロリー理論)

二郎も0kcalだったとは思わぬ発見ですね。これで安心して二郎ダイエットの日々を送れそうです。

3位: 和菓子はわびさびを体現した食べ物。わびさびの心にカロリーの話を持ち出すのは言語道断である。(和菓子のカロリー理論)

シンプルに意味がわからない。千利休が泣いていないか心配です。

なぜ作った

お笑いと食が好きだったからです。
「食」とか「笑える」に関わる面白いアプリを開発できないかと色々考えてたら、ふと思い付きました。

Zerorieを使った先に見える未来

何を食べてもゼロカロリーなので、日々のカロリー管理が楽ちん。

いくら食べても摂取カロリーの合計はゼロだから計算が楽チンですね。

好きなモノを好きに食べる自分を、正当化できる。

カロリーが無くなれば自分を責める理由なんて無くなりますよね?

笑える。ネタにできる。

「あはは!深夜にラーメン食べたけど0kcalだ!」って笑って誤魔化せます。
また、周りに「食べ過ぎだよ」と小言を言われても、Zerorieに責任転嫁すればいいし、「〇〇だから0kcal」って言えば場の空気が和むはずです。

使用技術

  • Semantic UI
  • Rails
  • AWS
  • Circle CIとCodeCov
  • Google Cloud Vision API(画像検索機能に使用)
    など

ER図

満たしたい要件やアプリの拡張性を考慮した結果、以下のようになりました。
テーブル設計は面白いけど、苦労しますね。
image.png

インフラ構成図

image.png

開発期間

デプロイまで2ヶ月かかりました。所要時間は約300〜350時間。

苦労した点

Active StorageとGoogle Cloud Vision APIによる画像検索能

メイン機能の1つ「画像検索機能」の実装は苦労しました。
Active Storageを使ってVision APIを叩く、画像検索に使用したデータをsessionで保持する、そもそも食べ物の画像検索機能をどうやって自前で用意するのか等、色々苦労した反面、非常に勉強になりました。

Rails6系をAWSでデプロイ(Capistrano使用)

これも苦しかったです。
Rails6系はwebpackerが標準搭載となるため、yarnのインストールが必要でしたがその辺を忘れていたり、あとはnginxの設定ファイルの記述で苦労したり。
そして何より、エラー文を読みにいっても何もヒントが書かれていなかった時が最も絶望しました。インフラムズカシイ。

今後Zerorieに実装したい機能

食べ物のカロリー理論を返してくれるLineBot

コレは開発当初から考えていた機能の1つです。
Lineで簡単に食べ物を検索できれば、もっと手軽にゼロカロリーの世界を楽しめると思うので、是非作り上げたいです。

自分の好きなカロリー理論に草スタンプを押せる

「Zerorieを見てて草 (いいね)が押したくなった」という意見があったので、是非実装したいと思いました。
また、ユーザーも食べ物のデータを登録する時にカロリー理論を作るケースがあるので、おもしろカロリー理論のランキングみたいなのがあると良いなと思いました。

おわりに

やっぱりプログラミングの楽しさは、自分の考えやアイデアを形にできることだと、改めて実感しました。
そして特に個人開発はその人の色・考え・個性が出てこそ、良さが現れるんじゃないかと思います。

他にも幾つかアイデアは考えているのでまた開発してみたいですが、次は笑えるよりもビジネス寄りなものを作りたいです。

以上、ご覧頂きありがとうございました!

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

railsを使って画像投稿を実装するには

Railsで画像投稿を実装する方法

はじめに

自分でrailsを使ってアプリを作ろうとした時、どうやって登録するのか、
画像の実装の仕方をメモを兼ねて記載しました。

まずは、ImageMagickをHomebrewからインストールします。

#ターミナル
% brew install imagemagick

次に、gemfile上で、記述します。バージョンが異なる場合があります。

gem 'mini_magick'
gem 'image_processing', '~> 1.2'

ターミナル上で、バンドルインストール。

% bundle install

ターミナル上で、下記を実行。

% rails active_storage:install

終わりに

いつも参考にさせてもらっているQiitaで自分も誰かの役に立てればと思いました。
実際書いてみると、少し書いただけでなんだか大変ですね。

なれでしょうか、少しづつアップできたらと思います。

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

Rails/ES6/OpenWeatherMapで天気予報を表示してみた

ezgif.com-gif-maker.gif

開発環境

Ruby: 2.6.5
Rails: 6.0.0

事前準備

OpenWeatherのHPにアクセスしアカウントを作成してください。

私は下記記事を参考にアカウントを作成しました。
【Rails】OpenWeatherMapを用いて、登録住所の天気予報を、日本語で表示する方法

実装

app/controllers/weathers_controller.rb
class WeathersController < ApplicationController
  def index; end
end

app/views/weathers/index.html.erb
<h1>明日の天気検索サイト</h1>

<%= select_tag 'select', options_for_select({
  "札幌": 2128295,
  "青森": 2130658,
  "盛岡": 2111834,
  "仙台": 2111149,
  "秋田": 2113126,
  "山形": 2110556,
  "福島": 2112923,
  "水戸": 2111901,
  "宇都宮": 1849053,
  "前橋": 1857843,
  "埼玉": 6940394,
  "千葉": 2113015,
  "東京": 1850147,
  "横浜": 1848354,
  "新潟": 1855431,
  "富山": 1849876,
  "金沢": 1860243,
  "福井": 1863983,
  "山梨": 1848649,
  "長野": 1856215,
  "岐阜": 1863640,
  "静岡": 1851715,
  "名古屋": 1856057,
  "津": 1849796,
  "大津": 1853574,
  "京都": 1857910,
  "大阪": 1853909,
  "神戸": 1859171,
  "奈良": 1855612,
  "和歌山": 1926004,
  "鳥取": 1849890,
  "松江": 1857550,
  "岡山": 1854383,
  "広島": 1862415,
  "山口": 1848689,
  "徳島": 1850158,
  "高松": 1851100,
  "松山": 1926099,
  "高知": 1859146,
  "福岡": 1863967,
  "佐賀": 1853303,
  "長崎": 1856177,
  "熊本": 1858421,
  "大分": 1854487,
  "宮崎": 1856717,
  "鹿児島": 1860827,
  "那覇": 1856035,
  }, 1),
  id: "wheather-select" %>

<div id="city-name"></div>
<div id="weather"></div>

<%= javascript_pack_tag 'weather' %>
app/javascript/packs/weather.js
// OpenWeatherAPIを使用しています。下記URLからアカウントを作成し、
// APIキー情報を利用してAPI_KEY変数に上書きしてください。
// https://openweathermap.org/

// API_KEYはアカウント登録した際のAPIキーを使用して下さい
const API_KEY = "***"

window.onload = function() {
  weather_search()
};

const wheather_select = document.querySelector('#wheather-select');
const options = document.querySelectorAll("#wheather-select option");
const weather_search = function () {
  const index =  this.selectedIndex;
  const city_id = index ? options[index].value : wheather_select.value
  const url = 'http://api.openweathermap.org/data/2.5/forecast?id=' + city_id + '&appid=' + API_KEY;

  fetch(url).then((data) => {
    return data.json();
  }).then((json) => {
    let insertHTML = "";
    let tomorrow = 8
    let weather = document.querySelector('#weather')
    insertHTML += buildHTML(json, tomorrow);
    weather.innerHTML = insertHTML
  }).catch(error => {
    console.error(error);
  });
}

wheather_select.addEventListener('change', weather_search);

function buildHTML(data, i) {
  let Week = new Array("(日)","(月)","(火)","(水)","(木)","(金)","(土)");
  let date = new Date(data.list[i].dt_txt);
  date.setHours(date.getHours() + 3);
  let month = date.getMonth()+1;
  let day = month + "" + date.getDate() + "" + Week[date.getDay()] + date.getHours() + ":00";
  let icon = data.list[i].weather[0].icon;
  let main = weatherJavaneseConversion(data.list[i].weather[0].main)

  let html =
  '<div class="weather-report">' +
    '<h2>明日の天気は'+ main +'です!</h2>' +
    '<img src="http://openweathermap.org/img/w/' + icon + '.png">' +
    '<div class="weather-date">' + day + '</div>' +
  '</div>'
    ;
  return html
}

function weatherJavaneseConversion(name) {
  switch (name) {
    case "Clear":
      return "晴れ"
    case 'Clouds':
      return "曇り"
    case "Rain":
      return ""
    case "Snow":
      return ""
    default:
      console.log(name)
      return name
  }
}

参考

RailsでOpenWeatherMapから天気予報を取得する
【Rails/JS】無料API「OpenWeatherMap」で天気予報を表示する
【Rails】OpenWeatherMapを用いて、登録住所の天気予報を、日本語で表示する方法

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

【while、each】【超初心者向け】繰り返し処理を使って配列に押し込む方法

はじめに

こんにちは!
最近はrubyの問題にハマっていて、気付いたら夜中、みたいない毎日です…。
そん中、意外と便利なのに、記事としてあまり見かけない方法で
while文なんかを使って一気に配列から配列に押し込む方法をご紹介いたします。

each文の活用

# こちらでは数字と文字列がごちゃごちゃになった配列を数字の配列(int)と文字の配列(str)に分けてます
x_arry = [1,"a",2,"b",3,"c"]

int = []
str = []
i = 0
x_arry.each do |n|
  i += 1
  if n.to_s =~ /^[0-9]+$/  #こちらは正規表現で、数字のみを条件分岐してます。
    int << n
  else
    str << n
  end
end
print int
# => [1, 2, 3]
print str
# =>["a", "b", "c"]

※正規表現については詳しい記事が山ほどありますので、そちらをご参照くださいませm(_ _)m

参考記事①
https://programming-dojo.com/%E3%80%90ruby%E5%85%A5%E9%96%80%E3%80%91%E6%95%B0%E5%AD%97%E3%81%8B%E3%81%A9%E3%81%86%E3%81%8B%E3%82%92%E5%88%A4%E5%AE%9A%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/
参考記事②
https://qiita.com/pecooh/items/ee392125727f04bafaed

次はwhile文みてみましょう。

while文の活用

# 配列にそれぞれaの配列とbの配列にある数字を足し算して配列に打ち込んでます。

a = [43,56,77,22,45,66,78,99,53,44]
b = [1,2,3,4,5,6,7,8,9,10]

answer_arry = []

i = 0
while i < a.length do
  ans = a[i] + b[i]
  answer_arry << ans
  i += 1
end

print answer_arry
# => [44, 58, 80, 26, 50, 72, 85, 107, 62, 54]

この様にして、繰り返し処理をしてもらって自動で格納してもらえるのは便利ですね❗️
しかも、格納される直前で条件分岐すると、一定の条件のものが格納することもできますので是非やってみてください?

クイズとか問題とかやっているとこういう処理が必要になってくることは多々ありますので重宝です?
ぜひ、遊んでみてください☺️
ちなみにこれを使ってこんなふうにするとちょっとしたおみくじみたいなゲームとか作れそうですね☺️

おまけ

a = [rand(100),rand(100),rand(100),rand(100),rand(100),rand(100),rand(100),rand(100),rand(100),rand(100)]
b = [1,2,3,4,5,6,7,8,9,10]

answer_arry = []

i = 0
while i < a.length do
  ans = a[i] + b[i]
  answer_arry << ans
  i += 1
end

print answer_arry

randを使うことで数字がランダムになって出てくるので「ゾロ目の数が多い方が勝ちな!」みたいなゲームだったり、
randメソッドについてはPCとジャンケン対戦ができる様なゲームに応用ができたり楽しいです?

それではまた❗️
ありがとうございましたm(_ _)m✨

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

【Ruby on Rails】初回ログイン時・jQueryを使用した、画面を真っ二つに割る方法

目標

split.gif

開発環境

ruby 2.5.7
Rails 5.2.4.3
OS: macOS Catalina

前提

【Ruby on Rails】初回アクセス時に一度だけ表示(jquery.cookie.js使用)
こちらに少し手を加えた形となりますので、
コードをそのまま使うとcookieがなくなるまでは表示出来ません。

実際のコード

app/views/layouts/application.html.erb
<div class="indication-left"></div> # 追加
<div class="indication-right"></div> # 追加
<div class="box">
  <p>下記の表示終了ボタンを押すと、<br>更新しても見ることは出来ません。<br>
    新しいブラウザを立ち上げると表示されます。
  </p>
  <button>表示終了</button>
</div>
app/assets/stylesheets/application.css
/* 追加 */
/* ここから */
 .indication-left, .indication-right{
  position: fixed;
  top: 0;
  width: 100%;
  height: 100vh;
  background-image: url("image1.jpg");
  background-size: cover;
  background-position: center;
  z-index: 1040;
  transition: 3s;
}
.indication-left{
  left: 0;
  clip: rect(0px 50vw 100vh 0px);
}
.indication-right{
  right: 0;
  clip: rect(0px 100vw 100vh 50vw);
}
.leftslide{
  transform: translateX(-100%);
}
.rightslide{
  transform: translateX(100%);
}
/* ここまで */


.box{
  position: absolute;
  top: 40%;
  left: 35%;
  width: 400px;
  height: 200px; 
  background-color: #ffffff;
  z-index: 1050; /* 変更 */
}
.box p{
    padding: 15px;
}
.box button{
  display: block;
  margin: 0 auto;
}
app/assets/javascripts/application.js
$(function(){
  $(".indication").show();
  if($.cookie('Flg') == 'on'){
    $(".box").hide(); // indicationの子ではなくなったので追加
    $(".indication-right").hide(); // 追加
    $(".indication-left").hide(); // 追加
  }else{  
    $(".box").show(); // 追加
    $(".indication-right").show(); // 追加
    $(".indication-left").show(); // 追加
  }
  $(".box button").click(function(){
    $(".indication-right").addClass("rightslide"); // 追加
    $(".indication-left").addClass("leftslide"); // 追加
    $(".box").fadeOut(); // 追加
    $.cookie('Flg', 'on', { expires: 1, path: '/' });
  });
});

z-indexについて

bootstrapを使用する場合、今回のような機能の実装では
.fixed-topよりも高い位置に表示する必要があったため、
1030より高い数値を指定しております。

bootstrap.css
.fixed-top {
  position: fixed;
  top: 0;
  right: 0;
  left: 0;
  z-index: 1030;
}

clip: rect( ); について

clip要素とは画像などの要素について、切り抜き領域の外にある内容を表示せず、
切り抜き領域を指定するプロパティです。
指定方法はrectととなり、rectの長さには
rect(上端からの距離, 右端からの距離, 下端からの距離, 左端からの距離)のように、
上から時計回りの順でコンマで区切って4つの値を指定します。

右側の画像clip: rect(0px 50vw 100vh 0px);
左側の画像clip: rect(0px 100vw 100vh 50vw);

まとめ

jqueryを使用せず、cssのinputを使用した方法もあるため、
両方の知識を入れておくのは大事だと思います。
近々更新できればと思います。

またtwitterではQiitaにはアップしていない技術や考え方もアップしていますので、
よければフォローして頂けると嬉しいです。
詳しくはこちら https://twitter.com/japwork

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

【Rails】人気投稿をランキング形式で表示させる【簡単】

個人開発アプリを作成していて、人気投稿順に見られると使いやすくなると思い、
基本的にこちらの記事を参考にしながら実装しました。

routes.rb

routes.rb
get 'rank' => 'shops#rank'

私の場合はshopsコントローラーのrankアクションに設定しました。

shops_controller.rb

shops_controller.rb
 def rank
    @all_ranks = Shop.find(Favorite.group(:id).order('count(shop_id) desc').limit(5).pluck(:shop_id))
 end

shopsコントローラーにrankメソッドを定義。いいねが多い投稿順に表示させます。

rank.html.slim

rank.html.slim
- @all_ranks.each.with_index(1) do |shop, i|
  h5.col-md-5
    .card.shadow
      | No.
      = i
      | 
       = link_to shop.name, shop_path(shop)
       = link_to((image_tag shop.picture.url), shop_path(shop.id), class: 'shop-picture') if shop.picture.url.present?

viewファイルを作成し、表示させます。例として抜粋しました。
後はCSSで外観を修正します。

@all_ranks.each.with_index(1) do |shop, i|

上記より、いいねが多い順に表示させることができます。

完成

お手軽にランク形式での表示が完成しました。

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

【Rails6】cocoonを使った動的フォーム入力画面の作り方

はじめに

本記事では、以下のような入力フォームを作成することをゴールとしています。
Image from Gyazo

概要

レシピとレシピに必要となる食材をまとめてDBに保存する機能の作成

テーブル構成

レシピとレシピの食材は親子関係であるため、以下のテーブル構成となります
親:レシピ( recipes )
子:レシピの食材( recipe_ingredients )
※ingredient_idはactivie_hashで実装します
Image from Gyazo

実装

以下の順に実施していきます。
1.jqueryの導入
2.cocoonの導入
3.モデルの作成
4.コントローラーの作成
5.ビューの作成

1.jqueryの導入

rails6でcocoonを使えるようにするために、jqueryをインストールします。

$ yarn add jquery 

config/webpack/environment.jsを編集します

config/webpack/environment.js
const { environment } = require('@rails/webpacker')

#追記ここから
const webpack = require('webpack')
environment.plugins.prepend('Provide',
    new webpack.ProvidePlugin({
        $: 'jquery/src/jquery',
        jQuery: 'jquery/src/jquery'
    })
)
#追記ここまで

module.exports = environment

2.cocoonの導入

gemの導入

Gemfile
gem 'cocoon'
$ bundle install

ライブラリの追加

$ yarn add github:nathanvda/cocoon#c24ba53

実行後、以下2点の項目をクリアできていればOKです。
・app/assets/javascripts/cocoon.jsが作成されている
・package.jsonに以下の記述が追加されている

package.json
"cocoon": "github:nathanvda/cocoon#c24ba53"

最後に、app/javascriptspacks/application.jsに以下の内容を追記

app/javascriptspacks/application.js
require('jquery')
import "cocoon";

3.モデルの作成

今回の実装内容と関係のない記述は省いております。

モデルの作成

$ rails g model Recipe
$ rails g model RecipeIngredient

マイグレーションファイルの編集

class CreateRecipes < ActiveRecord::Migration[6.0]
  def change
    create_table :recipes do |t|
      t.string     :name,     null: false
      t.timestamps
    end
  end
end
class CreateRecipeIngredients < ActiveRecord::Migration[6.0]
  def change
    create_table :recipe_ingredients do |t|
      t.references :recipe,            null: false, foreign_key: true
      t.integer    :ingredient_id,     null: false
      t.integer    :quantity,          null: false
      t.timestamps
    end
  end
end

マイグレーションの実行

$ rails db:migrate

アソシエーションの設定

recipe.rb
class Recipe < ApplicationRecord
  has_many :recipe_ingredients, dependent: :destroy
  accepts_nested_attributes_for :recipe_ingredients
end
recipe_ingredient.rb
class RecipeIngredient < ApplicationRecord
  belongs_to :recipe
end

accepts_nested_attributes_for

 指定したモデルのデータを配列としてパラメーターに含めることが出来ます。
 つまり、recipeとrecipe_ingredients両モデルのデータをまとめて保存できるようになります。

4.コントローラーの作成

コントローラーの作成

$ rails g controller recipes new create

コントローラーの内容を編集

recipes_controller.rb
class RecipesController < ApplicationController
  def new
    @recipe = Recipe.new
    @recipe_ingredients = @recipe.recipe_ingredients.build
  end

  def create
    @recipe = Recipe.new(recipe_params)
    if @recipe.save
      redirect_to root_path
    else
      render action: :new
    end
  end

  private

  def recipe_params
    params.require(:recipe).permit(:name, recipe_ingredients_attributes: [:id, :ingredient_id, :quantity, :_destroy])
  end
end

accepts_nested_attributes_forで指定したrecipe_ingredientモデルを、
paramsにrecipe_ingredients_attributes: []として、追加して送っています。

5.ビューの作成

モデルと同様に、今回の実装内容と関係のない記述は省いております。
※クラス名等も記述していないため、このコードのままではレイアウトは崩れます。

recipes/new.html.erb
<%= form_with model: @recipe, url: '/recipes', method: :post, local: true do |f| %>

  <!-- レシピ名 -->
  <%= f.text_area :name %>

  <!-- 食材入力フィールド -->
  <%= f.fields_for :recipe_ingredients do |t| %>
    <%= render "recipes/recipe_ingredient_fields", f: t %>
  <% end %>

  <!-- 食材追加ボタン -->
  <%= link_to_add_association "追加", f, :recipe_ingredients %>
<% end %>

fields_for

form_with内で異なるモデルを編集できるようになります。

recipes/_recipe_ingredient_fields.html.erb
<div class="nested-fields">
    <%= f.collection_select(:ingredient_id, {}, :id, :name, {}) %>
    <%= f.number_field :quantity %>
    <div></div>
    <%= link_to_remove_association "削除", f %>
</div>

nested-fieldsクラスが指定されたdivタグで囲んだ範囲が追加・削除する領域です。

レンダリングする部分テンプレート名には注意してください。
「_子モデル_fields.html.erb」でないとエラーとなります。

お疲れさまでした。
以上で、動的入力フォームが作成できるかと思います。

参考

Rails6でのcocoonの導入
ネストしたフォームを簡潔に実装できるcocoon gemをwebpack環境でセットアップする

動的入力フォームの作成について
【Rails】cocoonを用いて親子孫関係のテーブルに複数のデータを同時保存する方法

fields_forについて
fields_forの上手な使い方

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

【Rubyバージョンエラー】Your Ruby version is ~,but your Gemfile specified ~の解決方法

はじめに

本記事では、以下のエラーについて、解決方法と、なぜそう考えたかを書いていきます。
解決するにあたっては、多くの方の記事やブログを参考にさせていただきました。
リンクは、該当箇所に随時貼らせていただいてます。

Your Ruby version is 2.6.3, but your Gemfile specified 2.5.1

対象読者

・Rubyを学習しはじめて、数ヶ月〜1年程度の方。
・上記のエラーに初めてあたった方。
・「環境変数の設定をどうにかすれば、解決するらしいことはわかった。」
「しかし、vimやシェルという言葉を聞くと、解決する前に一呼吸おきたくなる」という方。

※本記事では、vimやシェルなどの用語について詳しい説明はいたしません。

目的

・vimを操作してrbenv下のファイルにPATH(以下、たんに「パス」といいます。)を通し、バージョンエラーを解決する。

・なぜ、パスを通すことで、問題が解決するのかを理解する。

Pathを通すとは、環境変数とは

「わかりそう」で「わからない」でも「わかった気」になれるIT用語「Path」

前提

・rbenv(rubyのバージョン管理用ツール)はインストール済み。

・変更したいrubyバージョン(今回でいうと、2.5.1)がインストールされていることは、確認済み。

rbenvでrubyを使う【zsh】

 

目次

1 エラー内容

2 Rubyのバージョン切り替えを試す

3 2で解決しなかった場合、rubyの参照先を確認する
 3−1 rubyコマンドを実行したときに起きていること
 3−2 rubyコマンドの実行元ファイルを確認する方法

4 rubyコマンドが、rbenv下にあるファイルから実行されるように設定する(パスを通す)

5 最後に

1 エラー内容

エラー内容はこちらです。

Your Ruby version is 2.6.3, but your Gemfile specified 2.5.1

エラーの意味は、
「あなたのPC環境におけるRubyのバージョンは、2.6.3です。」
「しかし、あなたが現在開発しているアプリケーションのRubyのバージョンは、2.5.1です。」
というものです。

2 Rubyのバージョン切り替えを試す。

以下の手順で、バージョンの切り替えを試してみます。
・Rubyのバージョンを確認する。
・rbenvを使用し、バージョンを切り替える。
・切り替わったか確認する。

(1)自分のPC環境におけるRubyのバージョンを確認する。

ruby -v

(2)開発中のアプリケーションに適用されているRubyのバージョンを確認する。

rbenv -v

(3)rbenvを使用し、バージョンの変更を試みる。

特定のディレクトリで使うRubyのバージョンを指定するとき。

rbenv local 2.6.3

システム全体で使うRubyのバージョンを指定するとき。

rbenv global 2.6.3

(4)Rubyのバージョンが切り替わっているか、確認する。

ruby -v

ruby 2.6.3p645 (〜)...         //出力結果

切り替りませんでした。

3 2で解決しなかった場合、参照先を確認する

上記の方法で切り替わらない場合、rubyコマンドを実行する際の参照先が違う可能性があります。

Rubyのバージョンが切り替わらない時の対処法!

本記事では、エラーの原因や、なぜその方法で解決できるのかを考えていきます。
このため、以下の流れで説明します。

3−1 rubyコマンドを実行したときに起きていること
3−2 rubyコマンドの実行元ファイルを確認する方法

3−1 rubyコマンドを実行したときに起きていること

私たちが持っているPC内には、あらゆるコマンドが格納されたファイルがたくさん入っています。

Pathを通すとは、環境変数とは

例えば、私たちがターミナル上でコマンドを打っているとき。
PC内では、たくさんあるファイルの中から、ターミナルで打ったコマンドが格納されているファイルを見つけ出し、そこからコマンドを取り出して実行します。

rubyコマンドも同じです。

しかし、rubyコマンドが入っているファイルは、一つではない場合があります。
どういうことかというと、今回のようにrbenvをインストールした場合は、
・インストールした際に作られた、rbenv下にあるファイル
・もともとPC内にあるファイル
の両方に、rubyコマンドが入っている場合がある、ということです。

今回のケースでいうと、
・rbenv下にあるファイル → 2.5.1バージョンのrubyコマンドが入っている。
・もともとPC内にあるファイル → 2.6.3バージョンのrubyコマンドが入っている。
という状況が考えられる、ということです。

3-2 rubyコマンドの実行元ファイルを確認する方法

では、実際に「rubyコマンドを打った場合、どこのファイルに入っているrubyコマンドを実行しているのか?」を確認してみましょう。
参照先を確認するには、whichコマンドを使用します。

which ruby

usr/bin/ruby   //出力結果

この出力結果は、
「rubyコマンドを実行することで、usr下のファイルにあるrubyコマンドを実行する」
という意味になります。

rbenvによってrubyのバージョン管理を行っている場合、rubyコマンドはrbenv下にあるファイルにも入っています。
そのrubyコマンドが実行されていれば、以下のような出力結果になります。

/Users/you/.rbenv/shims/ruby

なぜこのような構成になるかについては、こちらの記事を参考にさせていただきました。
rbenvの役割

記事の一部を引用させていただくと、
rbenvをインストールする際に、

~/.rbenv/ (ルートフォルダ )

~/.rbenv/shims/ (rubyやgemがインストールしてくれるコマンドのラッパーを保存するフォルダ)

などなどがPCに入ります。
このshimsフォルダの中に、実行したいrubyコマンドが格納されます。

4 rubyコマンドが、rbenv下にあるファイルから実行されるように設定する(パスを通す)

PCに、「usr/bin/ruby」ではなく、「/Users/you/.rbenv/shims/ruby」の方から、rubyコマンドを持ってくるよう、設定してあげます。

参考にさせていただいたのは、以下の記事です。

「パスを通す」でやっていること(macOS / zsh)

ここでは、以下の手順を書いていくこととします。
・vimを開く
・コードを書いて、保存、終了する。
・変更内容を反映させる。

(1)下記コマンドで、vimを開きます。
(シェルでbashを使用されている方は、「.zshrc」を「.bash_profile」にかえてください。)

vim ~/.zshrc

(2) i を押して、編集可能な状態にします。画面上は何も変わりませんが、追記や編集が可能になっています。

(3)以下のコードを書きます。すでに記載がある場合は、その下の行に書きます。

export PATH="~/.rbenv/shims:/usr/local/bin:$PATH"
eval "$(rbenv init -)"

(4) esc を押して、保存、終了が可能な状態にします。カーソルが一番下あたりに移動すると思います。
(5) :wq と打ち、enter を押します。
(6)元の画面に戻りますので、以下のコマンドを打ちます。sourceコマンドは、変更を反映させるコマンドです。

source ~/.zshrc

(7)rubyのバージョンを確認します。

ruby -v
ruby 2.5.1p645 (〜)...         //出力結果

うまくいきました!

5 最後に

記事の内容に間違い、誤字脱字などありましたら、コメントで教えていただけるとありがたいです。

参考、引用させていただいた記事、ブログの著者の方々、ありがとうございます。

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

Leet文字列への変換プログラム

【概要】

1.結論

2.Leet文字とは何か

3.どのようにコーディングするか

4.開発環境

1.結論

gsub!メソッドを使う


2.Leet文字とは何か

主に、インターネットで使用されるアルファベットの表記法のことをいいます。例えば、"HELLO"であれば"H3LL5"となります。アルファベットに似た数字や文字を当てはめる形になります。下記に具体例の表を載せておきますが、もちろんA~Zまであり、その表現方法はいくつもあります。

文字 数字
A 4
B 13
C [
D )
E 3

.
.
.

文字 数字
Z 2

参考にしたURL:
Wikipedia:Leet符号表

3.どのようにコーディングするか

変数 = gets.chomp
変数.gsub!(/変換前の文字列/,'変換後の文字列')
puts 変数

#ex)
#leet_str = gets.chomp
#leet_str.gsub!(/Z/,'2')
#puts leet_str
#"Z"と入力すると"2"に変換される

他の方法もありますが、自分はgsub!を使用しました。

参考にしたURL:
【Ruby入門】文字列の置換方法まとめ(gsub sub regex)

4.開発環境

Mac catalina 10.15.4
Vscode
Ruby 2.6.5
Rails 6.0.3.3

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

RubyでC拡張を使っているgemをインストールする際に、make -j4 みたいに複数のCPUのコアを使って早く終わらせたい

ruby-jp.slack.comにて

RubyでC拡張を使っているgemをインストールする際に、make -j4  みたいに複数のCPUのコアを使って早く終わらせたい時はどんなオプションをつければいいですか?

環境変数で設定した記憶があるけど忘れてしまった

export GNUMAKEFLAGS=-j4

というわけで、正解は

export GNUMAKEFLAGS=-j4

です。お手持ちのコンピュータのコア数に合わせて

GNUMAKEFLAGS=-j8 gem update

等してみてください。C拡張をゴリゴリ使っているgemの場合アップデートが高速に終了するかも知れません。

この記事は以上です。

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

RubyでC拡張ありのgemをインストールする際に、make -j4 みたいに複数のCPUのコアを使って早く終わらせたい

ruby-jp.slack.comにて

RubyでC拡張を使っているgemをインストールする際に、make -j4  みたいに複数のCPUのコアを使って早く終わらせたい時はどんなオプションをつければいいですか?

環境変数で設定した記憶があるけど忘れてしまった

export GNUMAKEFLAGS=-j4

というわけで、正解は

export GNUMAKEFLAGS=-j4

です。お手持ちのコンピュータのコア数に合わせて

GNUMAKEFLAGS=-j8 gem update

等してみてください。C拡張をゴリゴリ使っているgemの場合アップデートが高速に終了するかも知れません。

この記事は以上です。

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

トランザクションシミュレータ(ロック待ちバージョン)

トランザクションの検証が面倒すぎる。モデルとしては単純そうだから、作ってしまおう、と思った。

Ruby

tran_request.rb
class Request
end

class Read < Request
    attr_reader :var
    def initialize(var)
        @var = var
    end

    def to_s()
        return "Read(#{@var})"
    end
end

class Write < Request
    attr_reader :var,:val
    def initialize(var,val)
        @var = var
        @val = val
    end

    def to_s()
        return "Write(#{@var},#{@val})"
    end
end

class Insert < Request
    attr_reader :var, :val
    def initialize(var,val)
        @var = var
        @val = val
    end

    def to_s()
        return "Insert(#{@var},#{@val})"
    end
end

class Delete < Request
    attr_reader :var
    def initialize(var)
        @var = var
    end

    def to_s()
        return "Delete(#{@var})"
    end
end

class Lock < Request
    attr_reader :tr,:var,:lock_type
    def initialize(tr,var,lock_type)
        @tr = tr
        @var = var
        @lock_type = lock_type
    end

    def to_s()
        return "Lock(#{@tr},#{@var},#{@lock_type})"
    end
end

class Unlock < Request
    attr_reader :tr,:var
    def initialize(tr,var)
        @tr = tr
        @var = var
    end

    def to_s()
        return "Unlock(#{@tr},#{@var})"
    end
end

class Begin < Request
    def to_s()
        return "Begin"
    end
end

class Rollback < Request
    def to_s()
        return "Rollback"
    end
end

class Commit < Request
    def to_s()
        return "Commit"
    end
end

class Database
    attr_accessor :vars , :locks
    def initialize()
        @vars = {}
        @locks = []
    end

    def read(tr,var)
        if @locks.filter{|l| l.tr != tr && l.var == var && l.lock_type == :Exclusive}.empty? then
            return :success , @vars[var]
        else
            return :failure , nil
        end
    end

    def write(tr,var,val)
        if @locks.filter{|l| l.tr != tr && l.var == var}.empty? then
            @vars[var] = val
            return :success
        else
            return :failure
        end
    end

    def insert(tr,var,val)
        write(tr,var,val)
    end

    def delete(tr,var)
        if @locks.filter{|l| l.tr != tr && l.var == var}.empty? then
            unlock(tr,var)
            @vars.delete(var)
            return :success
        else
            return :failure
        end
    end

    def lock(tr,var,lock_type)
        if lock_type == :Exclusive then
            if @locks.filter{|l| l.tr != tr && l.var == var}.empty? then
                @locks << Lock.new(tr,var,lock_type)
                return :success
            end
            return :failure
        else
            if @locks.filter{|l| l.tr != tr && l.var == var && l.lock_type == :Exclusive}.empty? then
                @locks << Lock.new(tr,var,lock_type)
                return :success
            end
            return :failure
        end
    end

    def unlock(tr,var)
        @locks.filter!{|l| !(l.tr == tr && l.var == var)}
        return :success
    end

    def unlock_all(tr)
        @locks.filter!{|l| l.tr != tr}
        return :success
    end

    def begin(tr)
        unlock_all(tr)
        return :success
    end

    def rollback(tr)
        unlock_all(tr)
        return :success
    end

    def commit(tr)
        unlock_all(tr)
        return :success
    end
end

class Transaction
    attr_reader :db,:name,:requests,:counter,:vars,:status
    def initialize(db,name,requests)
        @db = db
        @name = name
        @requests = requests
        @counter = 0
        @vars = {}
        @status = :running # :running or :waiting
    end

    def next()
        req = @requests[@counter]
        if req.is_a?(Read) then
            status, value = @db.read(@name, req.var)
            if status == :success then
                @vars[req.var] = value
                @status = :running
                @counter += 1
                puts "#{@name} Read(#{req.var}) => #{value}"
            else
                @status = :waiting
                puts "#{@name} Read(#{req.var}) => fail"
            end
        elsif req.is_a?(Write) then
            status = @db.write(@name, req.var, req.val)
            if status == :success then
                @status = :running
                @counter += 1
                puts "#{@name} Write(#{req.var},#{req.val}) => success"
            else
                @status = :waiting
                puts "#{@name} Write(#{req.var},#{req.val}) => fail"
            end
        elsif req.is_a?(Insert) then
            status = @db.insert(@name, req.var, req.val)
            if status == :success then
                @status = :running
                @counter += 1
                puts "#{@name} Insert(#{req.var},#{req.val}) => success"
            else
                @status = :waiting
                puts "#{@name} Write(#{req.var},#{req.val}) => fail"
            end
        elsif req.is_a?(Delete) then
            status = @db.delete(@name, req.var)
            if status == :success then
                @status = :running
                @counter += 1
                puts "#{@name} Delete(#{req.var}) => success"
            else
                @status = :waiting
                puts "#{@name} Delete(#{req.var}) => fail"
            end
        elsif req.is_a?(Lock) then
            status = @db.lock(@name, req.var,req.lock_type)
            if status == :success then
                @status = :running
                @counter += 1
                puts "#{@name} Lock(#{req.var},#{req.lock_type}) => success"
            else
                @status = :waiting
                puts "#{@name} Lock(#{req.var},#{req.lock_type}) => fail"
            end
        elsif req.is_a?(Unlock) then
            status = @db.unlock(@name, req.var)
            if status == :success then
                @status = :running
                @counter += 1
                puts "#{@name} Unock(#{req.var}) => success"
            else
                @status = :waiting
                puts "#{@name} Unock(#{req.var}) => fail"
            end
        elsif req.is_a?(Begin) then
            status = @db.begin(@name)
            if status == :success then
                @status = :running
                @counter += 1
                puts "#{@name} Begin => success"
            else
                @status = :waiting
                puts "#{@name} Begin => fail"
            end
        elsif req.is_a?(Rollback) then
            status = @db.rollback(@name)
            if status == :success then
                @status = :running
                @counter += 1
                puts "#{@name} Rollback => success"
            else
                @status = :waiting
                puts "#{@name} Rollback => fail"
            end
        elsif req.is_a?(Commit) then
            status = @db.rollback(@name)
            if status == :success then
                @status = :running
                @counter += 1
                puts "#{@name} Commit => success"
            else
                @status = :waiting
                puts "#{@name} Commit => fail"
            end
        end
    end

    def current_request_info()
        return @requests[counter].to_s()
    end
end

class Scheduler
    attr_reader :trs, :schedule,  :counter
    def initialize(trs, schedule)
        @trs = trs
        @schedule = schedule
        @counter = 0
    end

    def next()
        # check for dead lock.
        if @trs.all?{|tr_name, tr| tr.status == :waiting} then
            raise("Dead lock.")
        end
        # re-run for all locked transactions.
        transaction_status()
        @trs.each {|tr_name, tr|
            if tr.status == :waiting then
                print "re-try:"
                tr.next()
            end
        }
        # execute scheduled transaction.
        printf("%6d:", @counter)
        @trs[@schedule[@counter]].next()
        @counter += 1
    end

    def transaction_status()
        @trs.each {|tr_name, tr|
            puts "status:#{tr_name}: #{tr.status} #{tr.current_request_info()}"
        }
    end
end

@tr_a_req = [
    Begin.new(),
    Write.new("X",10),
    Read.new("X"),
    Write.new("X",20),
    Commit.new()
]

@tr_b_req = [
    Begin.new(),
    Lock.new("tr_a","X",:Shared),
    Commit.new()
]

@schedule = [
    "tr_a",
    "tr_a",
    "tr_b",
    "tr_b",
    "tr_a",
    "tr_a",
    "tr_b",
]

@db = Database.new()

@tr_a = Transaction.new(@db,"tr_a",@tr_a_req)
@tr_b = Transaction.new(@db,"tr_b",@tr_b_req)
@trs = {
    "tr_a" => @tr_a,
    "tr_b" => @tr_b
}
@master = Scheduler.new(@trs, @schedule)

@schedule.size().times {
    puts
    @master.next()
}

実行例


status:tr_a: running Begin
status:tr_b: running Begin
     0:tr_a Begin => success

status:tr_a: running Write(X,10)
status:tr_b: running Begin
     1:tr_a Write(X,10) => success

status:tr_a: running Read(X)
status:tr_b: running Begin
     2:tr_b Begin => success

status:tr_a: running Read(X)
status:tr_b: running Lock(tr_a,X,Shared)
     3:tr_b Lock(X,Shared) => success

status:tr_a: running Read(X)
status:tr_b: running Commit
     4:tr_a Read(X) => 10

status:tr_a: running Write(X,20)
status:tr_b: running Commit
     5:tr_a Write(X,20) => fail

status:tr_a: waiting Write(X,20)
status:tr_b: running Commit
re-try:tr_a Write(X,20) => fail
     6:tr_b Commit => success

ステップ3でtr_bが共有ロックを取得したので、ステップ5でtr_aのWriteが失敗する。その後、tr_bがコミットをすると、tr_bが取得したロックが全て外れる。ので、このままステップ7を実行すれば、tr_aの待ちが解消されてWriteが成功する。

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

rails コマンドが使えなくなった時の対処法

rubyのバージョンを上げたところ、rails s しようとしたら、コマンドが使えなくなった。

$ rails --version rbenv: rails: command not found
The `rails' command exists in these Ruby versions:
2.6.5

結論 gem 'rails' をインストールしよう

1.gem update --system
2.gem install bundler
3.gem install rails

ターミナルで rails -vを打ち込み、Rails 5.2.3が表示されたらOKです。
 

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

deviseユーザー登録

1 deviseをインストール

ユーザー登録機能を実装するためには、deviseというgemをインストールします。

  1. Gemfileで gem 'devise'を追加

  2. ターミナルでbundle install

  3. ここでrails s でサーバー起動しないと反映されない

  4. rails g devise:install で設定ファイルを作成

2 ユーザーモデル+テーブルを作る

ここで注意したいのが普通のモデルを作る時と同じではないということです。

モデル作成

  • ターミナルで rails g devise user と入力(この時ルーティングが自動設定され、マイグレーションファイルも生成される)

  • db→migrate→2020〜のファイルにてテーブルに追加するカラムやカラムの型を記載する。

class DeviseCreateUsers < ActiveRecord::Migration[6.0]
  def change
    create_table :users do |t|
      t.string :name, null: false
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""

テーブル作成

  • ターミナルでrails db:migrate コマンドでテーブル作成

3 サインアップ(新規登録)

サインアップ時に入力する情報はパラメーターとしてサーバーに送信される。
通常コントローラーのストロングパラメーターで受け取るパラメーターを制限しているが、deviseの時は書き方が違う。

devise_parameter_sanitizerメソッド

deviseのUserモデルに関わる「ログイン」「新規登録」などのリクエストからパラメーターを取得できる。
下の記述は、サインアップの時にニックネームというキーのパラメーターを許可する記述。実際ニックネームの後にも新規登録時に必要な項目が追記される。ここでのpermitの中の引数は普通のパラメーターの時と違うので注意!

class ApplicationController < ActionController::Base
  before_action :configure_permitted_parameters, if: :devise_controller?

  private

  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
  end
end

初めのbefore_actionはdeviseによる処理であればconfigure_permitted_paramatersメソッドを実行するという設定。丸々必要なのだが、この辺は調べると出てくるので丸々覚える必要はない

これにより新規登録時の情報がテーブルに保存できている。

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

オブジェクト指向という考え方について1

Railsの勉強をやり直し始めたのでアウトプットとして残します。

オブジェクトとは、単純に翻訳すると「対象物」です。決して特殊なものではなく、世の中で皆さん自身も含めて皆さんがやり取りするもの全てがオブジェクトに当たります。オブジェクト指向とは、コンピューターの世界の全ての処理をオブジェクトを中心に取り扱う考え方です。

■オブジェクト(対象)とは、

●ある目的の振る舞いと、名前などの特徴となる固有の値とを持つ
●必要な時に呼び出される振る舞いを通し、固有の値を利用して目的とする処理を行う

ものだと言えます。少し硬い表現になりますが、この意味を理解することが重要です。

■オブジェクト思考プログラミングとは
何かのイベントを行う時、一般的に「式次第(プログラム)」を用意します。式を滞りながら運営するためには、この手順がしっかりできていることが重要です。なんらかの目的を持ったコンピュータプログラムを作ること(プログラミング)も、作業の手順(ロジックまたは手続き)をその目的に従って組み立てることになります。
従来、プログラミングは「全ての手順を一連のロジックで組み立てる」という方法で行われてきました。一方、オブジェクト指向は、

●オブジェクトというものを設定する
●オブジェクトに必要なロジックをそれぞれのオブジェクト内に閉じ込めて、必要な時にオブジェクトに指示して呼び出す。

という形で処理を組み立てていく方法です。Rubyは、「オブジェクト指向を完全に実現したプログラミング言語」と言われます。その理由はRubyで扱う全てのものがオブジェクトだからです。Rubyの中で取り扱う「数値」「文字の連なり(文字列)」「情報のかたまり」など、全てがオブジェクトとして扱われます。
 以上のことを認識することがRubyのオブジェクト指向を習得Railsを理解していく第一歩です。

某プログラミングスクールを卒業しただけでまだまだ理解が浅いのでこれからも頑張ります!!?

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