20200803のRubyに関する記事は18件です。

active_hashを使って疑似モデルを作ろう 〜都道府県データ〜

某メルカリコピーサイト作成中

active_hash

データベースを作ることなく擬似的にモデルを作成しデータを入れることができる

とのことなので active_hash なるgemを使ってみます

まずGemfileにactive_hashを追加

gem 'active_hash'

bundle install します

Model

でモデルファイルを作っていくんですが
今回は rails g model では作成しない様

普段はApplicationRecordを継承してるけど、
active_hashを使用するモデルはActiveHash::Baseを継承する必要があるからみたい

なので直接 app/models/ に作成していきます

prefecture.rb
class Prefecture < ActiveHash::Base

end

こんな感じで ActiveHash::Base を継承します

データの雛形はこんな感じ

prefecture.rb
class Prefecture < ActiveHash::Base

  self.data = [ ]

end

この中にデータを入れていきます

prefecture.rb
class Prefecture < ActiveHash::Base

  self.data = [
      {id: 1, name: '北海道'}, {id: 2, name: '青森県'}, {id: 3, name: '岩手県'},
      {id: 4, name: '宮城県'}, {id: 5, name: '秋田県'}, {id: 6, name: '山形県'},
      {id: 7, name: '福島県'}, {id: 8, name: '茨城県'}, {id: 9, name: '栃木県'},
      {id: 10, name: '群馬県'}, {id: 11, name: '埼玉県'}, {id: 12, name: '千葉県'},
      {id: 13, name: '東京都'}, {id: 14, name: '神奈川県'}, {id: 15, name: '新潟県'},
      {id: 16, name: '富山県'}, {id: 17, name: '石川県'}, {id: 18, name: '福井県'},
      {id: 19, name: '山梨県'}, {id: 20, name: '長野県'}, {id: 21, name: '岐阜県'},
      {id: 22, name: '静岡県'}, {id: 23, name: '愛知県'}, {id: 24, name: '三重県'},
      {id: 25, name: '滋賀県'}, {id: 26, name: '京都府'}, {id: 27, name: '大阪府'},
      {id: 28, name: '兵庫県'}, {id: 29, name: '奈良県'}, {id: 30, name: '和歌山県'},
      {id: 31, name: '鳥取県'}, {id: 32, name: '島根県'}, {id: 33, name: '岡山県'},
      {id: 34, name: '広島県'}, {id: 35, name: '山口県'}, {id: 36, name: '徳島県'},
      {id: 37, name: '香川県'}, {id: 38, name: '愛媛県'}, {id: 39, name: '高知県'},
      {id: 40, name: '福岡県'}, {id: 41, name: '佐賀県'}, {id: 42, name: '長崎県'},
      {id: 43, name: '熊本県'}, {id: 44, name: '大分県'}, {id: 45, name: '宮崎県'},
      {id: 46, name: '鹿児島県'}, {id: 47, name: '沖縄県'}
  ]

end

この様にハッシュ形式で入れていきます


次にアソシエーション

product.rb
class product < ApplicationRecord

  extend ActiveHash::Associations::ActiveRecordExtensions
  belongs_to_active_hash :prefecture

end

今回はproductテーブルと紐付けるのでproduct.rbに記述します

通常はbelongs_toですがactive_hashの場合はbelongs_to_active_hashになります

prefecture.rb
class Prefecture < ActiveHash::Base

  self.data = [
      {id: 1, name: '北海道'}, {id: 2, name: '青森県'}, {id: 3, name: '岩手県'},
      {id: 4, name: '宮城県'}, {id: 5, name: '秋田県'}, {id: 6, name: '山形県'},
      {id: 7, name: '福島県'}, {id: 8, name: '茨城県'}, {id: 9, name: '栃木県'},
      {id: 10, name: '群馬県'}, {id: 11, name: '埼玉県'}, {id: 12, name: '千葉県'},
      {id: 13, name: '東京都'}, {id: 14, name: '神奈川県'}, {id: 15, name: '新潟県'},
      {id: 16, name: '富山県'}, {id: 17, name: '石川県'}, {id: 18, name: '福井県'},
      {id: 19, name: '山梨県'}, {id: 20, name: '長野県'}, {id: 21, name: '岐阜県'},
      {id: 22, name: '静岡県'}, {id: 23, name: '愛知県'}, {id: 24, name: '三重県'},
      {id: 25, name: '滋賀県'}, {id: 26, name: '京都府'}, {id: 27, name: '大阪府'},
      {id: 28, name: '兵庫県'}, {id: 29, name: '奈良県'}, {id: 30, name: '和歌山県'},
      {id: 31, name: '鳥取県'}, {id: 32, name: '島根県'}, {id: 33, name: '岡山県'},
      {id: 34, name: '広島県'}, {id: 35, name: '山口県'}, {id: 36, name: '徳島県'},
      {id: 37, name: '香川県'}, {id: 38, name: '愛媛県'}, {id: 39, name: '高知県'},
      {id: 40, name: '福岡県'}, {id: 41, name: '佐賀県'}, {id: 42, name: '長崎県'},
      {id: 43, name: '熊本県'}, {id: 44, name: '大分県'}, {id: 45, name: '宮崎県'},
      {id: 46, name: '鹿児島県'}, {id: 47, name: '沖縄県'}
  ]

  include ActiveHash::Associations
  has_many :users

end

prefecture側はこの様に

あとは表示させるだけ!!

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

AWS Elastic Beanstalk + Rails環境でnginxのconfがうまく反映されない場合

■方法
公式ドキュメントの通り、[.platform]配下にファイルを配置すれば反映されると思います。

~/workspace/my-app/
|-- .platform
|  `-- nginx
|    `-- conf.d
|      `-- myconf.conf
`-- other source files

■公式ドキュメント
・Elastic Beanstalk Linux プラットフォームの拡張
https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/platforms-linux-extend.html

■おまけ
どうして公式に記載されている内容をわざわざ投稿したのかというと、全然検索に引っかからないからです。
[413 Request Entity Too Large]エラー対応でconfを編集する必要があり、
調べると2通りの記述方法が引っかかりました。

  1. [.ebextensions]配下に[nginx]を置く
  2. [.ebextensions]配下に[01_XXX.config]みたいなファイルを置く

この二つを延々試してたんですがウンともスンとも言わず、調べても他の方法が全然引っかからず・・・
デプロイ中にドキュメントを眺めてたら上記の内容を見つけた次第です。

JavaやGoの場合は[.ebextensions]に配置する方法が書かれており、
「Railsでも同じ形でいけるよ!!」って記事が上位に引っかかるのもハマりやすいポイントかと思います。(めちゃくちゃハマりました。)
・Increasing client_max_body_size in Nginx conf on AWS Elastic Beanstalk
https://stackoverflow.com/questions/18908426/increasing-client-max-body-size-in-nginx-conf-on-aws-elastic-beanstalk

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

フォロー機能(Ajax)実装

自分用にまとめます。

実装

モデル作成

$ rails g model Relationship follower_id:integer followed_id:integer
$ rails db:migrate


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

20200723070930_create_relationships.rb
class CreateRelationships < ActiveRecord::Migration[5.2]
  def change
    create_table :relationships do |t|
      t.integer :follower_id, null: false
      t.integer :followed_id, null: false

      t.timestamps
    end
  end
end


relationship.rb
class Relationship < ApplicationRecord

  # フォローするユーザー
  belongs_to :follower, class_name: 'User'
  # フォローされるユーザー
  belongs_to :followed, class_name: 'User'

  validates :follower_id, presence: true
  validates :following_id, presence: true

end

class_name: 'User':「followerもfollowedもUserにいるよ」という意味


app/models/user.rb
class User < ApplicationRecord

  # フォロー取得
  has_many :follower, class_name: 'Relationship', foreign_key: 'follower_id', dependent: :destroy

  # フォロワー取得
  has_many :followed, class_name: 'Relationship', foreign_key: 'followed_id', dependent: :destroy

  # 自分がフォローしている人
  has_many :following_user, through: :follower, source: :followed

  # 自分をフォローしている人(フォロワー)
  has_many :follower_user, through: :followed, source: :follower


  # ユーザーをフォローする
  def follow(user_id)
    follower.create(followed_id: user_id)
  end

  # ユーザーのフォローを外す
  def unfollow(user_id)
    follower.find_by(followed_id: user_id).destroy
  end

  # フォロー確認を行う
  def following?(user)
    following_user.include?(user)
  end

end


コントローラ作成

$ rails g controller relationships


config/routes.rb
Rails.application.routes.draw do

  post 'follow/:id', to: 'relationships#follow', as: 'follow'
  post 'unfollow/:id', to: 'relationships#unfollow', as: 'unfollow'
  get 'users/following/:user_id', to: 'users#following', as: 'users_following'
  get 'users/follower/:user_id', to: 'users#follower', as: 'users_follower'

end


users_controller.rb
class UsersController < ApplicationController

  # @userがフォローしているユーザー一覧
  def following
    @user = User.find(params[:user_id])
    @followings = @user.following_user
  end

  # @userをフォローしているユーザー一覧
  def follower
    @user = User.find(params[:user_id])
    @followers = @user.follower_user
  end

end


relationship_controller.rb
class RelationshipsController < ApplicationController

    # フォローする
    def follow
      @user = User.find(params[:id])
      current_user.follow(params[:id])
      render :create
    end

    # アンフォローする
    def unfollow
      @user = User.find(params[:id])
      current_user.unfollow(params[:id])
      render :destroy
    end

end

renderでcreate.js.erbとdestroy.js.erb呼び出すことで、
ページ遷移なしでフォロー・解除が行えるようになる。


users/show.html.slim
# create.js.erbとdestroy.js.erbで書き換えるため記述必須
div id="follow_form"

  # フォローボタン部分をパーシャルで飛ばす
  = render 'relationships/follow', user: @user 


_follow.html.slimファイルをrelationshipsディレクトリ配下に手動で作成
パーシャルで飛ばしたフォローボタン部分の記述を貼り付ける。

relationships/_follow.html.slim
- unless user == current_user
  - if current_user.following?(user)

    # jsファイルを呼び出すためにremote: trueを追記
    = link_to unfollow_path(user), method: :post, remote: true, class: 'btn btn-outline-info m-0 btn-sm' do
      i.fas.fa-user フォロー中
  - else

    # jsファイルを呼び出すためにremote: trueを追記
    = link_to follow_path(user), method: :post, remote: true, class: 'btn btn-outline-success m-0 btn-sm' do
      i.far.fa-user フォローする


create.js.erbファイルをrelationshipsディレクトリ配下に手動で作成

relationships/create.js.erb
# id="follow_form"部分を_follow.html.slimの内容にページ遷移なしで書き換える
$('#follow_form').html("<%= j(render 'relationships/follow',{ user: @user }) %>");


destroy.js.erbファイルをrelationshipsディレクトリ配下に手動で作成

relationships/destroy.js.erb
# id="follow_form"部分を_follow.html.slimの内容にページ遷移なしで書き換える
$('#follow_form').html("<%= j(render 'relationships/follow',{ user: @user }) %>");

完成!

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

Rails + postgres で jsonb の中の Array をクエリする方法

難しかったのでメモ

データの形

こんな感じのが jsonb のカラムの中に保存されている。

{
  hoge: String,
  items: String[]
}

やりたいことと解決策

それでやりたいのは items の中に特定の文字列 ["a", "b", "c"] のいずれかが含まれているものをクエリすること。

結論としては次のようなコードでいけた。

items_to_query = ["a", "b", "c"]
Model.where("jsonbColumnName -> 'items' @> ?", items_to_query.to_json)

参考

https://stackoverflow.com/questions/35737931/rails-postgres-query-with-jsonb-array
https://www.postgresql.org/docs/9.4/functions-json.html

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

Graphql-rubyでのエラーハンドリング

はじめに

最近、graphql-rubyでAPIを実装しています。
そこで、graphqlでのエラーハンドリングについて、ベストプラクティスを模索してみました。
まだ始めたばかりなので、もっといい方法あるよ!っていうコメント募集中です。

エラーの分類

エラーハンドリングの実装に移る前にエラーにはいくつか種類があるので、紹介します。
以下の記事が非常にわかりやすく、まとまっていたので参考にしています。

Railsアプリケーションにおけるエラー処理(例外設計)の考え方

ここでは、以下のように異常系と準異常系の2つに分類します。

  • 異常系:nwエラーや、プログラムのエラー(システムエラー)
  • 準異常系:作り手が予期できるエラー(業務エラー)

この2種類のエラーに対して、以下のような要件があります。

  • 異常系:フロント側でテンプレートメッセージを表示 & 開発者に通知
  • 準異常系:エラー内容や回避方法をフロント側(この辺りは要件によって変わってくるかもしれません)

肝となるのは、異常系は決まったテンプレートのメッセージを表示するが、準異常系はAPIからメッセージを送るというところです。この要件をどのように実装させるかが本題となります。

Graphql-rubyの仕様

graphql-rubyでは、エラーの場合以下のようなerrorsをkeyにしたjsonが返ってきます。

"errors": [
    {
      "message": "error message",
      "locations": [],
      "extensions": {
        "code": "ERROR_CODE"
      }
    }
  ]

このエラーメッセージは、主にインターフェイスでバグがあったりすると発生します。
例えばフロント側で渡す引数にnullが入ってるとき等です。

上のようなエラーは以下のように直接コードを書いて発生させることもできます。

sample.ruby
raise GraphQL::ExecutionError.new('error message', extensions: {code: "ERROR_CODE"})

実装

上記の仕様から異常系のエラーはerrorsが戻り値で返ってくることがわかります。
では準異常系はどうでしょうか?準異常系の要件は以下です。

  • 画面に表示するエラーメッセージを渡す
  • フロントが準異常系エラーと判断できる

まず1つ目の要件は上記のgraphqlエラーをraiseする方法でエラーメッセージを渡せるのでokです。しかし、そのままではフロント側で異常系のエラーと区別ができません。

そこで以下のようにjsonをカスタマイズすることにしました。

sample.ruby
raise GraphQL::ExecutionError.new('error message', extensions: {customCode: "ERROR_CODE"})

code->customCodeとなっています。フロント側ではcustomCodeがkeyとして存在すれば、そのままerror messageを表示。それ以外はテンプレートのメッセージを表示させることで、異常系と準異常系の処理を切り分けることができます。

参考資料

graphql-ruby公式
GraphQLにおけるエラーハンドリングの仕方

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

コメント機能(Ajax)実装

自分用にまとめます。

実装

コントローラー・モデル作成済み

routes.erb
  resources :posts do
    resources :comments, only: [:create, :destroy]
  end

コメントはpostsのshowページで投稿や一覧表示、削除など行うため、createとdestroyのみ作成。

comments_controller.rb
class CommentsController < ApplicationController

  def create
    @post = Post.find(params[:post_id])
    @comment = @post.comments.new(comment_params)
    @comment.user_id = current_user.id
    @comments = @post.comments.all
    @comment.save
    render :create
  end

  def destroy
    @comment = Comment.find_by(id: params[:id], post_id: params[:post_id]).destroy
    @comment.destroy
    render :destroy
  end

  private
    def comment_params
      params.require(:comment).permit(:comment, :post_id)
    end
end

redirect_to などで遷移の記述部分を変更。
上記の場合、
createアクションの際は、create.js.erb
destroyアクションの際は、destroy.js.erb

に飛ぶようになっている。

js.erbは後ほど作成するファイル。

posts_controller.rb
class PostsController < ApplicationController
  def show
    @post = Post.find(params[:id])
    @comment = Comment.new
    @comments = @post.comments.all
  end
end

今回はposts/showでコメントの投稿をできるようにする

posts/show.html.slim
# コメント一覧表示
.row
  .col-lg-4
    .col-lg-4

      # create.js.erbで書き換えるため記述必須
      div id="comment-text"

        # コメント一覧部分をパーシャルで飛ばす
        = render 'comments/comment', comments: @comments


# コメントフォーム
  .row
    .col-lg-3
    .col-lg-6.text-center
      .frame-post-show

        # jsファイルを呼び出すためにlocal: trueの記述を外す
        = form_with(model: [@post, @comment]) do |f|

          = f.label :comment, class: "font-weight-bold col-lg-3 text-center"
          <br>
          = f.text_area :comment, :size=>"57x5"
          <br>

          .text-center= f.submit "コメントする", class: "btn btn-outline-secondary btn-sm"


_comment.html.slimファイルをcommentsディレクトリ配下に手動で作成
パーシャルで飛ばしたコメント一覧部分を貼り付ける。

comments/_comment.html.slim
- @comments.each do |comment|

  # destroy.js.erbで書き換えるため記述必須
  div id="comment-#{comment.id}"
    .frame-post-comment
      = attachment_image_tag comment.user, :image, fallback: 'noimage.png', size: "50x40", class: "mb-3"
      = link_to comment.user.name, user_path(comment.user)
      - if comment.user == current_user

        # jsファイルを呼び出すためにremote: trueを追記
        = link_to '削除', post_comment_path(comment.post, comment), method: :delete, remote: true, data: { confirm: "削除してよろしいですか?" }, class: "btn btn-outline-danger btn-sm m-0 ml-3"
      <br>
      small.m-0= comment.created_at.to_s(:datetime_jp)
      .mt-4.mb-2= comment.comment


create.js.erbファイルをcommentsディレクトリ配下に手動で作成

comments/create.js.erb
# id="comment-text"部分を_comment.html.slimの内容にページ遷移なしで書き換える
$('#comment-text').html("<%= j(render 'comments/comment',{ comments: @comments }) %>");

# f.text_areaを空にする(記述しないと、投稿した後もフォームにコメント内容が残ったままになる)
$('textarea').val('');


destroy.js.erbファイルをcommentsディレクトリ配下に手動で作成

comments/destroy.js.erb
# "comment-#{comment.id}"を持った投稿を非表示にする
$('#comment-<%= @comment.id %>').remove();

完成!

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

No template for interactive requestの対処法

アプリ作成中にNo template for interactive requestが発生した。

エラー

私の場合は
No template for interactive request
PagesController#index is missing a template for request formats: text/html

であった。

routes.rb
Rails.application.routes.draw do
  resources :pages
  root 'pages#index'
end
pagescontroller
class PagesController < ApplicationController

  def index
  end
end

ビューファイルもしっかりapp/view/pagesにindex.html.hamlで作成していたので、原因がわからず解決できなかった。

原因

PagesController#index is missing a template for request formats: text/htmlとエラー文ではhtml文を呼んでいたが、自分はhamlファイルを生成してしまっていた。

解決法

ファイル名をindex.html.hamlからindex.html.erbに変更

これで解決する事ができた

hamlでのビューファイルを呼び出すために

投稿者はhamlを利用したかったが、hamlを使うには haml-railsというgemをインストールしなければならなかったらしい。 

gemfile
gem 'haml-rails'

これで、hamlファイルを呼び出す事ができた。

反省

この解決だけで1時間ほど時間を食ってしまったのが辛かったので、もっと速い間隔で試行錯誤を行うことを心がける。

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

ターミナルでコマンドを実行した際にOperation not permitted が表示された場合の対処法

rails中級チュートリアルアプリ作成

の最中にトップページへのルーティング、コントローラー作成をし、rails sを実行しようとしたところ、

ターミナル
Operation not permitted 

と、エラー文が表示されてしまった。

解決法

システム環境設定→セキュリティとプライバシー→プライバシー→左に並んでいる中からフルディスクアクセスを選択→ターミナルにチェックを入れる。

これでターミナルを再起動すると解決する事ができた。

参考サイト

https://gori.me/mac/mac-tips/112082

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

rails sを実行したら Address already in use と表示された時の対処法

アプリ作成中にこのエラーに遭遇したため記録しておく

解決したい事

rails sを行うと

Address already in use - bind(2) for "127.0.0.1" port 3000 (Errno::EADDRINUSE)

とターミナルに表示されてしまいrails sを実行できない

解決法

すでにrails sが他のターミナルなどで実行されているかを確認。

rails sが実行されているのが確認できなければ

ターミナル
% ps ax | grep rails

を打ち込み出てきたプロセス番号を

ターミナル
% kill -9 プロセス番号

でプロセスを止めることで解決する事ができる。

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

docker rails db:migrateにてエラー(StandardError: An error has occurred, all later migrations canceled:)

Qiita初投稿となります。よろしくお願いします。

環境

  • image: mysql:5.7
  • FROM ruby:2.6.3
  • Rails 5.2.4.3

エラー

docker環境で構築したrailsにて、docker-compose exec web rails db:migrateとしたところ、以下エラー

rails aborted!
StandardError: An error has occurred, all later migrations canceled:

Mysql2::Error: Invalid use of NULL value: ALTER TABLE `tasks` CHANGE `name` `name` varchar(255) NOT NULL
....以下省略

原因

完全な特定には至らなかったが、以前行ったマイグレーションの処理がうまくいっていない可能性がある。テーブル作成周りでエラーが出ていた。
エラーのMysqlに関しては修正しているはず・・・。

解決方法

データベースのリセットを行う。

$ docker-compose exec web rails db:migrate:reset

再度マイグレーション

$ docker-compose exec web rails db:migrate

これで修復できました。確認の為、コンソールから正しくDB周りが動いてるか見るといいと思います。

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

オブジェクト指向で考えるコードの書き方 Ruby

オブジェクト指向とは

 設計手法であって、文法では無い。最初聞いたときは何かの文法か構文の類か何かだと思っていましたが、そうでは無いんですね。Rubyはオブジェクト指向に沿って書きやすいように構文を揃えてくれている、というのが正しい理解のようです。

どうしてオブジェクト指向で書くのか

  • 非常にコードの可読性が向上する
  • 見えないバグを可視化しやすい

ことにあるのでは無いかと思っています。今回はここに焦点を置いて、まとめていこうと思います。

まずは、オブジェクト指向を考えないで書いてみる

toriaezuugoku.rb
x_max = ARGV[0]
y_max = ARGV[1]

if !x_max || !y_max
  puts "引数を指定してください"
  exit 1
end

x_max =  x_max.to_i
y_max =  y_max.to_i

#状態
x = 1
y = 1
step = 1
x_way = 1
y_way = 1

puts " #{step} (#{x},#{y})"
x += 1
y += 1
loop do
  step += 1
  puts " #{step} (#{x},#{y})"

  if y == 1 && x == x_max || x == 1 && y == y_max || x == 1 && y == 1 || x == x_max && y == y_max
    puts "GOAL!!"
    break
  elsif x == x_max
    x_way = -1
  elsif y == y_max
    y_way = -1
  elsif x == 1
    x_way = 1
  elsif y == 1
    y_way = 1
  end

  x += x_way
  y += y_way
end

 以前の記事で書いたコードです。関数定義もせず、上から下へ、全ての処理が流れるように処理されるように書いています。これが1番読みにくいコードとなります。変数の定義から何をしているのか予想して実際の処理を追わなければ、機能を読めない仕様になっているからです。このコードが何をしているのかをここで時間をかけて読もうとするのを諦めて次で書き換えたコードを見ていきます。

methodtohash.rb
def move_ball(hash)
    hash["x"] += hash["x_way"]
    hash["y"] += hash["y_way"]
    hash["step"] += 1
end

def reflect_x(hash)
    if hash["x_way"] == 1
        hash["x_way"] = -1
  elsif hash["x_way"] == -1
    hash["x_way"] = 1
  end
end

def reflect_y(hash)
    if hash["y_way"] == 1
        hash["y_way"] = -1
  elsif hash["y_way"] == -1
    hash["y_way"] = 1
  end
end

def goal?(hash, x_max, y_max)
  hash["y"] == 1 && hash["x"] == x_max \
  || hash["x"] == 1 && hash["y"] == y_max \
  || hash["x"] == 1 && hash["y"] == 1 \
  || hash["x"] == x_max && hash["y"] == y_max
end

def boundary_x?(hash, x_max)
  hash["x"] == x_max || hash["x"] == 1
end

def boundary_y?(hash, y_max)
  hash["y"] == y_max || hash["y"] == 1
end

x_max = ARGV[0]
y_max = ARGV[1]

if !x_max || !y_max
  puts "引数を指定してください"
  exit 1
end

x_max =  x_max.to_i
y_max =  y_max.to_i

state = {
  "x" => 1,
  "y" => 1,
  "step" => 1,
  "x_way" => 1,
  "y_way" => 1
}

puts " #{state["step"]} (#{state["x"]},#{state["y"]})"

loop do
  move_ball(state)

  puts " #{state["step"]} (#{state["x"]},#{state["y"]})"

  if goal?(state, x_max, y_max)
    puts "GOAL!!"
    break
  elsif boundary_x?(state, x_max)
    reflect_x(state)
  elsif boundary_y?(state, y_max)
    reflect_y(state)
  end
end

 今度は関数定義とハッシュを利用して書いてみました。こうしてみると、loopの文のところを見て見ると、どうやら、stateというハッシュの中身の状態をmove_ballというメソッドで操作して、条件式の中でboundary_xとboundary_yでボールがバウンドした時にxとy座標をreflect_xとreflect_yで向きを変えているのかな・・・と読めなくは無いものになってきています。
 関数定義した中身の処理が正しいとするならば、読む側の人はここだけ読めば、楽に何をやっているのか、このコードは何をするモノなのかが分かるようになります。状態をどういう時に変更しているのかの部分を細かく関数に分断していくとこういうメリットがあります。
 また、ハッシュを使えば、多くのグローバル変数を使って表現していた前のコードより、状態の管理を安全にできますし、ボールの数が増えたりしてもまだ多少の融通が効きます。(ボールの数が無茶苦茶多かったり、未知数だった場合、対応できないですが)
 が、まだ、読みやすさの追求においてまだ足りていないです。また、ハッシュにもし、タイポといったミスがあったとして、nilが返るだけになるこのコードは、エラーが発見しにくいものになります。大きいプロダクトであればあるほど発見しずらくなります。

ではオブジェクト指向の出番ですね

object.rb
class Ball
    attr_accessor :x, :y, :x_way, :y_way, :step

    def initialize(x: 1, y: 1, x_way: 1, y_way: 1, step: 1)
        @x = x
        @y = y
        @x_way = x_way
        @y_way = y_way
        @step = step
    end

    def move
        @x += @x_way
        @y += @y_way
        @step += 1
    end

    def reflect_x
        if @x_way == 1
            @x_way = -1
        elsif @x_way == -1
            @x_way = 1
        end
    end

    def reflect_y
        if @y_way == 1
            @y_way = -1
        elsif @y_way == -1
            @y_way = 1
        end
    end

    def goal?(x_max, y_max)
        @x == x_max && y == 1 \
        || @x == 1 && @y == y_max \
        || @x == 1 && @y == 1 \
        || @x == x_max && @y == y_max
    end

    def boundary_x?(x_max)
        @x == x_max || @x == 1
    end

    def boundary_y?(y_max)
        @y == y_max || @y == 1
    end
end

class BilliardTable
    attr_accessor :length_x, :length_y, :ball

    def initialize(length_x: nil, length_y: nil, ball: nil)
        @length_x = length_x
        @length_y = length_y
        @ball = ball
    end

    def cue
        print_status

        loop do
            @ball.move

            print_status

            if @ball.goal?(@length_x, @length_y)
                puts "GOAL!!"
                break
            elsif @ball.boundary_x?(@length_x)
                @ball.reflect_x
            elsif @ball.boundary_y?(@length_y)
                @ball.reflect_y
            end
        end
    end

    def print_status
        puts "#{@ball.step}, (#{@ball.x}, #{@ball.y})"
    end
end

x_max = ARGV[0]
y_max = ARGV[1]

if !x_max || !y_max
    puts "引数を指定してください"
    exit 1
end

x_max =  x_max.to_i
y_max =  y_max.to_i

ball = Ball.new()

bt = BilliardTable.new(length_x: x_max, length_y: y_max, ball: ball)

bt.cue

 上記のように書くことができるようになります。ボールの状態とビリヤード台の状態をクラスで分け、ボールの機能に必要な状態操作のメソッドを、ballクラスに、ボールを動かした台の上での操作の処理ををbilliardクラスにそれぞれ定義することで、実質、このコードの概ねの所作を知るためというのであれば、billiardクラスの処理系統と、コマンドライン引数を受け取る部分、つまり、クラスの外で書かれているコード部分を読めば、掴むことができます。英語の命名規則もグッと見やすくなっています。
 最終的に、bt(ビリヤード台)に対して、cue(突く)を実行するとボールが動くということですね。非常に読みやすいです。また、状態操作をかなり細かく定義しているので、コードの修正のしやすさや、メソッドの呼びやすさといったものも上がっていると思います。これによりバグ修正が先にあげた二つのベタ書きのコードやハッシュで書いたコードより容易になると言えると思います。

まとめ

 1番最初に書いたベタ書きの処理から、2段階コードを書き直してみましたが、自分の最初に書いたコードがいかに読みづらく、言ってしまえば、汚いコードであるかが理解できました。
 オブジェクト指向によるクラス設計が簡単にできるように作られたフレームワークであるところのrailsに私は1番最初に書いたようなコードの処理をガリガリ書いていたので、ヤベーコードを生み出していたということが更に際立ってよく理解できました。

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

Rubyの仕組み #1【基礎の基礎】

はじめに

こんにちは。
こちらの記事は、Ruby on rails をある程度学び、個人でアプリケーションをつくりあげた人間がRubyの基礎を学び直し短くまとめ上げた記事です。(かなり最低限。ここ大事。)

移動中とかに軽い気持ちで見ていただければと思います。

ちなみに作成したアプリケーションはこちら→ライブ情報共有アプリケーション Parrot

他の回はこちらから

シリーズ化してまとめております。

#2 → もうちょっと待ってね??‍♂️

そもそもRubyってなによ

日本人プログラマのである、まつもとひろゆき氏によって開発されたオブジェクト指向言語です。バージョン1.0は1996年に公開されたようです。(筆者の生まれる前でびっくり)
そして、皆さんもお馴染みフレームワークであるRuby on Rails は2004年に公開されました。
Rubyに魅力はたくさんありますが、なんと言っても「楽しさ」だと思います。筆者も実は高校生の頃にいわゆるC言語を学習していたことがありますが、当時は半泣きでやっていました。しかし、このRubyはエラーの原因が分かりやすかったり、プログラミング初心者の方であっても分かりやすい表現が多く比較的楽しく学習できています。

基礎知識

では早速基礎知識に入りましょう

オブジェクト指向言語って何?

Rubyは以下のように全てがオブジェクトになっており、数値やnillについてもメソッドを呼び出せます。
(.to_sは文字列化するメソッドです。)

sample.rb
1.to_s
> 1

nill.to_s
>""

メソッドの呼び出し

メソッドの呼び方については何個か種類があります。

sample.rb
オブジェクト.メソッド(引数1,引数2,,,

#カッコは省略可
オブジェクト.メソッド 引数1,引数2,,,

コメントのやり方

コメント化したい文の前に # をつけるだけでOKです。
改行までがコメントになります。

sample.rb
# コメントコメントコメント
1.to_s #こんな感じで行の途中からコメントにすることもできます。

リテラル

数値の123や、文字列などをソースコードに直接埋め込めることができる値のことです。(あまり意識しなくても良いかもしれません。)

sample.rb
# 数値
123

#文字列
"やぁ"

変数の扱い方

変数に文字列や数値を代入する場合は以下のようになります

sample.rb
a = "apple"

b = 1 + 1

#スネークケース(単語を_で区切る記法)で表現することも可能
admin_name = "taro"

#キャメルケース(大文字でで区切る記法)はあまり使いません
AdminName = "taro"

変数名をひらがなや感じにすることもできますが、全体のバランスが崩れますし一般的ではありません。

2つ以上の値に同時に代入することも可能です。ただ、これも理解時辛くなるのであまり一般的ではありません。

sample.rb
a, b = 1, 2

a 
>1
b
>2

#右辺が少ない場合はnillが入る。
c, d = 3

c
>3
d
>nill

#逆に多いと切り捨てられる
e, f = 4, 5, 6

e
>4
f
>5

#2こ以上の変数に同じ値を代入することも可能(理解しづらいので一般的ではない)
a = b = 7
a
>7
b
>7

最後に

今回は本当に基礎の基礎という感じでしたね。
だからと言って侮れるわけでもなく、意外に知らなかった表現方法もあるんだなぁと思いました。
(いろいろな表現方法を知っておくと、もしその表現方法に出会ったときにすぐ理解できますしね。)

ではでは。

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

Dockerでwheneverを扱う時No such file or directory - crontabが出る

簡単に定時処理が書ける便利なgem「whenever」

dockerでアプリ作成時、wheneverを使った処理をしようとしたが、つまづいてしまったので忘備録として記述しておきます。

環境

Ruby 2.5.1
Rails 5.2.4.3

やりたいこと

今回はpostというモデルを用意し、wheneverを使って1分事にpostを作成してみる。
dockerの環境構築は終わっているものとしてスタート。

modelとcontrollerを作成

docker上で

root@6181bdf78fa7:/myapp# bundle exec rails g model post name:string 
root@6181bdf78fa7:/myapp# bundle exec db:migrate
root@6181bdf78fa7:/myapp# bundle exec rails g controller posts

wheneverの設定

まずはgemをインストール

Gemfile
gem 'whenever', require: false

buildし直してgemをインストールしたらコマンドを実行してファイルを作成

root@6181bdf78fa7:/myapp# bundle exec wheneverize .
[add] writing `./config/schedule.rb'
[done] wheneverized!

作成されたschedule.rbに処理をかいていきます。

schedule.rb
require File.expand_path(File.dirname(__FILE__) + "/environment")
set :environment, :development
set :output, 'log/cron.log'
ENV.each { |k, v| env(k, v) }

every 1.minutes do
  runner "Post.create"
end

ここまできたら、cronに設定を反映させる

root@6181bdf78fa7:/myapp# bundle exec whenever --update-crontab
bundler: failed to load command: whenever (/usr/local/bundle/bin/whenever)
Errno::ENOENT: No such file or directory - crontab
  /usr/local/bundle/gems/whenever-1.0.0/lib/whenever/command_line.rb:77:in `popen'
  /usr/local/bundle/gems/whenever-1.0.0/lib/whenever/command_line.rb:77:in `write_crontab'
  /usr/local/bundle/gems/whenever-1.0.0/lib/whenever/command_line.rb:38:in `run'
  /usr/local/bundle/gems/whenever-1.0.0/lib/whenever/command_line.rb:6:in `execute'
  /usr/local/bundle/gems/whenever-1.0.0/bin/whenever:44:in `<top (required)>'
  /usr/local/bundle/bin/whenever:23:in `load'
  /usr/local/bundle/bin/whenever:23:in `<top (required)>'

エラーが出ましたね。
cron初心者の自分はここでつまづいてしまいました。

cronをインストール

どうやらdocker環境にcronをインストールしないといけないので、インストールに必要な処理をdockerfileに記述。
今回はこんな感じで1行追記しました。

FROM ruby:2.5.1
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs
RUN apt-get install -y cron  #この行を追記
RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp
root@6710f08a3504:/myapp# bundle exec whenever --update-crontab
[write] crontab file updated

無事updateされてcronに反映されました。
これで自動処理が始まってると思い、しばらく待ってみます…

…どうやら動いてないですね。
wheneverが作動していればclog/cron.logが作成されるはずなので。

cronを起動させる

cronが動いていないので状態を確認します。

root@827fe138767f:/myapp# service cron status
[FAIL] cron is not running ... failed!

やはり動いていませんでした。
起動しましょう。

root@827fe138767f:/myapp# service cron start 
[ ok ] Starting periodic command scheduler: cron.

1分後…

cron.log
Running via Spring preloader in process 122

ついにcron.logが生成されlogが書かれました。
rails consoleで確認します。

root@827fe138767f:/myapp# bundle exec rails c
Running via Spring preloader in process 135
Loading development environment (Rails 5.2.4.3)
irb(main):001:0> Post.all.count
   (4.5ms)  SELECT COUNT(*) FROM "posts"
=> 1

データが生成されたのがわかりますね!

課題

しかしcronの起動は手動で毎回行うのは面倒なので、できればdockerfileに記述して自動で起動されるようにしたいところです。
今後その方法も追記していきたと思います。

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

Dockerでwheneverを扱う時No such file or directory - crontabとなる

簡単に定時処理が書ける便利なgem「whenever」

dockerでアプリ作成時、wheneverを使った処理をしようとしたが、つまづいてしまったので忘備録として記述しておきます。

環境

Ruby 2.5.1
Rails 5.2.4.3

やりたいこと

今回はpostというモデルを用意し、wheneverを使って1分ごとにpostを作成してみる。
dockerの環境構築は終わっているものとしてスタート。

modelとcontrollerを作成

docker上で

root@6181bdf78fa7:/myapp# bundle exec rails g model post name:string 
root@6181bdf78fa7:/myapp# bundle exec db:migrate
root@6181bdf78fa7:/myapp# bundle exec rails g controller posts

wheneverの設定

まずはgemをインストール

Gemfile
gem 'whenever', require: false

buildし直してgemをインストールしたらコマンドを実行してファイルを作成

root@6181bdf78fa7:/myapp# bundle exec wheneverize .
[add] writing `./config/schedule.rb'
[done] wheneverized!

作成されたschedule.rbに処理をかいていきます。

schedule.rb
require File.expand_path(File.dirname(__FILE__) + "/environment")
set :environment, :development
set :output, 'log/cron.log'
ENV.each { |k, v| env(k, v) }

every 1.minutes do
  runner "Post.create"
end

ここまできたら、cronに設定を反映させる

root@6181bdf78fa7:/myapp# bundle exec whenever --update-crontab
bundler: failed to load command: whenever (/usr/local/bundle/bin/whenever)
Errno::ENOENT: No such file or directory - crontab
  /usr/local/bundle/gems/whenever-1.0.0/lib/whenever/command_line.rb:77:in `popen'
  /usr/local/bundle/gems/whenever-1.0.0/lib/whenever/command_line.rb:77:in `write_crontab'
  /usr/local/bundle/gems/whenever-1.0.0/lib/whenever/command_line.rb:38:in `run'
  /usr/local/bundle/gems/whenever-1.0.0/lib/whenever/command_line.rb:6:in `execute'
  /usr/local/bundle/gems/whenever-1.0.0/bin/whenever:44:in `<top (required)>'
  /usr/local/bundle/bin/whenever:23:in `load'
  /usr/local/bundle/bin/whenever:23:in `<top (required)>'

エラーが出ましたね。
cron初心者の自分はここでつまづいてしまいました。

cronをインストール

どうやらdocker環境にcronをインストールしないといけないので、インストールに必要な処理をdockerfileに記述。
今回はこんな感じで1行追記しました。

FROM ruby:2.5.1
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs
RUN apt-get install -y cron  #この行を追記
RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp
root@6710f08a3504:/myapp# bundle exec whenever --update-crontab
[write] crontab file updated

無事updateされてcronに反映されました。
これで自動処理が始まってると思い、しばらく待ってみます…

…どうやら動いてないですね。
wheneverが作動していればclog/cron.logが作成されるはずなので。

cronを起動させる

cronが動いていないので状態を確認します。

root@827fe138767f:/myapp# service cron status
[FAIL] cron is not running ... failed!

やはり動いていませんでした。
起動しましょう。

root@827fe138767f:/myapp# service cron start 
[ ok ] Starting periodic command scheduler: cron.

1分後…

cron.log
Running via Spring preloader in process 122

ついにcron.logが生成されlogが書かれました。
rails consoleで確認します。

root@827fe138767f:/myapp# bundle exec rails c
Running via Spring preloader in process 135
Loading development environment (Rails 5.2.4.3)
irb(main):001:0> Post.all.count
   (4.5ms)  SELECT COUNT(*) FROM "posts"
=> 1

データが生成されたのがわかりますね!

課題

しかしcronの起動は手動で毎回行うのは面倒なので、できればdockerfileに記述して自動で起動されるようにしたいところです。
今後その方法も追記していきたと思います。

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

[rails]redirect_toとrenderの違い

redirect_toとrenderの違い

初めの頃は違いなんて理解せずに使ってました。
処理の流れが違ったんですね。

redirect_toの場合

①controller(redirect_to) → ②HTTPリクエスト → ③ルーティング → ④controller → ⑤view

renderの場合

①controller → ②view

僕の感覚ではあるんですが、基本的にrenderは部分テンプレート以外であまり使わない気がします。

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

バリデーションを設定

バリデーションとは

パラメーターを受け取った時に該当カラムにデータが入っているか確認する機能です。

以下の例の場合、nameカラムがnil(データがない)であるかどうかを確認します。
nilだと保存されません。

app/models/user.rb
class User < ApplicationRecord

  validates :name, presence: true

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

[rails]バリデーションを設定

バリデーションとは

パラメーターを受け取った時に該当カラムにデータが入っているか確認する機能です。

以下の例の場合、nameカラムがnil(データがない)であるかどうかを確認します。
nilだと保存されません。

app/models/user.rb
class User < ApplicationRecord

  validates :name, presence: true

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

RSAなら、自分の好きな文字列を含む公開鍵が作れる件

はじめに

背景

※注: これは秘密鍵を10億個作れば、高確率で自分の名前を含む公開鍵が作れる件にインスパイアされて書いたネタ記事です

今、意識高い人向けにのSSH認証鍵(公開鍵/秘密鍵)はやはり ed25519 ですが、RSAであれば、なんと! 次のように自分の好きな文字列を含む公開鍵が作れてしまいます!
image.png

そう、つまりRSA最大のメリットは好きな文字列を含む自分だけの鍵をカスタマイズできることだったのです! ということで、RSAの魅力を見直そうという記事になります。( ウソです )

TL;DR;

  • 好きな文字列を公開鍵に埋め込めるネタツール(Rubyスクリプト)を作ったよ!
    https://github.com/angel-p57/qiita-sample/blob/master/rsa/rsa-genmykey.rb
  • RSAでは、公開鍵の主要パラメータ $n$ の値の範囲をコントロールできるので、結果として文字列埋め込みにつなげることができるよ!
  • RSAの鍵データを決めるのは、秘密鍵のパラメータ$p,q$ ( 2つの巨大素数 ) だけど、ランダムに作った $p$ に応じて $q$ の範囲を絞ることで、積 $n=pq$ の範囲をコントロールするよ!

※注: 「好きな文字列を埋め込む」ことが鍵の脆弱性にはつながらないと考えていますが、なにかあっても責任とれないので、あくまでネタということでお願いします。

作成したツール

仕様

  • 単一のRubyスクリプトです。
    https://github.com/angel-p57/qiita-sample/blob/master/rsa/rsa-genmykey.rb にあります
  • コマンドライン引数で好きな文字列を指定することで、RSA SSH秘密鍵 ( OpenSSH形式の新しくないやつ ) を出力します。
    ※リダイレクト等でファイルに保存してください
  • 鍵長は4,096固定にしています。
  • 文字列に指定できる文字種は英数および +/ の64種です。( つまりbase64の文字種 )
  • 原理的に、埋め込める文字列の長さはかなり長くできると思いますが、ツール上では64文字を上限にしています。
  • 特にチューニングしていないので、実行には数十秒~分単位で時間がかかるとお考え下さい。( 同じ環境でも結構ブレが出ます )

使用例

以下に、実際に作って試してみた時の例を挙げます。
image.png

  1. 秘密鍵生成
    ruby rsa-genmykey.rb 埋め込む文字列 > 保存先ファイル名 のようにして保存しています。
  2. 公開鍵抽出
    ツールはあくまで秘密鍵データを作るだけなので、公開鍵は ssh-keygen -y -f 秘密鍵ファイル > 保存先ファイル名 で抽出します。
  3. 試用
    実際に ssh-copy-id で接続先に公開鍵を登録し、公開鍵認証で使えることを確認しています。

からくり

公開鍵の内容

今回作った公開鍵のデータ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDF/angelp57/a+cat+of+Flanders/… ですが、先頭のssh-rsaを除くと、次の図が示すようなバイナリ(一部テキスト)をbase64変換した文字列になっています。

image.png

この中で、埋め込まれた文字列/angelp57/a+cat+of+Flanders/を決めているのは、巨大整数パラメータ $n$ ( n=0xc5fde9e07a5a79eff6be71ab7e… ) のうち、最上位の c5 を除いた上位桁です。
逆に言えば、パラメータ $n$ をある程度の大きさの範囲に絞り込むことができれば、好みの文字列を埋め込むことができるのです。
※なお、最上位の桁はある程度の範囲でランダムに決めています。

鍵のパラメータの調整

さて、RSAの場合にはいくつかの鍵のパラメータ ( いずれも整数 ) があります。
※詳細は公開鍵暗号RSAの数的構造をご覧ください

  • 秘密鍵
    • 素数 $p$(prime1), $q$(prime2)
    • 指数 $d$(privateExponent)
    • 派生パラメータ $d_p$(exponent1), $d_q$(exponent2), $q_{inv}$(coefficient)
  • 公開鍵
    • 積 $n$(Modulus)
    • 指数 $e$(publicExponent)

この中で $e$ は現在 65537 ( 0x10001 ) の固定値が一般的であり、それ以外のパラメータは $n=pq$ を含め、全て素数 $p,q$ によって決まります。
つまり、$n$をどう決めるかは$p,q$をどう決めるかの話に帰着するのです。

一般には、$n=pq$ が鍵長 ( ここでは4,096bit ) に合うように、$p,q$ がそれぞれ同じ桁数( 2,048bit )になるように、$p,q$が近すぎないように ( 少なくとも上位100bitで違いが出るくらい )、ランダムに素数を選びます。
ここで、$p$をランダムに選ぶのはあまり変えず、$q$をnの範囲から逆算して調整することで、最終的に$n$の範囲を調整することができます。

計算内容

今回作成したツールの計算内容は、ざっくりと次のようなことをしています。

  1. 埋め込む文字列から $n$ の範囲を決定
  2. 素数 $p$ の範囲を決定 ( $\sqrt{n}$ よりある程度以上大きくなる範囲 )
  3. 範囲内でランダムな素数 $p$ を決定
  4. $p$の値および$n$の範囲から、素数$q$の範囲を決定
  5. 範囲内でランダムな素数 $q$ を決定
  6. $p,q$ の値に基づき鍵データを生成

なので、「いかに素数を探すか」が計算の中心であり、以下の2つを実装しました。

  • 素数判定
    ミラー・ラビン判定法をそのまま実装しました。試行40回としているので、誤判定の確率 $1/2^{80}$ ということで、実用上問題にならないと思います。
    詳しくはFIPS186-4のAppendix C、C.3.1をご覧ください。
  • 素数候補探索
    小さめの素数2つから目的のサイズの素数の候補を探索する方法を実装しました。 詳しくはFIPS186-4のAppendix C、C.9をご覧ください。
    詳しくは精査していませんが、闇雲に候補を探すよりも効率が良いのではないかと思います。OpenSSLもbn_rsa_fips186_4.cで、関数bn_rsa_fips186_4_derive_prime()としてこの方法を採用しているようです。
    なお、小さな素数は普通にランダムに探します。サイズは171bitとしており、この数値はOpenSSLのbn_rsa_fips186_4.cの関数bn_rsa_fips186_4_aux_prime_min_size()を参考にしています。

鍵の安全性

RSAにおいて鍵の安全性は「$n$の素因数分解の困難性」として数体ふるい法の計算量が支配的であり、素数候補の無差別探索は攻撃者にとって割りに合わない方法です。
なので、素数の範囲にせいぜい数百bit程度の制限を設ける今回の手法であれば、鍵の安全性はほとんど低下しない…と考えています。
しかし、ツールにどんな瑕疵があるかは分かりませんので、あくまで「ネタ」としての利用にとどめることをお勧めします。

終わりに

秘密鍵を10億個作れば、高確率で自分の名前を含む公開鍵が作れる件がなければ、「公開鍵に文字列埋め込めるじゃん」と思いつくこともありませんでした。感謝です。
なお、このツールでは鍵データの出力 ( ASN1 )、素数判定等全部自前で簡易的に書いてるのですが、素直にOpenSSLの機能使った方が楽でかつ性能も良かったのではないかという気もしてます。
そこらへんの書き換えなんかも含め、RSAの応用として、今年の夏休みの自由研究にいかがでしょうか?

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