20200722のRubyに関する記事は24件です。

rubyでドローポーカーを作ってみる~実装編1(カード)~

概要

rubyでドローポーカーを作ってみる~準備編~

rubyでドローポーカーを作ってみる~test-unit準備編~

に続いて。

ソース: https://github.com/rytkmt/ruby_poker

今回からようやく実装に入っていこうと思います。

カードの実装

ポーカーで一番単一で動く末端はカードかなと思い、カードから作っていきます。
情報を整理していきましょう。

  • 数字
  • スート(記号)

をまず全カードが保持しているのでこれを実装します。

生成

  • 全カードを生成するため、その際は数字とスートを必ず渡すためinitializeの引数とする
  • 外部から数字とスートを参照できるが、変更はできないようにする
ruby_poker/card.rb
module RubyPoker
  class Card
    attr_reader :suit, :number

    def initialize(suit:, number:)
      @suit = suit
      @number = number
    end
  end
end

そして新しいファイルのため読込

ruby_poker.rb
require "ruby_poker/card"

これで終わりかと思いきや、次にカードを使う際のことを考えてみます。

比較

カードは数字とスートを使い「役」を作り、役が判定となるため、カードは参照できれば十分?とも思ったのですが、
詳しく役の説明を確認すると、同一の役の場合に役のなかで使われたカードの強弱をもとに判定する といったカード同士の強弱があるとのこと。

例えば「ツーカード」同士の場合
- 数字が大きいほうが勝ち
- 数字が同じ場合、スートの強いほうが勝ち

準備編で確認したとおり下記の順番となる。

  • 2人のプレイヤーが同じ役を作った場合は、役を構成しているカードの強い方が勝ちとなる
    • カードの強い順位は、A・K・Q・J・10~2
    • スートの強い順位は、スペード・ハート・ダイヤ・クローバー

配列の要素番号で判定できそうなので、定義する(定義は強い順に並んでいるのでindexを取る場合は逆順にする)

ruby_poker.rb
module RubyPoker
  NUMBERS = ([1] + [*2..13].reverse).freeze
  SUITS = %i[spade heart diamond club].freeze
end

またせっかくなので、card.rb側で引数チェックにも使用する

ruby_poker/card.rb
    def initialize(suit:, number:)
+      raise(ArgumentError) unless RubyPoker::SUITS.include?(suit)
+      raise(ArgumentError) unless RubyPoker::NUMBERS.include?(number)

また、要素の強弱を判定するユースケースですが、下記が考えられました。

  1. 自分の役に使われた手札の中で、一番強いカード がどれか(ストレート同士の比較の場合など)
  2. 敵の役との比較の際に、一番強いカード同士での比較

1に関しては、複数の中から一番強いものを取りたいためmax
2に関しては大小の比較>など

そのためComparableを使用し<=>を実装すれば解決(max<=>で判定されている Array#max

数字は単なる数字で比較してしまうと1が最弱になってしまうため、ちゃんとindexをもとに比較する

ruby_poker/card.rb
module RubyPoker
  class Card
+   include Comparable
    attr_reader :suit, :number
ruby_poker/card.rb
    def suit_level
      RubyPoker::SUITS.reverse.index(@suit)
    end

    def number_level
      RubyPoker::NUMBERS.reverse.index(@number)
    end

    def <=>(other)
      number_comparision = number_level <=> other.number_level
      number_comparision.zero? ? suit_level <=> other.suit_level : number_comparision
    end

テストケース

簡単にテストケースも実装する ※test-unit初めてなので記述でいい方法あれば教えてください

require "test_helper"

module RubyPoker
  class CardTest < Test::Unit::TestCase
    sub_test_case "#initialize" do
      test "correct arguments" do
        assert_nothing_raised do
          Card.new(suit: :heart, number: 3)
        end
      end

      test "wrong suit" do
        assert_raise_kind_of(ArgumentError) do
          Card.new(suit: :test, number: 3)
        end
      end

      test "wrong number" do
        assert_raise_kind_of(ArgumentError) do
          Card.new(suite: :heart, number: 14)
        end
      end
    end

    sub_test_case "#<=>" do
      sub_test_case "compare number" do
        test "simple numbers" do
          a = Card.new(suit: :heart, number: 8)
          b = Card.new(suit: :heart, number: 2)
          assert(a > b)
        end

        test "compare ace" do
          a = Card.new(suit: :heart, number: 13)
          b = Card.new(suit: :heart, number: 1)
          assert(a < b)
        end

        test "max number" do
          cards = [*1..5]
            .shuffle
            .map { |i| Card.new(suit: :heart, number: i) }

          assert_equal(1, cards.max.number)
        end
      end

      sub_test_case "compare suit(same number)" do
        test "spade and heart" do
          a = Card.new(suit: :spade, number: 1)
          b = Card.new(suit: :heart, number: 1)
          assert(a > b)
        end

        test "heart and club" do
          a = Card.new(suit: :club, number: 1)
          b = Card.new(suit: :heart, number: 1)
          assert(a < b)
        end

        test "spade and diamond" do
          a = Card.new(suit: :spade, number: 1)
          b = Card.new(suit: :diamond, number: 1)
          assert(a > b)
        end
      end
    end
  end
end

これでひとまずカードに関しては完成 かな?

続き


rubyでドローポーカーを作ってみる~実装編2(役)~

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

[Ruby]puts とreturn、出力と戻り値の違い

putsは出力するのみ。対してreturnは戻り値を返すだけ。
putsは値の受け渡しに使えない。returnは出力をしない。

puts.rb
def greet 
   puts "Hello"
end
@example = greet
@example =>nil
return.rb
def greet2
   return "Hello"
end
@example2 = greet2
@example =>"Hello"

値の受け渡しをするのかどうかという点が使い分けのミソかな?
戻り値について勉強が足りないなあ

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

overflowプロパティ

overflowプロパティについて覚えたので備忘録

値は主に4つ
1. [visible] ボックスからはみ出した要素がそのまま表示される、初期値
2. [hidden] ボックスからはみ出した要素は表示されない
3. [scroll] ボックスからはみ出した要素は表示されないがスクロールすることで表示される
4. [auto] はみ出した要素の処理がブラウザに依存する、基本的にはスクロールすることで表示される

補足として
1. overflow-x: scroll;
x軸(横方向)にのみスクロールさせる
2. overflow-y: scroll;
y軸(縦方向)にのみスクロールさせる

文字列が横に長いが折り返しさせたくない + 項目がボックス内に収まらない
上記のような場合に使用検討できる

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

overflowプロパティ【残54日】

overflowプロパティについて覚えたので備忘録

値は主に4つ
1. [visible] ボックスからはみ出した要素がそのまま表示される、初期値
2. [hidden] ボックスからはみ出した要素は表示されない
3. [scroll] ボックスからはみ出した要素は表示されないがスクロールすることで表示される
4. [auto] はみ出した要素の処理がブラウザに依存する、基本的にはスクロールすることで表示される

補足として
1. overflow-x: scroll;
x軸(横方向)にのみスクロールさせる
2. overflow-y: scroll;
y軸(縦方向)にのみスクロールさせる

文字列が横に長いが折り返しさせたくない + 項目がボックス内に収まらない
上記のような場合に使用検討できる

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

【ポートフォリオを作成する方へ】chartkickの使い方

chartkickはとても簡単にグラフを作ることができるライブラリです
スクリーンショット 2020-07-20 21.54.12.png

環境

Ruby 2.5.3
Ruby on Rails 5.2.4
chartkick 3.3.1

手順

1.インストール
Gemfile
 gem "chartkick"
 $ bundle install
2.javascript読み込み
app/javascripts/application.js
//= require chartkick
//= require Chart.bundle

準備完了です。
一度サーバー落としてrails sやり直した方がいいかもしれません。

オプション

ID,幅,高さ

<%= line_chart data, id: "users-chart", width: "800px", height: "500px" %>

軸のタイトル

<%= line_chart data, xtitle: "Time", ytitle: "Population" %>

これらを組み合わせるとこのような感じになります。

スクリーンショット 2020-07-20 21.51.41.png

managemantに売上(result),売上日(result_date)を用意し、

app/controllers/managemants_controller.rb
def index
    @managemants = Managemant.all
  end
app/models/managemant.rb
# chartkick用データ
  def self.chart_date
    order(result_date: :asc).pluck('result_date', 'result').to_h
  end
app/views/managemants/index.html.erb
<%= column_chart @managemants.chart_date, xtitle: "日付", ytitle: "売上(円)", width: "600px", height: "200px" %>

ビューのcolumn_chartの部分を変えるだけで色々なグラフに変えることができます。
・折れ線グラフ-line_chart
スクリーンショット 2020-07-20 21.54.12.png

・円グラフ-pie_chart
スクリーンショット 2020-07-20 22.26.09.png
・棒グラフ-pie_chart
スクリーンショット 2020-07-20 22.26.35.png

・面グラフ-area_chart
スクリーンショット 2020-07-20 22.26.58.png

簡単にきれいなグラフが作れるのでぜひ試してみてください。

参考

https://chartkick.com/

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

rubyでドローポーカーを作ってみる~test-unit準備編~

概要

rubyでドローポーカーを作ってみる~準備編~

に続いて。

ソース: https://github.com/rytkmt/ruby_poker

test-unit全然知らない・・・ということで今回はtest-unitの準備をしていきます。

準備

こちらの公式ページを参考に進めていく

が、gemではないので少し手順が変わりそう・・・
なのでそれも含めて手順を記録として残していきます

初期ファイルの準備

$ cd ruby_poker
$ bundle gem -t minitest ./
git status -sb

A  .gitignore
A  .travis.yml
A  CODE_OF_CONDUCT.md
A  Gemfile
A  LICENSE.txt
A  Rakefile
A  bin/console
A  bin/setup
A  lib/ruby_poker.rb
A  lib/ruby_poker/version.rb
A  ruby_poker.gemspec
A  test/ruby_poker_test.rb
A  test/test_helper.rb

結構作られる

gemではないためgemspec削除

$ git rm ruby_poker.gemspec

ファイルの修正

Gemfile

Gemfile
-# Specify your gem's dependencies in ruby_poker.gemspec
-gemspec
+gem "rake"
+group :test do
+  gem "pry-byebug"
+  gem "test-unit"
+  gem "test-unit-rr"
+end

gemspecの行削除
代わりにminitestからtest-unitに変更なのでまずgemをインストール

$ bundle install

このとき、bundlerにてインストールされたファイルがgitに上がらないように.gitignoreを必要に応じて編集

Rakefile

Rakefile
-require "bundler/gem_tasks"
 require "rake/testtask"

test/test_helper.rb

test/test_helper.rb
 $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
 require "ruby_poker"

-require "minitest/autorun"
+require "pry"
+require "test/unit"
+require "test/unit/rr"

test/ruby_poker_test.rb

test/ruby_poker_test.rb
 require "test_helper"

-class RubyPokerTest < Minitest::Test
+class RubyPokerTest < Test::Unit::TestCase
   def test_that_it_has_a_version_number
     refute_nil ::RubyPoker::VERSION
   end

bin/console

bundle exec consoleを実行したときにruby_pokerはLOAD_PATHに居ないためエラーになる。そのためLOAD_PATHに追加する

bin/console
 require "bundler/setup"
+$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
+
 require "ruby_poker"

動作確認

console

bundle exec console を実行し、irbが立ち上がればOK

test

bundle exec rake testを実行し1件は失敗するようにテストケースがサンプルとして作られてるため、1件成功、1件失敗となればOK

$ rake test
/home/vagrant/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/rake-12.3.2/lib/rake/file_utils.rb:54: warning: Insecure world writable dir /home in PATH, mode 040707
Loaded suite /home/vagrant/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/rake-12.3.2/lib/rake/rake_test_loader
Started
F
==============================================================================================================================================================
      6:   end
      7: 
      8:   def test_it_does_something_useful
  =>  9:     assert false
     10:   end
     11: end
/home/vagrant/private_workspace/ruby_poker/test/ruby_poker_test.rb:9:in `test_it_does_something_useful'
Failure: test_it_does_something_useful(RubyPokerTest): <false> is not true.
==============================================================================================================================================================
.
Finished in 0.004560792 seconds.
--------------------------------------------------------------------------------------------------------------------------------------------------------------
2 tests, 2 assertions, 1 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications
50% passed
--------------------------------------------------------------------------------------------------------------------------------------------------------------
438.52 tests/s, 438.52 assertions/s
rake aborted!
Command failed with status (1)

Tasks: TOP => test
(See full trace by running task with --trace)

続き


rubyでドローポーカーを作ってみる~実装編1(カード)~

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

[Rails]Administrateでメインアプリで使っていたCSSを適用させる方法

困ったこと、やりたいこと

\\\メインアプリのCSSが使えない///

Railsアプリで管理画面を作成するために、Administrateというgemを使用した時のことです。
メインアプリのビューに適用させているCSSを、admin以下のビューにも適用させようとしたのにできない…

メインアプリと同じクラス名使ってるのに…どうすればいいの???

環境

  • Ruby 2.5.1
  • Rails 5.0.7.2
  • Administrate 0.14.0
  • haml 5.1.2

結論

Administrateのスタイルシートの読み込み先を追加する

1. rails g administrate:views:layout_styoesheet.html.erbを生成

terminal
# 該当のアプリディレクトリで実行
$ rails g administrate:views:layout
  Running via Spring preloader in process 44282
      create  app/views/layouts/admin/application.html.erb
      create  app/views/admin/application/_navigation.html.erb
      create  app/views/admin/application/_stylesheet.html.erb #この子!!!
      create  app/views/admin/application/_javascript.html.erb
      create  app/views/admin/application/_flashes.html.erb
      create  app/views/admin/application/_icons.html.erb

※生成されるファイルはerbなので、環境がhamlの場合は$ rails haml:erb2hamlなどで変換してください。

2. _stylesheet.html.hamlにスタイルシートの読み込み先を追記する

/views/admin/application/_stylesheet.html.haml
- Administrate::Engine.stylesheets.each do |css_path|
  = stylesheet_link_tag css_path
  # この行↓を追記
  = stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'
= yield :stylesheet

この記述によって、/assets/stylesheets/application.scssのファイルを読み込みにいってくれるので、結果的にadministrateの画面でも既存のスタイルシートを適用することができます。

参考記事

【Rails5】Administrateのスタイルシート読込先を変更する - 196Log

余談:既存レイアウトのカスタマイズ

あまり需要もないかとは思いますが、既定のadministrate画面のレイアウトを変更(カスタマイズ)することも可能です。

こちらもGitHubのIssues(How to add custom CSS? #748)に挙げられていました。

スクリーンショット 2020-07-22 21.23.11.png

terminal
# 該当のアプリディレクトリで実行
$ rails g administrate:assets:stylesheets
  Running via Spring preloader in process 44122
      create  app/assets/stylesheets/administrate
      create  app/assets/stylesheets/administrate/application.scss
      create  app/assets/stylesheets/administrate/base/_forms.scss
      create  app/assets/stylesheets/administrate/base/_layout.scss
      create  app/assets/stylesheets/administrate/base/_lists.scss
      create  app/assets/stylesheets/administrate/base/_tables.scss
      create  app/assets/stylesheets/administrate/base/_typography.scss
      create  app/assets/stylesheets/administrate/components/_app-container.scss
      create  app/assets/stylesheets/administrate/components/_attributes.scss
      create  app/assets/stylesheets/administrate/components/_buttons.scss
      create  app/assets/stylesheets/administrate/components/_cells.scss
      create  app/assets/stylesheets/administrate/components/_field-unit.scss
      create  app/assets/stylesheets/administrate/components/_flashes.scss
      create  app/assets/stylesheets/administrate/components/_form-actions.scss
      create  app/assets/stylesheets/administrate/components/_main-content.scss
      create  app/assets/stylesheets/administrate/components/_navigation.scss
      create  app/assets/stylesheets/administrate/components/_pagination.scss
      create  app/assets/stylesheets/administrate/components/_search.scss
      create  app/assets/stylesheets/administrate/library/_clearfix.scss
      create  app/assets/stylesheets/administrate/library/_data-label.scss
      create  app/assets/stylesheets/administrate/library/_variables.scss
      create  app/assets/stylesheets/administrate/reset/_normalize.scss
      create  app/assets/stylesheets/administrate/utilities/_text-color.scss

このように、スタイルシートがブワーッと生成されるので、あとは自分がカスタマイズしたい部分をいじれば変更が適用されます。

それにしてもAdministrateは都度都度こういうのがあるな…一通り実装終えたらシリーズ化できそうです笑

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

プログラミング未経験者が3ヶ月でポートフォリオを作成するまで

はじめに

プログラミング完全未経験者だった私がポートフォリオを作成するまでの3ヶ月で取り組んだことをまとめました。
ポートフォリオは基礎学習(1ヶ月)ポートフォリオ作成(2ヶ月)の計3ヶ月で作成しました。
私と同じように未経験からエンジニアを目指す方の参考になれば嬉しいです。

作成したポートフォリオ

【概要】
ゴルフ初心者向けの投稿アプリです。
学生時代の経験からゴルフ初心者が持つ課題を解決するためのツールとして作成しました。
【URL】
https://golfour.herokuapp.com
【GitHub】
https://github.com/matao0214/golfour
【言語・使用技術】
・Ruby 2.5.1
・Ruby on Rails 5.2.4
・HTML(Slim)
・CSS(Sass)
・Bootstrap4
・JavaScript
・jQuery
・PostgreSQL 12.2
・GoogleMapsAPI
・Heroku
・Git
・GitHub

基礎学習(1ヶ月)

まずは基礎的な知識をインプットするために以下の書籍を使って学習を進めました。
これからWebをはじめる人のHTML&CSS、JavaScriptのきほんのきほん
プロを目指す人のためのRuby入門
現場で使える Ruby on Rails 5速習実践ガイド

この1ヶ月はかなり辛かったですが以下の2点を習慣化して取り組みました。

1. 知らない単語が出なくなるまでググり続ける
わからないことを調べるとその説明文の中に知らない単語が出てきて更に調べて、というのを何度も繰り返しました。
ただ、それを続けていくと確実に知識量が増えて調べる量は減っていくので、諦めずに調べ続けることが重要です。

2. インプットした内容はQiitaでアウトプットする
インプットした知識は理解度を高めるために、Qiitaの記事にまとめてアウトプットしていました。
本を読んで「理解した!」と思ってもいざアウトプットしようとすると言語化出来ず、十分に理解できていないことが多々ありました。
理解度の確認・定着のためにもQiitaへのアウトプットは非常に有効だと思うのでおすすめです。

わかりやすい文章を書こう!とは考えずにとりあえず書いてみるのが重要です!
数をこなしていけば書き慣れていくので積極的にアウトプットして習慣化するのが良いと思います。

ポートフォリオ作成(2ヶ月)

基礎学習が一通り終わったところでポートフォリオ作成に移りました。
ポートフォリオは以下の手順で作成しました。
1. ポートフォリオのアイデア出し
2. 機能・DBの設計
3. ポートフォリオの作成

1. ポートフォリオのアイデア出し

ポートフォリオはどういうコンセプト・背景があってポートフォリオを作成したのか?という点を意識して設計しました。

これまでに自分または身近な人が抱えている(抱えていた)問題を書き出してみて、
その問題はどういう機能・仕組みがあれば解決できるかを考えポートフォリオに落とし込みました。

具体的には以下の順序でアイデアを出して形にしていきました。

私は大学生の時、研究室に入るのをきっかけにゴルフを始めた。そしてこれまでにゴルフに関して印象に残った2つの経験があった。

  1. 私が以前働いていた会社でゴルフを始めた先輩が2人いた。2人ともなかなか上達せず途中で辞めそうになっていたが、アドバイスしあいながら練習を続けた結果、徐々に上達し今でもゴルフを楽しんで続けている。
  2. 大学の同期に「ゴルフを始めたいが一緒に練習に行ってくれる同年代(20代)の人がなかなかいない」という人が結構いた。

この経験からゴルフ初心者には次の課題があると感じた。
ゴルフ初心者はなかなか上達が難しく、途中で諦めてしまうことが多い。
ゴルフを始めたい20代は一定数いるが、一緒に始める人が身近にいない。

課題の解決策:同じ境遇(ゴルフを始めたい・ゴルフを始めたばかり)の若い世代の人が身近にいれば、ゴルフを始めやすい環境、挫折しにくい仕組みが作れるのでは?

サービスの形:ゴルフの練習記録を投稿して共有するアプリケーション

2. 機能・DBの設計

ポートフォリオのアイデアが固まったところで機能・DBの設計を行いました。
ゴルフの練習記録を投稿して共有する機能を中心に、練習のモチベーションを維持できる機能を併せて設計をしました。

機能設計
新規投稿機能
一覧表示機能
詳細表示機能
編集機能
削除機能
ログイン機能
検索機能
いいね機能
位置情報投稿機能(GoogleMapAPIの利用)
投稿データからグラフ作成機能

DB設計
Usersテーブル

カラム名 データ型 制約
nickname string NOT NULL,10字以内
email string NOT NULL,UNIQUE
password_digest string NOT NULL
golf_reki string 5字以内
goal string 50字以内

TrainingPostsテーブル

カラム名 データ型 制約
training_place string NOT NULL, 50字以内
training_task string NOT NULL, 150字以内
training_impression string 150字以内
user_id integer NOT NULL, FOREIGN KEY

TrainingContentsテーブル

カラム名 データ型 制約
training_post_id integer NOT NULL,Foreign_key
training_time integer NOT NULL
training_hits integer NOT NULL

Likesテーブル

カラム名 データ型 制約
user_id integer NOT NULL, FOREIGN KEY
training_post_id integer NOT NULL, FOREIGN KEY

Spotsテーブル

カラム名 データ型 制約
address integer NOT NULL, 50字以内
latitude float NOT NULL
longitude float NOT NULL
training_post_id integer NOT NULL, FOREIGN KEY

3. ポートフォリオ作成

機能・DB設計の終わりようやくコードを書く作業に入りました。
ポートフォリオの作成手順は以下の通りです。
1. 基礎学習で使った書籍をベースにCRUD機能を実装
2. 実装したい機能をQiitaの記事・公式ドキュメントなどを参考に実装
3. UI/UXを意識したデザイン

1. 基礎学習で使った書籍をベースにCRUD機能を実装

基礎学習を終えた直後ではまだまだコーディングに慣れていないので「この機能を実装しよう!」と思っても
・どうやって実装する?
・何がわからないのかわからない

という状態だったのでコードに慣れる意味合いも込めて書籍を参考にしました。

結果的に基礎的な知識の復習とプログラム全体の構造に慣れることができました。
また、自分でもここまでできるんだ!と自信を持てるので
モチベーションを維持するためにも難易度の低いことから手をつけるのが良いと思います。

2. 実装したい機能をQiitaの記事・公式ドキュメントなどを参考に実装

CRUD機能を実装した後はいいね機能の実装やGoogle MAP APIの利用等に取り組みました。

機能の実装ではググりながらQiitaや公式ドキュメントを参考に実装したのですが、
調査する上で重要だと感じたのは絶対に公式ドキュメントを読むことです。

公式ドキュメントを読むと実装したい機能の説明の他にこんなオプションもあるよ!と書いてあることが多いです。
そういったオプションなどを取り入れることで機能が予定していた以上に充実したことが何度もありました。

Qiitaの記事はわかりやすくまとめられていて非常に読みやすく便利です。
ただ、当たり前ですがソースの信頼性が公式ドキュメントに比べると低く、必要以上の情報に触れられないので、Qiitaの記事だけではなく公式ドキュメントも読むべきですね。

3. UI/UXを意識したデザイン

一通り機能の実装が終わった後、UI/UXを意識してデザインに取り掛かりました。
UI・UX改善入門:「UIとUXの違い」から「UX改善の3ポイント」を大解説!

具体的には以下の3点を意識しました。
・ターゲット(20代)を意識したデザイン
・使い続けたくなるデザイン
・直感的なデザイン

そしてポートフォリオには以下の形で落とし込みました。
・若者向けのポップな背景・フォント
・投稿内容の入力欄を具体的な選択肢からの選択式に変更(入力内容を考えさせる手間を省略)
・グラフを利用して直感的に練習記録を可視化

この中でも特にグラフによる可視化は取り入れて良かったです。
最初はユーザーの練習記録を文字と数字で表示していましたが、データをグラフ化することで欲しい情報が視覚的に得られやすいデザインを実現できました。
chartkickというjemを使えば簡単にグラフを作成できるのでおすすめです。

ポートフォリオ作成で意識したこと・工夫した点

・とにかくできることから手を動かしてコードに慣れる
・使い続けたくなる機能の実装・仕組みの構築
・ターゲットを意識したデザイン
・ユーザー目線での使いやすさ
・保守性の高いコーディング

ポートフォリオ作成を通して学んだこと・成長したこと

・自分のアイデアが形になる楽しさ(一番実感したことです:smile:
・サービスを1から作れるエンジニアとしての自走力
・わからないことを言語化して調査する能力(ググる力)
・参考文献の選び方(公式ドキュメントは必須)
・アウトプットの重要性

まとめ

ポートフォリオ作成を通してこの3ヶ月間で多くのことを学び成長することができました。
全くプログラミングを触ったことがない自分でもここまで作れるんだという自信が得られたこと、そして何より自分のアイデアでサービスを作る楽しさを知ることができました。

AWSによるインフラ構築などまだまだやりたいこともありますが、まずはエンジニアへの就職活動を始めます。
ポートフォリオをアップデートしながら就活をがんばっていきたいと思います!

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

find_in_batchesでメモリ消費量を1/100にしたお話

メモリ消費を抑えた大量データ取り扱い方法について

Railsでメモリを意識してコードを書いていますでしょうか?

RailsではRubyのガベージコレクション※1を利用しているため、メモリ解放などを気にすることなくコードを書くことが出来ます。

※1 Rubyは使用されなくなったオブジェクトを回収し、自動的にメモリを解放します。

その為、いつの間にかメモリをクソほど食う実装をしているにも関わらず、その事に気づかずに本番サーバーが急に落ちる(メモリエラーで)といった非常事態になるケースがあります。

なぜそんなことが言えるかというと、僕が今働いている現場でこの現象が起きたからですw

実装修正の担当が自分になり修正したのですが、その経験で多くを学ぶことが出来たので忘れないためにもメモ残します。

原因調査

まずはそもそもどこで、メモリエラーになっているのかを調査しなければなりません。

Railsでメモリ使用量の調査をする為にObjectSpace.memsize_of_allを利用しました。

このメソッドを利用することで、すべての生存しているオブジェクトが消費しているメモリ使用量をバイト単位で調査することが出来ます。

このメソッドを実行処理が落ちそうな箇所にチェックポイントとして設置し、どこでメモリを大量消費しているのかを地道に調べていきます。

■ メモリ使用量を調べる使用例

class Hoge
  def self.hoge
    puts 'mapでメモリ展開される前のオブジェクトメモリ数'
    puts '↓'
    puts ObjectSpace.memsize_of_all <==== チェックポイント
    array = ('a'..'z').to_a
    array.map do |item|             <==== 
      puts "#{item}のオブジェクトメモリ数"
      puts '↓'
      puts ObjectSpace.memsize_of_all <==== チェックポイント
      item.upcase
    end
  end
end

■ 実行結果

irb(main):001:0> Hoge.hoge
mapでメモリ展開される前のオブジェクトメモリ数
↓
137789340561

aのオブジェクトメモリ数
↓
137789342473

bのオブジェクトメモリ数
↓
137789342761

cのオブジェクトメモリ数
↓
137789343049

dのオブジェクトメモリ数
↓
137789343337

eのオブジェクトメモリ数
↓
137789343625

.
.
.

xのオブジェクトメモリ数
↓
137789349097
yのオブジェクトメモリ数
↓
137789349385
zのオブジェクトメモリ数
↓
137789349673
=> ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]

この実行結果からまずmapで渡されるデータを一気にメモリ展開しており、そこでメモリ消費量が増えたことがわかります。(①の箇所)

さらにループ処理される度にメモリ消費量が増えていることもわかります。

今回のサンプルコードのように処理が単純である場合は特に問題ありませんが。

渡されるデータが大量であり、なおかつループ処理で行う実装が複雑であればメモリ消費量が圧迫されて。

メモリーエラー(メモリ処理が追いつかなくなった場合に起こるエラー)になってしまいます。

今回の調査も以上の手順で調べました、その結果、渡されるデータが大量であり尚且つmapでクエリを吐きまくる重い処理を実装していたのでメモリエラーになったという結論になりました。

対策方法

原因はわかりました。

次に対策方法について考えましょう。

最初に考えついた対策は以下の3つです。

1. 金の力でメモリ増やす
2. Thread(スレッド)で並行処理にする
3. バッチ処理にする

1. 金の力でメモリ増やす

正直これが一番早い、お金の力でサーバーのメモリスペックを上げれば済むことなのでこれにしよう!

っと、思ったのですが。

この処理以外にメモリ負担の大きい実装はないので、この箇所のためだけにお金をかけるのは馬鹿らしいなと思いこの案はやめました。

2. Thread(スレッド)で並行処理にする

次の対策方法としてRubyの並行処理を考えついたのですが、ボトルネックが処理時間(timeout)の場合、複数スレッドを立てて並列して計算させてマージすると早くなるので正しいのですが、今回はメモリエラーでボトルネックがメモリ圧迫なので、複数スレッドにしようが扱うデータ量は変わらないので結局メモリエラーになると想定されるので、この案はやめました。

3. バッチ処理にする

今回のメモリエラーになる最大の原因は大量のデーターを一気にメモリ展開して、ループで高負荷処理を繰り返すことが原因で発生するメモリエラーです。

なので、大量データを一気にメモリ展開せずにバッチ処理で1,000件単位などに分けて実装すればメモリを節約しながら実装できるので良いのではないかと考えました。

Railsではfind_in_batchesというメソッドが準備されており、こちらを利用するとデフォルトで1000件ずつ処理を実施することができます。

例)10,000件の場合は1,000件の処理に分けて10回のバッチ処理に分ける。
find_in_batchesで制限をかけて処理することで利用するメモリを少なくするイメージ。

結論

find_in_batchesを利用してバッチ処理にする

実装

対策方法がわかれば、あとは実装あるのみです。

実装していきましょう。(実際に会社のコードを見せる事はできないのでイメージだけ記載します)

■ 実装イメージ

User.find_in_batches(batch_size: 1000) do |users|
  # なんか処理
end

もし仮にUserデータが10,000件取得されたとしても、find_in_batchesを利用すれば1000ずつ処理されます。

つまり、10,000 / 1000 = 10回の処理に分けるイメージです。

結果

メモリ消費量が1/100になりました。

もっと良くするためのアイデア

ただ、この実装の最大のデメリットは、処理時間がかかりすぎるポイントです。

herokuなどを利用している場合はこの実装ではRequestTimeOutエラー※1になります。

※1 herokuでは30秒以上かかる処理はRequestTimeOutエラーになる仕様

ですので、この高負荷処理がかかる実装はバックグランド処理に移動させるのがベターと考えます。

Railsを利用している場合はSidekiqなどを利用すれば実現可能です。

以下のような手順で作業すれば、良いと思います。

STEP1. find_in_batchesを利用してメモリ消費量を抑える

STEP2. STEP1が完了した段階で、時間はかかるけどメモリエラーにならずに動く状態になってるはず。
ただ、処理に時間がかかるのでその処理をバックグランドに移動させる

まとめ

最初は、めんどくさそうなタスクだな〜と思ってたのですが。

学びが多く、今思うと実装してよかったです。

参考

https://techblog.lclco.com/entry/2019/07/31/180000
https://qiita.com/kinushu/items/a2ec4078410284b9856d

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

find_in_batchesでメモリ消費量を1/100にしたお話(体験談)

メモリ消費を抑えた大量データ取り扱い方法について

Railsでメモリを意識してコードを書いていますでしょうか?

RailsではRubyのガベージコレクション※1を利用しているため、メモリ解放などを気にすることなくコードを書くことが出来ます。

※1 Rubyは使用されなくなったオブジェクトを回収し、自動的にメモリを解放します。

その為、いつの間にかメモリをクソほど食う実装をしているにも関わらず、その事に気づかずに本番サーバーが急に落ちる(メモリエラーで)といった非常事態になるケースがあります。

なぜそんなことが言えるかというと、僕が今働いている現場でこの現象が起きたからですw

実装修正の担当が自分になり修正したのですが、その経験で多くを学ぶことが出来たので忘れないためにもメモ残します。

原因調査

まずはそもそもどこで、メモリエラーになっているのかを調査しなければなりません。

Railsでメモリ使用量の調査をする為にObjectSpace.memsize_of_allを利用しました。

このメソッドを利用することで、すべての生存しているオブジェクトが消費しているメモリ使用量をバイト単位で調査することが出来ます。

このメソッドを実行処理が落ちそうな箇所にチェックポイントとして設置し、どこでメモリを大量消費しているのかを地道に調べていきます。

■ メモリ使用量を調べる使用例

class Hoge
  def self.hoge
    puts 'mapでメモリ展開される前のオブジェクトメモリ数'
    puts '↓'
    puts ObjectSpace.memsize_of_all <==== チェックポイント
    array = ('a'..'z').to_a
    array.map do |item|             <==== 
      puts "#{item}のオブジェクトメモリ数"
      puts '↓'
      puts ObjectSpace.memsize_of_all <==== チェックポイント
      item.upcase
    end
  end
end

■ 実行結果

irb(main):001:0> Hoge.hoge
mapでメモリ展開される前のオブジェクトメモリ数
↓
137789340561

aのオブジェクトメモリ数
↓
137789342473

bのオブジェクトメモリ数
↓
137789342761

cのオブジェクトメモリ数
↓
137789343049

dのオブジェクトメモリ数
↓
137789343337

eのオブジェクトメモリ数
↓
137789343625

.
.
.

xのオブジェクトメモリ数
↓
137789349097
yのオブジェクトメモリ数
↓
137789349385
zのオブジェクトメモリ数
↓
137789349673
=> ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]

この実行結果からまずmapで渡されるデータを一気にメモリ展開しており、そこでメモリ消費量が増えたことがわかります。(①の箇所)

さらにループ処理される度にメモリ消費量が増えていることもわかります。

今回のサンプルコードのように処理が単純である場合は特に問題ありませんが。

渡されるデータが大量であり、なおかつループ処理で行う実装が複雑であればメモリ消費量が圧迫されて。

メモリーエラー(メモリ処理が追いつかなくなった場合に起こるエラー)になってしまいます。

今回の調査も以上の手順で調べました、その結果、渡されるデータが大量であり尚且つmapでクエリを吐きまくる重い処理を実装していたのでメモリエラーになったという結論になりました。

対策方法

原因はわかりました。

次に対策方法について考えましょう。

最初に考えついた対策は以下の3つです。

1. 金の力でメモリ増やす
2. Thread(スレッド)で並行処理にする
3. バッチ処理にする

1. 金の力でメモリ増やす

正直これが一番早い、お金の力でサーバーのメモリスペックを上げれば済むことなのでこれにしよう!

っと、思ったのですが。

この処理以外にメモリ負担の大きい実装はないので、この箇所のためだけにお金をかけるのは馬鹿らしいなと思いこの案はやめました。

2. Thread(スレッド)で並行処理にする

次の対策方法としてRubyの並行処理を考えついたのですが、ボトルネックが処理時間(timeout)の場合、複数スレッドを立てて並列して計算させてマージすると早くなるので正しいのですが、今回はメモリエラーでボトルネックがメモリ圧迫なので、複数スレッドにしようが扱うデータ量は変わらないので結局メモリエラーになると想定されるので、この案はやめました。

3. バッチ処理にする

今回のメモリエラーになる最大の原因は大量のデーターを一気にメモリ展開して、ループで高負荷処理を繰り返すことが原因で発生するメモリエラーです。

なので、大量データを一気にメモリ展開せずにバッチ処理で1,000件単位などに分けて実装すればメモリを節約しながら実装できるので良いのではないかと考えました。

Railsではfind_in_batchesというメソッドが準備されており、こちらを利用するとデフォルトで1000件ずつ処理を実施することができます。

例)10,000件の場合は1,000件の処理に分けて10回のバッチ処理に分ける。
find_in_batchesで制限をかけて処理することで利用するメモリを少なくするイメージ。

結論

find_in_batchesを利用してバッチ処理にする

実装

対策方法がわかれば、あとは実装あるのみです。

実装していきましょう。(実際に会社のコードを見せる事はできないのでイメージだけ記載します)

■ 実装イメージ

User.find_in_batches(batch_size: 1000) do |users|
  # なんか処理
end

もし仮にUserデータが10,000件取得されたとしても、find_in_batchesを利用すれば1000ずつ処理されます。

つまり、10,000 / 1000 = 10回の処理に分けるイメージです。

結果

メモリ消費量が1/100になりました。

もっと良くするためのアイデア

ただ、この実装の最大のデメリットは、処理時間がかかりすぎるポイントです。

herokuなどを利用している場合はこの実装ではRequestTimeOutエラー※1になります。

※1 herokuでは30秒以上かかる処理はRequestTimeOutエラーになる仕様

ですので、この高負荷処理がかかる実装はバックグランド処理に移動させるのがベターと考えます。

Railsを利用している場合はSidekiqなどを利用すれば実現可能です。

以下のような手順で作業すれば、良いと思います。

STEP1. find_in_batchesを利用してメモリ消費量を抑える

STEP2. STEP1が完了した段階で、時間はかかるけどメモリエラーにならずに動く状態になってるはず。
ただ、処理に時間がかかるのでその処理をバックグランドに移動させる

まとめ

最初は、めんどくさそうなタスクだな〜と思ってたのですが。

学びが多く、今思うと実装してよかったです。

参考

https://techblog.lclco.com/entry/2019/07/31/180000
https://qiita.com/kinushu/items/a2ec4078410284b9856d

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

Yay! I'm on Rails! Again

はじめに

Ruby on Rails三回目記念です。

on Rails!

20200722.png
おじさんが帽子をかぶってる!

環境

前回、Yay! I'm on Rails!raspberry pi 3 B+で、少しの嵌りで乗り切りました。
しかし、次のraspberry pi zeroは嵌りの連続で、いまだrails sが成功していない状態です。

  • sudo apt-get ruby-dev
  • sudo gem install sassc
  • sudo gem install sassc-rails
  • sudo gem update sass-rails
  • sudo gem install semantic-range
  • sudo gem install webpacker

そこで、気分を変えWindows10rails sしました。

嵌ったところ

嵌りらしい嵌りはないように感じました。

D:\ruby\rails>rails new test271

Done in 3983.70s.
Webpacker successfully installed ? ?

しかし、時間が掛かり過ぎの様な気もします。

まとめ

  • 初RoR on Windows10
  • 次回こそは外部サーバに挑戦

参照したサイト
Rails Girls インストール・レシピ

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

IGVをソケット通信をつかって操作する方法、および、その方法を利用してRubyのGemを作った話

はじめに

IGVはゲノムブラウザと呼ばれるソフトウェアです。アライメントされたリードのbamファイルや、ゲノム上の位置情報にアノテーションを加えたbedファイル、遺伝子情報の書かれたgff3ファイルなどさまざまなファイルを閲覧することができます。bioinformaticsに関わったことがある方は、このソフトをご存知の方が多いのではないでしょうか。

GithubのIGVのリポジトリ
IGV.png
※画像はIGVのホームページより

そんなIGVですが、マウスでクリックしながら操作すると少し手間がかかることがあります。

  • リファレンスゲノムを指定して
  • 必要なファイルを読み込んで
  • 注目している場所を一つずつみてまわって
  • スクリーンショットをとって画像として保存する

目視で結果を確認することは楽しいことでもあり、とても大事な作業だと思いますが、一方で定型的な作業はなるべく自動化していきたいという気持ちもあると思います。そこでIGVの操作をプログラミング言語から行うことを考えます。

※ 最近はJavaScriptで作られたigv.jsというものが活発に開発されて広く使われるようになっているようです。これに関しては調査が不十分なのでこの記事では触れません。(しかしいずれはQiita記事にしてきたいと思います。)

ソケット通信を利用してIGVを操作する

実はIGVはソケット通信を利用してport 60151番から操作できるようになっています。

メニューバーの View > Preference の中に advanced というタブがあります。Enable portにチェックが付いていない時は、ここをチェックします。

image.png

するとport 60151番を使って、ソケット通信を利用してIGVを操縦することができるようになります。

IGVの操作に使えるコマンドの一覧

公式リファレンスをDeepL翻訳を使いながら日本語に翻訳してみました。

Command Description
new 新しいセッションを作成します。 デフォルトのゲノムアノテーション以外のすべてのトラックを取り除きます。
load file データまたはセッションファイルを読み込みます。フルパスまたはURLをカンマ区切りで指定します。
collapse trackName 指定されたtrackNameを折りたたむ。trackNameを指定しない場合はすべてのトラックが折りたたまれます。
echo レスポンスに "echo "を返します。 (テスト用)
exit IGVアプリケーションを終了します。
expand trackName 指定したtrackNameを展開します。trackNameを指定しない場合はすべてのトラックが展開されます。
genome genomeIdOrPath idでゲノムを選択、または指定されたパスからゲノム(インデックス化されたfasta)をロードします。
goto locus or listOfLoci 単一の遺伝子座またはスペースで区切られた遺伝子座のリストにスクロールします。リストが提供されている場合は、これらの座位が分割スクリーンビューで表示されます。 IGV検索ボックスで有効な構文ならどれでも大丈夫です。
goto all ゲノム全体の表示にスクロールします。
group option アライメントトラックのみ。 次のオプションのいずれかでアライメントをグループ化します。 STRAND, SAMPLE, READ_GROUP, LIBRARY, FIRST_OF_PAIR_STRAND, TAG, PAIR_ORIENTATION, MATE_CHROMOSOME, SUPPLEMENTARY, MOVIE, ZMW, HAPLOTYPE, READ_ORDER, NONE, BASE_AT_POS
region chr start end 2つの遺伝子座で囲まれた関心領域を定義します(例えば、region chr1 100 200)。
maxPanelHeight height 画像に含める各パネルの縦方向のピクセル数(高さ)を設定します。ポートコマンドまたはバッチスクリプトから作成された画像は、画面上に表示されるデータに限定されません。別の言い方をすれば、スクロール可能な画面領域に表示されている部分だけでなく、パネル全体を画像に含めることができます。この設定のデフォルト値は1000で、より多くのデータを表示するにはこの値を大きくし、より小さい画像を作成するにはこの値を小さくします。
setLogScale(true or false)
setSleepInterval ms 遅延(スリープ)時間をミリ秒単位で設定します。 スリープ間隔は、連続するコマンド間に呼び出されます。
snapshotDirectory path 画像を書き込むディレクトリを設定します。
snapshot filename IGV ウィンドウのスナップショットを画像ファイルに保存します。 filenameを省略した場合、軌跡に基づいて生成されたファイル名を持つPNGファイルを書き込みます。 filenameが指定された場合、ファイル名の拡張子によって画像ファイルの形式が決定され、.png、.jpg、または.svgでなければなりません。
sort option locus アライメントまたはセグメント化されたコピーナンバーのトラックをソートします。 セグメント化されたコピーナンバーのoptionに適応される値は、(1)セグメント化されたコピー番号のAMPLIFICATION と DELETION、(2)アライメントトラックのPOSITION、STRAND、BASE、QUALITY、SAMPLE、READGROUP、INSERSTSIZE、FIRSTOFPAIRSTRAND、MATECHR、READORDER、およびREADNAMEです。 optionは、大文字と小文字を区別しません。 locusを指定すると、単一の位置または範囲を定義することができます。 オプションを指定しない場合は、表示されている領域、または表示されている領域の中心位置に基づいてソートが実行されます。
squish trackName 与えられた trackName を Squish します。 trackName はオプションで、指定しない場合はすべてのアノテーショントラックが Squish されます。
viewaspairs trackName アライメントトラックの表示モードを "View as pairs "に設定します。
preference key value keyという名前の設定を指定した値に一時的に設定します。この設定は、IGVがシャットダウンされるまでのみ有効です。

IGVをプログラミング言語から操る

Java

IGVはJavaで開発されているソフトウェアなので、公式のexampleもJavaで書かれています。

  Socket socket = new Socket("127.0.0.1", 60151);
  PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
  BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

  out.println("load na12788.bam,n12788.tdf");
  String response = in.readLine();
  System.out.println(response);

  out.println("genome hg18");
  response = in.readLine();
  System.out.println(response);

  out.println("goto chr1:65,827,301");
  //out.println("goto chr1:65,839,697");
  response = in.readLine();
  System.out.println(response);

  out.println("snapshotDirectory /screenshots");
  response = in.readLine();
  System.out.println(response);

  out.println("snapshot");
  response = in.readLine();
  System.out.println(response);

R

さて、Java以外のプログラミング言語ではどうでしょうか。Rを使っている場合は、あまり詳しくないですが、bioconductorあたりからIGVを操作するライブラリが提供されているでしょうから、それを使えばよいでしょう。少し検索するだけでも igvRというソフトウェアがヒットします。これは igv.jsを活用するものらしいので、デスクトップのIGVを自動操作するものではないかも知れませんが…。

Python

少し古いスクリプトですが、最近精力的にNim言語を使用してバイオインフォマティックスのツールを開発されているBrent Pedersenさんが作成した igv.pyというツールがあります。これは上記のソケット通信をラップした小さなライブラリです。

Ruby

私はRubyが好きです。ナニナニ? ツールが少ない? それなら自分で作ってしまえばいいでしょうが!
ということで、上記のBrent Pedersenさんのスクリプトをまるっと参考にして、Ruby言語からIGVを操作できる ruby-igv というツールを作成しました。これでRuby言語からも簡単にIGVを操作できるようになります。

https://github.com/kojix2/ruby-igv

使い方はこんな感じです。

igv = IGV.new

igv.load 'na12788.bam'
igv.genome 'hg18'
igv.go 'goto chr1:65,827,301'
igv.save 'image.png'

まだ出来たてホヤホヤのツールです。
粗削りのところとか、バグとかに遭遇した場合、あるいは要望を見つけましたらぜひGithubのissueに報告してください。もちろんプルリクエストも歓迎します。

おわりに

 bioinformaticsに限らずですが、どうしても、どうすれば既存の道具を組み合わせて目的が達成できるか、どうすればツールを使いこなせるかという点に注目が集まりがちです。そして、せこせこと道具を作っていると、目的と手段が逆転しているなどという風にとらえられることもありえます。
 でもそれは、ある意味では、とてもセルフィッシュな視野の狭い考え方だと思うんですよね。もっと道具を作って公開する人がいれば、それだけ世界は便利になって広がって豊かになっていきます。みんなもっと自由に道具を作って公開しよう。(別にRubyじゃなくてもいいので)

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

これで分かった!最短マッチ

はじめに

正規表現で最短マッチというのがあるが、いくつかサンプルで動作を見ながら、どういう使い方をするのか確認してみよう。

内容

str = "ああああ「あ」い「うう」ええ「おおお」かかか"
このような文字列の中から、括弧で囲まれた部分のみ抽出したい(つまり、「あ」「うう」「おおお」の3ヶ所を抽出したい)場合、最短マッチを利用する事になります。

その前に、簡単な動きから確認してみよう。

は、1文字以上でマッチするため、この例ではマッチしません。

str = "ああああ「」"
puts str.scan(/「.+」/)
=>マッチしない

は、0文字以上でマッチするため、この例ではマッチします。

str = "ああああ「」"
puts str.scan(/「.*」/)
=>「」
次の場合はどうだろうか

の文字が1文字あるためマッチします。

str = "ああああ「あ」"
puts str.scan(/「.+」/)
=>「あ」

こちらも、の文字が0文字あるためマッチします。結果的に同じです。

str = "ああああ「あ」"
puts str.scan(/「.*」/)
=>「あ」
少し、本題に入ります

この例だと、最初に出現した、と、最終に出現した、で囲まれた部分でマッチしてしまいます。やりたい事はこれではありません。

str = "ああああ「あ」い「うう」ええ「おおお」かかか"
puts str.scan(/「.+」/)
=>「あ」い「うう」ええ「おおお」
で、どうすればいいか

を付加すれば、最短マッチをしてくれるようになります。

str = "ああああ「あ」い「うう」ええ「おおお」かかか"
puts str.scan(/「.+?」/)
=>「あ」「うう」「おおお」

おめでとうございます。:clap::clap::clap:

こうすればどうなる?

の代わりに、にしても結果的には同じではありますが・・・

str = "ああああ「あ」い「うう」ええ「おおお」かかか"
puts str.scan(/「.*?」/)
=>「あ」「うう」「おおお」

「」をマッチさせたいか、させたくないかで、を使い分ける事になります。

「」をマッチさせたくない場合は、1文字以上でマッチする、を使います。

str = "ああああ「あ」い「うう」ええ「おおお」かかか「」"
puts str.scan(/「.+?」/)
=>「あ」「うう」「おおお」

「」をマッチさせたい場合は、0文字以上でマッチする、を使います。

str = "ああああ「あ」い「うう」ええ「おおお」かかか「」"
puts str.scan(/「.*?」/)
=>「あ」「うう」「おおお」「」

C'est fini :sweat_smile:

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

[Rails]deviseにカラムを追加する

なんで書いた

deviseでユーザー認証を作るとemailとpasswordは最初からあるけど、ユーザー登録するのに名前は必要でしょ。といつも思ってるのでメモっとく。

前提

  • 既にdeviseのgem追加してること
  • rails g devise Userしてあること

カラムを追加する

DBにカラムを追加するときは、以下のような書き方をするのが一般的です。
とりあえず、そのマイグレーションファイルが何をするためのファイルがわかる名前にしましょう。

名前つけるとき、AddColumnToUsersって書いて「ユーザーテーブルにカラム追加する」みたいな意味だと、次カラム追加する時名前困るので注意。そもそもカラムを追加することになる=DB設計ちゃんとしろってことなのかと思ったりしてますが、この辺はまだまだ知識が浅いので強い方教えて欲しいです。

$ rails generate migration Addカラム名Toテーブル名 追加するカラム:データ型
$ rails generate migration AddNameToUsers name:string
XXXXXXXXXXX_add_name_to_users.rb
class AddNameToUsers < ActiveRecord::Migration[5.2]
  def change
    add_column :users, :name, :string
  end
end
$ rails db:migrate

ControllerとViewの修正

registrations/new.html.erb
<h2>Sign up</h2>

<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
  <%= render "devise/shared/error_messages", resource: resource %>

    # ここから追加
 <div class="field">
    <%= f.label :name %><br />
    <%= f.text_field :name, autofocus: true %>
  </div>
    # ここまで

  <div class="field">
    <%= f.label :email %><br />
    <%= f.email_field :email, autofocus: true, autocomplete: "email" %>
  </div>

  <div class="field">
    <%= f.label :password %>
    <% if @minimum_password_length %>
    <em>(<%= @minimum_password_length %> characters minimum)</em>
    <% end %><br />
    <%= f.password_field :password, autocomplete: "new-password" %>
  </div>

  <div class="field">
    <%= f.label :password_confirmation %><br />
    <%= f.password_field :password_confirmation, autocomplete: "new-password" %>
  </div>

  <div class="actions">
    <%= f.submit "Sign up" %>
  </div>
<% end %>

<%= render "devise/shared/links" %>

Viewから飛んできたnameの情報を受け取れるようにしたいので、
application_controller.rb
に以下を追記します。

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

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

以下のコードをapplication.html.erbへ記述します。
current_userはdeviseが提供しているメソッドの一つで、ログインしているユーザーの情報を取得することができます。

application.html.erb
<% if current_user.present? %>
  <p>こんにちは、<%= current_user.name %>さん!</p>
<% else %>
  <p>こんにちは、ゲストさん!</p>
<% end %>

うまく表示されていればOK!

スクリーンショット 2020-07-22 17.47.14.png

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

Rails6で作ったアプリをGitHubへプッシュしたい

手順

0.設定 (複数人で開発する場合)

ターミナル
$ git config --global user.name "名前"
$ git config --global user.email xxx@xxx.com #アドレス

1.rails newで作られたgitリポジトリの初期化

ターミナル
$ git init #初期化

2.gitリポジトリへデータを追加してcommitする

ターミナル
$ git status #ファイルの状態を確認する
$ git add -A #保存するファイルを指定する -Aは全ファイル追加、ファイル名を指定して1つずつ追加することもできる
$ git commit -m "メッセージ内容"

3.GitHubでpush先のリポジトリを立ち上げる

github 1.png

4.GitHubへプッシュする

ターミナル
$ git remote add origin https://github.com/tkse16/sumple_app.git #GitHubのリポジトリとoriginを紐つける
$ git push -u origin master #GitHubへプッシュする。-uはなくてもいい

以上!

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

RFC emaillバリデーション

 #不備メアド  理由     
 h-1.k-4.@  @前の記号     
 zkl.106.302.@  @前の記号     
 gaboratory.u.s.a.@  @前の記号     
 k.t_0807_@  @前の記号    RFC違反ではない 
 rspone/fine@  使用不可記号    RFC違反ではない 
 hiro.0308-_-@  @前の記号&記号の連続使用    RFC違反ではない 
 taeko.iwahashi.@  @前の記号     
 t_h_@  @前の記号    RFC違反ではない 
 t496y519k018...@  @前の記号&記号の連続使用     
 yu.ya.to.mi.@  @前の記号     
 akn-szn-sck-hdk...@  @前の記号&記号の連続使用      h-1.k-4.@ 
 zkl.106.302.@ 
 gaboratory.u.s.a.@ 
 k.t_0807_@ 
 rspone/fine@ 
 hiro.0308-_-@ 
 taeko.iwahashi.@ 
 t_h_@ 
 t496y519k018...@ 
 yu.ya.to.mi.@ 
 akn-szn-sck-hdk...@ 

なメアドにバリデーションを引っかからせたい

URI::MailTo::EMAIL_REGEXPで定義されているところから、ダメな文字の/を抜いて、@の前に記号が入らないように書きました

[4] pry(main)> URI::MailTo::EMAIL_REGEXP
=> /\A[a-zA-Z0-9.!\#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*\z/
/\A[a-zA-Z0-9.!\#$%&'*+\/=?^_`{|}~-]{0,63}[a-zA-Z0-9]@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*\z]/

作成URL regulex

だけど実際/はRFC違反の記号じゃないみたい
ドットの連続が違反らしい

@ の前が、最大64文字
@ の後ろが、最大253文字
全部での最大が、最大254文字
ですね。

結局

なので結局どうなったかというと
バリデーションは
1, URI::MailTo::EMAIL_REGEXPを使う
2, URI::MailTo::EMAIL_REGEXPでチェックできてない、一文字目のドット、連続ドット、@直前のドット の3つを弾くように追加

追加バリデーションについて

value =~ /^[.]/ #一文字目のドット禁止
value =~ /\.{2,}/ #連続ドット禁止
value =~ /(?<=\.)@/ #@直前のドット禁止 #肯定後読み

こんなURLは全弾きされます

.??..@aa.com

Qiita でまとめてくれている人がいました。
RFC 5322 & 5321に沿ったメールアドレス(local-part)に使える文字まとめ

肯定後読み参考url
こんどこそわかる(肯|否)定(先|後)読み
直後に~がある文字列、直後に~がない文字列、にパターンマッチさせる正規表現

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

【メモ】bundle installとupdateの違い

bundle install しようとすると bundle updateしてくれと怒られた。

調べたところ・・・

ターミナル
$ bundle install #bundle に省略可能

Gemfile.lockの内容をbundle install前と比較し、更新されているgemのみをインストールする

ターミナル
$ bundle update

Gemfile.lockの内容を無視して全てのgemをインストールする


以上!

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

Railsでアプリケーションを起動する際にffiのインストールに失敗した時の対処法

Ruby on RailsでRailsのバージョンインストールには成功したものの、Railsのアプリケーションを起動した際に以下のようにffiのインストールに失敗しました。
その際に行なった対処法を残しておきます。

エラーメッセージ

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

原因

おそらくMacOSのMojave環境に原因があるらしいです。
原因としては、HomebrewでRubyをインストールするとどうやらffiが無いそうです。

解決方法

まず、ffiがないのでMojave用のlibffiを再インストールします。以下の方法で再インストールします。

brew reinstall libffi

ただ、現状ではlibffiのパスが見えない場所にあるので指定します。

export LDFLAGS="-L/usr/local/opt/libffi/lib" && \
export PKG_CONFIG_PATH="/usr/local/opt/libffi/lib/pkgconfig" && \
bundle install

これでffiのインストールエラーがなくなりrailsのアプリケーションが起動できました!

参照記事

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

いいね機能の実装

目次

ルーティング追加

config/routes
resources :post_images, only: [:new, :create, :index, :show] do
  resource :favorites, only: [:create, :destroy]  resources :post_comments, only: [:create, :destroy]
end

いいねテーブル作成

$ rails g model Favorite user_id:integer post_image_id:integer

マイグレーション=>データベース反映

$ rails db:migrate
app/models/user.rb
class User < ApplicationRecord
 ...
  has_many :favorites, dependent: :destroy
 ...
app/models/post_image.rb
class PostImage < ApplicationRecord
...
  has_many :favorites, dependent: :destroy
  def favorited_by?(user)
    favorites.where(user_id: user.id).exists?
  end
end
...
app/models/favorite.rb
class Favorite < ApplicationRecord

  belongs_to :user
  belongs_to :post_image
end

controller作成

$ rails g controller Favorites
app/controllers/favorites_controller.rb
class FavoritesController < ApplicationController

   def create
    post_image = PostImage.find(params[:post_image_id])
    favorite = current_user.favorites.new(post_image_id: post_image.id)
    favorite.save
    redirect_to post_image_path(post_image)  end

  def destroy
    post_image = PostImage.find(params[:post_image_id])
    favorite = current_user.favorites.find_by(post_image_id: post_image.id)
    favorite.destroy
    redirect_to post_image_path(post_image)  end
end

viewを編集

app/views/post_images/show.html.erb
<% if @post_image.favorited_by?(current_user) %>
<li>
  <%= link_to post_image_favorites_path(@post_image), method: :delete do %>
    <i class="fa fa-heart" aria-hidden="true" style="color: red;"></i>
    <%= @post_image.favorites.count %> いいね
  <% end %>
</li>
<% else %>
<li>
  <%= link_to post_image_favorites_path(@post_image), method: :post do %>
    <i class="fa fa-heart-o" aria-hidden="true"></i>
    <%= @post_image.favorites.count %> いいね
  <% end %>
</li>
<% end %>

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

Rubyでちょっとずつポーカーを実装する その5

前回の記事

その1その2その3その4

その5のゴール

その1で@r12tkmtさんから受けたアドバイスを元にリファクタリングする。

カードの情報をクラスを切ってもよいかも

Cardクラスを切って、suitとnumberをinitializeで受け取るようにする

カード一枚一枚を連想配列{suit: suit, num: num}で管理していたのを、以下のようなCardクラスに変更しました。

card.rb
class Card
  SUITS = [:♠︎, :♣︎, :, :♦︎]

  def initialize(suit, num)
    @num = num
    @suit = suit
  end
end

コミット履歴がこちら

suitはSymbolとし、画面表示用に記号を返却するメソッド

suitのSymbolを表す定数の配列と、それを画面表示用に戻すMARKという定数の連想配列を作りました。ついでに、11はJ(ジャック)、12はQ(クイーン)、13はK(キング)と表示されるようにするようにしました。

card.rb
class Card
  SUITS = [:spade, :heart, :diamond, :clover]

  MARK = {
    spade: "♠",
    heart: "♡",
    diamond: "♢",
    clover: "♣",
    1 => "A",
    11 => "J",
    12 => "Q",
    13 => "K"
  }

~省略~

  def show
    corresponding_mark(@suit) + corresponding_mark(@num)
  end

  def corresponding_mark(sym)
    if MARK[sym]
      return MARK[sym]
    else
      return sym.to_s
    end
  end
end

コミット履歴はこちら

playerが役の判定までがっつり持ちすぎでは?

役の判定を別のmoduleなどに切り出す

役の判定をするplayer.judgeメソッドを、JudgeHandというmoduleを作って分けました。手札を引数として渡すと役が文字列で返ってきます。
結局、このmoduleはplayerクラスがincludeするので、playerが役割持ちすぎ問題は解決していないです?理由はplayerのインスタンス変数のhands配列(手札)の受け渡しが楽なので。どう書いたら良かったのか…

コミット履歴はこちら

symbolで役名を返すようにし勝敗判定を数値の比較する

どう書いていいか思い浮かばなかったので、一旦放置としました?

その5のコード

https://github.com/paraizo2424/poker_game/commit/7fc417a84faac4b68a70743b2751fa19d1229340

次回

その6製作中

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

STIパターンでtweet機能を作った学習記録

この記事の内容は現在レビュー待ちなので変更あるかもです!

STI(単一テーブル継承)とは

文字通り一つのテーブルを親クラスから子クラスに継承させる事!
今回の場合、親Tweet→ 子Mediatweet Texttweetになります。それぞれメディアツイートとテキストツイート用のクラスです!

といっても、テーブルが同じなので、親も子も全てのクラスが同じカラムを持ってます。
なのでMediatweetにもcontentカラムがありますし、Texttweetにもimgカラムがあります。

db/schema.rb
  create_table "tweets", options: hogehoge
    t.text "content"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.string "img"
    t.integer "user_id"
    t.string "type"
  end

何故そうするのか

モデル事に差分を書き分けやすくなります。
例えば空欄無効のバリデーションをtexttweetにだけ書くと、画像はテキスト無しのツイートが可能になります。
でもほぼ同じ内容なので、テーブルは共有できちゃうSTIが良いのでは、というわけです。

実装方法

1、しれ〜っとdb/schema.rbに既にありましたが、親クラス(テーブル)にtypeカラム(string型)を持たせます。
2、各モデルを作ります。親モデルはrails g modelなどで作って子モデルなどはapp/model/に直接作ります

models/tweet.rb
class Tweet < ApplicationRecord
end
models/mediatweet.rb
class Mediatweet < Tweet
end
models/texttweet.rb
class Texttweet < Tweet
end

とりあえずこれだけでSTIの実装は終わりです。あとは、自動でやってくれます。
例えばこれでMediatweet.create等でデータベース登録すればtypeカラムにMediatweetとデータが入ったレコードが追加されます。

form_withで取得したparamsの内容でモデル振り分け

メディアデータがあるかどうかで自動的にモデルを振り分けたいので下記のように実装しました。

index.html.erb
<%= form_with model: @tweet, url: tweets_path do |form| %>
  <%= form.text_area :content %><br>
  <%= form.label "画像をアップロード" %><br>
  <%= form.file_field :img %>
  <%= form.submit '投稿' %><br>
<% end %>

今回は、indexにそのまま投稿フォームがある投稿兼一覧ページです。
画像のアップローダーについてはcarriewaveで実装しています。そこについては割愛します。
上記フォームからsubmitして送られるパラメータは

{
"authenticity_token"=>"hoge", 
"tweet"=>{"content"=>"hoge", "img"=>"hoge"}, 
"commit"=>"投稿"
}

こんな感じの二重構造({}の中に{}がある構造)のパラメータが取得できます。

ちなみにですが
form_withで model: を指定するとこのような構造になり、url:のみ指定すると二重構造になりません。
僕はこれがわかってなくてかなりハマってました、、、

そしてコントローラーのcreateアクションへ自動でマッチします

tweets_controller.rb
  def create
    @tweet = tweettype_class.new(tweet_params)
    if @tweet.save
      redirect_to("/tweets")
    else
      @tweets = Tweet.all.order(created_at: :desc)
      render("index")
  #レンダリングで元の投稿件一覧ページに戻りますこの際、form_withのurlを指定していないと、
  #form_withのルートが子モデルに引っ張られてエラーになります(例)元teets_path レンダリング後→texttweets_pathでno muchになる。
    end
  end
  private

  def tweet_params
  #requireでキーがtweetの部分だけ抽出してます({"content"=>"hoge","img"=>"hoge"})
    params.require(:tweet).permit(:content, :img).merge(user_id: @current_user.id)
  end
  #[:img]のデータの有無でモデルを振り分けています
  #二重構造なのでキーも二重に指定しないと正しく値がとれません
  def tweettype
    case
    when params[:tweet][:img].present?
      'mediatweet'
    when params[:tweet][:img].blank?
      'texttweet'
    end
  end
  #もらった文字列をキャメルケースに変換して,さらに定数名に変換しています
  #(例)mediatweet.cmelize=>Mediatweet.constantize=>Mediatweet(id: integer, content: text, created_at: datetime, hogehoge.... )
  def tweettype_class
    tweettype.camelize.constantize
  end

こんな感じで、画像がアップロードされたかどうかで自動でモデルを振り分けてみました。

こうすることで、それぞれのモデルで役割を書きわけやすくなりました!

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

Rails tutorial 1.3.2でRailsページが表示されない時の対処法

記事作成日:2020/07/21

自己紹介

こんにちは。
最近、プログラミングを勉強し始めたおかむと申します。
初めて記事を投稿するので、拙い部分があるかと思いますがご了承ください。

内容

さて、本題に入っていきます。
Ruby on Rails チュートリアル Rails6.0(第6版)にて、Rails tutorialを進めていた途中つまづいた所があったので、つまづいた所と私が行った対処法を共有したいと思います。

つまづいた所

Rails tutorial Rails6.0(第6版)←有料のやつ
1.3.2 rails server
という章のrails serverを起動し、Railsページを表示させるところで表示されるページが違うという点でつまづきました。
↓このような画面が表示されるはずが
スクリーンショット 2020-07-21 03.53.24.png
↓このような画面が表示されてしまいました。
https3A2F2Fqiita-image-store.png

対処法

上のような所でつまづいたのですが、検索をしながら対処したら表示できたので対処法を述べます。
簡単に述べると

  • Cloud9を落とす
  • awsマネジメントコンソールを開きEC2を検索する
  • Cloud9のインスタンスを停止する
  • 再度Cloud9で画面を表示するとチュートリアル通りの画面が表示される

このような方法です。
言葉だけだと説明しづらいので以下に画像を載せながら説明していきたいと思います。

まず、「Cloud9を落とす」
これはWindowsだったら×ボタン、Macだったら左上の×ボタンをCloud9を開いた状態で押します。
スクリーンショット 2020-07-21 03.53.24.png

次に「awsマネジメントコンソールを開きEC2を検索する」
これはCloud9を開いた時のようにawsを開き、サービスの検索欄に「EC2」と入力し、そのサービスを開きます。
スクリーンショット 2020-07-21 22.05.37.png

そして「Cloud9のインスタンスを停止する」
EC2を開いたら、そのアカウントで使用しているインスタンスの一覧が表示されます。
その中で緑色の丸でrunningと書かれているインスタンスがあると思うので、そのインスタンスのチェックマークにチェックをします。
チェックをしたら、画面上部にあるアクションボタンをクリックし、メニューが出てくるので「インスタンスの状態」→「停止」クリックします。
スクリーンショット 2020-07-21 22.07.08.png

そしたら以下のような警告が出てくると思うのですが、無視して「停止する」ボタンを押してください。
スクリーンショット 2020-07-22 01.49.10.png

以上の段階を踏み、再度Cloud9で画面を表示するとチュートリアル通りの画面が表示される。
スクリーンショット 2020-07-21 03.53.24.png
私は、この方法で表示させることができました。
皆様の参考になれば幸いです。

参考にした記事

https://qiita.com/taraka/items/0c98afb92c93ebae4947

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

rubyでドローポーカーを作ってみる~準備編~

きっかけ

@paraizo2424
Rubyでちょっとずつポーカーを実装する その1

こちらを見たときにいいチャレンジだな~と思いコメントを入れたのですが
はたして自分はアドバイスできるほどの技術力があるのだろうか?
まだまだアドバイスをもらう側ではないのか?

と考えたときに、自分ならどう設計・実装するのか?を改めて整理しながら
自分との見つめ合い ということで作ってみようと思いました

仕事でrubyを使っていますが、入社当初はruby何それ?って名前くらいしか知らないレベルだったため
そういう意味も込めて振り返れたらなと思います

まずポーカーのルールを整理

参考: https://playingcards.jp/game_rules/drawpoker_rules.html

使用カード

  • 全スートの1~13 + ジョーカーあり?
    • 今回はjoker無しで行きます
    • もしかしたら追加するかも?

プレイヤー

  • 2..7

ルール

  1. 各プレイヤーに山札から5枚ずつ配る
    • 各プレイヤーは5枚を周りに見せない
  2. 各プレイヤー順番に、1回のみ好きな枚数カードの交換が可能
  3. 各プレイヤー手札を見せ、手札の組み合わせ(役)に応じて勝敗が決まる
    • 本来はここにベット(掛け金)があり、これを得るための勝負となる
    • 今回はひとまずベットも無しとする

  • 下記の上から順番に強い役となる
    • ロイヤルストレートフラッシュ
      • 同じマークの10、J、Q、K、Aをそろえる
    • ストレートフラッシュ
      • 同じマークで、5枚の数字が連続する
    • フォーカード
      • 同じ数字のカードが4枚ある
    • フルハウス
      • スリーカードとワンペアが1組ずつできる
    • フラッシュ
      • 同じマークのカードが5枚ある
    • ストレート
      • マークに関係なく5枚の数字が連続する
      • (10-J-Q-K-AはストレートとなるがQ-K-A-2-3はストレートにならない
      • すなわちKとAは連続するがK-A-2含むものはストレートにはならない)
    • スリーカード
      • 同じ数字のカードが3枚ある
    • ツーペア
      • 同じ数字のカードが2組ある
    • ワンペア
      • 同じ数字のカードが1組だけある
  • 2人のプレイヤーが同じ役を作った場合は、役を構成しているカードの強い方が勝ちとなる
    • カードの強い順位は、A・K・Q・J・10~2
    • スートの強い順位は、スペード・ハート・ダイヤ・クローバー
  • 役を構成しているカードも同じ場合は、役に使われていないカードが強い方が勝ちとなる

疑問点

  • 捨てたカードは公開する?
    • 公開しないらしい
  • フルハウス同士の比較は?
    • フルハウス同士の場合は、3 枚 1 組のカードのランク
  • ストレート同士の比較は?
    • 一番強いカードで比較
  • ストレートの小技
    • > 注意: エースに限りランクが一番上または一番下のカードとして使用できます。 最も強いストレートは A-K-Q-J-T (エースハイ)、最も弱いストレートは 5-4-3-2-A (ファイブハイ) です。

参考
- https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q11159415671
- https://www.pokerstars.com/ja/poker/games/rules/hand-rankings/?no_redirect=1

今回の実装範囲の決定

  • ベットが無いため連続した勝負とはせず1回の勝負の実行とする
  • 画面などの作り込むのは面倒なのとrubyのクラス設計・実装などを目的とするため、コンソールでの実行とする
  • 全プレイヤーが交換を行うようにしないと最初の5枚で勝負というのは厳しいと思うため、全プレイヤーを実行者が操作するものとする(勝負の意味w)

実装環境の決定

  • ruby2.6.5を使用
  • test-unitを使用
    • 普段は仕事ではrspecしか使用していないためせっかくなので触ってみる

登場人物の整理

なんと表現するのが適切かわかりませんが、モノと、モノではないもの(= 概念)という意味で分けてみる

モノ

  • カード
  • プレイヤー

概念

  • 山札
    • カード全て
  • 手札
    • 山札から配られた各プレイヤーの手札(5枚)
    • 手札の中の組み合わせ
    • 下記を持つ
    • 役の種別
    • 役の中での強さ

ソース

https://github.com/rytkmt/ruby_poker

これから作っていくため、まだ空で作成したのみです。
ここから。楽しみ。

続き


rubyでドローポーカーを作ってみる~test-unit準備編~

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

【Rails】devise 導入方法

deviseとは

  • Railsで作成したアプリケーションへ簡単に認証機能を実装することができるgem(ライブラリ)の一つ
  • ログイン、サインアップなどのログイン機能が作成出来る

導入方法

①Gemfileに追加

Gemfile
gem 'devise'

② bundle install を実行

ターミナル
$ bundle install

③設定ファイルを作成

ターミナル
$ rails g devise:install
新規作成されるファイル
config/initializers/devise.rb
config/locales/devise.en.yml

④deviseの機能を持ったUserモデルを作成

ターミナル
$ rails g devise user
新規作成されるファイル
app/models/user.rb
db/migrate/20XXXXXXXXXXXX_devise_create_users.rb
test/fixtures/users.yml
test/models/user_test.rb

⑤deviseのviewファイルを作成

ターミナル
$ rails g devise:views
新規作成されるファイル
app/views/devise #以下のディレクトリにあるビューファイル各種

これで、deviseの導入が完了します

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