- 投稿日:2020-04-30T23:43:55+09:00
【�database.yml】DBをDockerとrails server両方で使えるように�設定
Dokerで開発時に、
docker-compose runやdocker-compose runよりも早いrails serverで一時的に動作確認をしたい場合があるかと思う。
そういった場合にも、以下のconfig/database.yml内の記述だけで対応することができる。検証環境
$ sw_vers ProductName: Mac OS X ProductVersion: 10.15.3 BuildVersion: 19D76$ ruby -v ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin19]$ rails -v Rails 5.2.4.2database.ymlについて
まず、database.ymlとは
config/database.yml(例)default: &default adapter: mysql2 encoding: utf8 collation: utf8_general_ci pool: 5 host: <%= ENV['MYSQL_HOST'] || 'localhost' %> username: <%= ENV['MYSQL_USERNAME'] || 'root' %> password: <%= ENV['MYSQL_PASSWORD'] || '' %> socket: /tmp/mysql.sock主な内容
adapter: 使用するデータベースの種類(postgresql, mysql2等)
encoding: 文字コード
collation: MySQLの文字列と照合順序(ソート順)、”文字コード言語名比較法”で構成される
pool: 確保する接続プールの数
host: データベースが動作しているホスト名またはIPアドレス
username,password: データベースに接続するユーザー名・パスワード
socket: DB通信の接続口
比較演算子: ||
orと同じ働きをする。
Ruby 2.7.0 リファレンスマニュアル 演算子式文法:
式 `||' 式
式 or 式
左辺を評価し、結果が真であった場合にはその値を返します。左辺の評価結果が偽であった場合には右辺を評価しその評価結果を返します。config/database.ymlのhost,username,passwordの部分をこれで書くことで、
ENV['MYSQL_HOST']等の環境変数がない場合に、localhost等を返してくれる。終わりに。
最後まで読んで頂きありがとうございます
転職の為、未経験の状態からRailsを学習しております。正しい知識を着実に身に着け、実力のあるエンジニアになりたいと考えています。継続して投稿していく中で、その為のインプットも必然的に増え、成長に繋がるかと考えています。
今現在、初心者だからといって言い訳はできないですが、投稿の内容に間違っているところや、付け加えるべきところが多々あるかと思いますので、ご指摘頂けると幸いです。この記事を読んで下さりありがとうございました。参考にさせて頂いた記事
- 投稿日:2020-04-30T23:42:01+09:00
文字列の中に変数を入れる記法
自分はもともとRubyでプログラミングに触れて、eRubyでCGIを書いたりしてたから文字列の中に
{}でくくった変数を入れるのを多用していたのですが。HelloWorld.rbstr1 = "Hello" str2 = "World!" print "#{str1}, #{str2}\n"これをC#で書こうとしたらこうなります。
HelloWorld.csvar str1 = "Hello"; var str2 = "World!"; Console.Write($"{str1}, {str2}\n") ;別解でこういう風にも書けるようです。
HelloWorldAlt.csvar str1 = "Hello"; var str2 = "World!"; Console.Write("{0}, {1}\n", str1, str2);ところで、最近Javaをはじめたのですが、Javaだとこういう風に書くみたいです。
HelloWorld.javavar str1 = "Hello"; var str2 = "World!"; System.out.printf("%s, %s\n", str1, str2);後で書いた
HelloWorldAlt.csのC#のパターンに近いですね。
ぶっちゃけJavaが一番わかりづらいので、今後C#で書く時もJava表記に近い後者の記法を書いていこうかなと思いました。
- 投稿日:2020-04-30T23:32:35+09:00
よくあるサイコロ系問題をRubyで解く
はじめに
競プロはじめたての初心者です。
言語はRubyをよく使っています。昔、どうしても解くことができなかった問題を、最近遂に解くことができたので、シェアしたいと思います。
※ 著作権の問題上、問題は少し変えています正解のコードを紹介する前に、私がつまずいたときの考え方とコードを先にシェアしています。
これは、初心者プログラマの考え方を知りたいという熟練者の方の手助けになれば良いなと考えたからです。
少々長くなってしまっているので、答えのみ知りたい方は、「私がつまずいた点」の部分をスキップして読んでもらえばと思います。サイコロの問題
問題は以下の通りです。
- 上記の展開図からなるサイコロがある
- このサイコロを、ある方向にある回数転がす
- 最後の上面の数字を出力せよ
入力
入力は、「N,S,E,W」のどれかなる、一つ以上の文字列である。
尚、「N,S,E,W」はそれぞれ上図の矢印方向にサイコロを1回転させることを意味する。入力例NW出力
入力された文字列の長さ分、サイコロを回転させたときの、上面の数字を出力する。出力例3私がつまずいた点
私がなぜ最初にこの問題を解けなかったのか、つまずいた点を紹介します。
初心者はこういうところを難しいと感じているということが伝わればいいなと思います笑私は、この問題を見た際、サイコロが縦方向と横方向に回転することから、縦方向の数値からなる配列と、横方向の数値からなる配列を作れば良いと考えました。
example.rb# サイコロが縦に転がった際の数値の配列 tate = [1,2,6,5] # サイコロが横に転がった際の数値の配列 yoko = [4,6,3,1]そして、サイコロがN方向に転がったときは、縦の配列の最初の要素(
tate[0])を、縦配列の最後(tate[-1])に持ってこれば良いと考えました。
この移動を行なった後の、配列の一番最初の要素が、サイコロの上面の数値になります。
サイコロがS方向に転がった際は、この逆の作業を行います。すなわち、縦配列の最後(tate[-1])を、縦配列の最初(tate[0])に持ってきます。example.rb# N方向への回転 # 配列の最初の値を、配列の最後に持ってくる tate << tate.shift # S方向への回転 # 配列の最後の値を、配列の最初に持ってくる tate.unshift(tate.pop)これで、縦方向にサイコロが回転した場合に、配列の一番目の数値を見れば、サイコロの上面の数値がわかるようになりました。
横方向にサイコロが回転した際も、縦方向に回転した場合と考え方は全く同じです。
example.rb# E方向への回転 # 配列の最初の値を、配列の最後に持ってくる yoko << yoko.shift # W方向への回転 # 配列の最後の値を、配列の最初に持ってくる yoko.unshift(yoko.pop)しかし、このコードでは動きません
すでにお気付きの方もいらっしゃるかもしれませんが、このコードは間違っています。
さて、どこが間違っているでしょう。サイコロの縦回転と横回転が繰り返されたケースを考えるとわかります。
実はこのコード、次の場合にのみ正しく動きます。
- サイコロが縦回転しかしない場合
- サイコロが横回転しかしない場合なぜこうなってしまうのでしょう?
サイコロがN方向に1回、E方向に2回、回転した場合を考えてみましょう。
まず、N方向に1回回転すると、サイコロ上面は、2になります。
次に、E方向に2回回転すると、サイコロ上面は、5になります。しかし、上記のコードでこれを実行すると、6が出力されます。
おかしいですね。私のコードがうまくいかない理由は、縦方向、もしくは横方向への回転により、縦配列、横配列の値が変化するということを無視しているコードになっているからです。
サイコロがN方向に1回、回転した場合、横方向の配列は次のように変わります。example.rb# yoko = [4,6,3,1] であったが、 # N方向に1回転した場合は、次のような配列になっていないといけない。 yoko = [4,5,3,2]このように、縦方向への回転と横方向への回転が組み合わさると、縦配列、横配列の値を動的に変化させないといけないことがわかりました。
最初に問題を解いたときも、ここまではたどり着けたのですが、結局どうすれば良いのかわからず寝ました笑
解答コード in Ruby
つい最近、同じ問題と出会い解法が閃きました(成長の証だと信じたい笑)
そのコードがこちらです。answer.rb# サイコロを用意 dice = [*1..6] # 回転方向(N,S,E,W)の入力結果を配列に commands = gets.chomp!.split("") # N方向への回転 def turn_north(dice) [dice[1], dice[5], dice[2], dice[3], dice[0], dice[4]] end # S方向への回転 def turn_south(dice) [dice[5], dice[0], dice[2], dice[3], dice[4], dice[1]] end # E方向への回転 def turn_east(dice) [dice[3], dice[1], dice[0], dice[5], dice[4], dice[2]] end # W方向への回転 def turn_west(dice) [dice[2], dice[1], dice[5], dice[0], dice[4], dice[3]] end commands.each do |c| case c when "N" dice = turn_north($dice) when "S" dice = turn_south($dice) when "W" dice = turn_west($dice) when "E" dice = turn_east($dice) end end # サイコロ上面の数値を出力 puts $dice.firstサイコロを回転させるメソッドのロジックがかなりわかりにくいと思うので、説明します。
まず、サイコロの縦方向ごと、横方向ごとに配列を用意するという考え方を捨てました。
理由は上記の通りです。発想を変えて、サイコロが回転したときに、上記の展開図の位置にどの数値が入るかを考えました。
今回の場合だと、N方向に1回転した場合、展開図の1のところに数値2がきます。
そして、展開図の2のところには、数値6がきます。
このように、展開図の場所にどの数値が入るかを、1から6まで考えます。
すると、次のような結果になります。N方向に1回転した場合
- 展開図の1に、数値2
- 展開図の2に、数値6
- 展開図の3に、数値3
- 展開図の4に、数値4
- 展開図の5に、数値1
- 展開図の6に、数値5この、動きをコードで再現したのが、
turn_north(dice)メソッドです。
このメソッドは、引数でサイコロ(今の展開図の数字順に、サイコロの数値が並んでいる配列)を受け取ります。def turn_north(dice) [dice[1], dice[5], dice[2], dice[3], dice[0], dice[4]] endそして、引数で受け取った配列に対して、N方向に一回転した際に、サイコロの数値と展開図の位置の変化を戻り値として返しています。
このコードは、N方向に回転した際、展開図の位置に対しサイコロの数値がどのように変化するかという性質を表したものです。
そのため、例えサイコロが途中で横方向に回転しようと、この性質が変わることはありません。
このように考えることによって、正しい出力を出せるコードが出来上がりました。[追記]
サイコロを転がすメソッドの部分は、Array#values_atメソッドを使えば、よりエレガントに記述できます。
例えば、turn_north(dice)メソッドは次のように書き換えられます。# 元のコード def turn_north(dice) [dice[1], dice[5], dice[2], dice[3], dice[0], dice[4]] end # Array#values_atを用いたコード def turn_north(dice) dice.values_at(1, 5, 2, 3, 0, 4) end詳しくは、こちらを参照ください
https://docs.ruby-lang.org/ja/2.7.0/method/Array/i/values_at.html
※ @scivola さん、ご指摘ありがとうございます!最後に
今回私が書いたコードは、非常にわかりにくいコードのような気がします。
特に、サイコロが回転したときの処理は、このように長々と説明しないと理解されないと思い、もっと綺麗なコードがあるのではないかと思います。もし、この記事を読んだ方で、もっと良い方法があるという方は、コメントご教授下さい。
- 投稿日:2020-04-30T23:11:48+09:00
Ruby Classの継承を使ってみた。
どうもチャンクノです。
今回はClassの継承を使ってみた話です。
ぶっちゃけ今までどういうところで使えばいいか分かってなかったんですよね。
でも個人開発している中で、ここで使うんじゃね?ってタイミングがあったので使ってみました!自分の作っているアプリにはTradeモデルがあり、最初はそこに勝率を求めるメソッドを書いていました。
class Trade < ApplicationRecord attr_accessor :current_user_id def search_user_fx_trades Trade.where("(user_id = ?) and (trade_category_id = ?)", current_user_id, 1) end def win_number_of_fx_trades search_user_fx_trades.where("result" => "資産増") end def win_number_of_fx_daytrades win_number_of_fx_trades.where("trade_style_id" => 1).count end def daytrade_win_rate return "0%" if win_number_of_fx_daytrades === 0 "#{(win_number_of_fx_daytrades / search_user_fx_trades.count.to_f * 100).floor(1)}%" end def fx_win_rate return "0%" if win_number_of_fx_trades.count === 0 "#{(win_number_of_fx_trades.count / search_user_fx_trades.count.to_f * 100).floor(1)}%" end endほんとはもっと書いてあるんですけど長くなってしまうのでこのぐらいに。
Tradeって他にもスイングトレードとスキャルピングトレードっていうのがあるんですがそれを書き終えた時に、このままいくとメソッドの数えぐいことになるなと気づきました。
まだ年単位や週単位のメソッドが残っていたので。
そこでClassの継承の出番か?と思い新たにClassを作成しました。class DayTrade < Trade def win_number_of_fx_daytrades win_number_of_fx_trades.where("trade_style_id" => 1).count end def daytrade_win_rate return "0%" if win_number_of_fx_daytrades === 0 "#{(win_number_of_fx_daytrades / search_user_fx_trades.count.to_f * 100).floor(1)}%" end endこんな感じ。
書き方は子クラス < 親クラスです。
これでDayTradeクラスでもTradeクラスのメソッドが使えるようになりました。
子クラスは親クラスの全てを引き継ぐので、attr_accessor :current_user_idなどを、改めて子クラスに記載する必要はありません。
注意点としては、DayTrade内にあるメソッドなので新たにDayTradeインスタンスを作成することと、作成したインスタンスにcurren_userを引数に取らなければいけないということです。@day_trade = DayTrade.new(current_user) こうすると @day_trade.daytrade_win_rate こんな感じで呼び出せるようになる。使用する場面があってるかは分かりませんが、こういう感じでそれぞれまとめることで分かりやすくなるんじゃないかなと思います!
なんかメソッドがめちゃくちゃ増えて分かりにくいなと感じてきたら別クラスに切り出せないか検討してみましょう!!
あ、ちなみにちゃんとTrade.rbというファイルとは別にDayTrade.rbというファイルを作ってくださいね!
そんなこと分かってるとは思いますが念の為?それでは今日はこの辺で!
皆様よきプログラミングライフを?
- 投稿日:2020-04-30T23:04:08+09:00
「破壊的メソッド」はRuby用語なのか?
昨日、「データサイエンティストが知るべき破壊的メソッドのすべて」という記事を書いたのですが、友人から次のような意見を貰いました。
微妙に気になったけど、「破壊的メソッド」「非破壊的メソッド」ってプログラミング全般でなくRuby用語で、かつ、「レシーバを変更するメソッド」っていう意味じゃない?
もしあえて名前で呼ぶなら、inplace methodが正しそう。(日本語は見つからない)
https://discuss.pytorch.org/t/what-is-in-place-operation/16244
https://ja.wikipedia.org/wiki/In-placeアルゴリズム更に、例えばpandasでもinplaceという引数名が使われているので、データサイエンティスト向けならinplaceのほうが馴染みあるかもしれないとも言われました。
たしかに「破壊的」と調べて出てくる記事は、Rubyのものが多いように思います。少し気になったので、いろいろな言語のドキュメントで「破壊的(destructive)」「インプレース(in-place)」という単語で調べて比較してみました。
Pythonの場合: in-placeが優勢
ドキュメントを検索したところ、実際に「インプレース(in-place)」という単語がよく使われているようです。例えば「プログラミング FAQ」の中では次のようにあります。
文字列をインプレースに変更するにはどうしたらいいですか?¶
文字列はイミュータブルなので、それはできません。殆どの場合、組み立てたい個別の部品から単純に新しい文字列を構成するべきです。
一方で、「破壊的(destructive)」という単語も多少は使われています。例えばPython2.7のドキュメントには「破壊的に(destructively)」という単語があります。最新バージョンのドキュメントでは「消去して返します」とありますが、日本語の訳語が変わっただけでした。
集合のアルゴリズムで使われるのと同じように、
popitem()は辞書を破壊的にイテレートするのに便利です。辞書が空であれば、popitem()の呼び出しはKeyErrorを送出します。Python3.8でも「curses --- 文字セル表示を扱うための端末操作」の中に「非破壊的(non-destructive)」という単語が見つかりました。
ウィンドウを
destwinの上に重ね書き (overlay) します。ウィンドウは同じサイズである必要はなく、重なっている領域だけが複写されます。この複写は非破壊的です。少し離れた箇所に「破壊的(destructive)」もあります。
destwinの上にウィンドウの内容を上書き (overwrite) します。ウィンドウは同じサイズである必要はなく、重なっている領域だけが複写されます。この複写は破壊的です。Rubyの場合: destructive methodという用語が説明されている
Official Ruby FAQの中に「What is a destructive method?」という項目が用意されていました。日本語版の訳は見つかりませんでした。
The plain version creates a copy of the receiver, makes its change to it, and returns the copy. The “bang” version (with the !) modifies the receiver in place.
説明の中に「in place」という単語も使われています。
ドキュメントではあまりヒットしなかったので、るびまも見てみます。やはり「破壊的」という単語がよく使われています。例えば「Ruby コードの感想戦 【第 2 回】 WikiR」より。
force_encoding は ! がついていないので名前だけではわかりづらいですが、破壊的なメソッドです。 そのため、戻り値を text に代入する必要はありません。これで十分です。
「6 月 10 日 午前の部」でin-placeという単語が使われている箇所もありました。
文法上、yield が先に入って、ブロックつき引数を後で導入したとき yield が邪魔になった。あと String で、in-place で mutate するしないがごっちゃになってよくない。Perl からもってきた組み込み変数の 98% は後悔してます。
PHPの場合: 両方とも併用されている
「in-place」と「destructive」という単語が両方とも使われているようです。これらの箇所の日本語への翻訳はまだ行われていない様子?
Sorts the sequence in-place, using an optional comparator function.
注意:
This method is not destructive.
その他の言語
Rubyに影響を与えたSmalltalkも調べてみたかったのですが、はっきりしたこととは分かりませんでした。ただ、Smalltalk-72のドキュメントを見ると、non-destructiveという単語が少なくとも一箇所使われていました。
Note that you can make non-destructive text by using xor ink which complements the background so that reshowing the text crases it while restoring what was
underneath.また、基本的に変数がイミュータブルなHaskellも調べてみたのですが、destructiveが「過去の互換性を切った言語仕様のアップデート」という意味で使われているものしか見つけられなかったのと、ドキュメント自体を読むのが今の私にとっては骨が折れそうだったので諦めました。
また、Rubyでは「destructive method」という固有名詞に近い使われ方をしているのに対して、他の言語のdestructiveは一般的な形容詞として使われているように見えます。もしかすると、「破壊的メソッド」というのはRubyのコミュニティで使われ始めた言葉が、日本語でプログラミング用語として認識されて広まったものなのかもしれません。機会があればまた調べてみます。
- 投稿日:2020-04-30T22:29:15+09:00
テストをまともにやってこなかったから、rspec-railsを使ってモデルの単体テストを初めてまともにやってみた話。
超簡単なモデルの単体テストをやってみる。
前回せっかくミニアプリまで作ったので、今までまともにやってこなかったモデルの単体テストもやってしまおう!
と、今回は、超簡単な単体テストを実施しました。
テスト環境の準備が色々あったので備忘録として記載します。動作環境
ruby 2.5.1
rails 5.2.4.2下準備
modelとかmigration等、ここまでの環境は前回記事の下準備をご覧ください。
テスト環境の準備
gemをインストール
.Gemfilegem 'rspec-rails' gem 'factory_bot_rails'factory_girlは使ったことないので今回はfactory_botで進めます。
terminal.$ bundle installrespecをインストール
terminal.$ rails g rspec:install.rspecへの追記
.rspec(以下を追記) --format documentationこれ、なんの意味があるのかと思ったら、書かないとターミナルにテスト結果がdocument形式で表示されません。
spec/rails_helper.rbへの追記
spec/rails_helper.rbRSpec.configure do |config| (以下を追記) config.include FactoryBot::Syntax::Methods #Factory_botのメソッドを使用するため endrspecファイルを作成する
terminal.$ bin/rails g rspec:model item単体テスト実装
それでは単体テストのコードを書いていきます。
とりあえずFactory_botをつくってみた。
まずは半端な知識でFactory_botを作ります。
spec/factoreis/item.rbFactoryBot.define do factory :item do #name に "test" とだけ入れます。 name {"test"} end endとりあえずテストコードも書いてみた。
次に半端な知識でテストコードも書いていきます。
spec/models/item_spec.rbrequire 'rails_helper' RSpec.describe Item, type: :model do describe '#create' do let(:item) {build(:item)} context 'can save' do it "is valid with a name" do expect(item).to be_valid #name に "test" が入っていれば成功する(はず) end end context 'can not save' do it "is valid without a name" do item.name = "" #name が 空の場合 expect(item).to be_invalid #失敗する(はず) end end end endテストコード走らせてみた。
Factoryも作った。テストコードも書いた。
次にやることと言ったら、もう決まってる。
いざ。terminal.$ bundle exec rspec spec/models/item_spec.rbterminal.Item #create can save is valid with a title can not save is valid without a title (FAILED - 1) Failures: 1) Item#create can not save is valid without a title Failure/Error: expect(item).to be_invalid expected `#<Item id: nil, title: "", created_at: nil, updated_at: nil>.invalid?` to return true, got false # ./spec/models/item_spec.rb:14:in `block (4 levels) in <top (required)>' Finished in 0.34277 seconds (files took 5.22 seconds to load) 2 examples, 1 failure Failed examples: rspec ./spec/models/item_spec.rb:12 # Item#create can not save is valid without a titleあれ? エラー?
あ、validation書いてないですねこれ。validationを追加してみた。
null: falseだけ追加します。app/models/item.rbclass Item < ApplicationRecord (中略) validates :name,presence: true #null: false end結果
terminal.$ bundle exec rspec spec/models/item_spec.rbterminal.Item #create can save is valid with a title can not save is valid without a title Finished in 0.33208 seconds (files took 6.29 seconds to load) 2 examples, 0 failures上手(?)にできました!
教訓
validationを忘れない!
今回は以上です。
参考にさせていただいた記事
- 投稿日:2020-04-30T21:43:18+09:00
Kinx ライブラリ - Net.Http
Network - Http
はじめに
「見た目は JavaScript、頭脳(中身)は Ruby、(安定感は AC/DC)」 でお届けしているスクリプト言語 Kinx。言語はライブラリが命。ということでライブラリの使い方編。
今回は Network(Http) です。
- 参考
- 最初の動機 ... スクリプト言語 KINX(ご紹介)
- 個別記事へのリンクは全てここに集約してあります。
- リポジトリ ... https://github.com/Kray-G/kinx
- Pull Request 等お待ちしております。
libcurl を抱えているので Http 以外も作れるはずだが、まずは一番欲しいのは Http/Https でしょう。
HTTP/HTTPS リクエスト
各メソッドの意味は後で記載することとして、まずは使い方から。
Http クライアント
Http クライアント・オブジェクトは
Net.Httpクラスを使用する。var http = new Net.Http();HTTP メソッド
head、get、post、put、deleteをサポート。HTTP HEAD -
head
HEADメソッドで情報を取得する。SSL に関しては一先ず false にして実行。var http = new Net.Http(); http.sslVerifyPeer(false); http.sslVerifyHost(false); var r = http.head("https://docs.ruby-lang.org/ja/latest/class/Range.html"); if (r.code == 200) { System.println(r.toJsonString(true)); }コールバック関数を指定することもできる。データは取得できたデータ分だけ毎回コールバックされる。その動作はメソッドに関わらず全て同じ動作をする。
また、データは単なるバイト列として扱われるため、日本語などのマルチバイト文字が混じる場合には区切り位置が文字コードの区切りとぴったりあった場所で区切られるとは限らないことに注意。なので、以下のように直接出力した場合、日本語が混じると変になる可能性がある。ヘッダはまだマシだがボディの場合は基本的にはバッファにためていくのが良いかと。
var http = new Net.Http(); http.sslVerifyPeer(false); http.sslVerifyHost(false); var r = http.head("https://docs.ruby-lang.org/ja/latest/class/Range.html", &(data) => { System.print(data); }); if (r.code == 200) { ... }コールバックでの取得結果は以下の通り。
HTTP/1.1 200 OK Connection: keep-alive Content-Length: 48121 Server: nginx/1.14.2 Content-Type: text/html Last-Modified: Wed, 15 Apr 2020 00:16:18 GMT ETag: "5e965252-bbf9" Cache-Control: public, max-age=43200, s-maxage=172800, stale-while-revalidate=86400, stale-if-error=604800 Accept-Ranges: bytes Date: Mon, 27 Apr 2020 07:25:51 GMT Via: 1.1 varnish Age: 12363 X-Served-By: cache-tyo19947-TYO X-Cache: HIT X-Cache-Hits: 1 X-Timer: S1587972352.977171,VS0,VE1 Vary: Accept-Encoding復帰値
rにはヘッダ情報をオブジェクト化したオブジェクトが返され、r.codeに HTTP ステータスコードが格納されており、r.bodyにボディの情報がテキストとして格納されている。この構造は他のメソッドでも同様。HEAD ではボディは無いためr.body == ""となる。上記の例では以下のようになる。
{ "Last-Modified": "Wed, 15 Apr 2020 00", "X-Cache-Hits": "1, 1", "body": "", "Server": "nginx/1.14.2", "code": 200, "Date": "Mon, 27 Apr 2020 07", "Via": "1.1 varnish", "X-Cache": "HIT, HIT", "Content-Type": "text/html", "Cache-Control": "public, max-age=43200, s-maxage=172800, stale-while-revalidate=86400, stale-if-error=604800", "X-Timer": "S1587972352.977171,VS0,VE1", "ETag": "\"5e965252-bbf9\"", "Vary": "Accept-Encoding", "Content-Length": 48121, "Accept-Ranges": "bytes", "X-Served-By": "cache-tyo19947-TYO", "Connection": "keep-alive", "Age": 12363 }
head以外のメソッドではbodyにボディ・データがテキストの形で格納される。なので、JSON 形式で受け取る場合などはJSON.parse(r.body)と自分でパースする必要があるので注意。HTTP GET -
get
GETメソッドで情報を取得する。コールバックを指定しなければ全てを受信し、情報を格納したオブジェクトを返す。r.bodyは文字列なので、JSON 形式等で受信した場合は自分でJSON.parse(r.body)等を行う。var http = new Net.Http(); http.sslVerifyPeer(false); http.sslVerifyHost(false); var r = http.get("https://docs.ruby-lang.org/ja/latest/class/Range.html"); if (r.code == 200) { System.println(r.toJsonString(true)); }応答はこんな感じ。
{ "Last-Modified": "Wed, 15 Apr 2020 00", "X-Cache-Hits": 1, "body": "<!DOCTYPE html>\n<html lang=\"ja-JP\">\n<head>\n ...省略(長い)...", "Server": "nginx/1.14.2", "code": 200, "Date": "Thu, 30 Apr 2020 12", "Via": "1.1 varnish", "X-Cache": "HIT", "Content-Type": "text/html", "Cache-Control": "public, max-age=43200, s-maxage=172800, stale-while-revalidate=86400, stale-if-error=604800", "X-Timer": "S1588250498.519558,VS0,VE1", "ETag": "\"5e965252-bbf9\"", "Vary": "Accept-Encoding", "Content-Length": 48121, "Accept-Ranges": "bytes", "X-Served-By": "cache-tyo19929-TYO", "Connection": "keep-alive", "Age": 102 }コールバックはヘッダーとボディそれぞれ設定できる。
http.get("https://docs.ruby-lang.org/ja/latest/class/Range.html", { header: &(data) => { ... }, body: &(data) => { ... }, });コールバックに直接関数オブジェクトを指定した場合、ボディのコールバックとして動作する。
http.get("https://docs.ruby-lang.org/ja/latest/class/Range.html", &(data) => { ... // ボディ・データが細切れに来る。 });HTTP POST -
post
POSTメソッドを発行する。POST するデータはHttp#setPostDataメソッドで設定する。その他、コールバック等はGETと同じ。
POSTはなかなか試す場所が無いのだが、Ruby で以下のサーバを立ち上げてアクセスしてみる。エラーはするが、アクセスされていることは確認できる。ruby -rwebrick -e 'WEBrick::HTTPServer.new(:DocumentRoot => "./", :Port => 8000).start'アクセスしてみる。
var http = new Net.Http(); http.setPostData("POST-DATA"); http.post("http://localhost:8000/index.html", System.print);GET と同じようにボディがコールバックされてくるため、以下の応答となる。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN"> <HTML> <HEAD><TITLE>Not Found</TITLE></HEAD> <BODY> <H1>Not Found</H1> `/index.html' not found. <HR> <ADDRESS> WEBrick/1.4.2 (Ruby/2.5.1/2018-03-29) at localhost:8000 </ADDRESS> </BODY> </HTML>サーバーのログは以下の通り。
[2020-04-21 17:33:53] ERROR `/index.html' not found. ::1 - - [21/Apr/2020:17:33:53 DST] "POST /index.html HTTP/1.1" 404 280 - -> /index.htmlHTTP PUT -
put
PUTはPOSTと同じで、メソッド名だけPUTに変更して実行する。var http = new Net.Http(); http.setPostData("PUT-DATA"); http.put("http://localhost:8000/index.html", System.print);HTTP DELETE -
delete
DELETEもGETと同じで、メソッド名だけDELETEに変更して実行する。var http = new Net.Http(); http.delete("http://localhost:8000/index.html", System.print);verbose
Http#setDebug(callback)を使ってデバッグ情報を取得することができる。以下はデバッグ情報だけ出力させる例。var http = new Net.Http(); http.setDebug(System.print); http.delete("http://localhost:8000/index.html");Curl の Verbose 情報を見ることができる。
* Trying ::1:8000... * Connected to localhost (::1) port 8000 (#0) > DELETE /index.html HTTP/1.1 Host: localhost:8000 Accept: */* * Mark bundle as not supporting multiuse < HTTP/1.1 405 Method Not Allowed < Content-Type: text/html; charset=ISO-8859-1 < Server: WEBrick/1.4.2 (Ruby/2.5.1/2018-03-29) < Date: Tue, 21 Apr 2020 08:49:07 GMT < Content-Length: 302 < Connection: close < * Closing connection 0ちゃんと
DELETEメソッドが発行されてますね。さらに、
setDebugDetail()メソッドで true を指定すると、送受信したデータを表示することも可能。データ量が多くなるので、適宜コントロールすること。var http = new Net.Http(); http.setDebugDetail(true); http.setDebug(System.print); http.delete("http://localhost:8000/index.html");こんな感じになる。
* Trying ::1:8000... * Connected to localhost (::1) port 8000 (#0) > DELETE /index.html HTTP/1.1 Host: localhost:8000 Accept: */* * Mark bundle as not supporting multiuse < HTTP/1.1 405 Method Not Allowed < Content-Type: text/html; charset=ISO-8859-1 < Server: WEBrick/1.4.2 (Ruby/2.5.1/2018-03-29) < Date: Tue, 21 Apr 2020 09:09:27 GMT < Content-Length: 302 < Connection: close < > Recv data, 0000000302 bytes (0x0000012e) 0000: 3c 21 44 4f 43 54 59 50 45 20 48 54 4d 4c 20 50 <!DOCTYPE HTML P 0010: 55 42 4c 49 43 20 22 2d 2f 2f 57 33 43 2f 2f 44 UBLIC "-//W3C//D 0020: 54 44 20 48 54 4d 4c 20 34 2e 30 2f 2f 45 4e 22 TD HTML 4.0//EN" 0030: 3e 0a 3c 48 54 4d 4c 3e 0a 20 20 3c 48 45 41 44 >.<HTML>. <HEAD 0040: 3e 3c 54 49 54 4c 45 3e 4d 65 74 68 6f 64 20 4e ><TITLE>Method N 0050: 6f 74 20 41 6c 6c 6f 77 65 64 3c 2f 54 49 54 4c ot Allowed</TITL 0060: 45 3e 3c 2f 48 45 41 44 3e 0a 20 20 3c 42 4f 44 E></HEAD>. <BOD 0070: 59 3e 0a 20 20 20 20 3c 48 31 3e 4d 65 74 68 6f Y>. <H1>Metho 0080: 64 20 4e 6f 74 20 41 6c 6c 6f 77 65 64 3c 2f 48 d Not Allowed</H 0090: 31 3e 0a 20 20 20 20 75 6e 73 75 70 70 6f 72 74 1>. unsupport 00a0: 65 64 20 6d 65 74 68 6f 64 20 60 44 45 4c 45 54 ed method `DELET 00b0: 45 27 2e 0a 20 20 20 20 3c 48 52 3e 0a 20 20 20 E'.. <HR>. 00c0: 20 3c 41 44 44 52 45 53 53 3e 0a 20 20 20 20 20 <ADDRESS>. 00d0: 57 45 42 72 69 63 6b 2f 31 2e 34 2e 32 20 28 52 WEBrick/1.4.2 (R 00e0: 75 62 79 2f 32 2e 35 2e 31 2f 32 30 31 38 2d 30 uby/2.5.1/2018-0 00f0: 33 2d 32 39 29 20 61 74 0a 20 20 20 20 20 6c 6f 3-29) at. lo 0100: 63 61 6c 68 6f 73 74 3a 38 30 30 30 0a 20 20 20 calhost:8000. 0110: 20 3c 2f 41 44 44 52 45 53 53 3e 0a 20 20 3c 2f </ADDRESS>. </ 0120: 42 4f 44 59 3e 0a 3c 2f 48 54 4d 4c 3e 0a BODY>.</HTML>. * Closing connection 0
setDebugDetail()のオプションに{ hex: false }を指定すると、16進データは表示しない形式で取得することもできる。var http = new Net.Http(); http.setDebugDetail(true, { hex: false }); http.setDebug(System.print); http.delete("http://localhost:8000/index.html");16進ダンプが無くなる。
* Trying ::1:8000... * Connected to localhost (::1) port 8000 (#0) > DELETE /index.html HTTP/1.1 Host: localhost:8000 Accept: */* * Mark bundle as not supporting multiuse < HTTP/1.1 405 Method Not Allowed < Content-Type: text/html; charset=ISO-8859-1 < Server: WEBrick/1.4.2 (Ruby/2.5.1/2018-03-29) < Date: Tue, 21 Apr 2020 09:09:48 GMT < Content-Length: 302 < Connection: close < > Recv data, 0000000302 bytes (0x0000012e) 0000: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">.<HTML>. <HEAD 0040: ><TITLE>Method Not Allowed</TITLE></HEAD>. <BODY>. <H1>Metho 0080: d Not Allowed</H1>. unsupported method `DELETE'.. <HR>. 00c0: <ADDRESS>. WEBrick/1.4.2 (Ruby/2.5.1/2018-03-29) at. lo 0100: calhost:8000. </ADDRESS>. </BODY>.</HTML>. * Closing connection 0Fiber
Fiber を使ってデータをループで処理させることもできる。EventMachine 的な使い方を想定しているが、まだ EventMachine は無いので今後の検討項目。
var http = new Net.Http(); http.sslVerifyPeer(false); http.sslVerifyHost(false); var fiber = new Fiber(&{ http.get("https://docs.ruby-lang.org/ja/latest/class/Range.html", &(data) => { yield data; }); }); var total = ""; while (true) { var d = fiber.resume(); break if (!fiber.isAlive()); total += d; System.println("read %d bytes, total %d bytes" % d.length() % total.length()); } System.println(total);こんな感じで取得できます。
read 1371 bytes, total 1371 bytes read 1371 bytes, total 2742 bytes read 1371 bytes, total 4113 bytes read 1371 bytes, total 5484 bytes read 1371 bytes, total 6855 bytes read 1371 bytes, total 8226 bytes read 1371 bytes, total 9597 bytes read 1371 bytes, total 10968 bytes read 1371 bytes, total 12339 bytes read 1371 bytes, total 13710 bytes read 1371 bytes, total 15081 bytes read 1371 bytes, total 16452 bytes read 1371 bytes, total 17823 bytes read 1371 bytes, total 19194 bytes read 1371 bytes, total 20565 bytes read 1371 bytes, total 21936 bytes read 1371 bytes, total 23307 bytes read 1371 bytes, total 24678 bytes read 1371 bytes, total 26049 bytes read 1371 bytes, total 27420 bytes read 1371 bytes, total 28791 bytes read 1371 bytes, total 30162 bytes read 1371 bytes, total 31533 bytes read 1371 bytes, total 32904 bytes read 1371 bytes, total 34275 bytes read 1371 bytes, total 35646 bytes read 1371 bytes, total 37017 bytes read 1371 bytes, total 38388 bytes read 1371 bytes, total 39759 bytes read 1371 bytes, total 41130 bytes read 1371 bytes, total 42501 bytes read 1371 bytes, total 43872 bytes read 1371 bytes, total 45243 bytes read 1371 bytes, total 46614 bytes read 1371 bytes, total 47985 bytes read 136 bytes, total 48121 bytes <!DOCTYPE html> <html lang="ja-JP"> <head> <!-- Global Site Tag (gtag.js) - Google Analytics --> <script async src="https://www.googletagmanager.com/gtag/js?id=UA-620926-3"></script> <script> window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments)}; gtag('js', new Date()); gtag('config', 'UA-620926-3'); </script> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="../style.css"> <link rel="stylesheet" href="../syntax-highlight.css"> <link rel="icon" type="image/png" href="../rurema.png"> <link rel="canonical" href="https://docs.ruby-lang.org/ja/latest/class/Range.html"> <title>class Range (Ruby 2.7.0 リファレンスマニュアル)</title> ...(以下省略)インスタンス・メソッド
Net.Httpクラス・インスタンスに定義されているメソッドは以下の通り。正直、証明書関係はちゃんとテストできていないが、libcurl のマニュアル通りの実装をしてみた。基本的には対応する CURL オプションを設定しているだけです。何かあれば教えていただけると助かります。
メソッド 意味 sslVerifyPeer(tf) true, 証明書を sslSetCaInfo()メソッド、またはsslSetCaPath()メソッドで証明ディレクトリを指定する。 false, 左記の検証を行わない。sslVerifyHost(verify) true, SSL ピア証明書に一般名が存在するかどうかを調べ、その名前がホスト名と一致することを検証する。false, 左記の検証を行わない。 sslSetCaInfo(path) 接続先を検証するための証明書を保持するファイル名。 sslVerifyPeer()とともに使用する。sslSetCaPath(path) 複数の証明書ファイルを保持するディレクトリ。 sslVerifyPeer()とともに使用する。setDebugDetail(tf, opts) true, デバッグ情報に送受信データを含める。 optsとして{ hex: false }を指定すると送受信データに 16 進ダンプを含めない。setUserPassword(user, pass) 接続に使用するユーザー名とパスワード。 setProxy(url) リクエストを経由させる HTTP プロキシの URL。 setProxyUserPassword(user, pass) プロキシに接続するためのユーザー名とパスワード。 setTimeout(millisec) タイムアウトをミリ秒で指定する。 setDebug(callback) デバッグ情報を受け取るコールバックを指定する。コールバックを指定するとデバッグ情報を取得するよう設定される。 addHeader(key, value) 設定する HTTP ヘッダフィールドを keyとvalueで指定する。removeHeader(key) keyで示されるヘッダを削除する。setRedirect(tf, opts) サーバーが HTTP ヘッダの一部として送ってくる "Location: " ヘッダの内容をたどる。 optsとして{ max: n }を指定するとリダイレクトする回数の上限を設定できる。setPostData(data) POSTまたはPUTで送信するデータを設定する。head(url, callback) HEADメソッドを発行する。コールバックを指定しなかった場合、取得したヘッダデータのオブジェクトを返す。get(url, callbacks) GETメソッドを発行する。コールバックはヘッダ・ボディ用関数、または{ header: f1, body: f2 }でそれぞれ指定可能。コールバックを指定しなかった場合、取得したデータのオブジェクトを返す。post(url, callbacks) POSTメソッドを発行する。コールバックはヘッダ・ボディ用関数、または{ header: f1, body: f2 }でそれぞれ指定可能。コールバックを指定しなかった場合、取得したデータのオブジェクトを返す。put(url, callbacks) PUTメソッドを発行する。コールバックはヘッダ・ボディ用関数、または{ header: f1, body: f2 }でそれぞれ指定可能。コールバックを指定しなかった場合、取得したデータのオブジェクトを返す。delete(url, callbacks) DELETEメソッドを発行する。コールバックはヘッダ・ボディ用関数、または{ header: f1, body: f2 }でそれぞれ指定可能。コールバックを指定しなかった場合、取得したデータのオブジェクトを返す。おわりに
ネットワーク系は色々使い道があるので今後充実させたいカテゴリー。まずは一番使いたい HTTP を用意してみました。libcurl ではできないものも含めてサポートしていきたい。SNMP とか、SSH とか。
ではまた次回。
- 投稿日:2020-04-30T18:52:22+09:00
Railsのform_withを使った時にページが更新されない時
form_withとは
Railsアプリケーションでformを作成する時にform_for/form_tagを使っていました。
任意のmodelに紐づくフォームを作成したい場合にはform_forを使い、modelに紐づかない場合にはform_withを使います。
form_forを使えばPOSTの送信先urlなどを全て自動で行いますが、form_forの場合は全て明示します。
HTMLタグのヘルパーのようなイメージで使います。
【Rails】form_for/form_tagの違い・使い分けをまとめた
しかし、
Rails5.1以降は2つのメソッドを統合したform_withが登場し、form_withの利用が推奨されています。form_withでページが更新されない
form_withを使ってユーザのログインフォームを作っていました。
form_withには
UserModelを紐づけており、バリデーションやログイン認証の結果にエラーがあれば、viewに反映せるようにしていました。views/users/_form.html.erb<%= form_with model: @user, url: user_path do |f| %> <%= render 'shared/error_messages', object: f.object %> <%= f.label :name %> <%= f.text_field :user_name, class: "form-control" %> <%= f.label :email %> <%= f.email_field :email, class: "form-control" %> <%= f.label :password %> <%= f.password_field :password, class: "form-control" %> <%= f.label :password_confirmation, "Confirmation" %> <%= f.password_field :password_confirmation, class: "form-control" %> <%= f.submit yield(:btn_text), class: "btn btn-primary" %> <% end %>ところが、エラーは発生しているのにviewには反映されない問題に衝突しました。
これは、
form_withでのパラメータの送信はajaxで行われているためです。HTMLのフォームとしてPOSTしたい場合は
local: trueオプションを付け加えます。views/users/_form.html.erb<%= form_with model: @user, url: user_path, local: true do |f| %> : <% end %>これでバリデーションなどのエラー結果を表示するviewを表示できます。
都度フォームにオプションをつけるのが面倒な場合は、
config/initializeディレクトリに適当なファイルを作成し以下のコードを追記します。config/initialize/some_file.rbRails.application.configure do config.action_view.form_with_generates_remote_forms = false end
- 投稿日:2020-04-30T18:31:00+09:00
[Rails]RuboCopが遅いときにやること
はじめに
AllCopsで対象外のファイルを指定したら急に動作が遅くなったRuboCopさんの動作速度を改善する方法。原因
AllCopsで除外ファイルを指定する前は明らかな不要フォルダは検索してなかった。
除外ファイルを指定すると、指定ファイル以外は全部検索していた。解決策
検索不要なフォルダを指定する。実際のやつはこんな感じ↓
rubocop.ymlAllCops: TargetRubyVersion : 2.6 Exclude: - 'db/schema.rb' - 'db/migrate/*' - !ruby/regexp /old_and_unused\.rb$/ - 'bin/*' - 'node_modules/**/*' - 'config/**/*' - 'public/**/*' - 'tmp/**/*' - 'log/**/*'
- 投稿日:2020-04-30T17:44:15+09:00
Ruby と Perl と Java と Python で解く AtCoder ATC 002 A
はじめに
AtCoder Typical Contest(ATC) とは、競技プログラミングにおける、典型問題を出題するコンテストです。
AtCoder さん、ありがとうございます。今回のお題
AtCoder Typical Contest 002 A - 幅優先探索
今回のテーマ、幅優先探索
Ruby
DFS(深さ優先探索)とBFS(幅優先探索)の違いについて、いろいろあると思いますが、ここではデータの流れに注目します。
DFS BFS 後入れ先出し 先入れ先出し データ構造 スタック キュー データを入れる push push データを取り出す pop shift ruby.rbr, c = gets.split.map(&:to_i) sy, sx = gets.split.map(&:to_i) gy, gx = gets.split.map(&:to_i) cm = Array.new(r + 1).map{Array.new(c + 1, 0)} 1.upto(r) do |i| s = gets.chomp 1.upto(c) do |j| cm[i][j] = -1 if s[j - 1] == '.' end end que = [] que.push(sy) que.push(sx) cm[sy][sx] = 0 while que.size > 0 y = que.shift x = que.shift if cm[y + 1][x] == -1 cm[y + 1][x] = cm[y][x] + 1 que.push(y + 1) que.push(x) end if cm[y - 1][x] == -1 cm[y - 1][x] = cm[y][x] + 1 que.push(y - 1) que.push(x) end if cm[y][x + 1] == -1 cm[y][x + 1] = cm[y][x] + 1 que.push(y) que.push(x + 1) end if cm[y][x - 1] == -1 cm[y][x - 1] = cm[y][x] + 1 que.push(y) que.push(x - 1) end end puts cm[gy][gx]que に push して shift して que が空になるまで while で回す要領です。
末尾にデータを追加 先頭のデータを取り出す push shift que.rbque.push(sy) que.push(sx)xy 座標を別々に push していますが、リファレンスで配列ごと渡してもいいと思います。
array.rbif cm[y + 1][x] == -1 if cm[y - 1][x] == -1 if cm[y][x + 1] == -1 if cm[y][x - 1] == -1上下左右をチェックしていますが、出題によっては右と下のみに減ったりします。
Python
python.pyfrom collections import deque r, c = map(int, input().split()) sy, sx = map(int, input().split()) gy, gx = map(int, input().split()) cm = [[0 for j in range(c + 1)] for i in range(r + 1)] for i in range(1, r + 1): s = input() for j in range(1, c + 1): if s[j - 1] == ".": cm[i][j] = -1 que = deque([]) que.append(sy) que.append(sx) cm[sy][sx] = 0 while len(que) > 0: y = que.popleft() x = que.popleft() if cm[y + 1][x] == -1: cm[y + 1][x] = cm[y][x] + 1 que.append(y + 1) que.append(x) if cm[y - 1][x] == -1: cm[y - 1][x] = cm[y][x] + 1 que.append(y - 1) que.append(x) if cm[y][x + 1] == -1: cm[y][x + 1] = cm[y][x] + 1 que.append(y) que.append(x + 1) if cm[y][x - 1] == -1: cm[y][x - 1] = cm[y][x] + 1 que.append(y) que.append(x - 1) print(cm[gy][gx])deque の場合
末尾にデータを追加 先頭のデータを取り出す append popleft Perl
perl.plchomp (my ($r, $c) = split / /, <STDIN>); chomp (my ($sy, $sx) = split / /, <STDIN>); chomp (my ($gy, $gx) = split / /, <STDIN>); my @cm; for my $i (1..$r) { chomp (my $s = <STDIN>); for my $j (1..$c) { $cm[$i][$j] = -1 if substr($s, $j - 1, 1) eq '.'; } } my @que; push @que, $sy; push @que, $sx; $cm[$sy][$sx] = 0; while(@que) { my $y = shift @que; my $x = shift @que; if ($cm[$y + 1][$x] == -1) { $cm[$y + 1][$x] = $cm[$y][$x] + 1; push @que, $y + 1; push @que, $x; } if ($cm[$y - 1][$x] == -1) { $cm[$y - 1][$x] = $cm[$y][$x] + 1; push @que, $y - 1; push @que, $x; } if ($cm[$y][$x + 1] == -1) { $cm[$y][$x + 1] = $cm[$y][$x] + 1; push @que, $y; push @que, $x + 1; } if ($cm[$y][$x - 1] == -1) { $cm[$y][$x - 1] = $cm[$y][$x] + 1; push @que, $y; push @que, $x - 1; } } print $cm[$gy][$gx], "\n";
末尾にデータを追加 先頭のデータを取り出す push shift Java
java.javaimport java.util.*; class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int r = Integer.parseInt(sc.next()); int c = Integer.parseInt(sc.next()); int sy = Integer.parseInt(sc.next()); int sx = Integer.parseInt(sc.next()); int gy = Integer.parseInt(sc.next()); int gx = Integer.parseInt(sc.next()); int cm[][] = new int[r + 1][c + 1]; for (int i = 1; i <= r; i++) { String s = sc.next(); for (int j = 1; j <= c; j++) { if (".".equals(s.substring(j - 1, j))) { cm[i][j] = -1; } } } sc.close(); Deque<Integer> que = new ArrayDeque<>(); que.add(sy); que.add(sx); cm[sy][sx] = 0; while (que.size() > 0) { int y = que.poll(); int x = que.poll(); if (cm[y + 1][x] == -1) { cm[y + 1][x] = cm[y][x] + 1; que.add(y + 1); que.add(x); } if (cm[y - 1][x] == -1) { cm[y - 1][x] = cm[y][x] + 1; que.add(y - 1); que.add(x); } if (cm[y][x + 1] == -1) { cm[y][x + 1] = cm[y][x] + 1; que.add(y); que.add(x + 1); } if (cm[y][x - 1] == -1) { cm[y][x - 1] = cm[y][x] + 1; que.add(y); que.add(x - 1); } } System.out.println(cm[gy][gx]); } }Deque の場合
末尾にデータを追加 先頭のデータを取り出す add poll
Ruby Python Perl Java コード長 791 Byte 935 Byte 915 Byte 1660 Byte 実行時間 10 ms 24 ms 5 ms 106 ms メモリ 1788 KB 3436 KB 512 KB 23636 KB まとめ
- ATC 002 A を解いた
- Ruby に詳しくなった
- Python に詳しくなった
- Perl に詳しくなった
- Java に詳しくなった
- 投稿日:2020-04-30T17:39:48+09:00
rails routesで覚えのないroutingが出力される。
問題のルーティング
こんなの設定してない、、、
$ rails routesrails_mandrill_inbound_emails POST /rails/action_mailbox/mandrill/inbound_emails(.:format) action_mailbox/ingresses/mandrill/inbound_emails#create rails_postmark_inbound_emails POST /rails/action_mailbox/postmark/inbound_emails(.:format) action_mailbox/ingresses/postmark/inbound_emails#create rails_relay_inbound_emails POST /rails/action_mailbox/relay/inbound_emails(.:format) action_mailbox/ingresses/relay/inbound_emails#create rails_sendgrid_inbound_emails POST /rails/action_mailbox/sendgrid/inbound_emails(.:format) action_mailbox/ingresses/sendgrid/inbound_emails#create rails_mailgun_inbound_emails POST /rails/action_mailbox/mailgun/inbound_emails/mime(.:format) action_mailbox/ingresses/mailgun/inbound_emails#create rails_conductor_inbound_emails GET /rails/conductor/action_mailbox/inbound_emails(.:format) rails/conductor/action_mailbox/inbound_emails#index POST /rails/conductor/action_mailbox/inbound_emails(.:format) rails/conductor/action_mailbox/inbound_emails#create new_rails_conductor_inbound_email GET /rails/conductor/action_mailbox/inbound_emails/new(.:format) rails/conductor/action_mailbox/inbound_emails#new edit_rails_conductor_inbound_email GET /rails/conductor/action_mailbox/inbound_emails/:id/edit(.:format) rails/conductor/action_mailbox/inbound_emails#edit rails_conductor_inbound_email GET /rails/conductor/action_mailbox/inbound_emails/:id(.:format) rails/conductor/action_mailbox/inbound_emails#show PATCH /rails/conductor/action_mailbox/inbound_emails/:id(.:format) rails/conductor/action_mailbox/inbound_emails#update PUT /rails/conductor/action_mailbox/inbound_emails/:id(.:format) rails/conductor/action_mailbox/inbound_emails#update DELETE /rails/conductor/action_mailbox/inbound_emails/:id(.:format) rails/conductor/action_mailbox/inbound_emails#destroy rails_conductor_inbound_email_reroute POST /rails/conductor/action_mailbox/:inbound_email_id/reroute(.:format) rails/conductor/action_mailbox/reroutes#create rails_service_blob GET /rails/active_storage/blobs/:signed_id/*filename(.:format) active_storage/blobs#show rails_blob_representation GET /rails/active_storage/representations/:signed_blob_id/:variation_key/*filename(.:format) active_storage/representations#show rails_disk_service GET /rails/active_storage/disk/:encoded_key/*filename(.:format) active_storage/disk#show update_rails_disk_service PUT /rails/active_storage/disk/:encoded_token(.:format) active_storage/disk#update rails_direct_uploads POST /rails/active_storage/direct_uploads(.:format) active_storage/direct_uploads#create解決方法
$ rails new プロジェクトの名前 --skip-active-storage --skip-action-mailer --skip-action-mailboxrails newでプロジェクトを立ち上げる際にオプションを付け加える事で解決。
既にrails newした後はapplication.rbファイルにコードを記述する事で表示されなくなりました。Application.rb class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. config.load_defaults 6.0 # CODE YOU SHOULD ADD vvvvvv # ここから initializer(:remove_action_mailbox_and_activestorage_routes, after: :add_routing_paths) { |app| app.routes_reloader.paths.delete_if {|path| path =~ /activestorage/} app.routes_reloader.paths.delete_if {|path| path =~ /actionmailbox/ } } ←# ここまで追加 # Settings in config/environments/* take precedence over those specified here. # Application configuration can go into files in config/initializers # -- all .rb files in that directory are automatically loaded after loading # the framework and any gems in your application. end end
- 投稿日:2020-04-30T17:26:32+09:00
Rubyとは
Ruby
特徴
・記述量が少ない
・JavaやPHPといった他の言語同様、オブジェクト指向プログラミング言語である。
・スクリプト言語であるため、コンパイルする必要がない
・日本で生まれたプログラミング言語である。記述量が少ない
他の言語であれば6行〜10行必要な場合でも、Rubyは1行で済む場合がある。
記述量が少ないということは作業の短縮になり、開発者にとって非常に助かると言う利点がある。オブジェクト指向とは
プログラムの動作を属性値とメソッドを持ったパーツの組み合わせで実現すると言う考え方である。
スクリプト言語とは
プログラミング言語のうち、プログラムの記述や実行を比較的簡易に行うことができる言語の総称。インタプリンタ型(ソースコードを即座に実行開始できる)型のため、コンパイラ(一括してから実行する方式)に比べ、開発や修正をテンポよく進めることができる。
デメリットして
処理速度が他の言語に比べて遅いため、大規模アプリや処理速度が重要なサービスには向いていない。
- 投稿日:2020-04-30T16:30:27+09:00
【Rails】Kaminariで同一ページにもっと見るを複数実装する
通常の場合
home_controller.rbdef index @cats = Cat.page(params[:page]).per(1) endapp/views/home/index.html.erb<%= paginate @cats %>複数の場合
home_controller.rbdef index @cats = Cat.page(params[:cats_page]).per(1) @dogs = Dog.page(params[:dogs_page]).per(1) endapp/views/home/index.html.erb<%= paginate @cats, param_name: 'cats_page' %> <%= paginate @dogs, param_name: 'dogs_page' %>ajaxを利用したもっと見るの場合
home_controller.rbdef index @cats = Cat.page(params[:page]).per(1) @dogs = Dog.page(params[:page]).per(1) return unless request.xhr? case params[:type] when 'dog', 'cat' render "#{params[:type]}" end endapp/views/home/index.html.erb<%= link_to_next_page @cats, 'もっと見る', remote: true, params: { type: :cat }, id: 'more-cat' %> <%= link_to_next_page @dogs, 'もっと見る', remote: true, params: { type: :dog }, id: 'more-dog' %>app/views/home/cat.js.erb$('.cat-wrap').append('<%= escape_javascript(render 'cat', object: @cats) %>'); $('#more-cat').replaceWith('<%= escape_javascript(link_to_next_page(@cats, 'もっと見る', params: { type: :cat }, remote: true, id: 'more-cat')) %>');app/views/home/dog.js.erb$('.dog-wrap').append('<%= escape_javascript(render 'dog', object: @dogs) %>'); $('#more-dog').replaceWith('<%= escape_javascript(link_to_next_page(@dogs, 'もっと見る', params: { type: :dog }, remote: true, id: 'more-dog')) %>');参考
https://qiita.com/Coolucky/items/bde74b020b8d37ccf426
https://www.rubydoc.info/github/amatsuda/kaminari/Kaminari/ActionViewExtension
- 投稿日:2020-04-30T15:34:43+09:00
Address already in use - bind(2) for "0.0.0.0" port 3000 (Errno::EADDRINUSE) が出たとき
- 投稿日:2020-04-30T14:44:15+09:00
[Rails]FullCalenderで投稿一覧も表示させつつ、マイページでは自分の投稿だけに絞ってカレンダーを表示する
目的
FullCalenderを使って、Twitter+マイページでは自分の投稿をカレンダーで見る
ということを実装する前提
フルカレンダーを実装し、カレンダーが表示できている
下記のサイトを参考に作りました。
https://qiita.com/sasasoni/items/fb0bc1644ece888ae1d4
https://qiita.com/imp555sti/items/ee9809768f6dc9439ab5やること
FullCalenderをまずは準備しておきます。
そして自分が一番詰まったのは、indexではフォローしている人全員を表示する。
しかし自分のマイページのカレンダーでは、自分の投稿のみに限定する。
ということです。どうやらFullCalenderの使い方としてindexアクションで定めた@eventsをカレンダーで表示するようなので
indexでは投稿一覧を@eventsではなく、別の名前を与えて。
ユーザーの投稿一覧を@eventsとしてあげます。index.html.erbdef index @all_events = Event.all.includes(:user) @user = User.find(current_user.id) #フォローしているユーザーを取得 @follow_users = @user.followings.map { |f| f[:id] } @follow_users << current_user.id #フォローユーザーの投稿のみ表示 @events_onlyfollow = @all_events.where(user_id: @follow_users).order("created_at DESC") # 自分の投稿のみ @events = Event.where(user_id: current_user.id) endまだまだ理解が浅くちゃんとできている訳ではないと思いますが。。。
とりあえずカレンダーが自分の投稿だけで絞れたのでひとまずOK
- 投稿日:2020-04-30T11:19:40+09:00
Ruby と Perl と Java と Python で解く AtCoder ABC 047 C
はじめに
AtCoder Problems の Recommendation を利用して、過去の問題を解いています。
AtCoder さん、AtCoder Problems さん、ありがとうございます。今回のお題
AtCoder Beginner Contest 047 C - 一次元リバーシ
Difficulty: 650今回のテーマ、正規表現
Ruby
例えば、
WWWWBBWBBBを W B でそれぞれまとめますとWBWBとなり、3回で一色にできることが分かります。
こういう文字列の処理は正規表現を使用すると簡単に解けます。
AtCoder に登録したら次にやること ~ これだけ解けば十分闘える!過去問精選 10 問 ~で有名な C - 白昼夢 も正規表現ですとスッキリ解けます。ruby.rbs = gets.chomp s.gsub!(/W+/, "W") s.gsub!(/B+/, "B") puts s.size - 1
W+は1文字以上の連続したW を表現しています。Python
python.pyimport re s = input() s = re.sub(r'W+', "W", s) s = re.sub(r'B+', "B", s) print(len(s) - 1)Python で正規表現を使用する場合、
import reが必要です。Perl
perl.plchomp (my $s = <STDIN>); $s =~ s/W+/W/g; $s =~ s/B+/B/g; print length($s) - 1, "\n";Java
java.javaimport java.util.*; class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); String s = sc.next(); sc.close(); s = s.replaceAll("W+", "W"); s = s.replaceAll("B+", "B"); System.out.println(s.length() - 1); } }
Ruby Python Perl Java コード長 71 Byte 97 Byte 87 Byte 310 Byte 実行時間 36 ms 38 ms 21 ms 239 ms メモリ 10076 KB 4468 KB 640 KB 35160 KB まとめ
- ABC 063 C をスッキリ解いた
- Ruby に詳しくなった
- Python に詳しくなった
- Perl に詳しくなった
- Java に詳しくなった
参照したサイト
pythonで、とっても便利な正規表現を!
Java での正規表現の使い方メモ
instance method String#gsub
ABC049C - 白昼夢を簡単に導く方法が知りたい(Golang)
- 投稿日:2020-04-30T11:18:14+09:00
resource resourcesって何が違うの??
Railsルーターの目的
そもそもルーティングは何をしてるんや。という話。
Railsのルーターは受け取ったURLを認識し、適切なコントローラ内アクションやRackアプリケーションに割り当てます。ルーターは、ビューでこれらのパスやURLを直接ハードコードすることを避けるためにパスやURLを生成することもできます。つまり受け取ったURLを捌いて指示を出す、司令塔ですよってこと。
resources と resource の違い
①URLにidを必要とするかしないのか
②resourceの場合単数なので、一覧みたいな概念はなく、indexが作られないresources 複数
リソースをいくつも定義しなければならない場合は、以下のように簡単にわかりやすくできる。get,new,create,edit,update,destroy,showがresourcesでまとめられる!(only、exceptで限定することも可能)
resources :photos, :books, :videos上の記法は以下と完全に同一です。
resources :photos resources :books resources :videosポイントとしては、リソース名がbooks、photosのような複数形になっていることにも注意
リソースが複数なのでidを持たないと識別できないresource 単数
ユーザーがページを表示する際にidを一切参照しないリソースが使われることがあります。たとえば、/profileでは常に「現在ログインしているユーザー自身」のプロファイルを表示し、他のユーザーidを参照する必要がないとします。このような場合には、単数形リソース (singular resource) を使ってshowアクションに (/profile/:idではなく) /profileを割り当てることができます。
get 'profile', to: 'users#show'結局どういうこと?
①URLにidを必要とするかしないのか
下記のようにresourcesが複数だとidが必要
resourceが単数だとidは要らない。/mobile/posts/:id(.:format) ←postは何個も存在するためidが必要 /mobile/profile/edit(.:format) ←profileは一つしか存在しないため、idがいらない②resourceの場合単数なので、一覧みたいな概念はなく、indexが作られない
routes.ebresource :users生成されるルーティング
new_users GET /users/new(.:format) users#new edit_users GET /users/edit(.:format) users#edit users GET /users(.:format) users#show PATCH /users(.:format) users#update PUT /users(.:format) users#update DELETE /users(.:format) users#destroy POST /users(.:format) users#create参考文献
https://railsguides.jp/routing.html#%E5%8D%98%E6%95%B0%E5%BD%A2%E3%83%AA%E3%82%BD%E3%83%BC%E3%82%B9
- 投稿日:2020-04-30T10:33:24+09:00
[devise]値を配列の形で保存する
背景
deviseを使っている上で、配列の形でデータを送りたいと考えたが、なかなかやり方が見つからず苦労してやっと実装出来たので、備忘録や他の人の役に立てればと思い書きました。
実装方法
deviseのデフォルトで設定されたカラム以外を保存する際に以下のコードを書いてあげるが、
配列を渡す時は「:category_ids => []」のように空の配列を一緒に付けてあげればうまく保存されます。application_controller.rb#中略 protected def configure_permitted_parameters devise_parameter_sanitizer.permit(:sign_up, keys: [:name, :self_introduction, :sex, :img_name, :category_ids => []]) devise_parameter_sanitizer.permit(:account_update, keys: [:name, :self_introduction, :sex, :img_name, :category_ids => []]) end #中略すごく時間がかかりましたが以外と簡単だったことに驚きました。。
deviseはやはり便利な分難しいですね
- 投稿日:2020-04-30T00:57:50+09:00
【Favorite】Rails いいね機能 実装
【ゴール】
ユーザーに投稿に対していいね機能を実装する
いいねを押すとハートが赤くなる参考:https://qiita.com/nojinoji/items/2c66499848d882c31ffa
【メリット】
UI、UXの向上
アソシエーションの理解度向上【開発環境】
■ Mac OS catalina
■ Ruby on Rails (5.2.4.2)
■ Virtual Box:6.1
■ Vagrant: 2.2.7【実装】 "user" "post"機能実装は割愛
- favorite model作成
mac.terminal$ rails g model Favorite
- アソシエーション 追記
※ user : favorite = 1 : 多
※ post : favorite = 1 : 多config/post.rbhas_many :favorites def favorited_by?(user) favorites.where(user_id: user.id).exists? endconfig/user.rbhas_many :favoritesconfig/favorite.rbbelongs_to :user belongs_to :postroute 追記
※ "favorite" は "post" に関連しているのでルートをネスト(親子)させるconfig/routes.rbresources :posts do resources :favorites , only: [:create , :destroy] endfavorite controller作成
※ "create" , "destroy"も一緒に作成mac.terminal$ rails g controller Favorites create destroyfavorite controller記述
① , ②で user_id post_id をparameterに渡すfavorites_controller.rbclass FavoritesController < ApplicationController def create @post = Post.find(params[:post_id]) ① favorite = @post.favorites.new(user_id: current_user.id) ② favorite.save flash[:success] = "Liked post" redirect_to request.referer end def destroy @post = Post.find(params[:post_id]) ① favorite = current_user.favorites.find_by(post_id: @post.id) ② favorite.destroy redirect_to request.referer end endview記述
※ modelで記述 ”@post.favorited_by?” を使用post/show.html/erb<% if @post.favorited_by?(current_user) %> <%= link_to post_favorite_path(@post), method: :DELETE do %> <i class="fa fa-heart" aria-hidden="true" style="color: red;"></i> <%= @post.favorites.count %>like <% end %> <% else %> <%= link_to post_favorites_path(@post) , method: :POST do %> <i class="fa fa-heart-o" aria-hidden="true"></i> <%= @post.favorites.count %>like <% end %> <% end %>以上



