20200211のRubyに関する記事は20件です。

【備忘録】Ruby : 基本的なprocオブジェクトの使い方とyieldの使い方

参考: https://shinmedia20.com/ruby-proc

sample.rb
addAB =  Proc.new { |a,b| a.to_i+b.to_i }
#ブロックをオブジェクト化
puts "和は#{addAB.call(2,4)}です。"
#callで実行することでオブジェクト化したブロックの処理を行える。
puts "三つ目の引数を加えた和は#{addAB.call(2,4,4)}"
#三つ目の引数は無視される


def sample(&sample_proc)
    #引数にブロックを渡すsampleメソッド
    #引数に&をつけることでブロックだと認識させている。
    puts sample_proc.call(2)
    #渡されたブロックに引数を2を渡して実行する。
end
sample { |n| n**4 }
#sampleメソッドに引数 { |n| n**4 } を渡している。
#sampleメソッド内でブロック変数2を渡してブロックを実行している。


def sample2 (&block)
    puts block.call(3)
end
sample2 { |n| n*n }
##出力値は 9


def sample3(&block)
    puts yield(5)
    # yield は引数で渡されたブロックを実行する
    # つまり渡された引数(ブロック)に対してcallメソッドを使わなくても良い。
end
sample3 { |n| n*n }


def sample4
    # sample3の引数(ブロック)の記述なしver
    puts yield(6)
end
sample4 { |n| n*n }


def sample5
    if block_given?
        #メソッドに引数としてブロックを渡したか判定
        #渡しているなら true , 渡していないなら false
    puts yield
    else
        puts "blockは渡されませんでした"
    end
end

sample5
## 引数を渡していない : expect => blockは渡されませんでした
sample5 { puts "blockです" }
## 引数を渡している : expect => blockです


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

[Ruby on Rails] includesメソッドの書き方まとめ

実務でまさかのincludesメソッドに戸惑う

「この画面の情報をスプレッドシートに出力しておいて」

「はーい」
(データを取ってくるだけなら余裕だろ、、、)

(あれ、関連するモデル多すぎじゃね?)

(関連するモデルに関連するモデルも取得、、あれ、、頭が、、、)

って感じで整理できていない部分がありましたので、今回まとめておきます。

前提

  • モデルの関連付けだけをテーマに書きます。
  • includesする際、単数形か複数形かはアソシエーションによって判断します。
  • N+1問題を解決するためにincludesします。( 参考記事 )

今回例示するモデル

  • Tweets:ツイート
  • Users:ユーザー
  • Comments:ツイートに対するコメント
  • Tags:ツイートにつけるタグ
  • Addresses:ユーザーの住む住所

ここでは便宜上、関連するモデルを子モデル、子モデルに関連するモデルを孫モデルと呼ぶことにします。

① 子モデルが1つの場合

Tweet.includes(:user)

こちらはTweetに紐づくUser(子)を取得します。

② 子モデルが2つの場合

Tweet.includes(:user, :tags)

こちらはTweetに紐づくUser(子)およびTag(子)を取得します。 ([:user, :tags]) と書く場合もあるので、それは所属するチームでの決まりに従うと良いでしょう。

③ 子モデル・孫モデルが1セットの場合

Tweet.includes(user: :address)

:(コロン)の位置に注意です。こちらはTweetに紐づくUser(子)とそのUserに紐づくAddress(孫)を取得します。

孫モデルが複数ある場合

Tweet.includes(user: [:address, :comments])

明示的に[]が必要です。こちらはTweetに紐づくUser(子)とそのUserに紐づくAddress(孫)およびComment(孫)を取得します。

③ 子モデル・孫モデルが1セットと子モデルが1つの場合

Tweet.includes(:tags, user: :address)

注意すべき点は、孫モデルまで参照するものを後ろに記述することです。こちらはTweetに紐づくTag(子)およびUser(子)とそのUserに紐づくAddress(孫)を取得します。

Tweet.includes(user: :address, :tags)とすると、筆者の場合 SyntaxError: unexpected ')', expecting => と表示されてしまいます。
※ もし子モデル・孫モデルのセットが増えたなら、後ろに加えれば大丈夫です。

【募集】 STIをincludesする場合

今現在まだ実務で出会っていませんが、STIを参照する際のincludesの形はどうなるのだろう、、と今から不安です。もし、参考記事などございましたらご教授いただければ幸いです。

これからも新しい書き方を見つけたら更新していきます

実務未経験から働き始めて約1週間。まだまだこんなものではないと思いますので、気付き次第随時更新していきます。

参考記事

Rails ActiveRecord/SQL 小技集

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

rails内の環境構築 その2

scaffoldでサンプルアプリを作る

docker-compose run web rails g scaffold  user name:string address:string age:integer

そして

docker-compose run web rails db:migrate

ブラウザでlocalhost:3000/usersでアクセスできますが、毎回めんどいのでrootに指定します

confing/routes.rb
Rails.application.routes.draw do
  resources :users
  root 'users#index'
end

slimを導入

gem 'slim-rails'
gem 'html2slim'

そして

docker-compose run web bundle install

さらに

docker-compose build

既存のerbファイルをslim可する

docker-compose run web bundle exec erb2slim app/views/layouts/ --delete
docker-compose run web bundle exec erb2slim app/views/users/ --delete

rspec導入

group :development, :test do
  gem 'rspec-rails'
  gem 'factory_bot_rails'
end

そして

docker-compose run web bundle install
docker-compose build

さらに

docker-compose run web rails g rspec:install
rm -r ./test

rspec使い方

docker-compose run web rspec

System Spec導入

Dockerfileに書き込む

  • dockerコンテナの中へ新たにchromedriverを準備なければなりません。
FROM ruby:2.5
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client

# chromeの追加
RUN apt-get update && apt-get install -y unzip && \
    CHROME_DRIVER_VERSION=`curl -sS chromedriver.storage.googleapis.com/LATEST_RELEASE` && \
    wget -N http://chromedriver.storage.googleapis.com/$CHROME_DRIVER_VERSION/chromedriver_linux64.zip -P ~/ && \
    unzip ~/chromedriver_linux64.zip -d ~/ && \
    rm ~/chromedriver_linux64.zip && \
    chown root:root ~/chromedriver && \
    chmod 755 ~/chromedriver && \
    mv ~/chromedriver /usr/bin/chromedriver && \
    sh -c 'wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -' && \
    sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list' && \
    apt-get update && apt-get install -y google-chrome-stable


RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp

# Add a script to be executed every time the container starts.
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

# Start the main process.
CMD ["rails", "server", "-b", "0.0.0.0"]

ディレクトリ作成

mkdir spec/system
mkdir spec/support
touch spec/support/capybara.rb

設定を書く

spec/support/capybara.rb
require 'capybara/rspec'
require 'selenium-webdriver'

Capybara.register_driver :selenium_chrome_headless do |app|
  options = ::Selenium::WebDriver::Chrome::Options.new


  options.add_argument('--headless')
  options.add_argument('--no-sandbox')
  options.add_argument('--disable-dev-shm-usage')
  options.add_argument('--window-size=1400,1400')


  driver = Capybara::Selenium::Driver.new(app, browser: :chrome, options: options)
end

Capybara.javascript_driver = :selenium_chrome_headless
spec/rails_helper.rb
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f }
#↑コメントアウトする これによりspec/support/capybara.rbが読み込まれます。

RSpec.configure do |config|
  config.before(:each) do |example|
    if example.metadata[:type] == :system
      if example.metadata[:js]
        driven_by :selenium_chrome_headless, screen_size: [1400, 1400]
      else
        driven_by :rack_test
      end
    end
  end
end
#type: :systemのときのみchromeを使うという設定です。

テストの実行

docker-compose run web rspec spec

参考

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

TwitterAPI 利用申請の手順

TwitterのAPIを利用するためには、事前の申請が必要です。
英語のサイト上で色々と入力が必要なので、手順をまとめました。

目的

TwitterAPIを利用してrubyからツイートするために、利用申請を行うこと。

手順1 Developerにアクセスする

以下サイトにアクセスして下さい。
ツイッターデベロッパー

手順2 ツイッターにサインインする

画面右上の「Sign in」ボタンからサインインして下さい。
Image from Gyazo

手順3 Applyページにアクセスする

サインインが完了したら、同じく画面右上の「Apply」ボタンをクリックして下さい。
Image from Gyazo

手順4 Apply for a developer account をクリックする

Image from Gyazo

手順5 デベロッパーツールの利用目的を選択する。

「Making a bot」にチェックを入れ、「Next」をクリックする。
Image from Gyazo

手順6 本人確認を行う

以下のような画面が表示されるので、アカウント名等に誤りが無いか確認してください。
Image from Gyazo

ページ下部では、メールアドレスを確認後、居住国と名前(ニックネームで可)を入力し、「Next」をクリックする。
Image from Gyazo

手順7 TwitterAPIの利用目的等を入力する

英語200文字以上でAPiの利用目的を入力してください。
Google翻訳に突っ込んだだけの文章ですが、よければコピペしてください。

I am studying programing.
I have never used the API, so I want to try making a bot.
In the future, I want to create a web application that can get information about tweets that users have searched for. 

Image from Gyazo

その他の項目についても以下のように入力していきます。
自動ツイート等の利用予定については、以下のような文章で問題ありません。
全ての項目の入力が完了しましたら、「Next」ボタンを押してください。

I do automatic tweeting as a practice for using Twitter api.
However, there are no plans to use it thereafter.

Image from Gyazo

Image from Gyazo

手順8 登録内容に誤りが無いか確認する。

Image from Gyazo

手順9 ポリシー等を読んで、問題なければチェックを入れて送信ボタンを押す

Image from Gyazo

10 完了確認

以下のような画面が表示されれば申請完了です。
Image from Gyazo

この後、実際にRubyでbotを作成するには、デベロッパー上でappを作成する必要があります。
その手順については、次の記事に記載してあります。

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

DockerでRailsの環境構築

docker-composeでrails環境を構築します。データベースはpostgresqlを使用します。

Setup

以下のような構成からスタートします。

./
|- docker-compose.yml
|- rails-app/
  |- Dockerfile

Dockerfileの作成

Dockerfile
FROM ruby:2.5.0

RUN apt-get update && apt-get install -y build-essential libpq-dev postgresql-client vim less
RUN gem install rails -v '5.2.1'
RUN mkdir /app
WORKDIR /app

railsのバージョンは5.2.1を指定しています。
マウント先のディレクトリとしてappディレクトリを作成しておきます。

docker-compose.ymlの作成

docker-compose.yml
version: "3"

services:
  rails-app:
    build: rails-app
    ports:
      - "3001:3001"
    environment:
      - "DATABASE_HOST=db"
      - "DATABASE_PORT=5432"
      - "DATABASE_USER=postgres"
      - "DATABASE_PASSWORD=<パスワード>"
    links:
      - db
    volumes:
      - "./rails-app:/app"
    stdin_open: true

  db:
    image: postgres:10.1
    ports:
      - "5432:5432"
    environment:
      - "POSTGRES_USER=postgres"
      - "POSTGRES_PASSWORD=<パスワード>"

ポートは3001番を指定していますが、3000番でもOKです。

コンテナの起動

docker-compose build
docker-compose up -d

コンテナにログインします。

docker-compose exec rails-app bash

以降はコンテナ内で操作を行います。

Railsプロジェクトの作成

cd /app
rails new . -d postgresql -BT

-Bでbundle installをスキップし、-Tでテストファイルの作成をスキップしています。
Gemfileにtherubyracerを追加します。

Gemfile
gem 'therubyracer', platforms: :ruby

この状態でbundle installします。

bundle install —-path vendor/bundle

これでプロジェクトが作成されました。

データベースの設定

config/database.ymlを編集します。

  • defaultにhost, port, username, passwordを追加
  • データベース名を rails_app_development に変更
config/database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  # For details on connection pooling, see Rails configuration guide
  # http://guides.rubyonrails.org/configuring.html#database-pooling
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
+ host: <%= ENV.fetch("DATABASE_HOST") { "localhost" } %>
+ port: <%= ENV.fetch("DATABASE_PORT") { 5432 } %>
+ username: <%= ENV.fetch("DATABASE_USER") { "root" } %>
+ password: <%= ENV.fetch("DATABASE_PASSWORD") { "password" } %>


development:
  <<: *default
- database: app_development
+ database: rails_app_development

データベースを作成します。

bundle exec rails db:create

起動

IPアドレスとポートを指定してサーバを起動します。

rails s -b 0.0.0.0 -p 3001

ブラウザでhttp://localhost:3001/を開いて、正しく起動できているか確認します。
スクリーンショット 2020-02-11 18.49.22.png

ホストPCとdockerコンテナ間でプロジェクトディレクトリを共有しているので(./rails-app:/app)、編集はホストPCで(vscode等で!)、実行は環境構築したコンテナで、という開発ができます。
幸せになりましょう。

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

ruby,railsの特徴

ruby

  • スクリプト言語である。

プログラミング言語にはスクリプト言語、コンパイラ言語と言われる言語があり、
人間が書いたコードを機械が実行するには翻訳を行う必要がある。
コンパイラ言語は事前に翻訳し、スクリプト言語は随時コンパイル(翻訳)しつつ実行される。
スクリプト言語であるrubyは翻訳する必要がないため開発しやすい反面、実行速度が遅めである。

  • オブジェクト指向である。

最初からオブジェクト指向の言語として開発されたため、
変更に強く、再利用しやすいコードを書きやすくなっている。

上記の理由から記述量が少なく済んだり、コンパイルする必要がないため生産性が高い。
そのため、フレームワークであるrailsと合わせて短期間で開発を進める必要があるスタートアップ企業などで好まれて使用されやすい。

rails

  • 言語としてrubyを使用しているため、比較的習得しやすい。

  • 習得したスキルを幅広く使用できる。
    rubyを取得してしまえばフレームワークはrailsほぼ一択になるため幅広く活用することが出来る。

  • 開発を効率化する仕組みが多数用意されているため生産性が高い。
    rails newでアプリの雛形を作成することができたり、ActiveRecordによってSQL操作ができるなど、
    開発効率を高める仕組みが多数用意されている。

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

RubyでAtCoder 版!蟻本 (初級編)を解いてみた

前置き

業務での実装力を高めようと、AtCoderをやっています。
AB問題の過去問を200問以上解いたのですが、なかなか灰コーダーから抜け出せないため、また、C++やPythonで取り組む人に比べるとRubyでAtCoderに取り組んでいる人は少ないかなと思い、初見で解けなかった問題も解説や他の解答見て作ることで残していきます。

引用元: AtCoder 版!蟻本 (初級編)


例題 1-1-1 くじびき

n,m=gets.split.map &:to_i
p=n.times.map{gets.to_i}+[0]
# 半分全列挙
a=p.repeated_combination(2).to_a.map{|i|i.inject(:+)}.sort.reverse
s=0
# 全探索
a.each do |left|
  # 二分探索
  right=a.bsearch{|r|r+left<=m}
  s=[s,left+right].max unless right.nil?
end
puts s

【参考リンク】

例題 1-6-1 三角形

N=gets.to_i
xy=N.times.map{gets.split.map &:to_i}
ans=0
# 全探索 (二重の for 文)
N.times do |i|
  N.times do |j|
    next if i==j
    x1=xy[i][0]
    y1=xy[i][1]
    x2=xy[j][0]
    y2=xy[j][1]
    # 三角形の成立条件
    res=((x1-x2)**2+(y1-y2)**2)**0.5
    ans = [ans, res].max
  end
end
puts ans
k,s=gets.split.map &:to_i
l=k+1
a=0
l.times do |x|
  l.times do |y|   
    z=s-x-y
    a+=1 if z>=0 && z<=k
  end
end
puts a

【別解(微妙かも)】

k,s=gets.split.map &:to_i
puts [*0..k].repeated_permutation(2).map{|a,b|a+b}.select{|i|i<=s}.count{|xy|(z=s-xy)>=0 && z<=k}
N,Y=gets.split.map &:to_i
n=N+1
f=false
n.times do |x|
  n.times do |y|
    break if x+y>N
    z=(Y-10000*x-5000*y)/1000
    if x+y+z===N && z>=0
      puts "#{x} #{y} #{z}"
      f=true
      break
    end
  end
  break if f
end
puts "-1 -1 -1" unless f

例題 1-6-2 Ants (POJ No.1852)

Atcoder Grand Contest 013 解説 C Ants on a Circle より

ここは分かった。

T 秒後にゼッケンのある座標の集合は、当然、T 秒後に蟻のいる座標の集合と同じなので、T 秒後にそれぞれの蟻がどこにいるかを求めると、番号は分からないが、どの座標にゼッケンがあるのかが分かります。

それ以外は解説読んでもコードに起こせない。

二つの蟻がゼッケンを交換する時、時計回りに歩いてる蟻のゼッケンの番号は 1 増え、反時計回りに歩いている蟻のゼッケンの番号は 1 減ります。ある二つの蟻が T 秒間にすれ違う回数は、O(1)で求めることができます。よって、最初に 1 のゼッケンをつけていた蟻が、T 秒間に他の蟻とすれ違う回数の合計は、O(N) で分かります

例題おまけ 累積和・しゃくとり法

つい先日のABC。頻出らしいのでついでに載せておく。

【累積和解法】

N,K=gets.split.map &:to_i
# 期待値の前計算
p=gets.split.map{|i|(i.to_f+1)*0.5}
# 累積和の計算
a=[0]
N.times do |i|
  a << a[i]+p[i]
end
# 隣接するK項の和の計算
s=0
(N-K+1).times do |i|
  r=a[i+K]-a[i]
  s=[s,r].max
end
puts s

【しゃくとり法解法】

N,K=gets.split.map &:to_i
# 期待値の前計算
p=gets.split.map{|i|(i.to_f+1)*0.5}
# しゃくとり法・隣接するK項の和の計算
r=s=p[0..K-1].inject(:+)
(N-K).times do |i|
  r+=p[i+K]-p[i]
  s=[s,r].max
end
puts s

【参考リンク】


例題 2-1-1 部分和問題

解答中

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

bundle execって必要なの?

rails sって書いても、bundle exec rails sって書いても同じ動きをするように見えるんですが、何が違うのでしょうか。気になったので調べてみました。

結論

  • bundle execをつけないと、PCにグローバルインストールされているgemが動く
  • bundle execをつけると、そのプロジェクトで管理しているgemが動く
  • bundle exec railsbin/railsは同じ動きをする → rails以外のコマンドの場合は違うっぽい。binディレクトリに該当のファイルが無いとbin/◯◯って書き方はできない

そもそもBundlerとは

  • プロジェクト内で使うGemのパッケージ管理ツール。Gemをプロジェクト単位で管理することができる。
  • rbenv(rubyのバージョンをプロジェクト単位で管理するツール)のGem版
  • bundle installコマンドを叩くと、Gemfileに記載されたGemをインストールする

bundle installした時のGemの保存先

rbenvを使っている場合

$ gem which byebug
/Users/***/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/byebug-11.0.1/lib/byebug.rb

思ったこと

bundle execは毎回付けた方が良いってことですかね。
めんどくさいので、早く開発環境をdockerで管理したいです。
dockerを使えば、そのプロジェクト以外のことは全無視できるはず。

参考

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

gem install pg が上手くいかない時の対処法

開発環境

ubuntu(wsl)
Ruby 2.5
Rails 5.2

エラー内容

bin/rails db:createを実行すると

Could not find gem 'pg (>= 0.18, < 2.0)' in any of the gem sources listed in your Gemfile.
Run `bundle install` to install missing gems.

言われてた通りbundle installを実行すると、

An error occurred while installing pg (1.2.2), and Bundler cannot continue.
Make sure that `gem install pg -v '1.2.2' --source 'https://rubygems.org/'` succeeds before bundling.

gem install pg -v 1.2.2を確認しろとのことなので、gem install pg -v 1.2.2を実行する。

To see why this extension failed to compile, please check the mkmf.log which can be found here:

  /home/username/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/extensions/x86_64-linux/2.5.0/pg-1.2.2/mkmf.log
extconf failed, exit code 1

Gem files will remain installed in /home/username/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/pg-1.2.2 for inspection.
Results logged to /home/username/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/extensions/x86_64-linux/2.5.0/pg-1.2.2/gem_make.out

解決策

下記のコマンドを実行して、その後gem install pg -v 1.2.2をする。

sudo apt install libpq-dev

参考文献

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

あんまり頭を使わないで構築するRailsAPI on Docker

すでに多くの記事がありますが、APIモードのRailsがDocker上で動くところまで、必要最小限の情報でまとめてみます。RubyMineでの設定も最後にちょっと書いてあります。

参考: 公式 Quickstart: Compose and Rails

ファイル準備

アプリケーションを作成したいディレクトリで設定ファイルを作成します。

 $ touch Gemfile Gemfile.lock Dockerfile docker-compose.yml entrypoint.sh 

各ファイルの内容を埋めます。

Gemfile

source 'https://rubygems.org'
gem 'rails', '~>6'

Dockerfile

FROM ruby:2.6
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client
RUN mkdir /app
WORKDIR /app
COPY Gemfile /app/Gemfile
COPY Gemfile.lock /app/Gemfile.lock
RUN bundle install
COPY . /app

# Add a script to be executed every time the container starts.
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

# Start the main process.
CMD ["rails", "server", "-b", "0.0.0.0"]
entrypoint.sh
#!/bin/bash
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /app/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"
docker-compose.yml
version: '3'
services:
  db:
    image: postgres
    volumes:
      - ./tmp/db:/var/lib/postgresql/data
    ports:
      - 5438:5432
  app:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/app
    ports:
      - "3008:3000"
    depends_on:
      - db
    environment:
      LANG: C.UTF-8
      BUNDLE_PATH: vendor/bundle
      RAILS_ENV: development
      DB_USER: postgres
      DB_NAME: app_db
      DB_PASSWORD: password
      DB_HOST: db

ファイルの内容ちょっと補足

  • Rubyは2.6、Railsは6系です
  • 公開するポートはrailsが3008、postgresqlが5438です
  • 後述するdatabase.ymlではwebサービスに設定した環境変数を読んで設定を行います

作る

$ docker-compose run app rails new . --force --no-deps --database=postgresql --api 

--api を消したら通常のRailsアプリケーションが作れます。

$ docker-compose build 

したら一通りRailsが必要なファイルを作ってくれます。自動で作成された database.yml を編集します。

database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  host: <%= ENV['DB_HOST'] %>
  username: <%= ENV['DB_USER'] %>
  password: <%= ENV['DB_PASSWORD'] %>
  pool: 5

development:
  <<: *default
  database: app_development

test:
  <<: *default
  database: app_test
$ docker-compose run app rails db:create

動作確認

$ docker-compose up

http://localhost:3008/で動いてるはずです。

補足: RubyMine使ってる方、ちょろっと設定編

インタプリタの設定

Preferences > Languages & Frameworks > Ruby SDK and Gems

で、追加 > Docker Composeをクリック > OK

読み込みが完了したら、該当のSDKをチェックし、APPLYして完了です。補完がいい感じに効くようになります。

DB設定

Database > 追加 > Data Source > PostgreSQL

  • Host: localhost
  • Port: 5438
  • User: postgres
  • Password: password

で接続ができるはずです。うまくいかない場合は、タブから適切なスキーマを選択したり、DBが起動しているか確かめたりしてください。

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

form_withの初歩的な事

= form_with ~.....
  = text_field....
  = submit

などの入力フォームを作る際、
submitしsaveされたあとのビュー、もしくはリダイレクト先をしっかりと明記しておかないとエラーが出る

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

【Rails】投稿とユーザーの紐付け(一対多)のメモ

経緯

現在ポートフォリオ用に「book memory phrase」というアプリを作っています。
自分が印象に残ったフレーズを引用した書籍とともに紹介して本との出会いを作る場です。

そこでユーザーと投稿の紐付けを行って、誰がどの投稿をしたか一覧で見れるような機能を実装したのですが、has_manyやbelongs_toなど学ぶことが多かったのでアウトプットしとこうと思います。

投稿したユーザーid

まずはデータベース上のidを紐付ける必要があります。

今回の場合だと、UserテーブルのidをPostテーブルに突っ込んで、誰の投稿かわかるようにします。

最初からこの機能は実装する気でいたので、Postテーブルを作る時点でidカラムとは別にuser_idカラムを作り、投稿する際にユーザーのidを突っ込めるようにしてました。

その辺については以前書いた【Rails】railsブログサイトの練習で躓いたところメモにも載せていますのでそちらを参考にしてもらえたらと思います。

Modelの設定

idが突っ込めたら次は紐付けです。これはModelで設定します。

has_many

has_manyは一対多の多の方です。
ユーザー1に対して投稿は多数あるので、ユーザーモデルにhas_manyを記述します。

user.rb
has_many :posts, dependent: :destroy

投稿は複数あるので複数系にしてください。

ちなみにdependent: :destroyはユーザーが削除されたら自動的に投稿も削除されるという優秀な機能です。

belongs_to

次は一対多の一の方、ユーザーの紐付けです。

post.rb
belongs_to:user

def user
   return User.find_by(id: self.user_id)
end

一の方はbelongs_toで紐付けられます。
また、userメソッドをモデルで定義しておけば汎用性が高くなるので書いときます。

Controllerの設定

私はuser_showというページで該当ユーザーの投稿一覧を表示したかったので、コントローラーに以下のように記述しました。

home_controller.rb
before_action :set_post, only[:user_show, :edit, :update, :destroy]

#省略

#@userにモデルで定義したuserメソッドを@post.userで代入
#@postsに@userの投稿を全て代入
def user_show
   @user = @post.user
   @posts = @user.posts
end

#省略

private
#Post.find_by(id: params[:id])はよく使うので定義しといてbefore_actionで反映。
def set_post
   @post = Post.find_by(id: params[:id])
end

これでコントローラーの準備は整いました。

Viewの設定

コントローラーで作った@postsをeach文で回してあげれば一覧が確認できます。

user_show.html.erb
<% @posts.each do |post| %>
   <div class="book-img col-lg-4 col-md-6 col-sm-12 center-block mx-auto">
      <div class="box">
         <div class="image-box">
            <h5><%= post.phrase %></h5>
            <p class="name">
               <span>投稿者&ensp;&ensp;</span><%= link_to("#{post.post_user}", "/home/#{post.id}/user_show")%>
            </p>
            <img src='<%= post.book_image %>' class="img-fluid d-block">
         </div>
         <div>
            <p class="title">
               『<%= post.title %>』
            </p>
            <p class="author">
               著者 <%= post.author %>
            </p>
            <p>★ おすすめポイント</p>
            <p class="content">
               <%= post.content%>
               <% if user_signed_in? && current_user.id == post.user_id %>
                  <span class="edit-delete">
                  <%=link_to("編集" , "/home/#{post.id}/edit",class:"text-muted") %>
                  <%=link_to("削除" , "/home/#{post.id}/destroy",method: :post,class:"text-muted") %>
                  </span>
               <% end %>
            </p>
         </div>
      </div>
   </div>
<% end %>

まとめ

投稿の紐付けは必須機能ですが、結構躓くところでもあると思います。

かく言う私も何度も躓いたのですがSQLを勉強したら結構スッと入ってこれました。
イメージって大事ですね。

もしこの記事が誰かの助けになれたら幸いです。
ではでは。

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

WSLでRuby on Railsの環境構築

やること

  • windowsでUbuntuを使えるようにする
  • Rubyのインストール
  • Railsのインストール
  • DBのインストール

windowsでUbuntuを使えるようにする

Ubuntuの入れ方については既に多くの記事がでているので省略します。

Ubuntuを立ち上げたら、ユーザ名とパスワードを入れます。
その後、パッケージを最新にするため下記のコマンドを以下のコマンドを実行してください。

sudo apt update
sudo apt upgrade -y

Rubyのインストール

Rubyをインストールする前にバージョン管理のために、rbenvをインストールします。
下記のコマンドを実行してください

git clone https://github.com/rbenv/rbenv.git ~/.rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc //パス設定と初期化
echo 'eval "$(rbenv init -)"' >> ~/.bashrc

ここで一旦終了し再び立ち上げ、下記のコマンドを入力しバージョンが返ってきたらokです。

rbenv -v

ruby-buildのセットアップとパッケージのインストールをします。

git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build
sudo apt-get install autoconf bison build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm5 libgdbm-dev

ここからRubyのインストールです。

rbenv install 2.6.5
rbenv global 2.6.5 
ruby -v
which ruby

ruby -vを実行して返ってきたらokです。

さらに、gemのアップデートとbundlerのインストールもしておきます。

gem update
gem install bundler

Railsのインストール

gem install rails -v 6.0.2
rails -v

ここでもバージョンが返ってきたらokです。

後に必要となるnode.jsもここでインストールしておきます。

curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash - //バージョンは最新のものを選択してください。
sudo apt install nodejs

DBのインストール

下記のコマンドを実行してください。

sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt/ 18.04.4 -pgdg main" >/etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo apt update
sudo apt install postgresql
psql -V

バージョンが返ってきたらokです。

Postgresqlを起動します。

sudo service postgresql start
sudo su postgres -c 'createuser -s ユーザ名'
psql postgres

\qを入れて終了します。
下記のコマンドで「pg」が利用するパッケージをインストールしておきます。

sudo apt install libpd-dev

参考文献

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

railsの環境構築 その1

はじめに

これからdockerで開発環境の構築からAWSデブロイまで数回に分けてまとめてみます

私が使った有料教材

Dockerについて

Dockerについては下記のサイトを見てください。
* 入門 Docker

Dockerでrailsの環境構築

参考

作業手順

ディレクトリを作成しそこで作業

mkdir ror_app

Dockerfileを作成Dockerfile内に下記を記述

touch Dockerfile
FROM ruby:2.5
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client
RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp

# Add a script to be executed every time the container starts.
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

# Start the main process.
CMD ["rails", "server", "-b", "0.0.0.0"]

コマンド

FROM: ベースとなるDocker Image を指定します。
COPY: Docker内へホストのファイル/ディレクトリをコピーします。
  COPY は基本的に2つの引数を設定します。1つ目はホスト側のディレクトリ、2つ目はDocker側のディレクトリです。
RUN: Docker内でコマンドを実行します。
CMD: Docker起動時にデフォルトで実行されるコマンドを定義します。
WORKDIR: Dockerfileでコマンドを実行する際に基準となるディレクトリを設定します。
EXPOSE: コンテナ起動時に公開することを想定されているポートを記述します
ENTRYPOINT: 指定されたコマンドを実行します。

GemfileとGemfile.lockの作成

  • rails newするときに必要
touch Gemfile && touch Gemfile.lock
source 'https://rubygems.org'
gem 'rails', '~>5'

entrypoint.shを作成

  • 特定のserver.pidファイルが存在するときにサーバーが再起動しないようにするRails固有の問題を修正するエントリポイントスクリプトを提供します。このスクリプトは、コンテナが開始されるたびに実行されます。
  • touch entrypoint.sh
entrypoint.sh
#!/bin/bash
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /myapp/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"

docker-compose.ymlの作成

touch docker-compose.yml
docker-compose.yml
version: '3'
services:
  db:
    image: postgres
    ports:
      - '5432:5432'
    volumes:
      - postgresql-data:/var/lib/postgresql/data
  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    depends_on:
      - db
volumes:
  postgresql-data:
    driver: local

docker上でrailsのファイルを作成

docker-compose run web rails new . --force --no-deps --database=postgresql

# rails new . とすることで、カレントディレクトリ配下にrailsファイルが作成される  
--forceで事前に作成したファイルを上書き、今回はGemfile等

gem 'pg'のバージョン変更

gem 'pg', '~> 0.20.0'

イメージをbuild

docker-compose build

すると

ror_app_web:latestになります。

databese.ymlの書き換え

default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: postgres
  password:
  pool: 5
# host,username,passwordを追加しました。
hostをdbにすることでdocker-compose.ymlのdbを指定

本番環境や開発環境でdatabase関連のエラーが良く出てきます。
特に本番環境をAWSにするとproduciton:配下を書き換えないといけません。

データベースの作成

docker-compose run web rake db:create

サービスの起動

docker-compose up
# 終了はCtrl+C

ブラウザでlocalhost:3000にアクセスするとrailsの初期画面が出現したと思います。

docker-composeコマンドまとめ

ローカル環境 docker環境
rails s docker-compose up
rails db:migrate docker-compose run web rails db:migrate
bundle install docker-compose run web bundle install
rails g model モデル名 docker-compose run web rails g model モデル名

git push

railsの初期画面が出てきたらgit pushしておきましょう。

お疲れさまでした。

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

Ruby コーティング規約について 命名規則編 2

はじめに

命名規則編 1 はこちらをクリック願います。
レイアウト編 3 はこちらをクリック願います。過去記事リンクあり。
構文編 2 はこちらをクリック願います。過去記事リンクあり。
Rubyの基礎を学習中の方に向けて記載致します。
私自身これからチーム開発を行う上で大事にしたい。知っておきたいことをOutputします。

命名規則について

① シンボル、メソッド、および変数名において、文字と数字を分離しないようにする。
qiita.rb
# 悪い例
:some_sym_1

some_var_1 = 1

var_10 = 10

def some_method_1
  # 処理
end



# 良い例
:some_sym1

some_var1 = 1

var10 = 10

def some_method1
  # 処理
end
② 述語メソッドに is、 does、 canのような助動詞をつけるべきではない。
  • 冗長になるため。
  • Rubyコアライブラリの述語メソッドのスタイル ( empty?や include?など)と矛盾するため。
qiita.rb
# 悪い例
class Person
  def is_buff?  #筋肉がある人?
    true
  end

  def can_play_rugbyfootball?
    false
  end

  def does_like_chocolate?
    true
  end
end



# 良い例
class Person
  def buff?
    true
  end

  def rugbyfootball_player?
    false
  end

  def likes_chocolate?
    true
  end
end

さいごに

毎日更新します。
皆様の復習等にご活用頂けますと幸いです。

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

Leetcode: Reverse Linked List

require 'minitest/autorun'
require 'pry'
class ReverseLinkedList < Minitest::Test

  def test_run
    # Input: 1->2->3->4->5->NULL
    # Output: 5->4->3->2->1->NULL
    head = ListNode.new(1)
    head.next = ListNode.new(2)
    head.next.next = ListNode.new(3)
    head.next.next.next = ListNode.new(4)
    head.next.next.next.next = ListNode.new(5)
    new_head = reverse_list(head)
    assert_equal(5, new_head.val)
    assert_equal(4, new_head.next.val)
    assert_equal(3, new_head.next.next.val)
    assert_equal(2, new_head.next.next.next.val)
    assert_equal(1, new_head.next.next.next.next.val)
    assert_equal(nil, new_head.next.next.next.next.next)
  end

  def reverse_list(head)
    return head if head.nil? || head.next.nil?

    p = head
    q = p.next
    q = reverse_list(q)

    # qはp.nextなので、p.next.next = p は q.next = pと同じ。なので、この行でq.nextが決まる。
    p.next.next = p
    p.next = nil
    q
  end

end

class ListNode
  attr_accessor :val, :next

  def initialize(val)
    @val = val
    @next = nil
  end

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

[-bash: rbenv: コマンドが見つかりません�]aws(ec2)上のrbenvの初期設定エラーの解決方法

1.エラーの内容

Neverland:.ssh kontatomoya$ ssh -i freemarket_sample_62d.pem ec2-user@3.115.38.38

Last login: Mon Feb 10 20:51:18 2020 from xx000000000000.au-net.ne.jp

       __|  __|_  )
       _|  (     /   Amazon Linux AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-ami/2018.03-release-notes/
-bash: rbenv: コマンドが見つかりません
#↑ec2に接続した時に出るこのエラーが本題です
[ec2-user@ip-000-00-00-00 ~]$ 

2.考えられる原因

1.そもそもrubyに関する環境構築をしていない

2.環境構築の際コマンドの順番を誤り.bash__profileでサーバーサイドが想定した記載になっていない。(自分が確認した限りではデプロイしたアプリへの影響はありませんでしたが、どこでバグの原因となるかわからないため解消することを推奨します)

3.解決方法

1.そもそもrubyに関する環境構築をしていない

この場合は下記の手順に従ってコマンドを打ち込むことで解消します
中途半端に設定した方はひとまず指示に従って全て打ち込んでください(ダブってしまう不要な箇所を4.で確認および削除し解決します。一度アプリケーションをデプロイして、再度違うアプリケーションをデプロイし直す方も同様にしてください)

[ec2-user@ip-000-00-00-00 ~]$ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv 
#rbenvをEC2にインストール
[ec2-user@ip-000-00-00-00 ~]$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile 
#パスを通すための記述を.bash_profileに追記
[ec2-user@ip-000-00-00-00 ~]$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
#rbenvを呼び出すための記述を.bash_profileに追記
[ec2-user@ip-000-00-00-00 ~]$ source .bash_profile
#.bash_profileをEC2に読み込み
[ec2-user@ip-000-00-00-00 ~]$ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
#ruby-buildのインストール
[ec2-user@ip-000-00-00-00 ~]$ rbenv rehash  
#rehashを行う
[ec2-user@ip-000-00-00-00 ~]$ rbenv install 2.0.0
#rubyのインストールを行う(2.0.0は自分のアプリのrubyバージョンに合わせる)
[ec2-user@ip-000-00-00-00 ~]$ rbenv global 2.0.0
#rubyをEC2上共通のバージョンとする
[ec2-user@ip-000-00-00-00 ~]$ rbenv rehash 
#rehashを行う
[ec2-user@ip-000-00-00-00 ~]$ ruby -v 
#バージョンを確認→"ruby 2.0.0p648 (2015-12-16) [x86_64-linux]"が出ればok

#設定の内容を見たい場合は下記コマンド
[ec2-user@ip-000-00-00-00 ~]$ vim ~/.bash_profile
#.bash_profile(初期設定の隠しファイル)をviエディターで確認する
2.環境構築の際コマンドの順番を誤り.bash__profileでサーバーサイドが想定した記載になっていない。

エラーを起こしている.bash__profileファイルは下記のようになっています

[ec2-user@ip-000-00-00-00 ~]$ vim ~/.bash_profile
#.bash_profile(初期設定の隠しファイル)をviエディターで確認する
.bash_profile
# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi

# User specific environment and startup programs

PATH=$PATH:$HOME/.local/bin:$HOME/bin

export PATH
eval "$(rbenv init -)"
export PATH="$HOME/.rbenv/bin:$PATH"
#↑環境構築のコマンドにより最下の行を追記しました。正しいコマンド通りだとした2行が逆転していなければなりません

コメントに従って下記の行を入れ替えることで正しい環境構築となります。エラーの理由はパスを通す前にrbenvを呼び出す記述となっているからでした。

4.中途半端に設定したあとにコマンドをした方の重複箇所のと確認と削除について

rbenv の環境構築で重複する箇所は.bash_profileだけなのでそちらを下記コマンドで確認し、一番最後に記載した.bash_profileのテンプレートと異なる部分の削除を行なっていただくことで正しく設定できます。

※また、注意点として、ローカルの.bash_profileとEC2(サーバー側)の.bash_profileは記載内容が異なり、今回は全てEC2(サーバー側)で作業を行なうようにしてください。

[ec2-user@ip-000-00-00-00 ~]$ vim ~/.bash_profile
#.bash_profile(初期設定の隠しファイル)をviエディターで確認する

※1.でなぜもう一度全て打ち直していただいたかというと.bash_profileにrubyやruby-buildが入っているか表示されないため、インストールされず進んでしまうおそれがあるからです。また、rubyやruby-buildは何度インストールしても自動でダブらないようにしてくれるため重複は気にしなくて大丈夫である(alreadyの文が出ます)ため、記載漏れしないように再度全て記述していただきました。(慣れている方はruby -vで環境の有無の確認の後.bash_profileに手打ちでもいいのですが、初期設定のファイルの存在自体がわかりにくく、これを見られているのは初学者の方が多いと思うのでコマンドから打って、最後に不要部分を削ることをお勧めします。)

<.bash_profileのテンプレート>

.bash_profile
# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi

# User specific environment and startup programs

PATH=$PATH:$HOME/.local/bin:$HOME/bin

export PATH
export PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)"

以上の方法でエラー文は解消されます

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

メタプログラミング理解の覚書

メタプログラミングとは、「プログラミングするためのプログラムを書くこと」らしい。
実務で遭遇した例としては、「任意の数の変数を作成し、その変数を利用する」場面。

[*1..3].each do |count|
  # user_1のような変数を作成し、値を「ユーザー1」と設定する
  instance_variable_set("@user_#{count}", "ユーザー#{count}")
  # evalを使って文字列をRubyプログラムとして評価させてputsする
  puts eval("@user_#{count}")
end
# 実行結果:
# ユーザー1
# ユーザー2
# ユーザー3

eval使うと、Rubocopに警告もらうので推奨されたやり方ではないのですが、こういうのがメタプログラミングというものだそうです。

もう少し実践的なメタプログラミングの概念は「オープンクラス」。
あるクラスを拡張しようと思ったら継承が必要ですが、継承せずに実行できること。
例えば、「このプロジェクトでは、足し算をするときに、足した結果にさらに1をプラスする必要がある」という要件を満たそうとする場合。

class Integer
  def plus_one(v)
    self + v + 1
  end
end

puts 1.plus_one 1
# 実行結果:
# 3

Integerクラスを継承することなく、plus_oneというメソッドを追加できました。
追加だけではなく、既にあるメソッドと同名を定義すれば上書きできます(これがモンキーパッチ)。

先程の要件を、メソッドの拡張ではなくモンキーパッチでやってみます。
def +(v)を上書きするわけです。
けれど以下の書き方だと+の定義が無限ループに陥るのでダメです。

class Integer
  def +(v)
    self + v + 1
  end
end
# 実行結果:
# `+': stack level too deep (SystemStackError)

こういう場合は、alias_methodを使用します。
alias_methodとは「メソッドに別名を定義する」というもの。

class Integer
  alias_method :plus, :+
  def +(v)
    self.plus(v).plus(1)
  end
end
puts 1 + 2 #=> 4

※この問題は、お仕事の面接の時に問題として出題されたものです。
当時はRubyを触って半年でメタプログラミング自体分かってなかったので答えられなかったのですが、最近勉強を始め、「これについて聞いていたのか!」と分かりました。
すごくすっきりした……!

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

herokuにデプロイするときの単純ミス

Railsで作成したアプリをHerokuでデプロイしようとした時のミス
スクリーンショット (318).png

terminal.
remote:  !
remote:  !     Failed to install gems via Bundler.
remote:  !     Detected sqlite3 gem which is not supported on Heroku:
remote:  !     https://devcenter.heroku.com/articles/sqlite3
remote:  !

結論

Gitリポジトリにデプロイするためgemを変更した修正を上げていなかった。。。
githubのリポジトリからデータがHerokuに送られているため、githubのコードを更新しなければならない!!!!!(そう言えばそうだった笑)

terminal.
$ git add *
$ git commit -m 'add to gemfile(メッセージは何でもいい)'
$ git push
$ git push heroku master

解決方法

HerokuにデプロイするときはたいていRails Tutorialを参考にしています。
Rails Tutorial "1.5デプロイする"

Gemfile.
group :development, :test do
  gem 'sqlite3', '1.3.13'
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
end

group :production do
  gem 'pg', '0.20.0'
end

・gem 'sqlite3'
・gem 'pg'
を挿入してgit push する!

terminal.
remote: Verifying deploy... done.

無事デプロイできました!

簡単なミスしないようにしたい。。。:sob:
これからも頑張ろう!

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

敢えてRubyで学ぶ「ゼロから作るDeep Learning」第3章のニューラルネットワークのMNIST推論処理

PyCallで取り込んだNumPyのデータを無理やりNumo::NArrayに変換してRubyで行列計算をする。

require 'numo/narray'
require 'numo/gnuplot'
require 'datasets'
require 'mini_magick'
require 'pycall/import'
require './neuralnet'
include PyCall::Import

def init_network
  pyimport :numpy
  pyimport :pickle
  pkl = open("sample_weight.pkl", "rb")
  pickle.load(pkl)
end

# 独自適当メソッド
# 無理やりnumpy形式をlist -> Ruby標準Array -> NArrayに変換する荒業
def numpy_to_narray(w)
  row = w.shape[0]
  return Numo::NArray.concatenate(Array(w.tolist).flatten) if w.shape.length == 1
  col = w.shape[1]
  Numo::NArray.concatenate(Array(w.tolist).flatten).reshape(row, col)
end

def predict(network, x)
  w1 = numpy_to_narray(network['W1'])
  w2 = numpy_to_narray(network['W2'])
  w3 = numpy_to_narray(network['W3'])
  b1 = numpy_to_narray(network['b1'])
  b2 = numpy_to_narray(network['b2'])
  b3 = numpy_to_narray(network['b3'])

  a1 = x.dot(w1) + b1
  z1 = sigmoid(a1)
  a2 = z1.dot(w2) + b2
  z2 = sigmoid(a2)
  a3 = z2.dot(w3) + b3
  softmax(a3)
end

# MNISTデータ取り込み
# train = Datasets::MNIST.new(type: :train)
test = Datasets::MNIST.new(type: :test)
x = Numo::NArray.concatenate(test.map{|t| t.pixels }).reshape(10000,784)
t = Numo::NArray.concatenate(test.map{|t| t.label })
network = init_network
# とりあえず一気に変換
y = predict(network, x)
accuracy_cnt = 0
10000.times do |i|
  p = y[i,true].to_a.index(y[i,true].max)
  accuracy_cnt += 1 if p == t[i]
end

p "Accuracy:#{Float(accuracy_cnt/10000.to_f)}"
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む