- 投稿日:2020-06-24T22:41:06+09:00
jqueryでsubmitボタンを毎回有効にする方法
テックキャンプでJavaScriptの学習中に学んだ事
jQueryを使って非同期通信の学習をしている最後に、送信ボタンを押してイベント発火後に
送信ボタンが無効化されているのを有効にする方法を記します。$('#hoge').prop('disabled', false);調べてみてわかった事は
- Railsのver5.0以降はdisabledがデフォルトで設定されている事(連打防止等の為)
- 他にも有効に出来る方法はある
例えば
$('#hoge').attr('disabled', false);自分のコードで試したが、どちらでも有効でした
今度は連打防止などの方法も調べて使え様にしていきます
非同期通信が自由に扱える様になると、少ないビューファイルの中に沢山の動的要素を
取り入れる事が出来て、かつレスポンスも早そうなので、プログラミングを学びたての自分でも
魅力的だなって感じました。難しいけど面白い
- 投稿日:2020-06-24T22:10:46+09:00
Array#sample と Random#rand ってどっちが速いんかな
バッチ処理で数十万回ループしてその中で毎回ランダムな数を選びたい場合、
Array#sample
とRandom#rand
でどっちがパフォーマンスがいいのか気になったので調べてみました。さっそく以下計測
range = (1..10000) array = range.to_a num = 1000000 Benchmark.bm 10 do |r| r.report 'Array#sample' do num.times do array.sample end end r.report 'Random#rand' do num.times do rand(range) end end end結果は
user system total real Array#sample 0.114216 0.002376 0.116592 ( 0.120891) Random#rand 0.198875 0.001285 0.200160 ( 0.206403)というわけで
Array#sample
がわずかに速かったです。ただ今回range
を渡しているのでもしかしたら内部的にto_a
とかしているせいかもしれない…
- 投稿日:2020-06-24T21:30:23+09:00
Rails 基礎的なCRUD機能実装手順 scaffold
前置き
Ruby on Railsを使って、基礎的なCRUD機能を実装する手順をまとめる。
CRUDとはCreate、Read、Update、Destroyの頭文字を取った用語。アプリ立ち上げ
ターミナルで、railsコマンドを使って、アプリを作成する。
rails new blog_app -d postgresql
このコマンドだと、新しくblog_appを作成している。
使い慣れているので、データベースはpostgreSQLにしている。何も指定しない場合、sqlite3がデータベースになる。その後、アプリのルートディレクトリに移動(cd blog_app)し、ターミナルでrails db:create
を入力し、データベースを立ち上げる。
サーバーを立ち上げて、アプリが出来ていることをローカルで確認する。rails s
上の画面が出ればOK。ctrl+Cでサーバーの立ち上げを終了できる。
CRUD機能
アプリが立ち上げられたので、ブログを投稿(create)、読み取り(read)、更新(update)、削除(delete)できる機能を実装する。
実は、railsジェネレーターのscaffoldを使うとコマンド2つで完了する。rails g scaffold blog title:string content:text rails db:migrate
最初のコマンドで、Blogモデル、ビュー、コントローラーとルーターの作成が一気にできる。この場合、Blogモデルに、string(文字列)型のインスタンス変数titleと、text(文章)型のインスタンス変数contentを作成している。
2つ目のコマンドは、データベースにblogsテーブルを作成するために必要。後書き
今度は、scaffoldを使わずにモデル、ビュー、コントローラーとルーターのコードについてまとめようと思います。
- 投稿日:2020-06-24T20:42:59+09:00
【Rails】CSVインポート機能の実装
目標
開発環境
・Ruby: 2.5.7
・Rails: 5.2.4
・Vagrant: 2.2.7
・VirtualBox: 6.1
・OS: macOS Catalina前提
下記実装済み。
実装
1.Gemを導入
Gemfile# 追記 gem 'roo'ターミナル$ bundle2.
application.rb
を編集application.rbrequire_relative 'boot' require 'rails/all' require 'csv' # 追記 Bundler.require(*Rails.groups) module Bookers2Debug class Application < Rails::Application config.load_defaults 5.2 end end3.モデル編集
book.rbdef self.import(file) CSV.foreach(file.path, headers: true) do |row| book = find_by(id: row["id"]) || new book.attributes = row.to_hash.slice(*updatable_attributes) book.save!(validate: false) end end def self.updatable_attributes ['id', 'title', 'body'] end① インポートするデータに同じIDが見つかればそのレコードを呼び出し、見つかれなければ新しく作成する。
book = find_by(id: row["id"]) || new② CSVファイルからデータを取得する。
book.attributes = row.to_hash.slice(*updatable_attributes)③ バリデーションを通さずに保存する。
book.save!(validate: false)④ CSVインポート時に受信するカラムを設定する。
def self.updatable_attributes ['id', 'title', 'body'] end4.コントローラーを編集
books_controller.rbdef import Book.import(params[:file]) redirect_to books_path end5.ルーティングを追加
routes.rbresources :books do collection { post :import } end6.ビューを編集
books/index.html.slim= form_tag import_books_path, multipart: true do = file_field_tag :file br = submit_tag "インポート", class: 'btn btn-success'
- 投稿日:2020-06-24T20:11:46+09:00
uriライブラリ 簡易まとめ
URI.scheme
スキームを文字列で返す。
URI.host
ホストを文字列で返す。
URI.port
ポート番号を文字列で返す。
URI.query
クエリを文字列で返す。
URI.path
パスを文字列で返す。
URI.request_uri
path + '?' + queryを文字列で返す。 query が nil である場合は、自身の path を返す。
実践
Qiitaでrubyを検索した結果画面のurlをURIオブジェクトにパースしてみましょう。
require 'uri' uri = URI.parse('https://qiita.com/search?q=ruby') puts uri.schem #=> https puts uri.host #=> qiita.com puts uri.port #=> 443 puts uri.path #=> /search puts uri.query #=> q=ruby puts uri.request_uri #=> /search?q=rubyjoin
引数に渡した文字列(変数)を連結してURIオブジェクトを生成する。
encode_www_form
引数で渡した値からURL-encoded form dataを生成する。
私値は配列やハッシュも可能。
GETでuriにパラメータを渡す時などに利用。uri = URI.join('https://qiita.com','/search') puts uri # => https://qiita.com/search params = { name: 'hogehoge', email: 'hogehoge@hogehoge.com' } uri.query = URI.encode_www_form(params) puts uri # => https://qiita.com/search?name=hogehoge&email=hogehoge%40hogehoge.com
- 投稿日:2020-06-24T19:40:58+09:00
CentOS 7にRuby 2.7をインストール(SCL)
はじめに
Software Collection(SCL)を利用してCentOS7にRuby 2.7をインストール
参考:Quick Start — Software Collectionsサポート
本手法で導入した場合、Red Hat Software Collections Product Life Cycle - Red Hat Customer Portalより、2023-05がEOLだと思われる。
それ以降に報告された脆弱性や不具合への対応は実施されない可能性がある。LOG
レポジトリ登録
# yum install -y centos-release-sclインストール
# cat /etc/redhat-release CentOS Linux release 7.8.2003 (Core) # yum install -y rh-ruby27 which # scl enable rh-ruby27 bash ... 略各種確認
# which ruby /opt/rh/rh-ruby27/root/usr/bin/ruby # ruby -v ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-linux] # yum info rh-ruby27 Loaded plugins: fastestmirror, ovl Loading mirror speeds from cached hostfile * base: ty1.mirror.newmediaexpress.com * centos-sclo-rh: ty1.mirror.newmediaexpress.com * centos-sclo-sclo: ty1.mirror.newmediaexpress.com * extras: ty1.mirror.newmediaexpress.com * updates: ty1.mirror.newmediaexpress.com Installed Packages Name : rh-ruby27 Arch : x86_64 Version : 2.7 Release : 2.el7 Size : 0.0 Repo : installed From repo : centos-sclo-rh Summary : Package that installs rh-ruby27 License : GPLv2+ Description : This is the main package for rh-ruby27 Software Collection.
- 投稿日:2020-06-24T17:40:17+09:00
【日本語化】 i18n rails 楽々日本語化 viewの表示のみ
【ゴール】
viewだけ日本語表示へと切り替え
【メリット】
■ UIの向上
■ 日本語なので可読性向上し、開発効率化【開発環境】
■ Mac OS catalina
■ Ruby on Rails (5.2.4.2)
■ Virtual Box:6.1
■ Vagrant: 2.2.7【実装】
アプリケーション作成
※ touchでfileを作成
mac.terminal$ rails new japoanese $ rails g controller homes index $ cd config/locale $ touch ja.yml※下記追記後 bundle install
gemfile.追加gem 'rails-i18n', '~> 5.1'※ホーム画面へhomes/indexを!!
routes.rbroot 'homes#index'※インデント要注意、
locale/ja.ymlja: homes: index: title: '題名' name: ’名前’ text: ’文章’ ## modelが関連すると書き方少し変化します。下記みたいな感じです。。。 activerecord: models: user: "ユーザー" attributes: user: name: "名前" age: "年齢"※下記重要
config/application.rbconfig.i18n.default_locale = :ja #追加※ja.ymlで定義」したものを引っ張ってきます。
homes/index.htmnl.erb<h2><%= t '.title'%></h2> <h2><%= t '.name'%></h2> <h2><%= t '.text'%></h2>以上!!
【合わせて読みたい】
■もっと詳しい記事
https://qiita.com/shimadama/items/7e5c3d75c9a9f51abdd5■エラーメッセージ
https://qiita.com/tanaka-yu3/items/63b189d3f15653cae263■rails メソッド 初学者者向け
https://qiita.com/tanaka-yu3/items/89abad875187494bec53
- 投稿日:2020-06-24T17:23:31+09:00
下位10%のダメなエンジニアにだけ解けないパズルにチャレンジしてみた
タイトルにあるようなパズルが数年前流行ったとのこと、
見つけたのでチャレンジ。まずはブラウザに直接打ち込んでみる。
http://challenge-your-limits.herokuapp.com/call/me
すると、下記のようなテキストが帰ってきた。{"message":"Almost! It's not GET. Keep trying."}なるほどGETではないとのことなので、
POSTでリクエストしてみよう。curlでやってもいいが、今回はRubyでリクエストを投げてみる。
require 'net/http' uri = URI.parse('http://challenge-your-limits.herokuapp.com/call/me') http = Net::HTTP.new(uri.host, uri.port) req = Net::HTTP::Post.new(uri.path) response = http.request(req) puts response.body #=>{"message":"Great! Please register as /challenge_users"}成功、そして次の課題が、
まずはパスを変えてそのままリクエスト。require 'net/http' uri = URI.parse('http://challenge-your-limits.herokuapp.com/challenge_users') http = Net::HTTP.new(uri.host, uri.port) req = Net::HTTP::Post.new(uri.path) response = http.request(req) puts response.body #=>{"message":"Validation Error, [:name, \"can't be blank\"]"}パラメータを渡せって指示がきました。
POSTなのでリクエストボディにデータを入れ込む。require 'net/http' require 'json' params = { name: 'hogehoge' } uri = URI.parse('http://challenge-your-limits.herokuapp.com/challenge_users') http = Net::HTTP.new(uri.host, uri.port) req = Net::HTTP::Post.new(uri.path) req.body = params.to_json response = http.request(req) puts response.body #=> {"message":"Validation Error, [:name, \"can't be blank\"]"}あれ?パラメータが渡せてない、
ここから熟考、、、そしてカンニング。笑リクエストボディにjson形式でパラメータを入れているのが原因だった。
ボディはjsonでしょと思い込んでいたことを反省、、、Net::HTTP::Postライブラリにはset_form_dataという便利なメソッドがあり、
引数にhashを渡せば文字列でパラメータをボディに入れてくれます。require 'net/http' params = { name: 'hogehoge' } # 省略 req.set_form_data(params) puts req.body #=> name=hogehoge puts req.body.class #=> Stringそして編集
require 'net/http' params = { name: 'hogehoge' } uri = URI.parse('http://challenge-your-limits.herokuapp.com/challenge_users') http = Net::HTTP.new(uri.host, uri.port) req = Net::HTTP::Post.new(uri.path) req.set_form_data(params) response = http.request(req) puts response.body #=> {"message":"Validation Error, [:email, \"can't be blank\"]"}パラメータ指定が永遠に続くとかないよね?
指示通りemailを追加require 'net/http' params = { name: 'hogehoge', email: 'hogehogehoge@hogehoge.com' } uri = URI.parse('http://challenge-your-limits.herokuapp.com/challenge_users') http = Net::HTTP.new(uri.host, uri.port) req = Net::HTTP::Post.new(uri.path) req.set_form_data(params) response = http.request(req) puts response.body #=> {"message":"Validation Error, [:email, \"is already taken\"]"}uniq: trueかよとか思いつつ、
別のアドレスを入れると成功しました。{"message":"Thanks! Please access to http://challenge-your-limits.herokuapp.com/challenge_users/token/********** from your web browser."}まだまだ下位10%だなぁと、自分の立ち位置を再確認できたよき機会でした。
POSTに関してリクエストパラメータの入れ込み知識がついたので、1歩前進かな。日々精進。
- 投稿日:2020-06-24T17:10:09+09:00
deviseの使い方 導入から設定変更
はじめに
勉強のためにdeviseを使い、ログイン周りを作成しました。
デフォルトではユーザー名、パスワードで認証しますが、今回社員番号、パスワードで認証するよう設定を変更していきます。環境
Ruby 2.5.3
Ruby on Rails 5.2.4
Devise 4.7.1完成
bootstrapで見た目を整えていますが、このようになるように設定を変更していきます。実装
Gemfilegem 'devise'$ bundle install●deviseの設定
$ rails generate devise:installこんな感じのメッセージがでます。
初心者なのでエラーメッセージかとびっくりしましたが、これが出れば成功です。create config/initializers/devise.rb create config/locales/devise.en.yml =============================================================================== Some setup you must do manually if you haven't yet: 1. Ensure you have defined default url options in your environments files. Here is an example of default_url_options appropriate for a development environment in config/environments/development.rb: config.action_mailer.default_url_options = { :host => 'localhost:3000' } In production, :host should be set to the actual host of your application. 2. Ensure you have defined root_url to *something* in your config/routes.rb. For example: root :to => "home#index" 3. Ensure you have flash messages in app/views/layouts/application.html.erb. For example: <p class="notice"><%= notice %></p> <p class="alert"><%= alert %></p> 4. You can copy Devise views (for customization) to your app by running: rails g devise:views ===============================================================================●メッセージの内容
1.新規登録など認証メールを送った際に、メールの文中にある承認リンクURLを設定します。config/environments/development.rbconfig.action_mailer.default_url_options = { host: 'localhost', port: 3000 }2.ルート設定
会員登録後などにルートに飛ぶ設定になっています。3.フラッシュメッセージを埋め込みます。ログイン、ログアウトの際にフラッシュを表示させたい時に使用します。私は共通ビューに埋め込みました。
app/views/layouts/application.html.erb<body> <p class="notice"><%= notice %></p> <p class="alert"><%= alert %></p> </body>4.ビューのカスタマイズをするために
$ rails g devise:views●deviseの設定変更
config/initializers/devise.rb43行目あたり 認証キーは社員番号を指定 - config.authentication_keys = [:email] + config.authentication_keys = [:employee_number] 55行目あたり 認証キーの値は大文字小文字を区別しない - config.case_insensitive_keys = [:email] + config.case_insensitive_keys = [:employee_number] 60行目あたり 空白キーを取り除く - config.strip_whitespace_keys = [:email] + config.strip_whitespace_keys = [:employee_number]●ユーザーモデルを作る
$ rails g devise userapp/models/user.rb# 以下3つのメソッドは、user名を認証キーとするので、 # 不必要なメソッドをオーバーライドして無効化しています。 def email_required? false end def email_changed? false end def will_save_change_to_email? false enddb/migrate/日付_devise_create_user.rbclass DeviseCreateUsers < ActiveRecord::Migration[5.2] def change create_table :users do |t| ## Database authenticatable t.string :employee_number, null: false, default: "" t.string :encrypted_password, null: false, default: "" ## Recoverable t.string :reset_password_token t.datetime :reset_password_sent_at ## Rememberable t.datetime :remember_created_at ## Trackable # t.integer :sign_in_count, default: 0, null: false # t.datetime :current_sign_in_at # t.datetime :last_sign_in_at # t.string :current_sign_in_ip # t.string :last_sign_in_ip ## Confirmable # t.string :confirmation_token # t.datetime :confirmed_at # t.datetime :confirmation_sent_at # t.string :unconfirmed_email # Only if using reconfirmable ## Lockable # t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts # t.string :unlock_token # Only if unlock strategy is :email or :both # t.datetime :locked_at t.timestamps null: false end ここを変更!! - add_index :users, :email, unique: true + add_index :users, :employee_number, unique: true add_index :users, :reset_password_token, unique: true # add_index :users, :confirmation_token, unique: true # add_index :users, :unlock_token, unique: true end end$ rials db:migrate●コントローラーの変更
application_controller.rbclass ApplicationController < ActionController::Base protect_from_forgery with: :exception before_action :configure_permitted_parameters, if: :devise_controller? protected # methodをオーバーライドする。 def configure_permitted_parameters sign_up_params = [:employee_number, :password, :password_confirmation] sign_in_params = [:employee_number, :password, :remember_me] # account_update, sign_in, sign_up, のフィールドを再定義 devise_parameter_sanitizer.permit(:sign_up, keys: sign_up_params) devise_parameter_sanitizer.permit(:sign_in, keys: sign_in_params) devise_parameter_sanitizer.permit(:account_update, keys: account_update) end end設定はこれで終わりです。あとはviewを変更すれば完成です。
参考
[Rails] deviseの使い方(rails5版)
Ruby on Rails 初心者が gem Devise 使ってみた。
- 投稿日:2020-06-24T15:13:12+09:00
RSpec でメソッド呼び出しの引数をブロックでチェック
RSpec の
expect(foo).to receive(:bar).with(...)
では引数のチェックがいくつかの方法で可能だが、ブロックで検証したいケースが結構ある。with には matcher を渡すことができるので、カスタム matcher を定義してやればよい。
下記の例では Struct の特定の attribute のみ検証しているRSpec::Matchers.define :a_valid_argument do match {|actual| block_arg.call(actual) } end it "should call with valid argument" do jon = Struct.new(:name).new("Jon") expect($stdout).to receive(:write).with( a_valid_argument {|a| a.name == "Jon" }, ) $stdout.write(jon) endなお、
with
による引数の検証は引数ごとに行われるので複数の引数をとるメソッドの場合は、引数ごとに matcher を渡す必要がある。it "should call with valid arguments" do jon = Struct.new(:name).new("Jon") dany = Struct.new(:name).new("Dany") expect($stdout).to receive(:write).with( a_valid_argument {|a| a.name == "Jon" }, a_valid_argument {|a| a.name == "Dany" }, ) $stdout.write(jon, dany) end
- 投稿日:2020-06-24T14:53:32+09:00
Ruby 様々な繰り返し処理について
前置き
Rubyの反復処理についてまとめる。
eachメソッド (配列・ハッシュ)
Rubyでは最も使う反復処理のメソッド。配列・ハッシュに対して便利。
each.rbfruits = ["apple", "banana", "grape"] fruits.each{ |fruit| puts fruit }配列fruitsの要素を、インデックスの若い順から1つずつ取り出して、引数fruitに入れて{}内の処理を実行する。処理が一行だけなので、{}を使っているが、
each_do.rbnumbers = [1, 2, 3, 4, 5] sum = 0 numbers.each do |number| if number % 2 == 0 sum += number / 2 else sum += number end end sum #=> 12複数行の場合は、do endを使うと書きやすい。
timesメソッド(繰り返す回数)
繰り返す回数が決まっている処理に対して便利。
times.rbsum = 0 10.times { |n| sum += n } sum #=> 45upto・downtoメソッド(数値)
初めと終わりの数値が決まっているときに便利。
upto.rb15.upto(20) do |age| if age < 18 puts "#{age}歳では選挙権はありません" else puts "#{age}歳は18歳以上なので選挙権があります" end enduptoは数値を増やす方向に処理を繰り返す。
指定した最初の数値15 から最後の数値20 まで処理を実行。downto.rb20.downto(15) do |age| if age < 18 puts "#{age}歳では選挙権はありません" else puts "#{age}歳は18歳以上なので選挙権があります" end enddowntoは数値を減らす方向に処理を繰り返す。
指定した最初の数値20 から最後の数値15 まで処理を実行。while文・until文(終了条件)
終了条件が決まっているときに便利
while.rbarray = (1..100).to_a sum = 0 i = 0 while sum < 1000 sum += array[i] i += 1 end sum #=> 1035whileの横にある条件が真の間、while endの間の処理を繰り返す。
上のコードでは、合計値sumが1000を超えたときに処理を終了する。until文は、while文とは逆で、条件が偽のときに処理を繰り返すので、
until.rbarray = (1..100).to_a sum = 0 i = 0 until sum >= 1000 sum += array[i] i += 1 end sum #=> 1035上のコードは、while.rbと同じ意味になる。
loopメソッド(無限ループ)
while trueでも無限ループを作れるが、loopメソッドを使うとよりシンプルに作れる。
loop.rbnumbers = [1, 2, 3, 4, 5, 6, 7] loop do n = numbers.sample puts n break if n == 7 endまとめ
繰り返し処理に使うメソッド・構文は、ケースにあったものを使うと便利。
参考文献
プロを目指す人のためのRuby入門
伊藤淳一 [著]
- 投稿日:2020-06-24T14:11:38+09:00
Ubuntu 16.04にパペットマスターとクライアントをインストールする
Puppetは、自動化からアップデートインストールまで、様々なアプリケーションに対応したオープンソースの設定管理システムです。
本ブログは英語版からの翻訳です。オリジナルはこちらからご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。
序章
Puppetは、自動化からアップデートインストールまで幅広く利用できるオープンソースの設定管理システムです。Rubyで書かれており、UnixやWindowsのようなOSの設定を管理するために特別に設計されています。1台のサーバから数千台の物理サーバや仮想サーバを一元管理して簡単に導入・管理することができます。
Puppetは、クライアントサーバ型のアーキテクチャでもスタンドアロン型のアーキテクチャでも使用できます。クライアント・サーバ・アーキテクチャでは、サーバはマスターとして、クライアントはエージェントとして知られています。Puppetには、EnterpriseとOpen sourceの2つのバージョンがあります。どちらも多くのLinuxディストリビューションとWindowsをサポートしています。Puppetは、システム管理者が反復的な作業に費やす時間を削減し、より大きなビジネス価値を提供するプロジェクトに集中できるようにすることで、システム管理者を支援します。
特徴
- PuppetはIdempotencyをサポートしており、同じマシン上で同じ設定を複数回実行することが容易になります。
- 同じ問題を解決している全員のタスクを重複して実行する必要がなくなります。
- すべてのタスクはネイティブコードで書かれており、簡単に共有することができます。
- 繰り返し可能な変更を自動的に行うことができます。
- 必要に応じて拡張機能を追加することで、余分な機能を追加することができます。
このガイドでは、オープンソースのPuppetをUbuntu 16.04サーバ上で、Alibaba Cloud Elastic Compute Service (ECS)インスタンスを使用してクライアント/サーバアーキテクチャでインストールし、設定する手順を説明します。
前提条件
- Ubuntu 16.04がインストールされたパペットマスター用のAlibaba Cloud ECSインスタンス。
- Ubuntu 16.04がインストールされたPuppetエージェント用のAlibaba Cloud ECSインスタンス。
- パペットマスターに静的IPアドレス192.168.0.103が設定されている。
- パペットエージェントに192.168.0.104の静的IPアドレスが設定されている。
- パペットマスターには最低4GBのメモリとデュアルコアCPUが必要。
- 両方のインスタンスにsudo権限を持つ非rootユーザが設定されている。
ホスト名の設定
始める前に、Server ノードと agent ノードで /etc/hosts と /etc/hostname ファイルを設定して、これらのファイルが相互に通信できるようにする必要があります。
Serverノードで/etc/hostsと/etc/hostnameファイルを開き、以下の変更を行います。
sudo nano /etc/hosts
ファイルの最後に以下の行を追加します。
192.168.0.0.103 puppet-server
sudo nano /etc/hostname
以下のようにファイルを変更します。
puppet-server
保存し、終了したらファイルを閉じます。
Agentノードで/etc/hostsと/etc/hostnameファイルを開き、以下の変更を行います。
sudo nano /etc/hosts
ファイルの最後に以下の行を追加します。
192.168.0.0.103 puppet-server
sudo nano /etc/hostname
以下のようにファイルを変更します。
puppet-agent
終了したら保存して閉じてください。
Puppetのインストール
Ubuntu 16.04のデフォルトリポジトリではPuppetサーバーは利用できません。そのため、MasterノードとAgentノードの両方にPuppet Labリポジトリを追加する必要があります。
それぞれのノードで以下のコマンドを実行して、Puppetのリポジトリをダウンロードしてインストールします。
wget https://apt.puppetlabs.com/puppetlabs-release-pc1-xenial.deb sudo dpkg -i puppetlabs-release-pc1-xenial.deb sudo apt-get update -y次に、以下のコマンドでマスターノードにPuppetサーバパッケージをインストールします。
sudo apt-get install puppetserver -y
Puppetサーバをインストールした後、メモリの割り当てを設定する必要があります。マスターノードのメモリ量に応じてメモリ使用量をカスタマイズすることをお勧めします。これは/etc/default/puppetserverファイルを編集することで行うことができます。
sudo nano /etc/default/puppetserver
サーバーの容量に合わせて行を変更してください。
以下の行を変更してください。
JAVA_ARGS="-Xms2g -Xmx2g -XX:MaxPermSize=256m”
から
JAVA_ARGS="-Xms512m -Xmx512m”
へ。保存してファイルを閉じ、以下のコマンドでPuppetサーバを起動し、起動時に起動できるようにします。
sudo systemctl start puppetserver sudo systemctl enable puppetserverPuppetサーバーの状態は以下のコマンドで確認できます。
sudo systemctl status puppetserver
すべてが正常な場合は、以下のような出力が表示されるはずです。
● puppetserver.service - puppetserver Service Loaded: loaded (/lib/systemd/system/puppetserver.service; enabled; vendor preset: enabled) Active: active (running) since Sat 2017-10-28 18:47:26 IST; 12min ago Process: 887 ExecStart=/opt/puppetlabs/server/apps/puppetserver/bin/puppetserver start (code=exited, status=0/SUCCESS) Main PID: 963 (java) CGroup: /system.slice/puppetserver.service └─963 /usr/bin/java -Xms256m -Xmx256m -Djava.security.egd=/dev/urandom -XX:OnOutOfMemoryError=kill -9 %p -cp /opt/puppetlabs/server/Puppet Agentのインストール
これでPuppetサーバーは稼働しています。いよいよAgentノードにPuppet agentをインストールする時が来ました。
Puppet agentをインストールする前に、AgentノードにPuppet Labリポジトリがインストールされていることを確認してください。次に、以下のコマンドを実行するだけでPuppet agentをインストールします。
sudo apt-get install puppet-agent -y
Puppet Agentをインストールしたら、puppet設定ファイルを編集し、puppetマスター情報を設定する必要があります。
これは以下のコマンドで行うことができます。
sudo nano /etc/puppetlabs/puppet/puppet.conf
以下の行を追加します。
[main] certname = puppet-agent server = puppet-server environment = IT保存してファイルを閉じ、以下のコマンドでPuppet Agentサービスを起動し、起動時に起動できるようにします。
sudo systemctl start puppet sudo systemctl enable puppetパペットサーバー上のパペットエージェント証明書に署名する
Puppetが初めてAgentノードを実行するとき、Puppetはパペットサーバに証明書署名要求を送信します。クライアント・サーバ型のアーキテクチャでは、エージェントノードを制御するために、パペットマスターサーバが各エージェントノードの証明書要求を承認する必要があります。
パペットサーバ上で、以下のコマンドですべての署名されていない証明書要求をリストアップします。
sudo /opt/puppetlabs/bin/puppet cert list
エージェントノードのホスト名で1つのリクエストが表示されているはずです。
"puppet-agent" (SHA256) 7C:28:E8:AF:09:23:55:19:AF:C1:EE:C3:66:F2:02:73:AD:7F:53:17:28:CE:B0:26:AE:C7:6C:67:16:05:6F:2E
次に、以下のコマンドで証明書要求に署名します。
sudo /opt/puppetlabs/bin/puppet cert sign puppet-agent
以下のような出力が表示されるはずです。
Signing Certificate Request for: "puppet-agent" (SHA256) 7C:28:E8:AF:09:23:55:19:AF:C1:EE:C3:66:F2:02:73:AD:7F:53:17:28:CE:B0:26:AE:C7:6C:67:16:05:6F:2E Notice: Signed certificate request for puppet-agent Notice: Removing file Puppet::SSL::CertificateRequest puppet-agent at '/etc/puppetlabs/puppet/ssl/ca/requests/puppet-agent.pem'これでパペットマスターサーバーはAgentノードと通信して制御できるようになりました。複数のノードの証明書要求に一度に署名したい場合は、以下のコマンドを実行します。
sudo /opt/puppetlabs/bin/puppet cert sign —all
PuppetマスターがPuppet Agent証明書に署名したら、Puppet Agentノードで以下のコマンドを実行してテストします。
sudo /opt/puppetlabs/bin/puppet agent —test
すべてが正しく行われていれば、以下のような出力が表示されるはずです。
Info: Using configured environment 'production' Info: Retrieving pluginfacts Info: Retrieving plugin Info: Caching catalog for puppet-agent Info: Applying configuration version '1509200872' Notice: Applied catalog in 0.09 secondsエージェントノードにApacheをインストールするためにPuppetサーバを設定する
これでPuppetマスター、エージェントノードともに設定が完了し、機能するようになりました。いよいよPuppetを検証してみましょう。
そのために、AgentノードにApacheウェブサーバをインストールするためのマニフェストファイルを作成します。マニフェストはクライアントの設定を含むデータファイルです。デフォルトでは、マニフェストファイルは /etc/puppetlabs/code/environments/production/manifests/directory.にあります。
マニフェストファイルの作成に進む前に、puppetlabs-apacheモジュールをインストールする必要があります。
Puppetマスターノードで、以下のコマンドを実行して、puppetlabs-apacheモジュールをインストールします。
sudo /opt/puppetlabs/bin/puppet module install puppetlabs-apache
以下のような出力が表示されるはずです。
Notice: Preparing to install into /etc/puppetlabs/code/environments/production/modules ... Notice: Downloading from https://forgeapi.puppet.com ... Notice: Installing -- do not interrupt ... /etc/puppetlabs/code/environments/production/modules └─┬ puppetlabs-apache (v2.3.0) ├── puppetlabs-concat (v4.1.0) └── puppetlabs-stdlib (v4.20.0)次に、以下のコマンドでPuppetマスター上にマニフェストファイルを作成します。
sudo nano /etc/puppetlabs/code/environments/production/manifests/site.pp
以下の行を追加します。
node 'puppet-agent' { class { 'apache': } # use apache module apache::vhost { 'localhost': # define vhost resource port => '80', docroot => '/var/www/html' } }上記の設定では、Apacheをインストールし、localhostというバーチャルホストを設定し、80番ポートでリスニングし、Agentノード上にドキュメントルート/var/www/htmlを持つようにします。
さて、Agentノード上で以下のコマンドを実行して、マニフェストファイルからすべての設定を取得します。
sudo /opt/puppetlabs/bin/puppet agent —test
すべてが成功した場合、以下のような出力が表示されるはずです。
`
Notice: /Stage[main]/Apache/Apache::Vhost[default]/File[15-default.conf symlink]/ensure: created
Info: /Stage[main]/Apache/Apache::Vhost[default]/File[15-default.conf symlink]: Scheduling refresh of Class[Apache::Service]
Notice: /Stage[main]/Main/Node[puppet-agent]/Apache::Vhost[localhost]/Concat[25-localhost.conf]/File[/etc/apache2/sites-available/25-localhost.conf]/ensure: defined content as '{md5}05a8b8c6772009021086814bdf8c985e'
Info: Concat[25-localhost.conf]: Scheduling refresh of Class[Apache::Service]
Notice: /Stage[main]/Main/Node[puppet-agent]/Apache::Vhost[localhost]/File[25-localhost.conf symlink]/ensure: created
Info: /Stage[main]/Main/Node[puppet-agent]/Apache::Vhost[localhost]/File[25-localhost.conf symlink]: Scheduling refresh of Class[Apache::Service]
Info: Class[Apache::Service]: Scheduling refresh of Service[httpd]
Notice: /Stage[main]/Apache::Service/Service[httpd]: Triggered 'refresh' from 1 events
Notice: Applied catalog in 53.11 seconds
おめでとうございます。これで Apache が Agent ノードにインストールされ、実行されています。
結論
このチュートリアルでは、本番環境にPuppetサーバーを簡単にインストールし、ITインフラ全体を簡単に管理することができます。Puppetの詳細については、Puppetの公式ドキュメントページを参照してください。その他のチュートリアルは、Alibaba Cloud Getting Startedチャンネルにも掲載されています。
アリババクラウドは日本に2つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
アリババクラウドジャパン公式ページ
- 投稿日:2020-06-24T13:57:41+09:00
[Rails] エラーメッセージ を表示する - render、redirect_toの違い、flashについて -
エラーメッセージを表示する方法について書きます。
Railsでメッセージ出力する際によく使用されるrender、redirect_to、flashについても簡単に書きます。実装したいこと
フォームの入力値に誤りがあるときに、以下のようなエラーメッセージを表示させる
実装したコード
login_controller.rb@error_txt = '※入力に誤りがあるか、登録されていません。' render :newインスタンス変数@error_txtにエラーメッセージをセットし、renderでテンプレートnewを表示させるように指定します。
※エラー判定の処理は省略していますnew.html.slim- if @error_txt p.error = @error_txtテンプレート側ではインスタンス変数の@error_txtの値の存在チェックを行い、あれば@error_txtを表示させます。
renderとは
renderとはテンプレートを指定して表示させる(レンダリングする)ためのメソッドです。
画面遷移させることなく、表示させることができます。redirect_toとの違い
renderと同様にページを指定して表示させるメソッドにredirect_toがあります。
renderが画面遷移することなく指定したテンプレートを表示するのに対して、
redirect_toメソッドはリダイレクトさせるためのメソッドで、URLを指定してリクエストを再送信するようにブラウザに指令を出します。
ブラウザはこの指令に応じ、指定されたURLに対して改めてリクエストをサーバーに送信します。
ブラウザとサーバー間のやりとりや処理が増えるため、改めてリクエストを送信させる必要がない場合は、renderを使うのが良いです。今回はフォームの入力内容に対してエラーメッセージを表示させるだけで、リダイレクトさせたくないためrenderを使用します。
flashとは
railsにおけるメッセージ表示について調べるとflashに関する記事が多くでてきます。
flashはsessionを利用した機能の一つでメッセージを画面に表示するためのメソッドです。
flashで設定したメッセージはセッションに保存され、リダイレクトされても保持されるためredirect_toメソッドを一緒に使うことが多いです。今回はrenderを使用しており、リダイレクトもなく、セッションに値を保持する必要がないのでflashを使わずにインスタンス変数を使いました。
まとめ
- リダイレクト不要なエラーメッセージはrenderとインスタンス変数で実装する
- リダイレクトが必要な場合は、redirect_toとflashで実装する
- 投稿日:2020-06-24T13:46:01+09:00
RailsでインスタやTwitterのようなハッシュタグ検索を実装(gemなし)
概要
私は現在DMMWEBCAMPというプログラミングスクールに通っておりまして
3ヶ月目の課題であるポートフォリオにインスタグラムやTwitterで使用されているような
ハッシュタグもどきを実装しました。
今後実装される方の参考になればと思います。参考サイト
Railsで作ったインスタもどきのキャプションにハッシュタグを実装
https://qiita.com/goppy001/items/791c946abdb41c9495bb大まかな流れは上記サイトと同じですが、うまく出来なかったところを変更しています。
完成図
投稿画面
投稿詳細画面
ハッシュタグ一覧及びハッシュタグ投稿一覧画面
事前準備DB
最初はbodyとuser_idのみのテーブル構成でしたが、ハッシュタグを入力するためのhashbodyカラムを追加しています。
ちなみに画像はポートフォリオの仕様上他テーブルへ保存しておりますが、imageのカラムがこのテーブル内にあっても問題はありません。モデル(DB)の作成
ハッシュタグモデル
$rails g model Hashtag hashname:stringハッシュタグ保存用のモデルを作成します。
hashnameカラムにハッシュタグが保存されます。マイグレーションファイルの編集
create_hashtags.rbclass CreateHashtags < ActiveRecord::Migration[5.2] def change create_table :hashtags do |t| t.string :hashname t.timestamps end add_index :hashtags, :hashname, unique: true end end中間テーブルの作成
$ rails g model HashtagPostImage post_image:references hashtag:referencesHashtagテーブルとPostImage(投稿)テーブルの中間テーブルです。
参考にさせて頂いた記事ではここのコマンドが若干違います。
中間テーブルなので外部キーとしてhashtagとpostimageのidを持ってきます。
references型なので作成時にhashtag_idと打ってしまうと
出来上がったカラム名がhashtag_id_idとなってしまうので注意が必要です。マイグレーションファイル
create_hashtag_post_images.rbclass CreateHashtagPostImages < ActiveRecord::Migration[5.2] def change create_table :hashtag_post_images, id: false do |t| t.references :post_image, foreign_key: true t.references :hashtag, foreign_key: true end end endマイグレート
$ rails db:migrate作成されたDB
モデルのアソシエーションとバリデーションの設定
ハッシュタグモデル
hashtag.rbclass Hashtag < ApplicationRecord validates :hashname, presence: true, length: { maximum: 50 } has_many :hashtag_post_images has_many :post_images, through: :hashtag_post_images endとりあえず50文字を上限にしました。
中間テーブル
hashtag_post_image.rbclass HashtagPostImage < ApplicationRecord belongs_to :post_image belongs_to :hashtag validates :post_image_id, presence: true validates :hashtag_id, presence: true endPostImageモデル
post_image.rbclass PostImage < ApplicationRecord has_many :hashtag_post_images has_many :hashtags, through: :hashtag_post_images endPostImageモデルに下記を追加
postimage.rbafter_create do post_image = PostImage.find_by(id: id) # hashbodyに打ち込まれたハッシュタグを検出 hashtags = hashbody.scan(/[##][\w\p{Han}ぁ-ヶヲ-゚ー]+/) hashtags.uniq.map do |hashtag| # ハッシュタグは先頭の#を外した上で保存 tag = Hashtag.find_or_create_by(hashname: hashtag.downcase.delete('#')) post_image.hashtags << tag end end #更新アクション before_update do post_image = PostImage.find_by(id: id) post_image.hashtags.clear hashtags = hashbody.scan(/[##][\w\p{Han}ぁ-ヶヲ-゚ー]+/) hashtags.uniq.map do |hashtag| tag = Hashtag.find_or_create_by(hashname: hashtag.downcase.delete('#')) post_image.hashtags << tag end end作成と更新時にこのアクションが実行されるように記入してあります。
・post_image = PostImage.find_by(id: id)
作成した投稿を探させます。・ hashtags = hashbody.scan(/[##][\w\p{Han}ぁ-ヶヲ-゚ー]+/)
ここでは入力されたハッシュタグ、先頭に[##]がつく入力値を探します。
hashbodyは私のDBのカラム名ですので、ここはアプリケーションにより異なります。
投稿テーブルのテキスト入力用のカラムであれば何でも良いです。・ hashtags.uniq.map do |hashtag|
# ハッシュタグは先頭の#を外した上で保存
tag = Hashtag.find_or_create_by(hashname: hashtag.downcase.delete('#'))
post_image.hashtags << tag
endmapで繰り返すことにより、複数のハッシュタグがpostimageに保存されます。
・post_image.hashtags.clear
更新時、一回ハッシュタグを消しているようです。routeの記載
routes.rbget '/post_image/hashtag/:name' => 'post_images#hashtag' get '/post_image/hashtag' => 'post_images#hashtag'私の場合はハッシュタグ一覧ページを作りたかったので二つのルートを用意しました。
PostImage ヘルパーの編集
post_images_helper.rbmodule PostImagesHelper def render_with_hashtags(hashbody) hashbody.gsub(/[##][\w\p{Han}ぁ-ヶヲ-゚ー]+/) { |word| link_to word, "/post_image/hashtag/#{word.delete("#")}",data: {"turbolinks" => false} }.html_safe end endlink_to word, "/post_image/hashtag/#{word.delete("#")}"
ここのurlはアプリケーションの内容によって異なります。
ハッシュタグをクリックするとここのurlに飛びますという意味です。
先ほどrouteに書いたurlを打ち込みましょう。View
投稿本文内で実際にハッシュタグを表示するところ
Viewにて以下を表記します。
post_images/show.html.erb<%= render_with_hashtags(@postimage.hashbody) %>上記は先ほどhelperで作成したメソッドを呼び出しています。
ちなみにpost_images/showのコントローラーはこちらです。controllers/post_images_controller.rbdef show @postimage = PostImage.find(params[:id]) end単純に@postimageのhashtag入力欄の情報をヘルバーに渡しているんではないかと考えています。
ハッシュタグ一覧ページ
PostImageコントローラーにhashtagアクションの追加
post_images_controller.rbdef hashtag @user = current_user if params[:name].nil? @hashtags = Hashtag.all.to_a.group_by{ |hashtag| hashtag.post_images.count} else @hashtag = Hashtag.find_by(hashname: params[:name]) @postimage = @hashtag.post_images.page(params[:page]).per(20).reverse_order @hashtags = Hashtag.all.to_a.group_by{ |hashtag| hashtag.post_images.count} end endここの表記は作成するサイトにより変わります。
私はハッシュタグ一覧がみれるページを作りたかったので、params[:name].nil?の場合は
post_imageを表示しないという条件分岐をしています。
またgroup_byですが、hashtagに紐づく投稿が多い順番でハッシュタグを表示できるように
このような表記をしています。ハッシュタグのView
post_images/hashtag.html.erb<div class="row"> <% if params[:name] == nil %> <% else %> <div class= "col-xs-12 col-lg-12 col-md-12 col-sm-12"> <div class="hashtag-post-box"> <h3 class="search-title">#<%= @hashtag.hashname %>: <%= @postimage.count %> 件 </h3> <div class="flex-box"> <% @postimage.each do |postimage| %> <div class= "post-image-index-post-box"> <p class="index-post-box-top"> <%= postimage.created_at.strftime("%Y/%m/%d") %> </p> <span class='far fa-comments index-comment-count' id='comment-count_<%= postimage.id %>' style="color: #777777;"> <%= render 'post_image_comments/comment-count', postimage:postimage %> </span> <span id = "favorite-button_<%= postimage.id %>"class="post-box-top-favorite"> <%= render 'post_image_favorites/favorite',postimage: postimage %> </span> <%= link_to post_image_path(postimage),data: {"turbolinks" => false} do %> <ul class="slider"> <% postimage.post_image_images.each do |post| %> <li> <%= attachment_image_tag post, :image ,size:'430x360', format:'jpg',class:"image" %> </li> <% end %> </ul> <% end %> <p class="hashtag-post-box-name"> <%= link_to user_path(postimage.user) do %> <%= attachment_image_tag postimage.user, :profile_image,size:'30x30', format:'jpg',fallback:'no_image.jpg',class:'min-image' %> <span class="index-post-box-user"><%= postimage.user.name %> </span> <% end %> </p> <div class="image-show-body-hash" style="padding:2%"> <%= simple_format(postimage.body.truncate(50))%> <% if postimage.body.length > 50 %> <span class="text-prev"><%= link_to '続きを読む', post_image_path(postimage), data: {"turbolinks" => false} %> </span> <% end %> </div> </div> <% end %> </div> </div> <div class="image-index-pagination" data-turbolinks="false"> <%= paginate @postimage,class:"paginate" %> </div> </div> <% end %> </div> <div class="row"> <div class= "col-xs-12 col-lg-12 col-md-12 col-sm-12"> <div class= "hashtag-name"> <% @hashtags.sort.reverse.each do |count| %> <% count[1].each do |hashtag| %> <p><%= link_to "##{hashtag.hashname} (#{hashtag.post_images.count}) 件","/post_image/hashtag/#{hashtag.hashname}",data: {"turbolinks" => false} %> </p> <% end %> <% end %> </div> </div> </div> </div>クラス名とかを使いまわしていて訳わかんなくなっていてすいません。
大事なところは以下です。post_images/hashtag.html.erb<% if params[:name] == nil %> <% else %> <% end %>この表記で先ほどrouteに書いたpost_image/hashtagとpost_image/hashtag/:nameでの条件分岐をしています。
paramsがnilのときの処理をコントローラーとViewそれぞれに書くことでエラーを起こさせないようにしています。post_image/hashtag.html.erb<div class= "hashtag-name"> <% @hashtags.sort.reverse.each do |count| %> <% count[1].each do |hashtag| %> <p><%= link_to "##{hashtag.hashname} (#{hashtag.post_images.count}) 件","/post_image/hashtag/#{hashtag.hashname}",data: {"turbolinks" => false} %> </p> <% end %> <% end %> </div>ここにハッシュタグ一覧を表示しています。
表示はハッシュタグに紐づく投稿が多い順に表示しています。まとめ
ハッシュタグ入力欄を別にしないと、投稿の説明文のところにそのまま文章としてハッシュタグが残ってしまうため別カラムへの保存という形で実装しました。
投稿と一緒にハッシュタグを表示させている箇所では、意図的にhashbodyを非表示にしています。
view上にやたらと存在するturbolinks falseですがjsがうまく動かなくて書いてあるものなので、無視して頂いて大丈夫です。初めての投稿で分かりづらい箇所があれば申し訳ないです。
これからポートフォリオを作成する方の参考になれば幸いです。
- 投稿日:2020-06-24T11:40:59+09:00
Rubyで最もシンプルなブロックチェーンを構築する方法
この記事では、Rubyを使ってシンプルなワーキングブロックチェーンデモを構築する方法を探っていきます。
本ブログは英語版からの翻訳です。オリジナルはこちらからご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。
ステージ1:送金
この段階で残高確認と振込を実施します。送金は口座残高に基づいて実行される加算または減算です。
この機能を実装するには、HTTPプロトコルのGETとPOSTが最適です。GETはサーバからデータを取得し、POSTはサーバ上のデータを変更します。
ここでは、UIの表示はHTMLプロトコルを必要としません。RubyのWebフレームワークSinatraを使ってURLや関連するメソッドを整理し、UEを使ってコマンドラインで転送情報を見ることができます。
クライアント側のメソッドとサーバ側のURLは非常にシンプルです。
クライアント: client.rb
def create_user(name) … end def get_balance(user) … end def transfer(from, to, amount) ... endサーバー:haseebcoin.rb
get "/balance" ... end post "/users" ... end post "/transfers" ... endこの層に必要な知識:ruby、HTTP GET、POST、Sinatra
ステージ2:ゴシップネットワークの構築
ブロックチェーンには "ゴシッププロトコル "と呼ばれる分散型の構造があります。ここでいう "ゴシップ "とは噂ではなく、分散型ネットワークで拡散される情報のことを指します。
映画の名前が交換されるゴシップネットワークを構築してみましょう。
client.rbは指定されたポートにメッセージを送信します。
def self.gossip(port, state) ... Faraday.post("#{URL}:#{port}/gossip", state: state).body ... endgossip.rbは、送信元ポートと送信先ポートの2つのパラメータを受け取ります。ポート1111や2222など、ソース側の特定のポートを介して情報を交換します。
実際の分散型ネットワークでは、2つのポートは本質的に2つのネットワークノードです。異なるローカルポート間で情報を交換することは、シミュレーションされたネットワークの異なるノード間の通信を表しています。
各ノードで
3 秒ごとに好きな映画の名前を話してください。every(3.seconds) do … gossip_response = Client.gossip(port, JSON.dump(STATE)) update_state(JSON.load(gossip_response)) ... end8秒ごとにお気に入りの映画名を変更します。
every(8.seconds) do … update_state(PORT => [@favorite_movie, @version_number]) ... endサーバはデータを受信して処理します。
post '/gossip' do … update_state(JSON.load(their_state)) … end4人のネットワークで
1、最初のノードで gossip.rb 1111 を実行します。最初のノードはポート1111で好きな映画の名前を話します。
2、gossip.rb 2222 1111を実行します。2番目のノードはポート2222で好きなムービー名を最初のノード(ポート1111)に発言します。
3、gossip.rb 3333 2222を実行します。3番目のノードは、ポート3333から2番目のノード(ポート2222)にお気に入りのムービー名を話します。
4、gossip.rb 4444 3333を実行します。4番目のノードは、ポート4444から3番目のノード(ポート3333)にお気に入りのムービー名を話します。しばらく実行してようやく4つのノードがピアエンドの情報を取得し、データは変化し続けます。これが単純なGossipネットワークです。
ステージ3:データの暗号化と復号化
トップレベルの暗号化アルゴリズムは、ブロックチェーンの基礎となるものです。この層では、ブロックチェーンアカウントを実装するために非対称暗号化技術が使用されています。RSAアルゴリズムは公開鍵、秘密鍵を生成し、非対称暗号化を強制することができます。
def generate_key_pair … end def sign(plaintext, raw_private_key) ... endRuby言語のOpenSSLモジュールのおかげで、非対称暗号化や署名検証を素早く実装することができます。ブロックチェーンでは、公開鍵はアカウント、秘密鍵はパスワードです。鍵のペアはそれぞれ1つのブロックチェーンアカウントになります。
暗号文を復号化する。
def plaintext(ciphertext, raw_public_key) … end暗号文がメッセージであるかどうかを確認します。
def valid_signature?(message, ciphertext, public_key) … endこの層に必要な知識:非対称暗号化アルゴリズム
ステージ4:データマイニング
この段階では、プルーフ・オブ・ワークが実装され、ブロックチェーン用のブロックが生成されます。これは時間と手間のかかるプロセスです。ハッシュ関数は不可逆的であり、競合はありません。計算プロセスは簡単です。入力に対してハッシュ演算を行うだけで結果が得られる。
入力とは、送金額、送金人の名前、受取人の名前など、送金に関する情報である。ハッシュ演算には様々なアルゴリズムがある。
ここでは、SHA256アルゴリズムを使用します。
def hash(message) … end同じ情報をハッシュ化すると、毎回違う結果が出てきます。得られた結果が、例えば「0の数桁から始まる」などの特徴を満たすまで演算を続けます。
結果が数桁の0から始まるかどうかを確認します。
def is_valid_nonce?(nonce, message) hash(message + nonce).start_with?("0" * NUM_ZEROES) end上記の条件を満たすための作業を行うことは容易ではない。多くの時間を消費する。このような作業を全てマイニングといいます。
def find_nonce(message) … until is_valid_nonce?(nonce, message) ... end入力には前回のハッシュ操作の結果が含まれます。したがって、各ハッシュ操作は前のハッシュ操作の影響を受けます。言い換えれば、これはチェーン構造である。これがブロックチェーンと呼ばれる所以です。
ステージ5:最長チェーンルール
この段階では、最初のブロックが初期化され、それに応じてブロックチェーン構造が生成され、ブロックチェーンが形成されます。ブロックチェーンはArray構造に格納されます。保存中に、ブロックは検証を受けなければなりません。
ブロックを初期化します。
def initialize(prev_block, msg) @msg = msg @prev_block_hash = prev_block.own_hash if prev_block mine_block! end採掘中に一番やりがいを感じる作業は、nonceを見つけることです。
def mine_block! @nonce = calc_nonce @own_hash = hash(full_block(@nonce)) end完全なブロックはこのように圧縮されます。
def full_block(nonce) [@msg, @prev_block_hash, nonce].compact.join endブロックチェーンを初期化する: class BlockChain
Arrayを使って保存するだけ!
def initialize(msg) @blocks = [] @blocks << Block.new(nil, msg) endチェーンにブロックを追加する。ブロックチェーン全体が継続的に成長している。
def add_to_chain(msg) @blocks << Block.new(@blocks.last, msg) puts @blocks.last endブロックが健全かどうかを厳密に検証する必要があります。
def valid? @blocks.all? { |block| block.is_a?(Block) } && @blocks.all?(&:valid?) && @blocks.each_cons(2).all? { |a, b| a.own_hash == b.prev_block_hash } endステージ6. ピースの組み合わせ
最後に、Blockchainは、ネットワーク内のすべてのコンポーネントとの調和のとれたコラボレーションを通じて、その魔法を働かせます。第一段階では、転送はトランザクションクラスであり、情報に署名するために秘密鍵を使用する必要があります。
@signature = PKI.sign(message, priv_key)最初のブロックを手に入れた鉱夫の報酬は50万枚の銀貨です。
def self.create_genesis_block(pub_key, priv_key) genesis_txn = Transaction.new(nil, pub_key, 500_000, priv_key) Block.new(nil, genesis_txn) endアカウントに請求された支出が有効かどうかを確認してください。
def all_spends_valid? compute_balances do |balances, from, to| return false if balances.values_at(from, to).any? { |bal| bal < 0 } end true endネットワークの成長を維持するために未知のノード$PEERSを追加します。
if PEER_PORT.nil? # You are the progenitor! $BLOCKCHAIN = BlockChain.new(PUB_KEY, PRIV_KEY) else # You're just joining the network. $PEERS << PEER_PORT endノード間のデータ処理は、ブロックチェーンとPEERを読み込んで更新します。
# @param blockchain # @param peers post '/gossip' do their_blockchain = YAML.load(params['blockchain']) their_peers = YAML.load(params['peers']) update_blockchain(their_blockchain) update_peers(their_peers) YAML.dump('peers' => $PEERS, 'blockchain' => $BLOCKCHAIN) end受信したブロックの処理は、チェーンが長くなっているかどうかに注目しています。
def update_blockchain(their_blockchain) return if their_blockchain.nil? return if $BLOCKCHAIN && their_blockchain.length <= $BLOCKCHAIN.length return unless their_blockchain.valid? $BLOCKCHAIN = their_blockchain end新しいものになるまでPEERを更新する。
def update_peers(their_peers) $PEERS = ($PEERS + their_peers).uniq end送金の際には、受取人のpub_keyを取得し、送金人のpub_keyを経由して送金します。
# @param to (port_number) # @param amount post '/send_money' do to = Client.get_pub_key(params['to']) amount = params['amount'].to_i $BLOCKCHAIN.add_to_chain(Transaction.new(PUB_KEY, to, amount, PRIV_KEY)) 'OK. Block mined!' endブロックチェーンをゴシップネットワークに入れて、すべての機能コンポーネントを組み立てる。これで完成です。ブロックチェーンの作成に成功しました。
このデモについての詳細はGithubで見ることができます: https://github.com/Haseeb-Qureshi/lets-build-a-blockchain
ブロックチェーンやその他の革新的な技術の詳細については、www.alibabacloud.com をご覧ください。
アリババクラウドは日本に2つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
アリババクラウドジャパン公式ページ
- 投稿日:2020-06-24T03:25:12+09:00
RubyでBlackJack-cliを作ってみた感想とか
Qiitaでこんな記事を見つけたので、BlackJackをRubyで作ってみました。
プログラミング入門者からの卒業試験は『ブラックジャック』を開発すべし | Qiita感想としては簡単なゲームを作るだけですが、とても楽しかったです。BlackJackを作ってみてゲーム以外にも色々作れそうな気がしたのでもう少しBlackJackのコードを変えながら遊んでみてから次何を作るか考えようかなと思ってます。
全てのコードはGithub上に上げているのでこちらから確認できます
BlackJack Ruby | Ryutaro - Githubブラックジャックのルール
ブラックジャックのルールについては、こちらの記事に書かれているルールを基準に作成しました。
- 初期カードは52枚。引く際にカードの重複は無いようにする
- プレイヤーとディーラーの2人対戦。プレイヤーは実行者、ディーラーは自動的に実行
- 実行開始時、プレイヤーとディーラーはそれぞれ、カードを2枚引く。引いたカードは画面に表示する。ただし、ディーラーの2枚目のカードは分からないようにする
- その後、先にプレイヤーがカードを引く。プレイヤーが21を超えていたらバースト、その時点でゲーム終了
- プレイヤーは、カードを引くたびに、次のカードを引くか選択できる
- プレイヤーが引き終えたら、その後ディーラーは、自分の手札が17以上になるまで引き続ける
- プレイヤーとディーラーが引き終えたら勝負。より21に近い方の勝ち
- JとQとKは10として扱う
- Aはとりあえず「1」としてだけ扱う。「11」にはしない
- ダブルダウンなし、スプリットなし、サレンダーなし、その他特殊そうなルールなし
悩んだところ
- 用意するクラスについて
- インスタンスメソッドまたはクラスメソッドどっちにするか
- データをどこで保持させるべきか(山札や手札など)
用意したクラス
次の6つのクラスを作成しました。
それぞれのクラスの役割は次になります。# カードNumberとダイヤやハートなどのマークをそれぞれ配列で用意するクラス class Card # 用意したカードから山札を作成してシャッフルするクラス、Cardクラスを継承している class Deck < Card # プレイヤーとディーラーのスーパークラスでそれぞれの共通処理をするクラス class PlayerBase # プレイヤー専用の処理を作成している、PlayerBaseを継承している class Player < PlayerBase # ディーラー専用の処理を作成している、PlayerBaseを継承している class Dealer < PlayerBase # ゲームの進行に必要な処理や手札や山札などのデータを保持するクラス class BlackJackプレイヤーとディーラーで共通する処理が多かったため
PlayerBase
というスーパークラスを作成することでメソッドの使い回しができるようになり楽に進められた気がします。
インススタンスメソッドまたはクラスメソッドにすべきか
これについてもめちゃくちゃ悩んで「ruby インスタンスメソッド クラスメソッド 違い」みたいなことを何回もググりました。
結果的に「基本的にはインスタンスメソッドで作成して、ちょっとインスタンスメソッドだと使いづらいかな?と感じたところはクラスメソッドにしよう」という少し抽象的な判断で決めています。
クラスメソッド例
class Card class << self def numbers no = [1, 2, 3, 4, 5, 6, 7 ,8 ,9 ,10, 11, 12, 13] end def suit suit = ["ダイヤ", "ハート", "クラブ", "スペード"] end end endインスタンスメソッド例
class PlayerBase def create_hand(deck) deck.pop(2) end # . # . # .手札や山札などのデータをどのクラスで保持するべきか
データの保管場所が一番悩んだところです。当初は「プレイヤーの手札だからPlayerクラスで、ディーラーの手札だからDealerクラスで管理しよう。山札に関しては共通のものだからPlayerBaseクラスだよね」と思ったのですが、進めていく途中でインスタンスを生成した際に2つの山札が作られてしまうなど色々面倒なことが多かったので、BlackJackクラスで全てのデータを保持する方針で決まりました。
詳細なコード説明
詳細なコードの説明はまた別で記事にしようと思います。今回は感想や苦労したところを書いてみました。
- 投稿日:2020-06-24T00:40:06+09:00
dockerとmysqlでrails環境を構築した
dockerにrails環境を作った
https://qiita.com/NA_simple/items/5e7f95ae58eec5d20e1f途中なぜか上手くいかないと思ったら、mysql-clientsがインストールできなくなっているらしい。書き換え方は下のURLを参考に。
https://qiita.com/yagi_eng/items/1368fb2a234629a0c8e7調子に乗ってすすめていると、またハマる。
terminal$ docker-compose run web rails db:create Starting postgress_db ... done Could not find activesupport-5.2.4.3 in any of the sources Run `bundle install` to install missing gems.なぜだ、、、と思ったらrubyのバージョンが違う??
rbenvでバージョンを探しても、2.7.1が見つからず。
rbenv古い事に気づき、アップデートrbenvをアップデート
https://qiita.com/pugiemonn/items/f277440ec260b8d4fa6aからのgemも古い事に気づき、
terminal$ gem updateまだいかない、、、
bundler updateを行う。ここらへんで絶望したので時間を置く。
一旦整理して、違うサイトの最初から手順をパクる。
https://toranoana-lab.hatenablog.com/entry/2020/06/05/173658
なんと止まること無くdockerの起動、localhostにアクセス可能に!!!
よっしゃ!!!!localhost_3000Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)
なんで :D
ググるとファイルが無いらしいからsudo touchで無理やり作ってる記事がちらほら。
でもファイルあるしなあ、と思いつつ削除&作成同じエラー。
???と思い、ここでmysql立ち上げていないことに気づく
これだ!!!と思ってterminalmysql.server start
を実行するも、起動しない。
ググるとどうやらterminalsudo rm mysql.sock brew uninstall mysql brew install mysql
と、sockファイルを消してからmysqlをアンインストール→インストールで治るらしい。
mysql.sockのパスは前のエラーで判明していたので、それを消してからterminalmysql.server start
…通った!!!!
これは行ったか…?
ヤッターーーーーーー!!!!!!!!!
docker理解してから構築したほうが早かったと思います。
勉強し直しましょう。自分。なにはともあれ動いてよかった
最終的な各ファイルの中身↓
gemfilesource 'https://rubygems.org' gem 'rails', '~>6'docker-compose.ymlversion: '3' services: db: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: ports: - '3306:3306' command: --default-authentication-plugin=mysql_native_password volumes: - mysql-data:/var/lib/mysql 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 stdin_open: true tty: true command: bundle exec rails server -b 0.0.0.0 volumes: mysql-data: driver: localDockerfileFROM ruby:2.7 RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \ && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list \ && apt-get update -qq \ && apt-get install -y nodejs yarn \ && mkdir /myapp WORKDIR /myapp COPY Gemfile /myapp/Gemfile COPY Gemfile.lock /myapp/Gemfile.lock RUN bundle install COPY . /myapp COPY entrypoint.sh /usr/bin/ RUN chmod +x /usr/bin/entrypoint.sh ENTRYPOINT ["entrypoint.sh"] EXPOSE 3000 CMD ["rails", "server", "-b", "0.0.0.0"]
- 投稿日:2020-06-24T00:40:06+09:00
dockerとmysqlでrails環境を構築したけどドハマリした
dockerにrails環境を作った
https://qiita.com/NA_simple/items/5e7f95ae58eec5d20e1f途中なぜか上手くいかないと思ったら、mysql-clientsがインストールできなくなっているらしい。書き換え方は下のURLを参考に。
https://qiita.com/yagi_eng/items/1368fb2a234629a0c8e7調子に乗ってすすめていると、またハマる。
terminal$ docker-compose run web rails db:create Starting postgress_db ... done Could not find activesupport-5.2.4.3 in any of the sources Run `bundle install` to install missing gems.なぜだ、、、と思ったらrubyのバージョンが違う??
rbenvでバージョンを探しても、2.7.1が見つからず。
rbenv古い事に気づき、アップデートrbenvをアップデート
https://qiita.com/pugiemonn/items/f277440ec260b8d4fa6aからのgemも古い事に気づき、
terminal$ gem updateまだいかない、、、
bundler updateを行う。ここらへんで絶望したので時間を置く。
一旦整理して、違うサイトの最初から手順をパクる。
https://toranoana-lab.hatenablog.com/entry/2020/06/05/173658
なんと止まること無くdockerの起動、localhostにアクセス可能に!!!
よっしゃ!!!!localhost_3000Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)
なんで :D
ググるとファイルが無いらしいからsudo touchで無理やり作ってる記事がちらほら。
でもファイルあるしなあ、と思いつつ削除&作成同じエラー。
???と思い、ここでmysql立ち上げていないことに気づく
これだ!!!と思ってterminalmysql.server start
を実行するも、起動しない。
ググるとどうやらterminalsudo rm mysql.sock brew uninstall mysql brew install mysql
と、sockファイルを消してからmysqlをアンインストール→インストールで治るらしい。
mysql.sockのパスは前のエラーで判明していたので、それを消してからterminalmysql.server start
…通った!!!!
これは行ったか…?
ヤッターーーーーーー!!!!!!!!!
docker理解してから構築したほうが早かったと思います。
勉強し直しましょう。自分。なにはともあれ動いてよかった
最終的な各ファイルの中身↓
gemfilesource 'https://rubygems.org' gem 'rails', '~>6'docker-compose.ymlversion: '3' services: db: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: ports: - '3306:3306' command: --default-authentication-plugin=mysql_native_password volumes: - mysql-data:/var/lib/mysql 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 stdin_open: true tty: true command: bundle exec rails server -b 0.0.0.0 volumes: mysql-data: driver: localDockerfileFROM ruby:2.7 RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \ && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list \ && apt-get update -qq \ && apt-get install -y nodejs yarn \ && mkdir /myapp WORKDIR /myapp COPY Gemfile /myapp/Gemfile COPY Gemfile.lock /myapp/Gemfile.lock RUN bundle install COPY . /myapp COPY entrypoint.sh /usr/bin/ RUN chmod +x /usr/bin/entrypoint.sh ENTRYPOINT ["entrypoint.sh"] EXPOSE 3000 CMD ["rails", "server", "-b", "0.0.0.0"]