Rails/複数のビューで使うransack検索

f:id:AK474747:20191019113241p:plain

 

久しぶりにブログ書くよ

ちょうど二週間前、スクール課題である某フリマサイトのクローンアプリを終わらせて今まで必死に個人アプリを作ってました。

色々と知見も溜まったかな?と思うしこれから就活なのもあるのでまたブログを書いていこうと思ってます。

今日はgem ransackについて

ransackとは

rails用の検索機能を実装するためのgemです。 簡単にできます。 実装は非常に簡単で、現場でも選定されやすいgemだとか。 ちなみに下記技術書に記載されてました。現場で使われがちな技術をチョイスしてくれてる本です。 https://www.amazon.co.jp/%E7%8F%BE%E5%A0%B4%E3%81%A7%E4%BD%BF%E3%81%88%E3%82%8B-Ruby-Rails-5%E9%80%9F%E7%BF%92%E5%AE%9F%E8%B7%B5%E3%82%AC%E3%82%A4%E3%83%89-%E5%A4%A7%E5%A0%B4%E5%AF%A7%E5%AD%90/dp/4839962227

使い方

さて本題。

まずいつも通りgemfileに記述する。

gem 'ransack' 

したらターミナルでbundle

bundle

これからransackをコントローラ側で設定していくことになるんですが、その前に

今回の想定では、ヘッダーに検索フォームを組み混みます。 ヘッダーが使われるページは、トップページ、検索結果ページ、投稿詳細ページに使われます。

つまりアクションとしては3つ。index, seaech, showアクションそれぞれにransackの設定を書くことになるよ。

参考までに見た目はこんな感じ。ちなみに僕が作ったアプリです。

・indexアクション

f:id:AK474747:20191019113432p:plain

・searchアクション

f:id:AK474747:20191019113442p:plain

・showアクション

f:id:AK474747:20191019113458p:plain

コントローラ設定

特にちゃんと設定しないといけないのはsearchアクションになるので、searchアクションから。

いきなり結論ですが、僕の場合はこんな感じになりました。

gears_controller.rb

def search
  @search = Gear.search(search_params)
  @gear = @search.result(distinct: true).order(created_at: 'DESC').page(params[:page]).per(10)  
end

def search_params
  params.require(:q).permit(:gearname_or_title_or_review_cont)
end

検索が実行された場合

1:まずsearch_params

paramsから:qというキーの中に入っている値が欲しいので、require(:q)を書きます。 binding.pryとかかけて見てみて。 必要なバリューとしては:gearname_or_title_or_review_contなのでpermit。 やたら長いですが、ビューの方で解説します。

2:Gear.search(search_params)

さっき取得したsearch_pramsを使ってGearテーブル内で検索をかけます。

ヒットした値を@searchというオブジェクト化。

3:@search.result(distinct: true).order(created_at: 'DESC').page(params[:page]).per(10)

@searchでオブジェクト化したものを@gearというインスタンス変数に変えています。

この@gearという値をビューに渡します。

ビュー

対応するビューはこんな感じ。

ヘッダーを部分テンプレートとして分けて、全てのアクションで下記hamlを読み出してます。

要は共通ってこと

_header.html.haml

.main-header-wrapper
  = search_form_for @search, url: gears_search_path, class: 'container-fluid shadow' do |f|
    .main-header.row.mx-2.py-3.align-self-center
      =link_to root_path, class: 'main-header__logo h4 col-lg-2 col-md-3 col-sm-4 col-6 text-left align-self-center mb-0' do
        MyNewGear
   
    .main-header__search.col-lg-7.align-self-center.mt-2.mt-lg-0.ml-lg-3
      =  f.search_field :gearname_or_title_or_review_cont, class: 'form-control', placeholder: 'キーワードを入力' 
 

ransackではsearch_form_forというヘルパーを使います。ここでは@searchをモデルとして指定します。

それと=f.search_fieldを記述します。これでいつも通りのフォームができるよ。

最後に:gearname_or_title_or_review_contという記述。

これは、カラムと検索条件を指定しています。

Gearテーブルのgearnaemカラム or titleカラム or reviewカラムでテキストを含むもの(cont)を検索対象とする。と言う意味です。

contってなんやねん!って感じですね。でもこの記述も重要なんです。許してあげてください。

indexとshowでも有効にする

ここまで来たら検索機能の設定はほぼおしまいです。

ただ、indexとshowアクションでの設定が必要です。コントローラに以下のように追記してあげてください。

gears_controller.rb


before_action :set_search, only: [:index, :show]

    def set_search
      @search = Gear.ransack(params[:q])
    end

公式ドキュメントにも載っていますが、この記述がないとparamsがransackに対応してくれないようです。

最後に記載してしまいましたが、基本的に検索はトップページからすることが多いと思うので、indexアクションに最初から設定しとくのも有りかと思います。

Rails/CSRF対策

f:id:AK474747:20190917125102p:plain


 

久々にブログ更新。

 

スクールではチーム開発が始まり、なんか知らんけどスクラムマスターになりました。

他メンバーよりもコードを書く時間がないっていうのがちょっと辛いところですが、インフラからフロントまで広く勉強していけるのはいいですね。

 

いいです。いい・・かなぁ?器用貧乏さが増すような・・。まぁいいや。

 

今日はRailsCSRF対策について簡単に。

 

CSRFとは

クロスサイトリクエストフォージェリと呼ばれる。 この攻撃により、掲示板や問い合わせフォームなどを処理するWebアプリケーションが、本来拒否すべき他サイトからのリクエストを受信し処理してしまいます。

具体的な手順はこんな感じ

1:攻撃者は攻撃用Webページを準備し、ユーザがアクセスするよう誘導する。

2:ユーザが攻撃用Webページにアクセスすると、攻撃用Webページ内にあらかじめ用意されていた不正なリクエストが攻撃対象サーバに送られる。

3:攻撃対象サーバ上のWebアプリケーションは不正なリクエストを処理し、ユーザが意図していない処理が行われる。

フィッシングサイトとか、詐欺メールとかよく言われるやつかなと思います。

Railsで行われているCSRF対策

application controllerにprotectfromforgery with: :exceptionの記述がある。

この記述により、Railsが生成する全てのフォームやAjaxリクエストで自動的にセキュリティトークンを含めることができる

application.html.erbにcsrfmetatagsというメソッドも埋め込まれている

RailsjQueryはPOST送信時にこのメソッドで追加されるHTMLタグの情報を自動的に使用するため、このメソッドがあれば特に何もせずともCSRF対策がなされる

こんな感じで、コントローラ及びビューそれぞれで脆弱性対策を行なっているようです。

MYSQL/pid not foundもしくはpermission deniedの対応方法

f:id:AK474747:20190831004510p:plain

 

まいえすきゅーえるううううううううう

ぐぬぬぬぬぬお前のせいで今日1日を費やしたぞ。

ついさっきようやく解決したので備忘録を。お風呂に入りたいので早めに書きます。

原因

MYSQL@5.7をインストールしてsever.start後、MYSQL@5.6をインストールして動かそうとすると、MYSQL@5.7で使おうとしていたファイルを参照するらしい。

残っているファイルを消すことが必要になる。

経緯

ことの発端はどこかのタイミングでbrew updateをしてしまったらしく、MYSQL@8系のバージョンが入ってしまっていた。

それにより、railsでアプリケーションを立ち上げようとした時にエラーが起きてしまったので、ダウングレードしたり様々なことをやった結果、「PIDファイルがないエラー」と「権限がないエラー」の無限ループにはまり込んでしまった

現象

MYSQLサーバーを起動させようとするとエラー

$ mysql.server start

/usr/local/Cellar/mysql@5.6/5.6.43/bin/mysqld_safe: line 138: /usr/local/var/mysql/username.local.err: Permission denied
 ERROR! The server quit without updating PID file (/usr/local/var/mysql/username.local.pid).

どうやら一つは権限がない、もう一つはPIDファイルがないらしい。

とりあえず権限を付与。

$ sudo chmod 777 /usr/local/var/mysql

$ mysql.server start
 ERROR! The server quit without updating PID file (/usr/local/var/mysql/username.local.pid).

権限問題は消えた。

PIDファイルを作るディレクトリに移動して、touchコマンドでpidファイルを作成。

$ cd /usr/local/var/mysql

$ sudo touch prkrsignMacBookPro.local.pid

$ mysql.server start
 ERROR! The server quit without updating PID file (/usr/local/var/mysql/username.local.pid).

これでもダメ。 /usr/local/var/mysqlディレクトリのファイルリストを表示したが、pidファイルがなかった。

どうやら作られても消えてしまう?らしい。

そこでこの記事を発見。

https://qiita.com/furafura_nau/items/7d8f5370899df125d459

一度でも5.7を起動してしまうと、同じデータを使って5.6を起動すると次のようなエラーが出るようになります。

Starting MySQL
. ERROR! The server quit without updating PID file (/usr/local/var/mysql/ogin.local.pid).
mysqld等は動いていなかったので権限周りと思われますが、うまく解決できませんでした。
(バージョンによってディレクトリ構成が違っていたので、権限以外にも何か影響しているのかもしれません)

とのこと。

記事を参考に、

$ sudo rm -rf /usr/local/mysql
$ sudo rm -rf /Library/StartupItems/MYSQL
$ sudo rm -rf /Library/PreferencePanes/MySQL.prefPane
$ sudo rm -rf /Library/Receipts/mysql-.pkg
$ sudo rm -rf /usr/local/Cellar/mysql*
$ sudo rm -rf /usr/local/bin/mysql*
$ sudo rm -rf /usr/local/var/mysql*
$ sudo rm -rf /usr/local/etc/my.cnf
$ sudo rm -rf /usr/local/share/mysql*
$ sudo rm -rf /usr/local/opt/mysql*

<!--最後にver5.6をインストール。-->
<!--元々MYSQL@5.6が入っていて、アンインストールせずにそのままインストールしちゃいました。-->
$ brew install mysql@5.6

忘れずにPATHを通そう。

$ echo 'export PATH="/usr/local/opt/mysql@5.6/bin:$PATH"' >> ~/.bash_profile
$ source ~/.bash_profile
$ /usr/local/opt/mysql@5.6/bin/mysql.server start

Starting MySQL
. SUCCESS! 

これはドヤ顔。エラー解決に8時間かけたのにたまらずドヤ顔

記事を参考にMYSQLに入れることも確認しときます。いけました。

$ /usr/local/opt/mysql@5.6/bin/mysql -u root

とりあえず所感として。

MYSQLでエラーが出たら、原因はほぼ二つ。

「PIDがなくなっている」か「権限がない」。

touchを使ってPIDファイルを作成、もしくはchmodを使って権限の再設定をまず試してみるのがいいと思います。

それで改善しないなら潔く再インストールが多分手っ取り早いです。

再インストールの場合は上記のようにMYSQLが持ってるファイルを全部消して、MYSQL@5.6をインストール、パスの設定がいいんじゃないかなと思います。

@8だったり@5.7だったり、なかなかバージョン関係でいざこざ起きやすいようなので、初めに環境構築した時のバージョンを再インストールしなおすのがいいんじゃないかなと思います。

DApps/truffleフレームワークによる開発準備

f:id:AK474747:20190828000208p:plain

前回、RailsにgemをインストールすることでEhereumネットワークと接続することができるよ。

これでDAppsが作れるよ。ということを書いたんですが・・・。

ぼくには無理でした。

RailsとEthereumを連携させるという事例はなかなかなく・・・参考にさせていただいたサイトもいくつかあるんですが僕には環境構築がうまくできませんでした・・・。

と、いうことでEthereumネットワークを用いたDAppsを作成する際に、truffleというフレームワークが多く使われているようです。

今回はこのフレームワークを使う王道方式で行こうかと思います。

truffleとは

いい匂いしそう。 ではなく、開発に必要となるコンパイルやテスト、デプロイなどを可能にするEthereumスマートコントラクト開発用フレームです。

開発環境の構築というのは、アプリケーションを作る際に常に必要な作業になるとは思うのですが、スマートコントラクト機能を持つDAppsの場合その難易度はかなり上がるんじゃないかなと思います。

というのも、スマートコントラクトとなるとgethやsolidityといった開発環境を構築していくことになるのですが、 これらの環境はまだ過渡期といってもいいような状態です。

要は、前のsolidityバージョンではこの記述でできたのに、別のsolidityバージョンではエラーがでる。なんてことが頻繁に起きます。

言語単体の話だけでなく、gethとweb3.js間のバージョンが整合性取れずに・・なんてこともあった気がします。というか原因特定に至らなかったんですがそういう雰囲気のエラーはでました。

DAppsの場合、フロントからサーバー、Ethereumネットワークまで連携的に動いていく必要があるのですが、一つ一つ構築していくとなかなか難しいです。

そこでこのtruffleをインストールすると、truffle自体が様々な機能を包括的に持っているので簡単にアプリケーション開発に望むことができます。

truffle使い方

インストール方法はネット上を探せばあるのと思うので省略させてください。

インストールしたらバージョン確認をします。最新版はv5系なのですが、安定しているらしいということでv4.1.15を使用していきます。

基本的には安定板を使用していったほうがいいと思います。本当にいろんなところでひっかかるし、ネット上にあるリファレンスが全然使えなくなったりするので・・・。

$ truffle version
Truffle v4.1.15 (core: 4.1.15)
Solidity v0.4.25 (solc-js)

truffleプロジェクトの作成

まずはプロジェクト用のディレクトリを作成します。

$ mkdir myapp

作成したディレクトリに移動してtruffleプロジェクトを新規作成します。

$ cd myapp
$ truffle init

作成されたtruffleプロジェクトのディレクトリ構造は下記の通りです。

$ tree
.
├── contracts
│   └── Migrations.sol
├── migrations
│   ├── 1_initial_migration.js
├── test
└── truffle.js

truffle developについて

truffleには、開発用ブロックチェーンとしてtruffle developが用意されています。 truffle developはトランザクション発行後に即ブロックに取り込む機能を備えています。 トランザクションの結果を即座に確認することができるため、開発の際には重宝するそうです。 gethみたいに目の前でマイニングの様子を見せてくれるわけではないみたいですね。(あれはあれで何かロマン)

truffle developの起動

$ truffle develop

上記コマンドを実行すると、次の内容を知らせてくれます。

http://127.0.0.1:9545/にてtruffle developクライアントが起動 ・10個のアカウントを発行 ・それぞれの秘密鍵ニーモニックを表示

起動後はtruffleコンソールに切り替わります。このコンソールでは、任意のEthereumクライアントが指定されています。

デプロイ先のEthereumネットワーク設定

デプロイ先のネットワークを設定します。

ここでは、gethプライベートネットとganacheの設定を行います。

gethのインストールなんかは調べてみてください。

truffle-config.jsを開き、下記の通りに編集します。

module.exports = {
  networks: {
      development: {
          host: '127.0.0.1',
          port: 8545,
          network_id: 15,
          gas: 4700000
      },
      ganache: {
          host: '127.0.0.1',
          port: 7545,
          network_id: '*'
      }
  }
}

gethプライベートネットワークのdevelopmentネットワークと、ganacheアプリケーションが提供するプライベートネットワークを指定します。

truffleコンソール

truffle-config.jsで設定したネットワークを指定して、truffleコンソールを起動します。

--networkの引数にtruffle-config.jsで指定したネットワーク名を付与して、truffle consoleコマンドを実行します。

$ truffle console --network development
truffle(develop)>

ちなみにネットワーク名がdevelopmentの場合は、truffle consoleだけでも起動できます。

ganacheのプライベートネットを指定する場合も操作方法は同じになります。

$ truffle console --network ganache
truffle(ganache)>

これでtruffleによる開発準備は完了です。

って感じです。

色々と飛ばしちゃったなぁ。ブロックチェーンの概念とかも読み深めていきたいところ。

とりあえず、しばらくは個人アプリ開発奮闘記みたいな構成で書いていこうかなと思ってます。

RubyOnRails/Ethereumとの連携

f:id:AK474747:20190822004601p:plain

プログラミングスクールの課題で個人アプリの作成という課題がある。

個人的にはすごく重きを置いているカリキュラムなんだけれども、とにかく自分の作りたいものを作るというコンセプトで作成をしていくつもり。

で、僕の作りたいものとしてどうしてもスマートコントラクトの機能を使いたい。

スクールの課題ということもあるので、スマートコントラクトを実装したRailsのwebアプリケーションを作るという方針で行こうと思ってます。

ネット上を調べたところ、railsイーサリアムに接続してコントラクトコードを実行するという手法があることがわかったので、簡単にまとめようかなと思います。

動作環境

Rails v5.2.3

・ethereum.rb v2.2

・Ganache v2.1.0

 rails newでプロジェクト作成

いつも通りですね。プロジェクトを作ります。

rails new ethereum-test

gemのthereum.rbをインストール

このgemが今回の肝とも言えるかもしれません。

イーサリアムサーバーに接続し、コントラクトコードの実行を可能にするgemです。

Gemfileにethreum.rbを記述してbundle installします。

// Gemfileに記載
gem 'ethereum.rb'

// ターミナルで実行
bundle install

コントラクトコードの実装

プロジェクトのルートパス配下にcontractsフォルダを作成し、コントラクトファイルを作成して実装します。

ethereumのコントラクトを実装するには、solidityという言語を使用します。

コードの説明は別日に基礎からブログにまとめていこうかと思うのですが、ごく簡単な処理を記述しています。

機能としては、デプロイ時に渡した文字列を呼び出したり、デプロイしたオーナーのアドレス/残高を取得できるだけのものになっています。

contracts/HelloWorld.sol

pragma solidity ^0.4.24;

contract HelloWorld {
    string public greeting;
    address public owner;

    function HelloWorld(string _greeting) {
        greeting = _greeting;
        owner = msg.sender;
    }

    function greet() constant public returns (string) {
        return greeting;
    }

    function getBalance() constant public returns (uint balance) {
        return owner.balance;
    }

    function getAddress() constant public returns (address) {
        return owner;
    }
}

コントラクトコードの実装

コントラクトコードを記述したので、TopControllerというコントローラーファイルを作成します。

ここの記述でethereum.rbを利用したEthereumへの接続を実施を行います。

app/controllers/top_controller.rb

class TopController < ApplicationController
    ETHEREUM_TOKEN_PATH = "#{Dir.pwd}/contracts/HelloWorld.sol"
    GANACHE_URL = 'HTTP://127.0.0.1:7545'
  
    def index
      @client = Ethereum::HttpClient.new(GANACHE_URL) #①
      @contract = Ethereum::Contract.create(file: ETHEREUM_TOKEN_PATH, client: @client) #②
      @contract.deploy_and_wait('Hello, World!') #③
    end
end

①ではGanacheに接続するための@clientオブジェクトを作成します。GANACHE_URLにはGanacheアプリケーションのRPC SEVERに表示されているURLを入力します。

②ではcreateメソッドを使ってcontractインスタンスを生成しています。

③で作成したコントラクトをブロックチェーン上にデプロイします。

ちなみにviewではこんな記述にしています。

app/views/top/index.html.erb

Markup
<! -- index.html.erb -->
<div class="container">
  <h3>Ethereum.rb テストページ</h3>
  <p>アドレス: <%= @contract.call.get_address() %></p>
  <p>残高: <%= @contract.call.get_balance()%></p>
  <p>GreetMethod: <%= @contract.call.greet() %></p>
</div>
Markup
 @contract.call.get_address()

これだけで、HelloWorld.solに記述したfunctionを呼び出すことができます。

Ganacheの起動

アプリと連携させるためにGanacheを起動させます。

Ganacheはイーサリアム開発用のパーソナルブロックチェーンです。

起動するだけでアカウント・残高・契約作成・ガスコストなどを確認できるので、ブロックチェーン関連のアプリケーションを作成した場合に、テストとして有用です。

ブラウザで動作確認

アプリを起動させて、http://localhost:3000/にアクセスします。

bundle exec rails s

こんな感じのサイトにアクセスできればOKです。

f:id:AK474747:20190822004433p:plain

うーん、たったこれだけではあるんだけど、概念理解にすごく時間がかかってしまった。

ほんとはsolidityを使ったコントラクトコードとフロントエンドの連携は、web3.jsっていうjavascriptフレームワークを使ったりするらしいんですが・・。

個人アプリではそこまで新機能もりもりにするのはちょっとつらいので、ethereum.rbを使って連携をして、Railsコントローラの感覚に落とし込んでからコントラクトコードをビューで反映する、という手法で行こうかなと思っています。

RubyONRails/データベース設計における制約について

f:id:AK474747:20190813143311p:plain

 

簡単なブログアプリを作ってるんすが、データベース設計の際に必要になりそうなものがあったので、 手早くまとめます。

意外と検索してもヒットしなかったんだこれが。

制約とは

制約とは特定のデータの保存を許さないためのバリデーションです。例えば同じメールアドレスのユーザーを登録できないようにする、名前のデータが空のユーザーを保存できないようにするといったことができるようになります。 RubyOnRailsの場合だと、rails g model [テーブル名(単数形)]をターミナルで打ち込むと、マイグレーションファイルが出来上がります。 このファイルにカラムの指定をした後、rake db:migrateすることでデータベースにカラムが反映されます。 制約はこのカラム一つ一つに対して使います。

NOT NULL制約

NOT NULL制約を設定すると、そのカラムの値にはNULL(空の値)を入れることができなくなります。 ブログアプリの場合でしたらユーザー登録が必要になるので、ユーザー登録の際のEmailやパスワード、nameなんかが対象になります。下記のnull: falseが入っている箇所のことです。

マイグレーションファイル

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :name, null: false
      t.timestamps null: false
    end
  end
end

一意性制約

一意性制約はテーブル内で重複するデータを禁止する制約です。 ユーザー登録をする際に、もう登録したことあるサイトなのに、自分のEメールアドレスを登録しようとしたことってありませんか?すでに使われてるアドレスです、なんて怒られたと思います。

その制約をカラムに対して行うことですね。

ブログアプリの場合はやはりEmailカラムが対象になります。unique :trueが制約している文になります

マイグレーションファイル

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :name  , null: false
      t.string :email , null: false , unique: true
      t.timestamps null: false
    end
  end
end

外部キー制約

外部キー制約は、外部キーの対応するレコードが必ず存在しなくてはいけないという制約です。

これはミニアプリの場合、UserテーブルではなくArticle(記事)テーブルになるかと思います。 記事を投稿するのに、投稿したユーザーが不明瞭ではだれが書いたがわかりませんよね?

この制約は、t.referenceを使います。これによりuserではなくuser_idというカラムを作成してくれるため、テーブル間のリレーションを意識しやすくなります。また、後述しますがインデックスを自動で貼ってくれます。

foreign_key: trueというのが制約文に当たります。

マイグレーションファイル

class CreateArticles < ActiveRecord::Migration
  def change
    create_table :articles do |t|
      t.string     :text
      t.references :user , foreign_key: true
    end
  end
end

インデックスとは

インデックスはデータベースの機能の一つで、テーブル内のデータ検索を高速化することができます。インデックスはカラムに対して設定することができ、設定したカラムでの検索が高速になります。

ただし、インデックスには以下の2つのデメリットがあります。

・データを保存・更新する速度が遅くなる ・データベースの容量を使う

ミニアプリであれば、Userテーブルのnameなんかが該当するでしょうか。Articleテーブルのnameも該当しそうですね。投稿者名で検索、記事名で検索みたいな。

ただし記事名にインデックスを貼るのは考えた方がいいかもしれません。データの保存・更新に関してはスピードを要すルものではないかもしれませんが、データベース容量はユーザーが増えてくればサーバーサイドとの相談になりそうですね。

add_index :usersがインデックスを貼り付ける文になります。 補足的にですが、同時に二つのカラムにインデックスを貼る場合も書いています。

class CreateUsers < ActiveRecord::Migration
  (省略)
  add_index :users  # インデックスを一つに貼る 
  add_index :users,  [:name, :email] # インデックスを2つにまとめて貼る
  end
end

主キー制約

主キー制約は、主キーである属性値が必ず存在してかつ重複していないことを保証する制約です。主キーに対してNOT NULL制約と一意性制約を両方設定するのと同義になります。

railsの場合はもともと機能が備わっていて、データベースを見たときに、それぞれのテーブルでIDというカラムがあるかと思います。

それが主キーに当たります。

制約文といいうよりは概念として非常に重要ですので記載しました。

ってまた30分くらいかかっちゃったよおおお。

手早くって言ったのにいいい・・・

オブジェクト指向とは

f:id:AK474747:20190811212328p:plain

今日は中々打ち合わせやらで、自分の勉強が進まなかったんだけど、 極力毎日ブログは書きたいので、簡単なものを書こうかなと。

しばらくAWSの流れだったんだけど、AWSは理解が難しいので今日はオブジェクト指向ってやつについて書くよ。

僕はプログラミング初学者なわけでRubyをずっと使ってきたんだけど、Rubyオブジェクト指向言語と言われているらしい。

で、オブジェクト指向ってそもそもなんだよっていう話。今回はRubyを用いてまとめていこうかと思うよ。

オブジェクト指向とは

オブジェクト指向とは、複数のオブジェクトを組み合わせてプログラムを構築する考え方。

オブジェクトとはデータと処理の集まりのことですが、漠然として集合体のことではなく、一つのテーマを持った集合体のことです。

人であれば「名前」、「年齢」、「出身地」などのデータを持ちます。

オブジェクト(今回のテーマは人)であれば、こういったデータの他に「振る舞い」があります。

例えば名前を聞くという「振る舞い」と、それに対して、自分の名前を返すという「振る舞い」。 ここでいう「振る舞い」をオブジェクト指向で考えると処理にあたるということです。

概念的ではありますが、特別理解できないということではないと思います。

オブジェクト指向って何?という問いに対して、「現実と一緒だ」なんて回答もあるくらいです。

オブジェクト指向とクラス

オブジェクト指向の概念を説明しても、じゃあプログラミングに落とし込んだらどうなるか中々想像できないかと思います。

そこで必要になるのがクラスの概念です。

クラスとは

オブジェクト指向言語において、データと処理をひとまとめにしたもの。 オブジェクトの設計図とも呼ばれる。

実際にRubyで書いてみます。

class Person
  def initialize(name, age , birthplace)
    @name = name
    @age = age
    @birthday = birthday
  end

  def answer_name
    puts @name
  end
end

人(person)クラスを定義して、名前や生年月日を持たせています。これがオブジェクト指向におけるデータのことです。

人(person)クラスで定義された人は、answer_nameメソッドという「振る舞い」をします。これがオブジェクト指向における処理のことです。

ここで定義されたクラスもオブジェクト、@nameといったインスタンス変数もオブジェクト、answer_methodもオブジェクトということになります。

結局、オブジェクト指向で生まれたものは全てオブジェクトと呼ばれることになります。

その中でもクラスは設計図、インスタンスは実体化したデータ、メソッドは実体化した処理とでもイメージすればいいのかなと思います。

いいか?結局、現実と一緒だ