- 投稿日:2020-07-04T21:25:41+09:00
タクシー数をRubyで調べてみた
不思議な数をRubyで検証シリーズ第2弾!(あと何回続くんだ?)
前回の第1回はこちら↓
ある範囲内の整数にカプレカ数があるかRubyで調べてみた今回はタクシー数です。
前回同様Youtubeから題材をいただきました。予備校のノリで学ぶ「大学の数学・物理」
ラマヌジャンの天才エピソードでおなじみ【タクシー数】タクシー数とは
n 番目のタクシー数(タクシーすう、taxicab number、Ta(n)もしくはTaxicab(n)と表記される)とは、2つの立方数の和として n 通りに表される最小の正の整数と定義される。
「タクシー数」と言う名前はハーディが乗ったタクシーの番号1729についてそれがTa(2)であることをシュリニヴァーサ・ラマヌジャンが指摘したエピソードから来ている引用元:Wikipedia
立法数とはある数を3乗した数のことです。
平方数が2乗なのでその進化系ですね。そしてタクシー数は立法数の和(足し算)で何通りかに表されるものらしい
調べてみた
内容:
x^3 + y^3
でn通りに表される最小の正の整数(x, y
の組み合わせの出力を含む)
条件:(1 ≦ x ≦ y ≦ 500)
taxi.rbdef safe_invert(orig_hash) orig_hash.each_key.group_by { |key| orig_hash[key] }.sort.to_h end hash = {} (1..500).each do |y| (1..500).each do |x| hash.store([x, y], x ** 3 + y ** 3) if x == y break end end end taxi = [] n = 1 safe_invert(hash).each do |k, v| if v.size == n taxi.push("Ta(#{n}) => #{k}: #{v}") n += 1 end end puts taxiTa(1) => 2: [[1, 1]] Ta(2) => 1729: [[9, 10], [1, 12]] Ta(3) => 87539319: [[255, 414], [228, 423], [167, 436]]立法数の和として3通りで表せる最小の数が既に8753万とは、かなり大きな数ですね。
コード説明
順を追って説明します
簡略化するために範囲を小さくしてみていきましょう条件:
(1 ≦ x ≦ y ≦ 5)
taxu.rbhash = {} (1..5).each do |y| (1..5).each do |x| hash.store([x, y], x ** 3 + y ** 3) end end p hash{[1, 1]=>2, [2, 1]=>9, [3, 1]=>28, [4, 1]=>65, [5, 1]=>126, [1, 2]=>9, [2, 2]=>16, [3, 2]=>35, [4, 2]=>72, [5, 2]=>133, [1, 3]=>28, [2, 3]=>35, [3, 3]=>54, [4, 3]=>91, [5, 3]=>152, [1, 4]=>65, [2, 4]=>72, [3, 4]=>91, [4, 4]=>128, [5, 4]=>189, [1, 5]=>126, [2, 5]=>133, [3, 5]=>152, [4, 5]=>189, [5, 5]=>250}まず
x
とy
に1〜5までの整数を与え.それぞれ3乗した数を足した答え(和)を総当たりに調べて
hash
に追加していきましょう。
Hashクラスのstore
メソッドは、第一引数にkey、第二引数にvalueとする要素を追加するメソッドです。
hash
の長さは 5 × 5 = 25通りになります。表を見ていただいてお分かりの通り、xとyを入れ替えて求められる答えは同じです。
(x, y) = (2, 5)
のときも、(x, y) = (5, 2)
のときも答えは133
。
これは2通りとは数えません。1通りです。
なので表の中で求める必要があるのはこの範囲ということで、
x
とy
が同じ場合はhash
に要素を追加したらループを抜けるようにbreak
しますtaxu.rbhash = {} (1..5).each do |y| (1..5).each do |x| hash.store([x, y], x ** 3 + y ** 3) if x == y break end end end p hash{[1, 1]=>2, [1, 2]=>9, [2, 2]=>16, [1, 3]=>28, [2, 3]=>35, [3, 3]=>54, [1, 4]=>65, [2, 4]=>72, [3, 4]=>91, [4, 4]=>128, [1, 5]=>126, [2, 5]=>133, [3, 5]=>152, [4, 5]=>189, [5, 5]=>250}
続いて後半
特にメソッドの中が複雑です。hashの中はkeyに
[x, y]
という配列、valueに立法数の和
という要素が入っていましたが、
safe_invertメソッド
を通すと、重複を考慮した上でkeyとvalueを逆にしたハッシュを作ります。taxi.rbdef safe_invert(orig_hash) orig_hash.each_key.group_by { |key| orig_hash[key] }.sort.to_h end p safe_invert(hash){2=>[[1, 1]], 9=>[[1, 2]], 16=>[[2, 2]], 28=>[[1, 3]], 35=>[[2, 3]], 54=>[[3, 3]], 65=>[[1, 4]], 72=>[[2, 4]], 91=>[[3, 4]], 126=>[[1, 5]], 128=>[[4, 4]], 133=>[[2, 5]], 152=>[[3, 5]], 189=>[[4, 5]], 250=>[[5, 5]]}
each_key.group_by { |key| orig_hash[key] }
で各keyをvalueに、
orig_hash[key]
(つまりvalue)をkeyとするハッシュを作ります。
key valueの反転です。難しい発想ですがこちらを参考にしました
Hash#invert (Ruby 2.7.0 リファレンスマニュアル)そして
sort
でkeyの昇順に並べ替えると同時に配列に変換されてしまうので、
.to_h
でハッシュに戻します。
x, y
が1〜5までではこの処理のメリットがいまいちピンとこないと思いますが、
Ta(2)
である1729が出現するよう範囲を1〜12まで広げると、出力結果でこのように…{ ......, 1729=>[[9, 10], [1, 12]], ......}valueの配列の長さが2つになり、1729の立法数の和としての表し方が2通りあることがわかりますね。
taxi.rbtaxi = [] n = 1 safe_invert(hash).each do |k, v| if v.size == n taxi.push("Ta(#{n}) => #{k}: #{v}") n += 1 end end puts taxi最後に出来上がったハッシュに対して
each
で
valueの配列の長さが1から順に最初にマッチしたものを空の配列taxi
に追加し、
結果を出力して終了です。余談
Wikipediaを見て知ってしまったのですが
Ta(4)
は範囲を1〜19000まで広げないと出てきません。試しに
(1..19000)
で実行してみましたが、
数分待っても処理が終わらず断念。やはりRubyは網羅的な検証には向かないかも
もっといい書き方がありましたらコメントで教えてください!
(2020/07/05 追記)
コメントにて改良版をご提案いただきました!
- 投稿日:2020-07-04T20:43:05+09:00
【Ruby】条件分岐について[第一回]
本日より学習したことのアウトプットや備忘録を兼ねて、記事を書いていきます。
最初のうちは、基礎的な内容を中心に考えています。記事内容に誤りなどございましたら、指摘いただければ幸いです。
本日はRubyの条件分岐一回目について、書いていきたいと思います。
if式
ある条件式が真の場合、if式の処理が実行されます。
ポイントとして「false」と「nil」は偽として判定され、それ以外は真と判定されるという点です。if 条件式 then # 条件式が真の場合の処理 end※thenは省略可能で、省略するのが一般的なようです。以後の項目は省略して記述します。
else式
if式の条件式が偽の場合の処理を実行します。
if 条件式 # 条件式が真の場合の処理 else # 条件式が偽の場合の処理 endelsif式
elsif式を使うことでより多くの分岐を記述できます。
if 条件式1 # 条件式1が真の場合の処理 elsif 条件式2 # 条件式2が真の場合の処理 else # いずれの条件式も偽の場合の処理 endif式やelse式は値を返す
Rubyの多くの式は値を返すことができ、if式やelse式も同様に値を返すことができます。
ifやelseの最後の値が戻り値となります。result = if 条件式 '条件式が真です' else '条件式が偽です' end条件式が真の場合、resultには'条件式が真です'という文字列が格納されます。
条件式が偽の場合、resultには'条件式が偽です'という文字列が格納されます。unless式とelse式
if式と異なり、偽の場合に処理を実行します。
unless式の場合はelse式は使えますが、elsif式は使えません。
また、条件が複雑になると分かりにくくなる印象で、if式を使うかは条件次第で検討した方が良いと感じます。unless 条件式 # 条件式が偽の場合の処理 else # 条件式が真の場合の処理 end今回は以上となります。
- 投稿日:2020-07-04T19:40:41+09:00
rails s 実行時のCould not find a JavaScript runtime.のエラー対応方法
macOSのバージョンを上げてしまい、開発中のRailsアプリのローカル環境でローカルサーバーが起動出来なくなり、以下のようなエラーが発生したため、忘備録のために投稿します。
macOS Catalina バージョン 10.15.5
環境:Ruby,Ruby on Rails,JavaScriptエラー内容
Could not find a JavaScript runtime. See https://github.com/rails/execjs for a list of available runtimes. (ExecJS::RuntimeUnavailable)解決方法
Node.jsの最新版をインストールする。
以上です。これだけでした。
- 投稿日:2020-07-04T19:39:52+09:00
Rails5.2から導入されたcredentials.yml.encの使い方
Rails5.2では新規アプリを作成した時にconfig/secrets.ymlが生成されず
代わりにconfig/credentials.yml.encが生成されるようになったみたいです。既に本番環境などでRailsの古いバージョンで運用していてRails5.2にアップグレードする場合は
config/secrets.ymlではなく、config/credentials.yml.encの仕組みが使われるみたいです。Rails5.2までは従来のconfig/secrets.ymlを使用するやり方などもあるみたいですが
Rails6アップグレードのことも考えconfig/credentials.yml.encを導入してみましたので
忘備録のために投稿します。1. credentials.yml.encとmaster.keyの生成と設定
credentials.yml.encは直接エディタから編集する事はできないので、ターミナルでエディタを指定して作成、編集する。
$ EDITOR=vim bundle exec credentials:editちなみに、.bash_profileなどに以下のように設定しておけば、EDITOR="vim"の指定は不要になります。
~/.bash_profile $ echo 'export EDITOR="vim"' >> ~/.bash_profile $ source ~/.bash_profile $ bundle exec credentials:edit上記のコマンドを実行すると、config/credentials.yml.encとconfig/master.keyが生成される。
config/master.keyはgitで管理しないため必ず.gitignoreに追加する。.gitignore # Ignore master key for decrypting credentials and more. /config/master.key生成されたconfig/credentials.yml.encを以下のように修正する。
config/credentials.yml.enc # aws: # access_key_id: 123 # secret_access_key: 345 # Used as the base secret for all MessageVerifiers in Rails, including the one protecting cookies. secret_key_base:
- 今回はsecret_keyだけ設定する。AWSの設定は既存のままいくのでコメントアウトのまま
- 上記の画面にawsのaccess_key_idやsecret_access_key、その他APIキーなどを入力すれば暗号化されて保存される
- 環境変数など使用せず、直接入力して問題ない
- シングルクオーテーションやダブルクオーテーションは不要
本番環境ではcredentialを使うので config/environments/production.rb で次の変数にtrueをセットする
config/environments/production.rb config.require_master_key = true2.Capistranoによる自動デプロイ
本番環境のshared/configにmaster.keyを配置しないとデプロイできない。
本番環境のサーバーにscpコマンドなどで、config/master.keyを転送する。$ scp -i ~/.ssh/example.pem config/master.key ec2-user@x.x.x.x:/var/www/AppName/shared/config/master.key ex. /var/www/AppName/shared/config/master.keyもしくは、本番環境サーバーのbashファイルにRAILS_MASTER_KEY環境変数を設定する。
Capistranoは.bash_profileに書いても読み込まれないので、~/.bashrcに記載する必要がある。
config/master.keyをRAILS_MASTER_KEYとしてexportします。つまり、.bashrcに以下のように設定する。~/.bashrc export RAILS_MASTER_KEY='XXXXXXXXXXXXXXXXXXX'次に、config/deploy.rbでデプロイ時の設定ファイルにシンボリックリンクを指定する。
set :linked_files, fetch(:linked_files, []).push('config/master.key')3.Capistranoを使ってデプロイできれば完了。
$ bundle exec cap production deploy
- 投稿日:2020-07-04T18:30:39+09:00
Rails5でECサイトを作る② ~Bootstrap4設定、Controller・アクション定義~
はじめに
架空のベーカリーで買い物できるECサイトを作るシリーズ、Rails5でECサイトを作る①の続きです。
必要なControllerとViewを揃え、アクションも定義だけ書いて、最低限のページ遷移ができるようにします。ソースコード
https://github.com/Sn16799/bakeryFUMIZUKI
Controller
コントローラを一気に作ります。Viewも伴うアクションは、ここでまとめて作ってしまいます。
Customerサイト
$ rails g controller addresses edit index $ rails g controller cart_items index $ rails g controller customers edit show withdraw $ rails g controller genres index show $ rails g controller homes about top $ rails g controller order_items index $ rails g controller orders confirm index new show thanks $ rails g controller products index showAdminサイト
$ rails g controller admin::customers edit index show $ rails g controller admin::genres edit index $ rails g controller admin::homes top $ rails g controller admin::order_items $ rails g controller admin::orders index show $ rails g controller admin::products edit index new show $ rails g controller admin::searches searchアクション
ViewのないアクションをControllerファイルに記述していきます。
詳しい内容は後で書くので、今は一通りアクションを定義して、ページ遷移できることを優先します。Customerサイト
app/controllers/addresses_controller.rbdef create end def update end def destroy endapp/controllers/cart_items_controller.rbdef create end def update end def destroy end def destroy_all endapp/controllers/customers_controller.rbdef udpate end def withdraw_done endapp/controllers/order_items_controller.rbdef new endapp/controllers/orders_controller.rbdef create endAdminサイト
app/controllers/admin/customers_controller.rbdef update endapp/controllers/admin/genres_controller.rbdef create end def update endapp/controllers/admin/order_items_controller.rbdef update endapp/controllers/admin/orders_controller.rbdef update endapp/controllers/admin/products_controller.rbdef create end def update endBootstrap4 読み込み
gem(bootstrap, jquery-rails)のインストールについては前回行ったので割愛します。
app/assets/stylesheets/application.cssをapplication.scssにリネームしておきます。
そのファイル内にBootstrapの読み込みを記述します。appseets/stylesheets/application.scss@import 'bootstrap';javascriptファイルにも同様に記述を行います。
app/assets/javascripts/application.js//= require rails-ujs //= require activestorage -------------------------------- //= require jquery3 //= require popper #ここを追記 //= require bootstrap-sprockets -------------------------------- //= require_tree .これでBootstrapを利用できるようになりました。試しに適当なところで使ってみましょう。
app/views/homes/top.html.erb<h1>Homes#top</h1> <p>Find me in app/views/homes/top.html.erb</p> <%= link_to 'ABOUT', homes_about_path, class: 'btn btn-info' %>正しくページが表示され、"ABOUT"と書かれたリンクがボタンになりました! きちんとBootstrapが適用されていますね。
containerなどの枠組みをまだ何も設定していないので、全体的におそろしく端に寄ってしまいました。後ほど直しますが、今はとりあえず気にしないことにします。後記
ひとまずRoutingとControllerを作ったので、必要なページは全て表示できるようになりました。次の記事から、具体的な機能の実装に入れそうです。
ところで、ページのデザインをどんな感じにするか、まだ迷っています。基本的にはBootstrapを下地としたレスポンシブ対応の設計にする予定ですが、おしゃれなCSSに挑戦するのも悪くないなぁと思ったり……。
今更ながら「パン屋の温かみあるイメージ」と「スタイリッシュな今風のサイト」が全然結び付かず、テーマ選びを間違えた感じがしているのですが、写真素材がすでに手元にあるのでこのまま進めます。
果たして、webサイトを違和感なく仕上げられるのか? 次回へ続く!
- 投稿日:2020-07-04T18:27:37+09:00
Crystal というプログラミング言語について
はじめに
まず Crystalとはなんぞや!ですが、簡単に言えばrubyの構文を使ってC言語みたいな実行速度でプログラムが動くように設計されたプログラミング言語です。今回は、このcrystalの魅力を簡単にご紹介できればと思い記事にいたしました。
実行速度の確認
まず、crystalを入れていない方は公式サイトから環境に合わせてインストールしてください。
その後で、適当なところにcrystalフォルダを作成します。
続けて、crystalフォルダの中にtest.crを作成し、中身を以下のように編集してください。puts "Hello World!"見ていただくと分かるように、文字を表示するプログラムです。
これをrubyのように実行すると、実行速度は次の通りになります。time crystal test.cr → Hello world! → crystal test.cr 0.85s user 0.27s system 134% cpu 0.833 total今度は、test.crをコンパイル(一度にファイルの中身を全てパソコンが読み込める状態に変換すること)を行ってから実行すると、次の通りとなります。
crystal build test.cr --release time ./test → Hello world! → ./test 0.00s user 0.00s system 2% cpu 0.263 total比較すると、前者が0.85秒だったのに対して、後者は0.00秒と最低でも10倍以上速くなっていることが分かります。
ここまでのことはこちらのサイトにも記載されていますので、さらに知りたい方はこちらもご覧いただけたら良いかと思います。
- 投稿日:2020-07-04T17:10:45+09:00
【Rails】FullCalendarを用いたスケジュール管理昨日の実装
目標
開発環境
・Ruby: 2.5.7
・Rails: 5.2.4
・Vagrant: 2.2.7
・VirtualBox: 6.1
・OS: macOS Catalina前提
下記実装済み。
・Slim導入
・Bootstrap3導入
・Font Awesome導入
・ログイン機能実装
・投稿機能実装実装
1.Gemを導入
Gemfile# 追記 gem 'jquery-rails' gem 'fullcalendar-rails' gem 'momentjs-rails'ターミナル$ bundle2.
application.scss
を編集application.scss*= require_tree . *= require_self *= require fullcalendar /*追記*/3.
application.js
を編集application.js//= require rails-ujs //= require activestorage //= require turbolinks //= require jquery //= require moment // 追記 //= require fullcalendar // 追記 //= require_tree .4.JavaScriptファイル作成・編集
ターミナル$ touch app/assets/javascripts/calendar.jscalendar.js$(function() { function eventCalendar() { return $('#calendar').fullCalendar({}); } function clearCalendar() { $('#calendar').html(''); } $('#calendar').fullCalendar({ events: '/events.json', titleFormat: 'YYYY年 M月', dayNamesShort: ['日', '月', '火', '水', '木', '金', '土'], header: { left: '', center: 'title', right: 'today prev,next', }, defaultTimedEventDuration: '03:00:00', buttonText: { prev: '前', next: '次', prevYear: '前年', nextYear: '翌年', today: '今日', month: '月', week: '週', day: '日', }, timeFormat: 'HH:mm', eventColor: '#63ceef', eventTextColor: '#000000', }); });【解説】
① turbolinks対策の為、カレンダーを読み込む関数と削除する関数をそれぞれ用意する。
function eventCalendar() { return $('#calendar').fullCalendar({}); } function clearCalendar() { $('#calendar').html(''); }② 日本語で表示する。
// カレンダー上部を年月で表示させる titleFormat: 'YYYY年 M月', // 曜日を日本語表示 dayNamesShort: ['日', '月', '火', '水', '木', '金', '土'],③ ボタンのレイアウトを整える。
header: { left: '', center: 'title', right: 'today prev,next', },④ イベントの設定をする。
// 終了時刻がないイベントの表示間隔を設定 defaultTimedEventDuration: '03:00:00', buttonText: { prev: '前', next: '次', prevYear: '前年', nextYear: '翌年', today: '今日', month: '月', week: '週', day: '日', }, // イベントの時間表示を24時間にする timeFormat: 'HH:mm', // イベントの色を変える eventColor: '#63ceef', // イベントの文字色を変える eventTextColor: '#000000',4.モデルを作成
ターミナル$ rails g model Event user_id:integer title:string body:text start_date:datetime end_date:datetime~_create_events.rbclass CreateEvents < ActiveRecord::Migration[5.2] def change create_table :events do |t| t.integer :user_id t.string :title t.text :body t.datetime :start_date t.datetime :end_date t.timestamps end end endターミナル$ rails db:migrate5.コントローラーを作成
ターミナル$ rails g controller events new show edit my_calendarevents_controller.rbclass EventsController < ApplicationController before_action :set_event, only: [:show, :edit, :update, :destroy] def new @event = Event.new end def create @event = Event.new(event_params) @event.user_id = current_user.id @event.save ? (redirect_to event_path(@event)) : (render 'new') end def index @events = Event.where(user_id: current_user.id) end def show end def edit unless @event.user == current_user redirect_to root_path end end def update @event.update(event_params) ? (redirect_to event_path(@event)) : (render 'edit') end def destroy @event.destroy redirect_to my_calendar_path end def my_calendar end private def set_event @event = Event.find(params[:id]) end def event_params params.require(:event).permit(:user_id, :title, :body, :start_date, :end_date) end end6.ルーティングを追加
routes.rb# 追記 resources :events get 'my_calendar', to: 'events#my_calendar'7.
json.jbuilder
ファイルを作成・編集index.json.jbuilderjson.array!(@events) do |event| json.extract! event, :id, :title, :body json.start event.start_date json.end event.end_date json.url event_url(event) end【解説】
①
index
アクションで抽出したレコードを繰り返し処理し、配列を作成する。json.array! @category_children do |children|② 各データを
①
で作成した配列に格納する。json.extract! event, :id, :title, :body json.start event.start_date json.end event.end_date json.url event_url(event)8.ビューを編集
new.html.slim
を編集① HTMLを作成する。
new.html.slim.row .col-xs-3 .col-xs-6 = form_with model: @event, url: events_path, local: true do |f| = f.label :title, 'スケジュール名' br = f.text_field :title, class: 'form-control' br = f.label :body, 'スケジュール内容' br = f.text_area :body, class: 'form-control' br = f.label :start_date, '開始日時' br = f.datetime_select :start_date, {}, class: 'form-control datetime-form' br br = f.label :end_date, '終了日時' br = f.datetime_select :end_date, {}, class: 'form-control datetime-form' br br = f.submit '新規登録', class: 'btn btn-success btn-block' .col-xs-3② CSSでデザインを整える。
application.scss// 追記 .datetime-form { display: inline-block; width: auto; }
show.html.slim
を編集show.html.slim.row .page-header h3 | スケジュール管理 .row #calendar br .row table.table.table-bordered tbody tr th.active | スケジュール名 td = @event.title tr th.active | スケジュール内容 td = @event.body tr th.active | 開始日時 td = @event.start_date.to_s(:datetime_jp) tr th.active | 終了日時 td = @event.end_date.to_s(:datetime_jp) .row - if @event.user === current_user .pull-right = link_to 'スケジュール登録', new_event_path, class: 'btn btn-success' = link_to '編集', edit_event_path(@event), class: 'btn btn-primary' = link_to '削除', event_path(@event), method: :delete, data: { confirm: '本当に削除しますか?' }, class: 'btn btn-danger'
edit.html.slim
を編集edit.html.slim.row .col-xs-3 .col-xs-6 = form_with model: @event, url: event_path(@event), local: true do |f| = f.label :title, 'スケジュール名' br = f.text_field :title, class: 'form-control' br = f.label :body, 'スケジュール内容' br = f.text_area :body, class: 'form-control' br = f.label :start_date, '開始日時' br = f.datetime_select :start_date, {}, class: 'form-control datetime-form' br br = f.label :end_date, '終了日時' br = f.datetime_select :end_date, {}, class: 'form-control datetime-form' br br = f.submit '保存', class: 'btn btn-primary btn-block' .col-xs-3
my_calendar.html.slim
を編集my_calendar.html.slim.row .page-header h3 | マイカレンダー .row = link_to 'スケジュール登録', new_event_path, class: 'btn btn-success' #calendar br注意
turbolinks
を無効化しないとカレンダーが表示されない事があるので、必ず無効化しておきましょう。
- 投稿日:2020-07-04T16:57:20+09:00
Rails migration
Railsのmigrationを触るのは初めてだったので、勉強備忘録のために簡単に書きとどめてみる。
migrationについて
マイグレーションは、データベーススキーマの継続的な変更 を、統一的かつ簡単に行なうための便利な手法。
migrationファイルを作成する
サンプルとしてCompanyテーブルを準備
カラム名 データ型 id integer name string description text created_at datetime updated_at datetime $ rails g migration CrateCompanyActive Recordにはマイグレーションの実行順序をファイル名のタイムスタンプでの表示を自動でやってくれる。
作成されたファイルはdb/migrate
ディレクトリに保存される。作成されたファイル
class CrateCompany < ActiveRecord::Migration[5.2] def change end endActiveRecord::Migration[]にはバージョンが入る。
chengeの代わりにupとdownを使うことができる。
upメソッドにはmigrationする時の内容、downメソッドにはrollbackする時の内容を書く。class CrateCompany < ActiveRecord::Migration[5.2] def up end def down end end変更を加える
マイグレートファイルを作成し
rails db:migrate
を打てば実行してくる。
また直前の変更を取り消すためにはrails db:rollback
テーブルを作成する
class CrateCompany < ActiveRecord::Migration[5.2] def change create_table :companies do |t| t.string :name t.text :description t.timestamps end end endこのコマンドを打てば自動で上記のようなもの作成してくれる
$ rails g migration CrateCompany name:string description:textテーブルを変更する
class ChangeTableCompany < ActiveRecord::Migration[5.2] def change change_table :companies do |t| t.remove :name t.string :root_number t.index :root_number t.rename :description, :description_note end end end上のマイグレーションではnameカラムが削除され、stringカラムであるroot_numberが作成されてインデックスがそこに追加されます。そして最後にdescriptionカラムをリネームしている。
カラムを変更する
change_column :companies, :root_number, :textモデル名の
root_number
のカラムをtext
に変更。ここでの注意点だが、
change_column
はchange
メソッドではロールバックすることができない。
change
メソッドではサポートさていないとのこと。
change
でサポートされているマイグレーション定義はadd_column
add_foreign_key
add_index
add_reference
add_timestamps
change_column_default (:fromと:toの指定は省略できない)
change_column_null
create_join_table
create_table
disable_extension
drop_join_table
drop_table (ブロックを渡さなければならない)
enable_extension
remove_column(型を指定しなければならない)
remove_foreign_key(2番目のテーブルを指定しなければならない)
remove_index
remove_reference
remove_timestamps
rename_column
rename_index
rename_tableもしロールバックする場合はup,downメソッドであれば
change_column
を使用可能。class ChangeColumnCompany < ActiveRecord::Migration[5.2] def up change_column :companies, :root_number, :text end def down change_column :companies, :root_number, :string end endまだまだmigrationについては知らないことばかりだが、身につけていきたい。
- 投稿日:2020-07-04T16:36:09+09:00
[Ruby] whileにおける条件式の評価の挙動について
はじめに
whileを使っていたときに初めての挙動に遭遇したのでメモしておきます。
環境
ruby: 2.7.1
現象
現象_A
a = 0 while if a == 5 break end a += 1 end puts a # 実行結果: 0現象_B
b = 0 while b += 1 if b == 5 break end end puts b # 実行結果: 5現象_C
c = 0 while c < 5 do c += 1 end puts c # 実行結果: 5現象_D
d = 0 loop do if d == 5 break end d += 1 end puts d # 実行結果: 5現象_E
e = 0 loop do e += 1 if e == 5 break end end puts e # 実行結果: 5想定していた結果としては、現象_Aでも
5
が出力するものだと思っていました。なぜこうなるのか
(@scivolaさんのコメントにより解決することができました。)
どうやら、
while
の直後の式が条件式として評価されるようです。つまり、今回の現象_Aでは、if a == 5 break endこの箇所が
while
の条件式として初回に評価され、当然a == 5
はfalse
となりif
式の値はnil
となるのでループから抜けてしまっていたようです。ちなみにRubyでは
nil
とfalse
以外の全ての値がtrue
となります。試しに以下のように条件式を与えてやるとループ内の処理が実行されました。
a = 0 while true do # doは省略可 if a == 5 break end a += 1 end puts a # 実行結果: 5ループ内にある式が、実は条件式になっていたことが今回の落とし穴でした。
編集履歴
2020/07/04 17:11 コメントにて@scivolaさんから問題の原因を解説いただきましたので「なぜこうなるのか」を編集しました。
2020/07/04 17:31 タイトルを内容に即したものに変更し、文章を少し校正しました。備考
普段は
while
やloop
は使わず、別の繰り返し用のメソッドを使っています。
- 投稿日:2020-07-04T16:36:09+09:00
[Ruby] whileの挙動について
はじめに
whileを使っていたときに初めての挙動に遭遇したのでメモしておきます。
環境
ruby: 2.7.1
現象
現象_A
a = 0 while if a == 5 break end a += 1 end puts a # 実行結果: 0現象_B
b = 0 while b += 1 if b == 5 break end end puts b # 実行結果: 5現象_C
c = 0 while c < 5 do c += 1 end puts c # 実行結果: 5現象_D
d = 0 loop do if d == 5 break end d += 1 end puts d # 実行結果: 5現象_E
e = 0 loop do e += 1 if e == 5 break end end puts e # 実行結果: 5想定していた結果としては、現象_Aでも
5
が出力するものだと思っていました。なぜこうなるのか
(@scivolaさんのコメントにより解決することができました。)
どうやら、
while
の直後の式が条件式として評価されるようです。つまり、今回の現象_Aでは、if a == 5 break endこの箇所が
while
の条件式として初回に評価され、当然a == 5
はfalse
となりif
式の値はnil
となるのでループから抜けてしまっていたようです。(ちなみにRubyでは
nil
とfalse
以外の全ての値がtrue
となります)。試しに以下のように条件式を与えてやるとループ内の処理が実行されました。
a = 0 while true do # doは省略可 if a == 5 break end a += 1 end puts a # 実行結果: 5ループ内にある式が、実は条件式になっていたことが今回の落とし穴でした。
編集履歴
2020/07/04 17:11 コメントにて@scivolaさんから問題の原因を解説いただきましたので「なぜこうなるのか」を編集しました。
備考
普段は
while
やloop
は使わず、別の繰り返し用のメソッドを使っています。
- 投稿日:2020-07-04T16:23:46+09:00
Your Ruby version is 2.4.6, but your Gemfile specified 2.6.4
マイグレーションファイルを作成しようとしたら、RubyのバージョンがGemfileで指定しているものと違うと言われ、実行できなかった。
$ bin/rails g migration hoge Your Ruby version is 2.4.6, but your Gemfile specified 2.6.4rbenvがインストールされていることを確認。
$ which rbenv /usr/local/bin/rbenv指定されたRubyのバージョンをインストール。
$ rbenv install 2.6.4 Downloading openssl-1.1.1g.tar.gz... -> https://dqw8nmjcqpjn7.cloudfront.net/ddb04774f1e32f0c49751e21b67216ac87852ceb056b75209af2443400636d46 Installing openssl-1.1.1g... Installed openssl-1.1.1g to /Users/tamu/.rbenv/versions/2.6.4 Downloading ruby-2.6.4.tar.bz2... -> https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.4.tar.bz2 Installing ruby-2.6.4... ruby-build: using readline from homebrew Installed ruby-2.6.4 to /Users/tamu/.rbenv/versions/2.6.4インストールされたことを確認。
$ rbenv versions system * 2.4.6 (set by /Users/tamu/.rbenv/version) 2.6.4今回は、特定のディレクトリ配下にのみ適用したかったので、以下のように指定。
$ rbenv local 2.6.4切り替わったことを確認。
$ ruby -v ruby 2.6.4p104 (2019-08-28 revision 67798) [x86_64-darwin18]
- 投稿日:2020-07-04T15:56:30+09:00
migrateファイルの変更(rails db:rollback)
こんにちは、tt_tsutsumiです。
今回はmigrateファイルの変更方法についてです。
こちらの記事が何方かのお役に立てると嬉しいです。アプリケーション作成中にカラムの変更や追加を行った時に
普通のコードの書き方と違いが生まれたので困惑しました。
その際に自分が行った工程と流れの記載を致します。1. rails db:migrate:status
まずは現在作成しているアプリケーションのmigrateの稼働状況の確認を行いましょう。
コンソールにて下記コードを入力します。$ rails db:migrate:status Status Migration ID Migration Name -------------------------------------------------- up year/month/day Devise create users up year/month/day Create spots※ year/month/dayの部分はご自身で作成された日付等が表示されます
上記でstatusの部分がupになっている場合、migrateファイルは稼働しております。
この際にmigrateファイルの変更や追加を行っても反映されません。2. rails db:rollback
migrateファイルの稼働状況をdownします。
$ rails db:rollback $ rails db:migrate:status Status Migration ID Migration Name -------------------------------------------------- up year/month/day Devise create users down year/month/day Create spotsここで重要なのは rails db:rollback です!!
このコードを打つことにより稼働しているmigateファイルをdownさせる事ができます。※ 注意点としてこちらのコードはファイルを1つずつしかdownに出来ません。
3. rails db:migrate
downになっているのを確認してからmigrateファイルの変更や消去を行って下さい。
そして変更が終わったら保存をし、rails db:migrate を行います。$ rails db:migrate $ rails db:migrate:status Status Migration ID Migration Name -------------------------------------------------- up year/month/day Devise create users up year/month/day Create spotsこれでmigrateファイルの変更と保存は終了です。
ご覧いただきありがとうございました !!
- 投稿日:2020-07-04T15:45:04+09:00
Ruby シンボルについて
rubyのシンボルについて学習したので、メモ。
シンボルは一見、文字列に見えるがコンピューターは整数として扱うので、
処理速度が向上するというメリットがある。
- 投稿日:2020-07-04T14:00:59+09:00
JWTを用いたTokenAPIの実装(Rails)
JWTとは
JSON Web Tokenの略称です。
今回はJWTを用いたTokenAPIをRailsに実装するのが目的なのでJWTについては簡単な説明だけにします。
TokenAPIは単純にemail,passwordでログインチェックを行って該当ユーザーが存在する時にそのユーザーのTokenを返すAPIです。
詳細内容については以下のリンクを参考にしてください。
https://openid-foundation-japan.github.io/draft-ietf-oauth-json-web-token-11.ja.htmlJWT構成
ヘッダ、ペイロード、署名の3つのパートになっててそれぞれBase64でエンコードされている。
ヘッダ{ "typ":"JWT", "alg":"HS256" }ペイロード{ "sub": "1234567890", "iss": "John Doe", "aud": "audience", "exp": 1353604926 }署名HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)3つのパートは . (ドット) で結合されている。
ヘッダ・ペイロード・証明を簡単に作ってみたいなら以下のリンクでできます。
https://jwt.io/#debuggerJWTeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ1c2VyIiwic3ViIjoidGVzdCIsImF1ZCI6ImF1ZGllbmNlIiwicGFyYW1zIjoie1wiZW1haWxcIjogXCJ0ZXN0QGdtYWlsLmNvbVwiLCBcInBhc3N3b3JkXCI6IFwicGFzc3dvcmRcIn0iLCJleHAiOiIxNTkzODM2ODA2In0.4fC4yLEmYTjiwaXk3R_AUUPEQSuI_ARmkoMqosWEJ-cJWTクレーム
JWT クレームセットは JSON オブジェクトであり, それぞれのメンバは JWT として送られるクレームである. JWT クレームセット内のクレーム名は一意でなければならない
今回は以下の4つのクレームを使います。"iss" (Issuer) クレーム:JWTの発行者の識別子
"sub" (Subject) クレーム:JWTの主語となる主体の識別子
"aud" (Audience) クレーム:JWTを利用することが想定された主体の識別子一覧
"exp" (Expiration Time):JWTの有効期限APIプロジェクト生成
console$ rails new jwt --apiGemfileにjwt追加
gem 'jwt'Jwt認証チェックモジュール作成
app/controllers/concerns/signature.rbmodule Signature extend ActiveSupport::Concern def verify_signature render status: 401, json: { message: '認証エラー'} if request.headers['jwt-signature'].blank? request_params = JSON.parse(request.body.read) @signature ||= JwtSignature.new(jwt: request.headers['jwt-signature']) @signature.verify!(params: request_params) rescue JwtSignature::InvalidSignature render status: 401, json: { message: '認証エラー'} end endJwt認証処理モデル作成
app/models/jwt_signature.rbclass JwtSignature class InvalidSignature < StandardError; end ALGORITHM = 'HS256' ISSUER = 'user' AUDIENCE = 'audience' SUB = "test" TOKEN_TYPE = 'JWT' # SECRET_KEYは重要なので環境ごとに定義して安全に管理してください〜 SECRET_KEY = '1gCi6S9oaleH22KWaXyXZAQccBx4lUQi' def initialize(jwt:) @jwt = jwt end def verify!(params:) raise InvalidSignature unless valid_payload? && valid_params?(params: params) && valid_header? end private def valid_payload? return false unless jwt_payload['iss'] == ISSUER return false unless jwt_payload['sub'] == SUB return false unless jwt_payload['aud'] == AUDIENCE true end def valid_header? return false unless jwt_header['alg'] == ALGORITHM return false unless jwt_header['typ'] == TOKEN_TYPE true end def valid_params?(params:) JSON.parse(jwt_payload['params']) == params end def jwt_header @jwt_header ||= decoded_jwt.second end def jwt_payload @jwt_payload ||= decoded_jwt.first end def decoded_jwt @decoded_jwt ||= JWT.decode(@jwt, SECRET_KEY, true, algorithm: ALGORITHM) rescue JWT::DecodeError raise InvalidSignature end endJWT.decodeはHashのArrayを返すので
decoded_jwt.firstでPayload、decoded_jwt.secondでHeaderを取得
User Table作成
app/models/user.rbが生成される
$ rails g model User name:string email:string token:string expired_at:datetime $ rails db:migrateroutes.rbにAPI追加
routes.rbRails.application.routes.draw do post 'tokens/create' endToken Controller作成
tokens_controller.rbclass TokensController < ActionController::API include Signature # createの時だけ認証を確認する before_action :verify_signature, only: %i(create) def create # 今回は認証確認処理だけ実装 user = User.find_by(email: params[:email], password: params[:password]) return render status: 400, json: { message: 'ユーザーが存在しません。' } unless user # Tokenが存在しない場合は更新 if user.token.blank? user.token = SecureRandom.uuid user.save end render status: 200, json: { name: user.name, email: user.email, token: user.token } end endテストユーザー登録
$rails c irb(main):001:0> User.new(name: 'test', email: 'test@gmail.com', password: 'password') (0.5ms) SELECT sqlite_version(*) => #<User id: nil, name: "test", email: "test@gmail.com", password: [FILTERED], token: nil, expired_at: nil, created_at: nil, updated_at: nil> irb(main):002:0> User.new(name: 'test', email: 'test@gmail.com', password: 'password').save (0.1ms) begin transaction User Create (0.9ms) INSERT INTO "users" ("name", "email", "password", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?) [["name", "test"], ["email", "test@gmail.com"], ["password", "password"], ["created_at", "2020-07-04 02:30:17.701626"], ["updated_at", "2020-07-04 02:30:17.701626"]] (0.8ms) commit transaction => trueJwtEncodedデータ生成
https://jwt.io/#debugger
上記のリンクからJwtEncodedデータを生成
Payload部分は自分が必要なJwtクレームとパラメータを追加
paramsにemail, passwordを追加してAPIのパラメーターのJsonとPayloadのJsonを比較している
VERIFY SIGNATUREのSecurityキーも自分のSecurityに変更(JwtSignatureモデルのSECRET_KEY使用)
満期時間を設定したい場合はexpにUnixtimeを設定unixtime(現在時間から5分後)irb(main):040:0> (Time.now + 300).to_i => 1593838401Postmanで実行してみる
Headerに「jwt-signature」を追加してJwtEncodedデータを追加
JwtEncodedデータeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ1c2VyIiwic3ViIjoidGVzdCIsImF1ZCI6ImF1ZGllbmNlIiwicGFyYW1zIjoie1wiZW1haWxcIjogXCJ0ZXN0QGdtYWlsLmNvbVwiLCBcInBhc3N3b3JkXCI6IFwicGFzc3dvcmRcIn0iLCJleHAiOiIxNTkzODM4NDAxIn0.dSNqdhHBJKUJHnJa_2sS_3Qr4oNNdr5MKFx5ufwqLv4Bodyにjson形式でemail, password追加
json{ "email": "test@gmail.com", "password": "password"}実行
同じ状態で5分後実行
- 投稿日:2020-07-04T13:35:06+09:00
acts-as-taggable-onを使って絞り込み機能を作る
環境
- ubuntu(WSL)
- rails 6.0.3
事前準備
以下の機能は作成済みとします。
- 投稿機能
- 投稿詳細
- gemのインストール
- テーブルの作成
手順
- タグの保存
- ビューで表示
- 絞り込みの実装
タグの保存
タグをつけたいモデルに以下を追加。
micropost.rbacts_as_taggable
保存するためにストロングパラメータに以下を追加。
念のためcreateも載せておきます。microposts_controller.rbdef create @micropost = Micropost.new(micropost_params.merge(user_id: current_user.id)) if @micropost.save redirect_to @micropost, flash:{success: "投稿しました"} else render :new end end def show @micropost = Micropost.find(params[:id]) end private def micropost_params params.require(:micropost).permit(:content, :image, :tag_list) endビューの作成と表示
ビューに以下を追加してください。
入力ビューと表示ビューを作ります。new.html.slim= form_with model: micropost, local: true do |f| .form-group = f.label :tag //,で区切る = f.text_field :tag_list, value: @micropost.tag_list.join(","), class: "form-control" = f.submit "送信", class: "btn btn-primary"show.html.slimtable.table.table-hover today tr th = Micropost.human_attribute_name(:tag) td - @micropost.tag_list.each do |tag| = link_to tag, microposts_path(tag_name: tag), class: "micropost_tags__link"絞り込み機能の実装
microposts_controller.rbdef inde if params[:tag_name] #選択した同じ投稿の情報を返す @microposts = Micropost.tag_search(params[:tag_name]).page(params[:page]) elsif params[:q] #投稿を一覧を返す @microposts = @q.result(distinct: true).page(params[:page]) else @microposts = Micropost.page(params[:page]) end end終わりに
間違いがありましたら編集リクエストまたはコメントお願いします。
- 投稿日:2020-07-04T12:06:21+09:00
オフラインどう書く第15回参考問題解答
問題はこちら->http://nabetani.sakura.ne.jp/hena/ord15subpalin/
最初と最後の文字の組み合わせから一文字づつ近づけながら2文字を比較し、
n1番目とn2番目が同じ文字なら長さ(ans)を2増やし
n1+1番目とn2-1番目の間で同じ文字を調べます。(loop関数のforループ中のloop)
最後n番目とn+1番目が同じにならなければ長さに1をたします。
最初Juliaで枝刈せずに遅かったので、NimやRubyでも試しましたが、
結局、今の長さ(ans)と残りの文字数の和が今までの最大の長さ(fans)より大きい場合
(fans<j-i+ans+1)のみ探索を進める簡単な枝狩りをし、
forループ中のloopの後にbreakを入れたら、だいぶ速くなりました。
Julia#Julia v 0.6-1.4 inp="0 I_believe_you_can_solve 9 evo_n_ove 1 a 1 a 2 aa 2 aa 3 aaa 3 aaa 4 ab 1 b 5 aabb 2 bb 6 ABBA 4 ABBA 7 Abba 2 bb 8 1234567890 1 0 9 1234567890987654321 19 1234567890987654321 10 abcdcba 7 abcdcba 11 0a1b2c3d4c5b6a7 7 abc4cba 12 abcdcba0123210 7 0123210 13 abcdcba_123210 7 abcdcba 14 _bcdcba0123210 7 0123210 15 abcddcba0123210 8 abcddcba 16 abcdcba01233210 8 01233210 17 a0bc1dc2ba3210a 9 a0123210a 18 a0bc1ddc2ba3210 8 0bcddcb0 19 3a0bc1ddc2ba3210 10 3abcddcba3 20 11oooo1111o1oo1o111ooooooooooo 20 oooo111o1oo1o111oooo 21 11o1111o1111oo11ooo11111ooo1oo 20 o1o1111oo11oo1111o1o 22 111111oo11o111ooo1o1ooo11ooo1o 21 1ooo11ooo1o1ooo11ooo1 23 11o1o1o11oo11o11oo111o1o1o11oo 27 11o1o1o11oo11o11oo11o1o1o11 24 oo111o1o11o1oo1ooo11o1o11o1o1o 27 oo111o1o11ooo1ooo11o1o111oo 25 1o1oo11111o1o1oo1o1o1111oo1o1o 28 1o1oo1111o1o1oo1o1o1111oo1o1 26 QQooooQooooQQyQoyQQQyyyyQQoyoy 15 ooQQyyQQQyyQQoo 27 oQoooQooooQyoyQoyoyyyQQyQQQQoQ 16 QoQQyQyyyyQyQQoQ 28 yyyyyooyQyyyoyyQyyooyQoQoQQoQy 17 yooQyoyyQyyoyQooy 29 yyQoyQoyyQyQQoyooooyyQQyQyooQy 24 yQooyQyQQyooooyQQyQyooQy 30 oQQooQoQyQQoyoQQoQyQyQyQoQoooo 24 oooQoQyQQyoQQoyQQyQoQooo 31 oQQyQQyyQyQQoooyQQyyyQQQyyQQoy 25 oQQyQQyyyQQoooQQyyyQQyQQo 32 WAk9iHI4jVDlStyudwTNqE138kwan2 3 wkw 33 c43fIu1Mlz0K9hEVOgGcUdbeB5ksa7 3 cGc 34 CAbYcW5VqHjzFdIkH_61PM0TsyRuie 3 HkH 35 jInQnUvSayrJTsQWujovbbqW0STvoj 10 jvTWbbWTvj 36 iZDrvpUKgtj3FrZsZ4CLjrEgUdZzQG 11 ZUgrZsZrgUZ 37 ROgYUOu6er_DA7nB6UGquO1GUHC62R 11 RUOu6B6uOUR 38 Oh_be_a_fine_girl_kiss_me 9 e_i_l_i_e 39 8086_6502_6809_Z80 11 8086_2_6808 40 xcode_visualstudio_eclipse 11 ce_iutui_ec 41 word_excel_powerpoint_outlook 9 ol_opo_lo 42 abcdefghijklmnopqrstuvwxyz0123 1 3" function main() local fans function loop(str,ans) if str !="" for i in 1:length(str)-1 for j in length(str):-1:i+1 if str[j]==str[i] && fans<j-i+ans+1 loop(str[i+1:j-1],ans+2) break end end end ans +=1 end if fans<ans fans=ans end end str0=split(inp,"\n") for s0 in str0 s1=split(s0," ") fans=0 ans=0 loop(strip(s1[2]),ans) if fans==parse(Int,s1[3]) sel="pass" else sel="fail" end print(sel," ",fans,"\n") end end @time main()Nim
Juliaと大差ない速さの時もありますが、この問題(コード)では、桁違いに速いです。#Nim v 0.194 import os,strutils,sequtils,times import math const inp="""0 I_believe_you_can_solve 9 evo_n_ove 1 a 1 a 2 aa 2 aa 3 aaa 3 aaa 4 ab 1 b 5 aabb 2 bb 6 ABBA 4 ABBA 7 Abba 2 bb 8 1234567890 1 0 9 1234567890987654321 19 1234567890987654321 10 abcdcba 7 abcdcba 11 0a1b2c3d4c5b6a7 7 abc4cba 12 abcdcba0123210 7 0123210 13 abcdcba_123210 7 abcdcba 14 _bcdcba0123210 7 0123210 15 abcddcba0123210 8 abcddcba 16 abcdcba01233210 8 01233210 17 a0bc1dc2ba3210a 9 a0123210a 18 a0bc1ddc2ba3210 8 0bcddcb0 19 3a0bc1ddc2ba3210 10 3abcddcba3 20 11oooo1111o1oo1o111ooooooooooo 20 oooo111o1oo1o111oooo 21 11o1111o1111oo11ooo11111ooo1oo 20 o1o1111oo11oo1111o1o 22 111111oo11o111ooo1o1ooo11ooo1o 21 1ooo11ooo1o1ooo11ooo1 23 11o1o1o11oo11o11oo111o1o1o11oo 27 11o1o1o11oo11o11oo11o1o1o11 24 oo111o1o11o1oo1ooo11o1o11o1o1o 27 oo111o1o11ooo1ooo11o1o111oo 25 1o1oo11111o1o1oo1o1o1111oo1o1o 28 1o1oo1111o1o1oo1o1o1111oo1o1 26 QQooooQooooQQyQoyQQQyyyyQQoyoy 15 ooQQyyQQQyyQQoo 27 oQoooQooooQyoyQoyoyyyQQyQQQQoQ 16 QoQQyQyyyyQyQQoQ 28 yyyyyooyQyyyoyyQyyooyQoQoQQoQy 17 yooQyoyyQyyoyQooy 29 yyQoyQoyyQyQQoyooooyyQQyQyooQy 24 yQooyQyQQyooooyQQyQyooQy 30 oQQooQoQyQQoyoQQoQyQyQyQoQoooo 24 oooQoQyQQyoQQoyQQyQoQooo 31 oQQyQQyyQyQQoooyQQyyyQQQyyQQoy 25 oQQyQQyyyQQoooQQyyyQQyQQo 32 WAk9iHI4jVDlStyudwTNqE138kwan2 3 wkw 33 c43fIu1Mlz0K9hEVOgGcUdbeB5ksa7 3 cGc 34 CAbYcW5VqHjzFdIkH_61PM0TsyRuie 3 HkH 35 jInQnUvSayrJTsQWujovbbqW0STvoj 10 jvTWbbWTvj 36 iZDrvpUKgtj3FrZsZ4CLjrEgUdZzQG 11 ZUgrZsZrgUZ 37 ROgYUOu6er_DA7nB6UGquO1GUHC62R 11 RUOu6B6uOUR 38 Oh_be_a_fine_girl_kiss_me 9 e_i_l_i_e 39 8086_6502_6809_Z80 11 8086_2_6808 40 xcode_visualstudio_eclipse 11 ce_iutui_ec 41 word_excel_powerpoint_outlook 9 ol_opo_lo 42 abcdefghijklmnopqrstuvwxyz0123 1 3""" proc main()= var fans=0 proc loop(str:string,ans:int)= var ans1=ans if str != "": for i in 0..len(str)-2: for j in countdown(len(str)-1,i+1): if str[j]==str[i] and fans<j-i+ans1+1: loop(str[i+1..j-1],ans1+2) break ans1=ans1+1 if fans<ans1: fans=ans1 for s0 in inp.splitLines : var s1=s0.split(" ") fans=0 loop(s1[1].strip,0) var sel="" if fans==s1[2].strip.parseInt: sel="pass" else: sel="fail" echo(sel," ",fans) var t = cpuTime() main() echo cpuTime()-tRuby
「どう書く」の参加者にはRuby使いの方が多かったような気がします。
私は「オブジェクト指向スクリプト言語Ruby」の初版を読んでいるのですが、
GUIプログラムはDelphiのほうが便利だし、パズルを解くには遅いという印象がありましたので、
たまにawkの代わりに使うくらいでした。
しかし別の問題で、他の方のコードを参考に書いてJuliaと比べたら結構早かったので、
今回も試してみました。
この問題では枝刈前はあまり早くありませんでしたが枝刈後はJuliaといい勝負です。
ruby使いの方から見れば古風で冗長な書き方かもしれませんが、枝刈した方を載せます。#ruby v 2.5.5 require 'benchmark' $inp="0 I_believe_you_can_solve 9 evo_n_ove 1 a 1 a 2 aa 2 aa 3 aaa 3 aaa 4 ab 1 b 5 aabb 2 bb 6 ABBA 4 ABBA 7 Abba 2 bb 8 1234567890 1 0 9 1234567890987654321 19 1234567890987654321 10 abcdcba 7 abcdcba 11 0a1b2c3d4c5b6a7 7 abc4cba 12 abcdcba0123210 7 0123210 13 abcdcba_123210 7 abcdcba 14 _bcdcba0123210 7 0123210 15 abcddcba0123210 8 abcddcba 16 abcdcba01233210 8 01233210 17 a0bc1dc2ba3210a 9 a0123210a 18 a0bc1ddc2ba3210 8 0bcddcb0 19 3a0bc1ddc2ba3210 10 3abcddcba3 20 11oooo1111o1oo1o111ooooooooooo 20 oooo111o1oo1o111oooo 21 11o1111o1111oo11ooo11111ooo1oo 20 o1o1111oo11oo1111o1o 22 111111oo11o111ooo1o1ooo11ooo1o 21 1ooo11ooo1o1ooo11ooo1 23 11o1o1o11oo11o11oo111o1o1o11oo 27 11o1o1o11oo11o11oo11o1o1o11 24 oo111o1o11o1oo1ooo11o1o11o1o1o 27 oo111o1o11ooo1ooo11o1o111oo 25 1o1oo11111o1o1oo1o1o1111oo1o1o 28 1o1oo1111o1o1oo1o1o1111oo1o1 26 QQooooQooooQQyQoyQQQyyyyQQoyoy 15 ooQQyyQQQyyQQoo 27 oQoooQooooQyoyQoyoyyyQQyQQQQoQ 16 QoQQyQyyyyQyQQoQ 28 yyyyyooyQyyyoyyQyyooyQoQoQQoQy 17 yooQyoyyQyyoyQooy 29 yyQoyQoyyQyQQoyooooyyQQyQyooQy 24 yQooyQyQQyooooyQQyQyooQy 30 oQQooQoQyQQoyoQQoQyQyQyQoQoooo 24 oooQoQyQQyoQQoyQQyQoQooo 31 oQQyQQyyQyQQoooyQQyyyQQQyyQQoy 25 oQQyQQyyyQQoooQQyyyQQyQQo 32 WAk9iHI4jVDlStyudwTNqE138kwan2 3 wkw 33 c43fIu1Mlz0K9hEVOgGcUdbeB5ksa7 3 cGc 34 CAbYcW5VqHjzFdIkH_61PM0TsyRuie 3 HkH 35 jInQnUvSayrJTsQWujovbbqW0STvoj 10 jvTWbbWTvj 36 iZDrvpUKgtj3FrZsZ4CLjrEgUdZzQG 11 ZUgrZsZrgUZ 37 ROgYUOu6er_DA7nB6UGquO1GUHC62R 11 RUOu6B6uOUR 38 Oh_be_a_fine_girl_kiss_me 9 e_i_l_i_e 39 8086_6502_6809_Z80 11 8086_2_6808 40 xcode_visualstudio_eclipse 11 ce_iutui_ec 41 word_excel_powerpoint_outlook 9 ol_opo_lo 42 abcdefghijklmnopqrstuvwxyz0123 1 3" def main() def loop(str,ans) if str !="" for i in 0..str.length-2 (str.length-1).downto(i+1) { |j| if str[j]==str[i] && $fans<j-i+ans+1 loop(str[i+1..j-1],ans+2) break end } end ans +=1#*string(str[1]) end if $fans<ans $fans=ans end end $inp.lines do |s0| s1=s0.split(" ") $fans=0 ans=0 loop(s1[1].strip,ans) if $fans==s1[2].to_i sel="pass" else sel="fail" end print(sel," ",$fans,"\n") end end time = Benchmark.realtime do main() end p time別解(Prolog)
元の文字列と逆向きの文字列で同じ文字の組み合わせの最長を求める方法です。メモ化再帰です。
二つの文字列のn1番目とn2番目が同じ文字なら、長さRを1増やしてn1+1番目とn2+1番目を比べます。
違う場合はn1+1番目とn2番目を比較した場合と、n1番目とn2+1番目を比較した場合の
長いほうとRを加えます。
コード風に書くと
f(n1,n2) = if n1==n2: f(n1+1,n2+1)+1 #solve/4の4節目
else:max(f(n1+1,n2),f(n1,n2+1)) #solve/4の5節目
メモ化の部分はfunctorを利用して二次元配列(F)のメモを作り、
solve/4の3節目で、メモに書き込まれている場合(nonvar(R1))、その値を利用します。
data/4はメモの書き込みにも読み込みにも用います。%SWI-Prolog v 7.4.2,7.6.4 %start. %:-initialization(start). %ideone twoar(_,0,_). % two dimensional array twoar(F,X,Y):-arg(X,F,V),functor(V,y,Y),X1 is X-1,twoar(F,X1,Y). data(F,X,Y,V):-arg(X,F,V1),arg(Y,V1,V). solve([],_,_,0). solve(_,[],_,0). solve(L1,L2,F,R):- length(L1,N1),length(L2,N2),data(F,N1,N2,R1),nonvar(R1),!,R=R1. solve([H1|T1],[H2|T2],F,R):- H1==H2,!,length([H1|T1],N1),length([H2|T2],N2), solve(T1,T2,F,R1),R is R1+1,data(F,N1,N2,R). solve([H1|T1],[H2|T2],F,R):- length([H1|T1],N1),length([H2|T2],N2), solve([H1|T1],T2,F,R1),solve(T1,[H2|T2],F,R2),R is max(R1,R2),data(F,N1,N2,R). start:-str(S),split_string(S,"\s,\n","\s",L),pre(L),!. disp(R,Q):- number_string(R,R1),(R1==Q->Str="pass ";Str=" fail "), write(" "),write(Str),writeln(R). pre([]). pre([_,B,C,_|T]):- atom_chars(B,L),reverse(L,L1),length(L,M),M1 is M+5,functor(F,x,M1),twoar(F,M1,M1), solve(L,L1,F,R),disp(R,C),pre(T). str("0 I_believe_you_can_solve 9 evo_n_ove 1 a 1 a 2 aa 2 aa 3 aaa 3 aaa 4 ab 1 b 5 aabb 2 bb 6 ABBA 4 ABBA 7 Abba 2 bb 8 1234567890 1 0 9 1234567890987654321 19 1234567890987654321 10 abcdcba 7 abcdcba 11 0a1b2c3d4c5b6a7 7 abc4cba 12 abcdcba0123210 7 0123210 13 abcdcba_123210 7 abcdcba 14 _bcdcba0123210 7 0123210 15 abcddcba0123210 8 abcddcba 16 abcdcba01233210 8 01233210 17 a0bc1dc2ba3210a 9 a0123210a 18 a0bc1ddc2ba3210 8 0bcddcb0 19 3a0bc1ddc2ba3210 10 3abcddcba3 20 11oooo1111o1oo1o111ooooooooooo 20 oooo111o1oo1o111oooo 21 11o1111o1111oo11ooo11111ooo1oo 20 o1o1111oo11oo1111o1o 22 111111oo11o111ooo1o1ooo11ooo1o 21 1ooo11ooo1o1ooo11ooo1 23 11o1o1o11oo11o11oo111o1o1o11oo 27 11o1o1o11oo11o11oo11o1o1o11 24 oo111o1o11o1oo1ooo11o1o11o1o1o 27 oo111o1o11ooo1ooo11o1o111oo 25 1o1oo11111o1o1oo1o1o1111oo1o1o 28 1o1oo1111o1o1oo1o1o1111oo1o1 26 QQooooQooooQQyQoyQQQyyyyQQoyoy 15 ooQQyyQQQyyQQoo 27 oQoooQooooQyoyQoyoyyyQQyQQQQoQ 16 QoQQyQyyyyQyQQoQ 28 yyyyyooyQyyyoyyQyyooyQoQoQQoQy 17 yooQyoyyQyyoyQooy 29 yyQoyQoyyQyQQoyooooyyQQyQyooQy 24 yQooyQyQQyooooyQQyQyooQy 30 oQQooQoQyQQoyoQQoQyQyQyQoQoooo 24 oooQoQyQQyoQQoyQQyQoQooo 31 oQQyQQyyQyQQoooyQQyyyQQQyyQQoy 25 oQQyQQyyyQQoooQQyyyQQyQQo 32 WAk9iHI4jVDlStyudwTNqE138kwan2 3 wkw 33 c43fIu1Mlz0K9hEVOgGcUdbeB5ksa7 3 cGc 34 CAbYcW5VqHjzFdIkH_61PM0TsyRuie 3 HkH 35 jInQnUvSayrJTsQWujovbbqW0STvoj 10 jvTWbbWTvj 36 iZDrvpUKgtj3FrZsZ4CLjrEgUdZzQG 11 ZUgrZsZrgUZ 37 ROgYUOu6er_DA7nB6UGquO1GUHC62R 11 RUOu6B6uOUR 38 Oh_be_a_fine_girl_kiss_me 9 e_i_l_i_e 39 8086_6502_6809_Z80 11 8086_2_6808 40 xcode_visualstudio_eclipse 11 ce_iutui_ec 41 word_excel_powerpoint_outlook 9 ol_opo_lo 42 abcdefghijklmnopqrstuvwxyz0123 1 3").
- 投稿日:2020-07-04T10:41:30+09:00
【Rails】jquery を使わずに javascript で flashメッセージをフェードアウトさせる
はじめに
Railsアプリを開発していてflashメッセージをフェードアウトさせたく、javascriptを用いて実装したので書く。
こういったやつ↓↓(Bootstrapのalertを適用させています)
これをフェードアウトさせる
環境
Ruby: 2.5.1
Rails: 5.2.4.2実装
実装イメージとしては徐々に透明度を高くしていき、最終的に非表示にします。
要素のstyle属性
①opacityの値を減少させていく
②opacityが0になったらdisplay: none; にするviewファイル
erbはこのようになっている
_flash_messages.html.erb<% flash.each do |message_type, message| %> <div class="alert alert-<%= message_type %>"><%= message %></div> <% end %>jsファイル
flash_message.js// turbolinks:loadでページ読み込み時に実行 document.addEventListener('turbolinks:load', () => { // flashメッセージ要素を取得 const flashMessage = document.querySelector('.alert'); // フェードアウトさせる(徐々に透過し,非表示にする)関数を定義 const fadeOutFlashMessage = () => { // setIntervalを特定するために返り値を変数timer_idに格納 const timer_id = setInterval(() => { // flashメッセージのstyle属性 opacityを取得 const opacity = flashMessage.style.opacity; if (opacity > 0) { // opacityの値が0より大きければ0.02ずつ値を減少させる flashMessage.style.opacity = opacity - 0.02; } else { // opacityの値が0になったら非表示に flashMessage.style.display = 'none'; // setIntervalをストップさせる clearInterval(timer_id); }; }, 50); // 今回は0.05秒ごとにsetIntervalを実行 } // flashメッセージがある場合のみ実行 if (flashMessage !== null) { // style属性opacityをセット flashMessage.style.opacity = 1; // 今回は表示から3秒後に上記で定義したフェードアウトさせる関数を実行 setTimeout(fadeOutFlashMessage, 3000); }; });参考文献
下記記事を参考にさせていただきました。
ありがとうございました。・turbolinksチートシート
・【JavaScript】Railsのflashをフェードアウトして消す方法最後に
読んでいただきありがとうございます。
間違いや、より効率的な記述方法等あればご指摘いただけると非常に嬉しいです。
- 投稿日:2020-07-04T08:49:22+09:00
[Rspec]更新前のデータに対するmethod呼び出し確認テストでハマった
ある特定のモデルインスタンスがupdateされた時にafter_updateで呼び出したmethodの中で、更新前のrelation関係にあるmodelに対してmodel_methodが呼ばれているか確認するテストで結構ハマったので備忘録
model.rbafter_update :hoge_method def hoge_method old_fuga = Fuga.find_by(id: fuga_id_before_last_save) fuga&.model_method old_fuga&.model_method endこういうのがあったとして、fugaに対する呼び出しのチェックは、これでいけた
let!(:hoge) { create :hoge } let(:fuga) { create :fuga } it 'invokes model_method of the related fuga.' do allow(fuga).to receive(:model_method) hoge.update(fuga: fuga) expect(fuga).to have_received(:model_method) end更新後のモデルインスタンスに対してmodel_methodの呼び出しできたー
じゃ、これ最初からそいつ紐づけてallowで監視しとけばいけるんじゃね?
と思っただから、最初から紐づけて監視してupdateで全く違うインスタンスに更新することにした。
let!(:hoge) { create :hoge, fuga: fuga } let(:fuga) { create :fuga } let(:other_fuga) { create :fuga } it 'invokes model_method of the related fuga.' do allow(fuga).to receive(:model_method) hoge.update(fuga: other_fuga) expect(fuga).to have_received(:model_method) endがこれだと、failした。
どうやらfind_byで参照しているモデルインスタンスと、exampleで使っているモデルインスタンスは全く別のものとして捉えられるらしい。
元のコードを、def hoge_method new_fuga = Fuga.find_by(id: fuga_id) old_fuga = Fuga.find_by(id: fuga_id_before_last_save) new_fuga&.model_method old_fuga&.model_method endとすると更新後のfugaへのテストもfailすることが確認できた。
じゃ、どうするか
モデルに対してfind_byが呼ばれた時に戻り値としてdoubleを返すmockを用意することで解決した。let!(:hoge) { create :hoge, fuga: fuga } let(:fuga) { create :fuga } let(:other_fuga) { create :fuga } let(:mock_fuga) { double('mock') } it 'invokes model_method of the related fuga.' do allow(Fuga).to receive(find_by).with(id: fuga.id).and_return(mock_fuga) allow(mock_fuga).to receive(:model_method) hoge.update(fuga: other_fuga) expect(mock_fuga).to have_received(:model_method) endwith引数はなくてもいける。
これに到達するまでにだいぶ時間を使ってしまった。
調べるといっぱい出てくるが応用することができなかった。
でも、こうやってみてみるとめっちゃ簡単だな〜
- 投稿日:2020-07-04T05:10:39+09:00
名古屋で開催されている技術イベント・勉強会
はじめに
この度、名古屋を離れ、関東へ引っ越すことになりました。名古屋(東海圏)エンジニアを増やして地元を盛り上げていくという夢が叶わなくなってしまいました。
名古屋でもエンジニアコミュニティを盛り上げようと頑張っている企業さんや、エンジニアさんがたくさんいることを多くの人に共有したくこの記事を書いています。
名古屋へのUターンを考えていたり、リモートができるようになり都心を離れようかなぁと考えている人は、ぜひ次の拠点として名古屋を選択に入れる参考にしてみてください。
*以下イベント情報の概要はリンクページから一部引用させていただいています。
定期開催編
以下、定期開催されている勉強会です。
Yahoo! JAPAN Nagoya
主催:Yahoo! JAPAN
概要:ヤフー株式会社の名古屋オフィスで開催するクリエイター向け勉強会コミュニティ。 多種多様なクリエイター同士が交流できる場所として、開発スキルやノウハウについて学びながら、社内外のクリエイターがアウトプット/インプットできる機会になるべく、2019年3月にスタート。フロントエンドもくもく会
主催:Nagoya Frontend User Group
概要:フロントエンドを中心にしたもくもく会。名古屋の企業・団体からの会場提供を受けている。名古屋アジャイル勉強会
概要:アジャイルの考え方や方法を体験的に学び、職場で活かすことを応援する、誰でも参加できるグループ。
Mobile Act
主催:フェンリル
概要:モバイルアプリ開発関連の情報共有や参加者同士の交流を目的とした勉強会。Nagoya.Swift+
概要:技術者としての好奇心や向上心を満たすために技術的な挑戦をするふりをして遊びます。
nagoya.go
概要:名古屋のGoコミュニティ。もくもく会やGo勉強会が開催されている。
OthloTech
主催:OthloTech
概要:OthloTech<オスロテック>は東海圏の学生エンジニア・デザイナーによる学校を超えたコミュニティ。 月に1〜2回、学生限定の勉強会やハッカソンを開催。JAWS-UG名古屋
主催:JAWS-UG名古屋支部
概要:Amazon Web Services(AWS)のユーザグループ、JAWS-UGの名古屋支部のイベント。
AWSに興味があるんだけど周りに知ってる人がいない、がっつり勉強したい!という人たちが集い、一緒に勉強する場を企画。MISO MOKU
主催:Misoca Developer Meetup
概要:毎週ベースで行われていた、エンジニア・デザイナー向けのもくもく会。弥生株式会社と合併したため、2020年7月以降の開催は未定。Nagoya.unity
概要:名古屋を中心に活動を行うUnityユーザのコミュニティで、主に勉強会などの開催を行っています。
OWASP Nagoya
主催:OWASP Nagoya Chapter
概要:Webをはじめとするソフトウェアのセキュリティ環境の現状、またセキュアなソフトウェア開発を促進する技術・プロセスに関する情報共有と普及啓発を目的としたプロフェッショナルの集まる、オープンソース・ソフトウェアコミュニティ。名古屋ギークバー
概要:技術的なものから、アナログゲーム、LT大会、生ハムを食べるなど、幅広くイベントを開催され、名古屋のギークな人達に会える。
Nagoya.php
概要:名古屋のPHPユーザーのコミュニティで、隔月で勉強会をやっています。(現在コロナのため休止中)
番外編
開催頻度が低いけど大規模だったり、面白い試みをしているイベントを書いていきます。
NGK
概要:NGKは、東海地方IT系コミュニティ合同の大新年会。普段から東海地方の勉強会に参加している人、今まで参加したことがない人、他地域の人など、 誰にとっても、さまざまなコミュニティとつながりを広げ、深める良い機会になることを目指すイベント。
東海のエンジニアはみんな参加しているのではないか?と思うぐらい大規模なイベント。
みそかつウェブ
概要:名古屋という土地を生かし、エンジニア&デザイナーコミュニティを盛り上げるため、 IT業界に関わる人同士の交流の場として似た境遇の仲間を探したり、相談できる友人を作ったりできるコミュニティです。
最後に
思いついたイベントをばっと書いているので、どんどん追記していきます。他もあるよ~みたいなご意見ありましたら是非いただけますと嬉しいです。
コミュニティも盛り上がっているので、ぜひ色々参加してみてください。
割とアットホームな土地(外からはそう思われていないかもしれないが)なので、いいですよ~。
- 投稿日:2020-07-04T05:10:39+09:00
名古屋で開催されいている技術イベント・勉強会
はじめに
この度、名古屋を離れ、関東へ引っ越すことになりました。名古屋(東海圏)エンジニアを増やして地元を盛り上げていくという夢が叶わなくなってしまいました。
名古屋でもエンジニアコミュニティを盛り上げようと頑張っている企業さんや、エンジニアさんがたくさんいることを多くの人に共有したくこの記事を書いています。
名古屋へのUターンを考えていたり、リモートができるようになり都心を離れようかなぁと考えている人は、ぜひ次の拠点として名古屋を選択に入れる参考にしてみてください。
*以下イベント情報の概要はリンクページから一部引用させていただいています。
定期開催編
以下、定期開催されている勉強会です。
Yahoo! JAPAN Nagoya
主催:Yahoo! JAPAN
概要:ヤフー株式会社の名古屋オフィスで開催するクリエイター向け勉強会コミュニティ。 多種多様なクリエイター同士が交流できる場所として、開発スキルやノウハウについて学びながら、社内外のクリエイターがアウトプット/インプットできる機会になるべく、2019年3月にスタート。フロントエンドもくもく会
主催:Nagoya Frontend User Group
概要:フロントエンドを中心にしたもくもく会。名古屋の企業・団体からの会場提供を受けている。名古屋アジャイル勉強会
概要:アジャイルの考え方や方法を体験的に学び、職場で活かすことを応援する、誰でも参加できるグループ。
Mobile Act
主催:フェンリル
概要:モバイルアプリ開発関連の情報共有や参加者同士の交流を目的とした勉強会。Nagoya.Swift+
概要:技術者としての好奇心や向上心を満たすために技術的な挑戦をするふりをして遊びます。
nagoya.go
概要:名古屋のGoコミュニティ。もくもく会やGo勉強会が開催されている。
OthloTech
主催:OthloTech
概要:OthloTech<オスロテック>は東海圏の学生エンジニア・デザイナーによる学校を超えたコミュニティ。 月に1〜2回、学生限定の勉強会やハッカソンを開催。JAWS-UG名古屋
主催:JAWS-UG名古屋支部
概要:Amazon Web Services(AWS)のユーザグループ、JAWS-UGの名古屋支部のイベント。
AWSに興味があるんだけど周りに知ってる人がいない、がっつり勉強したい!という人たちが集い、一緒に勉強する場を企画。MISO MOKU
主催:Misoca Developer Meetup
概要:毎週ベースで行われていた、エンジニア・デザイナー向けのもくもく会。弥生株式会社と合併したため、2020年7月以降の開催は未定。Nagoya.unity
概要:名古屋を中心に活動を行うUnityユーザのコミュニティで、主に勉強会などの開催を行っています。
OWASP Nagoya
主催:OWASP Nagoya Chapter
概要:Webをはじめとするソフトウェアのセキュリティ環境の現状、またセキュアなソフトウェア開発を促進する技術・プロセスに関する情報共有と普及啓発を目的としたプロフェッショナルの集まる、オープンソース・ソフトウェアコミュニティ。名古屋ギークバー
概要:技術的なものから、アナログゲーム、LT大会、生ハムを食べるなど、幅広くイベントを開催され、名古屋のギークな人達に会える。
Nagoya.php
概要:名古屋のPHPユーザーのコミュニティで、隔月で勉強会をやっています。(現在コロナのため休止中)
番外編
開催頻度が低いけど大規模だったり、面白い試みをしているイベントを書いていきます。
NGK
概要:NGKは、東海地方IT系コミュニティ合同の大新年会。普段から東海地方の勉強会に参加している人、今まで参加したことがない人、他地域の人など、 誰にとっても、さまざまなコミュニティとつながりを広げ、深める良い機会になることを目指すイベント。
東海のエンジニアはみんな参加しているのではないか?と思うぐらい大規模なイベント。
みそかつウェブ
概要:名古屋という土地を生かし、エンジニア&デザイナーコミュニティを盛り上げるため、 IT業界に関わる人同士の交流の場として似た境遇の仲間を探したり、相談できる友人を作ったりできるコミュニティです。
最後に
思いついたイベントをばっと書いているので、どんどん追記していきます。他もあるよ~みたいなご意見ありましたら是非いただけますと嬉しいです。
コミュニティも盛り上がっているので、ぜひ色々参加してみてください。
割とアットホームな土地(外からはそう思われていないかもしれないが)なので、いいですよ~。
- 投稿日:2020-07-04T03:29:51+09:00
Ruby on Rails ポートフォリオ実装 - 要件定義 - Port 1
ポートフォリオ実装にあたり各工程ごとに、学習のアウトプットとして手順や詳細について、記し共有させていただきますので、一つの例として参考にしていただければ幸いです。
<アウトプットする理由について>
・"わかった気になっている"を無くすため
・フィードバックを受ける機会を得るため
・得た情報を自分の中にしっかり定着させるため
・数多くの情報から本当に必要な情報を判断できるようになるため<各工程>
1. 要件定義(仕様決め、ガントチャート作成)
2. 設計(画面設計、DB設計、URL設計、タスクばらし)
3. 実装(たくさん...)上記のように、各工程で中身がいくつも分岐してくるため 3工程でも何記事かに分ける必要があるかと思います。
ポートフォリオ作り終わる頃には合計で 10記事くらいで濃い内容をアウトプットしていく予定です。
また、実装部分については全てアウトプットする必要はないので、自身が難しいまたは面白い、メモに残す必要があるといった機能を記していきます。要件定義とは
要件定義は、本格的な開発工程の前段階で、要求をまとめ具体的な進め方を決めることです。システム開発では、ユーザー側の要求を実現することがゴールです。
そのため、開発をスタートする前に、実装する機能や性能などを決めておかなければなりません。要件定義は本格的な開発工程の前段階で、具体的にどのように進めていくかを決めるために必要です。
※引用:https://it-trend.jp/development_tools/article/32-0060とのこと。
今回要件定義として私が実施したのは、サービスにどのような機能や技術を実装、使用するかを決める「仕様決め」とすスケジュール管理をする「ガントチャートの作成」です。
考えてみた後にだいぶ規模が大きくなってしまうことに気づきますが、こちらを目標として進めます。仕様決め
下記のようにコンセプト〜インフラをどうするかまで詳細を決めていきます。
ついては、自身でもなかなか規模の作品になり相当苦労するだろうと認識しています。
差別化するという箇所としては 私自身、以前にセキュリティエンジニアで脆弱性診断の経験があり、脆弱性診断の自動化の組み込みは何とか実装したいと思っています。【コンセプト】
舞台観劇を通して繋がる口コミサービス【言語・フレームワーク】
・Ruby / RubyonRails 5
・bootstrap or vue.js【開発環境】
ローカル(Rubymine -ver 2019-3)【実装予定の機能】
・ログイン/ログアウト機能(devise)
・画像付き投稿機能(観た舞台(口コミ)、観たい舞台(期待度とコメント))
・投稿編集機能
・投稿一覧表示機能(ページネーション)
・同じ舞台に関する口コミをまとめて表示機能
・同じ舞台への評価の平均点表示機能
・ユーザーの口コミに対する評価の平均点表示機能
・投稿詳細表示機能(自分の投稿であれば編集可)
・投稿コメント機能
・星評価機能
・プロフィール編集機能(アイコン画像あり)
・いいね機能(非同期処理)
・フォロー機能(非同期処理)
・ダイレクトメッセージ機能
・キーワード検索機能
・都道府県絞り込み機能
・地図検索機能(google map API)
[管理機能]
・管理ユーザーログイン機能
・DBテーブルのリレーション管理
・DBトランザクション制御機能
[Rspec]
・単体テスト機能
・統合テスト機能【インフラ】
第一段階:Heroku
第二段階:AWS
第三段階:開発環境にDockerを導入
第四段階:CircleCIを使用してCI/CDパイプラインを構築しテスト自動化
余裕があれば、脆弱性診断の自動化の組み込み
https://circleci.com/ja/integrations/devsecops/また詳細を決め終わったら、どなたか実際のエンジニア等にポートフォリオ開発の事前レビューをしていただくことをオススメします。
理由としては、もし仕様決めの時点で何か問題があってそのまま開発を進めていくと後から修正できない事態になりかねないからです。
また仕様決め段階で一点不安がありました、それはサービスのコンセプトに悩みオリジナリティのあるコンセプトを決めることができなかった点についても相談しました。私はオンラインサロンの方で事前レビューをしていただき以下の仕様決めで特に問題ないことを確認していただきました!
下記、レビュー内容抜粋
「過去のご経歴の中で非常に強く感じた問題点の解決」をテーマにした方が企業さん側に響きやすいとは思いますが、そこら辺の判断は人それぞれなので、こちらのテーマでも大きな問題はないのではないかと思います。
「ポートフォリオにおいてほぼ誰でも最低限実装してきそうな一般的な機能だけ」になってしまっているので、もうちょっと印象度が強かったり実用性の高い機能があった方が企業さん側からの評価は高くなりやすいと思います。ガントチャート作成
私は Google スプレッドシートのテンプレートを使って直近の予定をざっくり立てました。
ポートフォリオの作成期間としては約2ヶ月半を想定してますが、転職活動をする必要があるので巻きで作業を進めていきたいところですね。
ガントチャートやタスク管理については個々のやり方があるかと思うので、参考までに。
https://www.google.com/intl/ja_jp/docs/about/
以上、要件定義についてのアウトプットといたします。
- 投稿日:2020-07-04T03:29:51+09:00
Rails ポートフォリオ実装 - 要件定義 -
ポートフォリオ実装にあたり各工程ごとに、学習のアウトプットとして手順や詳細について記し共有させていただきますので、一つの例として参考にしていただければ幸いです。
<アウトプットする理由について>
・"わかった気になっている"を無くすため
・フィードバックを受ける機会を得るため
・得た情報を自分の中にしっかり定着させるため
・数多くの情報から本当に必要な情報を判断できるようになるため<各工程>
1. 要件定義(仕様決め、ガントチャート作成)
2. 設計(画面設計、DB設計、URL設計、タスクばらし)
3. 実装(たくさん...)上記のように、各工程で中身がいくつも分岐してくるため 3工程でも何記事かに分ける必要があるかと思います。ポートフォリオ作り終わる頃には合計で 10記事くらいで濃い内容をアウトプットしていく予定です。
また、実装部分については全てアウトプットする必要はないので、自身が難しい、または面白い、メモに残す必要があると判断した機能やエラーなどを記していきます。要件定義とは
要件定義は、本格的な開発工程の前段階で、要求をまとめ具体的な進め方を決めることです。システム開発では、ユーザー側の要求を実現することがゴールです。
そのため、開発をスタートする前に、実装する機能や性能などを決めておかなければなりません。要件定義は本格的な開発工程の前段階で、具体的にどのように進めていくかを決めるために必要です。
引用:https://it-trend.jp/development_tools/article/32-0060とのこと。
難しく書いていますが、個人ポートフォリオで要件定義として私が実施したのは、サービスにどのような機能や技術を実装、使用するかを決める「仕様決め」とすスケジュール管理をする「ガントチャートの作成」の2つだけとなります。仕様決め
下記のようにコンセプト〜インフラをどうするかまで詳細を決めていきます。
ついては、自身でもなかなか規模の作品になり相当苦労するだろうと認識しています。
差別化するという箇所としては 私自身、以前にセキュリティエンジニアで脆弱性診断の経験があり、脆弱性診断の自動化の組み込みは何とか実装したいと思っています。【コンセプト】
舞台観劇を通して繋がる口コミサービス【言語・フレームワーク】
・Ruby / RubyonRails 5
・bootstrap or vue.js【開発環境】
ローカル(Rubymine -ver 2019-3)【実装予定の機能】
・ログイン/ログアウト機能(devise)
・画像付き投稿機能(観た舞台(口コミ)、観たい舞台(期待度とコメント))
・投稿編集機能
・投稿一覧表示機能(ページネーション)
・同じ舞台に関する口コミをまとめて表示機能
・同じ舞台への評価の平均点表示機能
・ユーザーの口コミに対する評価の平均点表示機能
・投稿詳細表示機能(自分の投稿であれば編集可)
・投稿コメント機能
・星評価機能
・プロフィール編集機能(アイコン画像あり)
・いいね機能(非同期処理)
・フォロー機能(非同期処理)
・ダイレクトメッセージ機能
・キーワード検索機能
・都道府県絞り込み機能
・地図検索機能(google map API)
[管理機能]
・管理ユーザーログイン機能
・DBテーブルのリレーション管理
・DBトランザクション制御機能
[Rspec]
・単体テスト機能
・統合テスト機能【インフラ】
第一段階:Heroku
第二段階:AWS
第三段階:開発環境にDockerを導入
第四段階:CircleCIを使用してCI/CDパイプラインを構築しテスト自動化
余裕があれば、脆弱性診断の自動化の組み込み
https://circleci.com/ja/integrations/devsecops/また詳細を決め終わったら、スクールやオンラインサロンで実際のエンジニア等にポートフォリオ開発の事前レビューをしていただくことをオススメします。
理由としては、もし仕様決めの時点で何か問題があってそのまま開発を進めていくと後から修正できない事態になりかねないからです。
私は、仕様決め段階でサービスのコンセプト考案に悩み、オリジナリティのあるコンセプトを決めることができなかった点について不安があったのでその点を相談したりして、事前レビューをしていただき、これからの実装について不安点を取り除くことができました。--------------------------下記、レビュー内容抜粋--------------------------
「過去のご経歴の中で非常に強く感じた問題点の解決」をテーマにした方が企業さん側に響きやすいとは思いますが、そこら辺の判断は人それぞれなので、こちらのテーマでも大きな問題はないのではないかと思います。
「ポートフォリオにおいてほぼ誰でも最低限実装してきそうな一般的な機能だけ」になってしまっているので、もうちょっと印象度が強かったり実用性の高い機能があった方が企業さん側からの評価は高くなりやすいと思います。ガントチャート作成
私は Google スプレッドシートのテンプレートを使って直近の予定をざっくり立てました。
ポートフォリオの作成期間としては約2ヶ月半を想定してますが、転職活動をする必要があるので巻きで作業を進めていきたいところですね。
ガントチャートを作成する時点で自分が毎日どれだけ開発に時間をあてることができ、いついつまでに完成させるというを各工程の目安時間と照らし合わせながら、考えていく必要があるため意外とガントチャート作成には時間がかかりまそうです。
しっかりとしたタスク管理ツールを使った方が良いかもしれませんが、ポートフォリオのため自分が一番見やすいガントチャートにいたしました。タスク管理については個々のやり方があるかと思うので、参考までに。
https://www.google.com/intl/ja_jp/docs/about/
以上、要件定義についてのアウトプットといたします。
※ちなみに、要件定義は約2~3日で終わるかと思います!
- 投稿日:2020-07-04T03:16:30+09:00
【Nuxt/Rails】axiosとdevise_token_authを使ってPOSTした実装
Nuxt.jsとRuby on Railsでaxiosとdevise_token_authを利用してPOSTする時に、地味に詰まってしまったので備忘録がてらまとめます。
Ruby on Rails側の実装
devise_token_authの設定諸々は省きます。
以下のURLあたりが参考になりましたので、そちらをご覧いただけると良いかもしれません。
https://github.com/lynndylanhurley/devise_token_auth
https://qiita.com/Masahiro_T/items/6bc49a625b437a7c2f45
https://sainu.hatenablog.jp/entry/2018/08/11/194319FormObjectを導入してるので、そちらも込みで載せます。
articles_controller.rbclass ArticlesController < ApplicationController def create @article = ArticleForm.new(article_params) if @article.save # 省略 end end private def article_params json_request = ActionController::Parameters.new(JSON.parse(request.body.read)) json_request.permit( :title, :description, ).merge(user_id: current_user.id) end endarticles_form.rbclass ArticleForm include ActiveModel::Model attr_reader :title, :description validates :title, presence: true, length: { maximum: 50 } validates :description, length: { maximum: 300 } def initialize(article_params) @article = article_params end def save return false if valid? Article.create(@article) true end endこれで、POSTするまでの準備が整いました。
補足
POSTされる時にJsonをごにょごにょすることになったので、JsonをParseする処理を書いてあげる必要がありました。(ここに凄くハマりました。)
def article_params json_request = ActionController::Parameters.new(JSON.parse(request.body.read)) json_request.permit( :title, :description, ).merge(user_id: current_user.id) end以下の記事に救われた(というかJsonのParse部分はコピペ)ので載せておきます。
Nuxt.js側の実装
Componentに書いた実装は省いて、Vuexの中でやってるaxiosでPOSTした部分の実装だけ切り取ります。
article.jsexport const actions = { async postArticle({ dispatch }, article) { await this.$axios .post('/articles', article, { headers: { 'Content-Type': 'multipart/form-data', // サムネ画像を送信する想定のため 'access-token': this.state.user.userToken.accessToken, client: this.state.user.userToken.client, uid: this.state.user.userToken.uid, }, }) .then(() => dispatch('getArticleList')) .catch((error) => console.log(error)) }, }devise_token_authのtokenをCookieに詰めて、nuxtServerInit時にVuexに書き出す実装をしていて、リクエスト時にヘッダーにTokenを突っ込めるようにしました。
ちなみに、Ruby on Railsではありませんが、GOのechoを利用した時に似たような実装をしていて、その備忘録を以下にまとめています。
- 投稿日:2020-07-04T02:58:06+09:00
ruby メソッドの定義
アウトプット用です。
rubyのメソッド定義を簡単にアウトプットしていきます。使用法としてはシンプル def メソッド名
end例えば下記使用していないパターン
puts "1" puts "2" puts "3" puts "4" puts "5" puts "6" puts "7" puts "8" puts "9" puts "10" puts "1" puts "2" puts "3" puts "4" puts "5" puts "6" puts "7" puts "8" puts "9" puts "10" puts "1" puts "2" puts "3" puts "4" puts "5" puts "6" puts "7" puts "8" puts "9" puts "10"使用したパターン
def number_count puts "1" puts "2" puts "3" puts "4" puts "5" puts "6" puts "7" puts "8" puts "9" puts "10" end number_count number_count number_count出力結果は同じです。
基本的にdef endはそのメソッドが読み込まれるまでは
飛ばされる処理になるので、そこだけ注意しておきたいところrailsに手こずってるので抑えておきたい基本です。