- 投稿日:2020-07-25T23:54:40+09:00
【Rails】命名規約について
Railsの原則として、「設定より規約」がある。モデル、コントローラ、ビューに関するクラス名やファイル名には命名規約(つまり名前の付け方)に決まりごとがある。
コントローラ名を「comments」とした場合のコントローラやビューに関する名前は以下の通りである。
コントローラの命名規約
名前 例 ルール コントローラクラス名 CommentsController 〇〇Controller、先頭は大文字 コントローラファイル名 comments_controller.rb 〇〇_controller.rb テンプレートのディレクトリ名 app/views/commnents app/views/〇〇 モデル名を「comment」とした場合の名前は以下の通りである。
モデルの命名規約
名前 例 ルール データベーステーブル名 comments 先頭は小文字、複数形にする モデルクラス名 Comment 先頭は大文字 モデルクラスのファイル名 comment.rb 〇〇.rb ※データベーステーブル名に2つの単語からなる名前を付けたいときは、
「shopping_carts」
のようにアンダースコアで単語と単語を結ぶ。この場合、
- コントローラクラス名:ShoppingCartsController
- モデルクラス名:ShoppingCart
となる。
- 投稿日:2020-07-25T23:42:18+09:00
rubyでタイピングゲームを作る
こんにちは。今回はRubyでタイピングゲームを作ろうと思います。とりあえずやってみたいって人はここからやってみてください。
それじゃあ作り方?を書いていこうと思います。
[1] 単語をを集める
今回は面倒くさかったので英単語100個のみにしていますがお好みで足してください。ちょっと変えれば日本語もできるはずです(ヘボン式に対応するのが面倒くさそうではありますが)(Hashのvalueをlistにして~とかすればいいのかな?)
まあここは適当にやっていいと思います。そんな大事じゃないですし
[2] キーイベントを取得する
io/console
を使うと楽にできます。Rubyはこういうのが楽でいいですね。require 'io/console' ch = STDIN.getch puts ch[3] 一気にハイライトと核の部分を書く
wordsに[1]で書いたwordのlistが入ってるものとします。
require 'io/console' miss = 0 all = 0 flag = false while true word = words.sample puts "\e[36m#{word}\e[0m" i = -1 wl = word.length print "\e[2m#{word}\e[0m" while i != (wl-1) i += 1 key = STDIN.getch all += 1 if key == word[i] print "\r#{word[0..i]}\e[2m#{word[i+1..wl]}\e[0m" elsif key == "\C-c" flag = true break else print "\r#{word[0...i]}\e[31m#{word[i]}\e[0m\e[2m#{word[i+1..wl]}\e[0m" miss += 1 i -= 1 end end break if flag puts endまあやってることは単純なのでわかるでしょう。
\r
はキャリッジリターン、\e[~~m
はANSIエスケープシーケンスです。成績表示をする
require 'io/console' require 'benchmark' miss = 0 all = 0 flag = false result = Benchmark.realtime do while true word = words.sample puts "\e[36m#{word}\e[0m" i = -1 wl = word.length print "\e[2m#{word}\e[0m" while i != (wl-1) i += 1 key = STDIN.getch all += 1 if key == word[i] print "\r#{word[0..i]}\e[2m#{word[i+1..wl]}\e[0m" elsif key == "\C-c" flag = true break else print "\r#{word[0...i]}\e[31m#{word[i]}\e[0m\e[2m#{word[i+1..wl]}\e[0m" miss += 1 i -= 1 end end break if flag puts end end print "\e[2K\e[1A\e[2K\r" puts "miss: #{miss}" printf "press: %.5f/s\n" %(all / result)まあこれも単純ですね。
Benchmark.realtime
でC-c
されるまでの時間を測り、それをもとに1秒当たりの打鍵数を求めています。\e[~~K
,\e[~~A
もANSIエスケープシーケンスですね。[4] 実行!
ruby main.rb
- 投稿日:2020-07-25T23:27:42+09:00
プログラミングスクールで150日間勉強してできるようになったこと・思ったこと
はじめに
自分は今、フィヨルドブートキャンプというプログラミングスクールで勉強しています。スクールで勉強したことや感想などを書こうと思います。
ちなみに前回プログラミングスクールで100日間勉強してできるようになったこと・思ったことを書きました。思いの外伸びてびっくりしました。よろしければ前回の記事と合わせてご覧ください。(重複する部分もあります?)
150日で勉強したこと
勉強時間とスクールの進度
770時間勉強しました。本やUdemyでインプット→課題→レビューを受けて修正、というサイクルを繰り返しています。
スクールの進度は62%まで進みました。だいぶ進んだとは思いますが、まだまだ先は長そうです。
読んだ本
プログラミングは基本的に本で勉強しています。改めて振り返ってみると結構読んだと思います。"読んだ本"と書きましたが、中には読んだけどよく分からなかった本や途中から理解できなくなって最後まで読めていない本もまあまああります?
Web技術系
- キタミ式イラストIT塾基本情報技術者
- プロになるためのWeb技術入門 なぜ,あなたはWebシステムを開発できないのか
- イラスト図解式 この一冊で全部わかるWeb技術の基本
- Webを支える技術 -HTTP、URI、HTML、そしてREST
HTML & CSS
Linux
Nginx
Ruby
- ゼロからわかるRuby超入門 はじめてのプログラミング
- プロを目指す人のためのRuby入門 言語仕様からテスト駆動開発・デバッグ技法まで
- オブジェクト指向設計実践ガイド ~Rubyでわかる 進化しつづける柔軟なアプリケーションの育て方
データベース
Ruby on Rails
150日できるようになったこと
- 静的ページならどんなサイトでも模写できるようになった!
- さくらVPSにインストールしたLinuxに、自分のMacから公開鍵と秘密鍵を使ってsshでログインできるようになった!
- HTMLを自分のドメインでNginxで配信できるようになった!
- Debian上のnginxでネームベースのVirtualHost + SSLを構築できるようになった!
- Vimを使いこなせるようになった!
- Git & GitHubを使えるようになった!
- Rubyで色々な物を作れるようになった!
- 基本的なデータベース操作ができるようになった!
- 正規化ができるようになった!
- SinatraとPostgreSQLを使ってシンプルなアプリケーションを作れるようになった!
- Railsでログイン機能を持つシンプルなアプリケーションを作れるようなった!
思ったこと
フィヨルドブートキャンプを卒業するのは凄まじく難しい
サイトのFAQにこのような記述があります。
卒業生が Ruby 界隈で有名な企業に就職していますが、私もそういった企業に就職できますか?
個人によります。弊社と仲良くしてくれてる Ruby 界隈で有名な企業に推薦をする場合もありますが、推薦をする側も責任があるため、誰でも推薦をすることができるとは言えません。ただし、そもそもフィヨルドブートキャンプを卒業することはとても難しく、それを達成できた時点で十分推薦できる人物だと判断することがほとんどです。
フィヨルドブートキャンプを卒業することはとても難しいとしっかりと書かれているのですが、自分が思っていた"とても難しい"と現実の"とても難しい"には大きなギャップがありました。 例えるなら、自分はラディッツと闘うつもりでいましたが、実際の相手の強さはナッパくらいでした。(ドラゴンボール知らない人ごめんなさい)
ホームページには大体900時間弱で卒業できると書いてあったのですが、自分は1200〜1500時間くらいかかりそうです。 フィヨルドは課題がとても難しいです。特にRubyのカリキュラムが重く、自分は2ヶ月かかりました。チェリー本でのインプットはとてもスムーズにできたのですが、そのあとの課題がキツかったです。本当に全く進まない日がたくさんあって、毎日唸ってばかりでした。
あとフィヨルドでの学習は全て能動的です。プログラミングスクールですがプログラミングを"教えてもらう"ということは無いです。質問したらもちろん教えてもらえます。学校のように授業を受けて復習みたいなことは一切無いという意味です。あるのはコードレビューです。生徒は「〇〇を実装してください」という課題が次々与えられて「こんなこと本当にできるのかな〜〜??」と思いながら大量にググって頑張ります。「あ!これは本で見たことやるやつだ!すぐできそう!って思うことがほぼ無いです。」例えるなら、師匠に岩を切れと言われて頑張ってる感じです。かなりハードです。卒業するには技術が大好きでなければ厳しいと思います。
数少ない卒業生のブログより引用します。(フィヨルドを卒業できる人は非常に少ないです)
アクトインディで正社員プログラマーとして働くことになりましたFjordの@komagata、@machidaのお二人は、結構な辛口です。どこかで恨まれてもおかしくないくらい辛口です。ただ、おっしゃっていることが実践できたり身についたりすればレベルが上がるということは、プログラミングのことはわからないうちからもひしひしと伝わってくるし、辛口を受け止める強さは必要です。私はそのへん全くだめで何度も心が折れました。折れた心が復活したと思ったらまた折れて・・・を繰り返していました。歩伏前進で山登りしてるような気持ちでやっていました。何度くじけかけたことか・・・!
そんな感じでいろいろ大変だったのですがめちゃくちゃ勉強になります。それは間違いないです。しょっちゅう家で泣いてましたがそれでもやってよかったと思います。
みんな口では辛いと言いませんが、辛い時はけっこうあると思います。自分は「こんだけやっているのに全くできるようにならない?」と思うことがしばしばあります。そんな時は「努力が足りないだけでしょう。"こんだけやっている"って本当に充分な勉強量なの?そうじゃないよね?嘆くなら嘆くに値する努力をしてから嘆こうね」と自分に言い聞かせています。それでもどうしてもやる気が出ない日は思いっきり休んでいます。
生き残ることが一番大事
プログラミングの挫折率は90%と言われますが、本当にそれは体感できます。というのもでツイッターで見ていた駆け出しエンジニアは半年でかなり減りました。スクールに入ったとしても(どのスクールでも)やめていく人は少なくないと思います。それだけ学習コストは高いし難しいです。投資の世界では、「まずは生き残れ、儲けるのはそれからだ!」と言われています。プログラミングもその精神でいくといいです。辛くなったら休めばいいと思います。2・3日も休めばまたやりたくなります。焦る必要はどこにもないです。まずは生き残りましょう。
独学ではここまで来れなかった
フィヨルドブートキャンプには本当に感謝しています。独学では絶対にここまで来れませんでした。独学している時は何を勉強すればいいのか分からなくて、「今やっていることは本当に正しい勉強なのだろうか」という不安が常にあって辛かったです。やるべきことが決まっているだけで本当に集中することができます。また質問できる環境だけでなく、オンラインでも継続して勉強できるように日報や草が生える仕組みなどがあってとてもいいです。値段に関しても他のスクールと比較するとかなり安いのでとても助かっています。
プログラミングは純粋に楽しい
プログラミングは本当に難しくて量が膨大でかなり大変です。ですが、技術を勉強すること、自分でコードを書いて何かを作ることはとても楽しいです。分からなかったことが分かるようになった時はとても嬉しいです。そして毎日成長を感じることができます。自分は独学期間も合わせて半年くらいプログラミングを勉強していますが、普通に好きじゃないと半年も続かないと思います。技術が好きな人でも分からなくて辛い時期が頻繁にあるくらいなので、(せめてある程度は)プログラミングを楽しめなかったらエンジニアは厳しいと思いました。
これからも技術を身に付けることを楽しんで、周りの優秀すぎる人たちと比較してモチベーションが下がるなんてことがないように、マイペースで、プログラミングをやっていこうと思います。
- 投稿日:2020-07-25T23:15:27+09:00
[4, 7, 9, 2, 3] から "2-4, 7, 9" を得る
はじめに
この記事は以下の記事を見て書いた。
Rubyのパターンマッチを使って簡単なプログラミング問題を解いてみた - Qiita上記の記事は,
"1, 5, 10-12, 15, 18-20"
という文字列から
[1, 5, 10, 11, 12, 15, 18, 19, 20]という配列を Ruby で得る方法について書かれている。
一方,こっちの記事はその逆。つまり,正の整数の配列が与えられたとき,それをソートしたうえで,さらに続き番号になっている箇所をハイフンで繋いだ表記にしてカンマ区切りの文字列を作るということ。
こういった処理は,例えば書籍の索引のページ番号の表記を作るのに使われる。
なお,このような表記には,
- 続き番号が 4, 5 のように二つしかなくても
4-5
とまとめる- 二つしか続かない場合は
4, 5
とバラバラにしておくという二つの流儀が考えられるが,この記事では前者を取る(後者の場合についても書く)。
コード
test-unit を使ったテストコードも書いておいた。
require "test/unit" def gather(array) array.uniq.sort .chunk_while{ |a, b| a.succ == b } .map{ |c| (c.size == 1) ? c : "#{c[0]}-#{c[-1]}" } .join(", ") end # ここから下がテストコード # スクリプトを実行すれば以下に記述したテストは自動的に行われる class TestGather < Test::Unit::TestCase test "バラバラ" do assert_equal "1, 3, 5", gather([3, 5, 1]) end test "重複あり" do assert_equal "2, 4", gather([4, 2, 2, 4, 4]) end test "まとめ" do assert_equal "1-2", gather([2, 1]) assert_equal "1-3", gather([2, 3, 1]) assert_equal "2-4, 7, 9, 11-12", gather([12, 11, 7, 9, 2, 4, 3]) end end解説
重複を省きソートする
最初に
array.uniq.sortとして,重複を省き,ソートしている。あまり説明は要らないと思う。
ただ,効率を考えると,このように先にuniq
してあとでsort
したほうがいい,ということに注意したい1。続き番号をカタマリにする
次に,このコードの肝といえるのが
chunk_while{ |a, b| a.succ == b }の部分。
実は公式リファレンスの Enumerable#chunk_while に,この記事のコードとそっくりなサンプルが書かれているのだが。
chunk_while
は実に Ruby 的な面白いメソッドだ。chunk_while
とは何者なのか?これは,配列などの Enumerable なオブジェクトについて,要素を端から舐めていって,隣り合う二つの要素の間をつなげるか切断するかをある判断基準に従って決定し,そうやってカタマリ(chunk)を作っていくメソッドだ。
ただ,返り値はカタマリの配列ではなく Enumerator である。Enumerator とは何か,については本記事では解説しないが,Enumerable なオブジェクトなのでto_a
すればカタマリの配列になる。たとえば,
[2, 6, 0, 3, 5, 8]という配列があって,これを偶数同士,奇数同士のカタマリに分けたいとしよう。
つまり[[2, 6, 0], [3, 5], [8]]という配列が欲しいわけ。
重要なのは隣り合う偶数同士,奇数同士しかカタマリにしないということ。
だから,最後の8
は2, 6, 0
とは一緒にならず,飛び地になっている。ところで,二つの整数
a
とb
が「共に偶数であるか,あるいは共に奇数である」という条件式はどう書けばいいだろう?
一つのやり方は(a.even? && b.even?) || (a.odd? && b.odd?)なのだが,こんな面倒なことをする必要はない。
「偶数と偶数の差は偶数」「奇数と奇数の差は偶数」「偶数と奇数の差は奇数」ということに気づけば(a - b).even?でよいと分かる。
さて,隣り合う偶数同士,奇数同士のカタマリの配列を得るには,
chunk_while
を使って以下のように書く。numbers = [2, 6, 0, 3, 5, 8] p numbers.chunk_while{ |a, b| (a - b).even? }.to_a # => [[2, 6, 0], [3, 5], [8]]この
chunk_while
はどのように働くのだろうか。
chunk_while
はeach
を使ってレシーバーから一つ一つ要素を取り出す。
まず最初に,そうやって二つの要素を取り出す。今の場合,2
と6
が取り出される。この二つをブロックに渡し,ブロックを評価する。すると(2 - 6).even?
は真。このときchunk_while
は「ふむふむ,では2
と6
の間は切断しないぞ」と決めるのだ。
次に,既に取り出している6
と,その次に取り出した0
をブロックに渡す。ここでもブロックは真を返すので,切断しない。
同様にして,0
と3
をブロックに渡すが,これは偽を返す。そうしてchunk_while
は「よっしゃ! ここで断ち切ったるで!」と決めるのだ。以下同様。
chunk_while
が一つずつ位置をずらしながら隣り合う 2 要素を取り上げてゆくさまは,each_cons(2)
に似ている。
each_cons(2)
はただ 2 要素を拾っていくだけだが,chunk_while
は結合・切断の箇所を判定するために 2 要素を拾っていくのだ。
chunk_while
の働きが分かったところで,chunk_while{ |a, b| a.succ == b }を検討しよう。
Integer#succ
は自身に 1 を足した整数を返すメソッド。
a.succ == b
でもって「a
の次がb
になっている」という条件を表している。続き番号のところはハイフンでまとめる
その次の
map{ |c| (c.size == 1) ? c : "#{c[0]}-#{c[-1]}" }は簡単。
おっとその前に一言。
chunk_while
の返り値は Enumerator オブジェクトなので,to_a
で配列にする必要はなく,そのままmap
を続けることができる。さて,この
map
のブロックだが,個々のカタマリが長さ 1 ならそのまま,2 以上なら先頭と末尾をハイフンで繋ぐ,ということを行っている。例えば
[7]
なら[7]
のままにし,[2, 3, 4]
なら"2-4"
に変えている。
うーん,変換後の配列は要素が配列だったり文字列だったりしてちょっと気持ち悪いな。いやこれで何の問題もない(後述)のだが,ちょっとムズムズするのは確か。カンマで繋げる
最後に
join(", ")で仕上げ。
これはまあ要素を単に", "
で繋ぐだけなのだが,前段で「要素が配列だったり文字列だったりするが問題ない」と述べたことに確信を持つためには,Array#join の正確な理解が必要だ。
join
は,要素がすべて文字列であれば,間に引数を挟んで繋げた文字列を返す。
要素に文字列でないものがあった場合,繋げる前にまずそいつを文字列化するのだが,そいつがもし配列だった場合,to_s
ではなくjoin
を使って文字化するのだ。その際のjoin
には元のjoin
と同じ引数が使われる。だから,
p [1, [2, 3]].join("-") # => "1-2-3"のようになる。
以上で動作が完全に理解できた。
バリエーション
「はじめに」の節で予告したが,続き番号が
4, 5
のように二つしか続いていない場合にハイフンでまとめないようにするにはどう改変すればよいか。つまり,
p gather([1, 2, 4, 5, 6]) # => "1, 2, 4-6"となるようにするには?
実は,Enumerable#chunk_while のサンプルコードはこの流儀にしたがって書かれている。
そのようにするには,
.map{ |c| (c.size == 1) ? c : "#{c[0]}-#{c[-1]}" }を
.map{ |c| (c.size < 3) ? c : "#{c[0]}-#{c[-1]}" }に変えればよい。
これだけの改変で済むのは,既に述べたjoin
の仕様から明らか。余談
Ruby の同系統のユニットテストライブラリーが test-unit と minitest に分裂したままなのは不幸というほか無い。
私の目には test-unit のほうが優秀な気がするのだが2,Rails が minitest(を魔改造したもの?)を採用しちゃってるので,世間的には minitest のほうが優勢なのかもしれない。
え? RSpec? いやー,ヘタレの私には意味不明すぎて書ける気がしない。
it
って何よ?
- 投稿日:2020-07-25T22:46:53+09:00
99%のメールアドレスにマッチする正規表現
そんなことできるんですか・・・?
サイトURLはこちら↓
http://emailregex.com/長すぎて読む気になれないw
- 投稿日:2020-07-25T22:32:45+09:00
NameError in Incomes#index のエラー
家計簿アプリ作成の上で
NameError in Incomes#index
のエラーが出ました
index.html.erb<% @page_title = "収入科目一覧" %> <h2><%= page_title %></h2> <% if @incomes.present? %> <table> <thead> <tr> <th>科目名</th> <th>備考</th> </tr> </thead> <tbody> <% @incomes.each do |income| %> <tr> <td><%= income.name %></td> <td><%= income.description %></td> </tr> <% end %> </tbody> </table> <% else %> <p>登録されている科目がありません</p> <% end %>よく見てみると、、、
2行目のpageの前
@
が抜けているではないか。
index.html.erb<h2><%= @page_title %></h2>これで無事エラー解消です。
タイプミスとか、少しの抜けとかでエラーになっちゃうから困りますよね、プログラミングというものは。初心者の私は特に。
エラーと闘いながら、今後も引き続き頑張ります
- 投稿日:2020-07-25T22:06:57+09:00
プログラミングスクールを卒業したての大学生が、Railsでポートフォリオを作る!
はじめまして
プログラミングスクール卒業したての文系大学生「しょうた」です私は2020年7月19日にプログラミングスクールを卒業しました。
学んだ言語は、Rubyです一通りカリキュラムを終えた私が、新たな目標
「IT企業への長期インターン」
に向けてポートフォリオを作成します。今後、その過程で躓いたことや、学んだことを記して、成長日記・備忘録代わりに使っていこうと思います。
私の記事がいつか誰かの参考になれば幸いです。
- 投稿日:2020-07-25T22:06:57+09:00
プログラミングスクールを卒業したての大学生がRailsで家計簿アプリを作る!
はじめまして
プログラミングスクール卒業したての文系大学生「しょうた」です私は2020年7月19日にプログラミングスクールを卒業しました。
学んだ言語は、Rubyです一通りカリキュラムを終えた私が、新たな目標
「IT企業への長期インターン」
に向けて自作家計簿アプリを作成します。今後、その過程で躓いたことや、学んだことを記して、成長日記・備忘録代わりに使っていこうと思います。
私の記事がいつか誰かの参考になれば幸いです。
- 投稿日:2020-07-25T18:55:42+09:00
post to Qiita api v2 (from org-file of emacs)
qiita post
localにあるorgファイルをapiでqiitaにあげられないかというのがお題.
ハマったけどダメ.Bad requestしか返ってこなくって(07/22 10:00ごろ).その直後にcurlからのを見つけて,全てうまくいく.
完動,最小版は,
post_min.rbrequire "net/https" require "json" lines = File.readlines("README.md") qiita = 'https://qiita.com/' path = 'api/v2/items' uri = URI.parse(qiita+path) http_req = Net::HTTP.new(uri.host, uri.port) http_req.use_ssl = uri.scheme === "https" params = { "body": "# テスト", #lines.join, "private": true, "title": "テスト", "tags":[ { "name": "hoge", "versions": [] } ] } ACCESS_TOKEN = ENV["QIITA_WRITE_TOKEN"] headers = {"Authorization" => "Bearer #{ACCESS_TOKEN}", "Content-Type" => "application/json"} res = http_req.post(uri.path, params.to_json, headers) p res.message p res.body p res.response結論は,「やっぱりtag」でした.やれやれ.動くまでにweb APIとのconnectionの流儀でだいぶ悩んだんで,それについても書いておきます.
コツは,
- 短いの: 必要最小限の「やりとり」を用意する.
- interactive: 通信の様子を見るために,ターミナルで直接やりとりする.curlを使え.
- 確認: どんな通信が来てるかを直接見る, webrickを立ち上げてlocalと通信する
- net/https, json: libのおきてにお任せがいいよね.
- faraday: 慣れるとfaradayなんかは綺麗にかけて,出力もリッチでいいけど,'Bad request'の本質を解決してくれるわけではない.net/httpでいい.
です.順を追って解説します.
curlから
唯一成功したのが,これ.
curl -v -X POST "https://qiita.com/api/v2/items" \ -H "Authorization: Bearer ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d "{\"body\": \"# テスト\",\"private\": true,\"title\": \"テスト\",\"tags\":[{\"name\": \"hoge\",\"versions\": []}]}"めちゃくちゃ簡単なんやけど...できた.https://qiita.com/daddygongon/private/01b62c9f716573b18e61
この-dの後の後ろのごちゃごちゃに気が付いたんがえらい.ここが本質でした.
tag
Qiita API v2を利用してcurlで投稿してみた に記述があるけど,tagが不可欠,しかもややこい.
ACCESS_TOKEN
group/user, read/writeそれぞれで違うtokenが発行される.この影響があったかも.
localでの検証
ruby webrick.rbで立ち上げて,http://localhost:8000/ で確認.qiitaに投稿する代わりにlocalに投げた場合,
require "net/https" require "json" url = 'http://localhost:8000/' path = 'api/v2/items' uri = URI.parse(url+path) http_req = Net::HTTP.new(uri.host, uri.port) params = { "body": "# test", "private": true, "title": "test", "tags":[ "hoge" ] } ACCESS_TOKEN = 'ACCESS_TOKEN' post_req = Net::HTTP::Post.new(uri.path) post_req["Authorization"] = "Bearer #{ACCESS_TOKEN}" post_req["Content-Type"] = "application/json" post_req.body = params.to_json res = http_req.request(post_req) p res.message p res.body p res.responseruby post_local.rb 380ms "OK " "<html><body>\nPOST /api/v2/items HTTP/1.1\r\n<br>{"body":"# test","private":true,"title":"test","tags":["hoge"]}\n</body></html>\n" #<Net::HTTPOK 200 OK readbody=true>と返って来ます.webrick側での表示は
> ruby webrick.rb [2020-07-23 07:32:04] INFO WEBrick 1.4.2 [2020-07-23 07:32:04] INFO ruby 2.6.5 (2019-10-01) [x86_64-darwin17] [2020-07-23 07:32:04] INFO WEBrick::HTTPServer#start: pid=8161 port=8000 ========== 2020-07-23 07:32:08 +0900 ========== POST /api/v2/items HTTP/1.1 Accept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3 Accept: */* User-Agent: Ruby Authorization: Bearer ACCESS_TOKEN Content-Type: application/json Connection: close Host: localhost:8000 Content-Length: 63 {"body":"# test","private":true,"title":"test","tags":["hoge"]}です.
net/https, json
net/http, https
net/httpとかの流儀は,
です.net/httpsとかはrubyではrequireを変えるでけではなくて,
http.use_ssl = trueだけは入れいます.でもあとは,普通に.
json
jsonが返って来てなくて,これがなんなのかわからなかった.多分,nginxがweb serverでそのdefaultでerrorが返ってくるときはhtmlみたい.さらに型判定が通ってrequestが上にあげられるとjsonが返ってくる.
うまくいくようになると,
p res.message JSON.parse(res.body).each do |key, cont| if key == 'rendered_body' or key == 'body' puts "%20s brabrabra..." % key next end print "%20s %s\n" % [key, cont] end p JSON.parse(res.body)["url"]などとして,
"Created" rendered_body brabrabra... body brabrabra... coediting false comments_count 0 created_at 2020-07-24T12:43:03+09:00 group id 277d42b24f195ce09471 likes_count 0 private true reactions_count 0 tags [{"name"=>"hoge", "versions"=>[]}] title テスト updated_at 2020-07-24T12:43:03+09:00 url https://qiita.com/daddygongon/private/277d42b24f195ce09471 user {"description"=>"Ruby, VASP, Maple, boundary, nucleation, Al, Ti, Mg, SiC, Si", "facebook_id"=>"", "followees_count"=>7, "followers_count"=>7, "github_login_name"=>"daddygongon", "id"=>"daddygongon", "items_count"=>30, "linkedin_id"=>"", "location"=>"Japan", "name"=>"", "organization"=>"Kwansei Gakuin University", "permanent_id"=>151211, "profile_image_url"=>"https://s3-ap-northeast-1.amazonaws.com/qiita-image-store/0/151211/1b7c18530785a67592309af94197e19e74c6aba2/x_large.png?1584337585", "team_only"=>false, "twitter_screen_name"=>nil, "website_url"=>""} page_views_count "https://qiita.com/daddygongon/private/277d42b24f195ce09471"とできます.
Faraday
faradayは綺麗で,出力もリッチだけど本質ではない.httpsに投げるとredirectが返ってくるだけ.でbad requestが治ったわけではない.
#+name: post_faraday.rb require "net/http" require "json" lines = File.readlines("README.md") qiita = 'https://qiita.com/' path = 'api/v2/items' uri = URI.parse(qiita+path) require 'faraday' require 'json' param = { body: '#sample', coediting: false, gist: false, private: true, tags: [], title: 'sample', tweet: false } url = 'http://qiita.com' conn = Faraday.new(url: url) do |builder| builder.request :url_encoded builder.response :logger builder.adapter :net_http #Faraday.default_adapter end ACCESS_TOKEN = ENV["QIITA_ACCESS_TOKEN"] response = conn.post do |request| request.url '/api/v2/items' request.headers = { 'Authorization' => "Bearer #{ACCESS_TOKEN}", 'Content-Type' => 'application/json' } request.body = JSON.generate(param) end p response puts JSON.pretty_generate(JSON.parse(response.body)) #json = JSON.parser.new(response.body)auto化
emacs README.org --batch -l ~/.emacs.d/site_lisp/ox-qmd -f org-qmd-export-to-markdown --killと-lでelファイルを指定して,その中にある関数を機能させる.
それとともに,tagやtitleをorgから取ってくる.以下は,全てを自動化したversion.
post_final.rb抜粋def get_title_tags(src) conts = File.read(src) title = conts.match(/\#\+(TITLE|title|Title): (.+)/)[2] || "テスト" m = [] tags = if m = conts.match(/\#\+(TAG|tag|Tag|tags|TAGS|Tags): (.+)/) m[2].split(',').inject([]) do |l, c| l << {name: c.strip, versions: []} end else [{ name: "hoge", versions: [] }] end p tags return title,tags end src = ARGV[0] || 'README.org' title, tags = get_title_tags(src) p title p tags system "emacs #{src} --batch -l ~/.emacs.d/site_lisp/ox-qmd -f org-qmd-export-to-markdown --kill" params = { "body": lines.join, #"# テスト", "private": true, "title": title, "tags": tags }あと,teamsに投げる.これはurlとaccess_token
qiita = 'https://nishitani.qiita.com/' ACCESS_TOKEN = ENV['QIITA_TEAM_WRITE_TOKEN']を少しいじるだけでできる.
- 投稿日:2020-07-25T18:39:34+09:00
post to Qiita patching version
すでにqiitaにあげた記事を更新するversion
に最初に投稿するversionの作成記録があります.さらに,すでにqiitaにあげた記事を更新するversionです.下のcodeを
ruby post_final.rb post_final.orgなんかでできます.最初のpostでは新しいのを作り,そのあとitemsのidをorgに記します.それがあるとそのidにpatchします.
さらに,'open', 'teams'を選べます.defaultは'private'.
ruby post_final.rb post_final.org teamsなんてね.
keyは
code
require "net/https" require "json" def get_title_tags(src) $conts = File.read(src) title = $conts.match(/\#\+(TITLE|title|Title): (.+)/)[2] || "テスト" m = [] tags = if m = $conts.match(/\#\+(TAG|tag|Tag|tags|TAGS|Tags): (.+)/) m[2].split(',').inject([]) do |l, c| l << {name: c.strip} #, versions: []} end else [{ name: "hoge"}] #, versions: [] }] end p tags return title,tags end src = ARGV[0] || 'README.org' title, tags = get_title_tags(src) p title p tags system "emacs #{src} --batch -l ~/.emacs.d/site_lisp/ox-qmd -f org-qmd-export-to-markdown --kill" lines = File.readlines(src.gsub('org','md')) m = [] patch = false if m = $conts.match(/\#\+qiita_id: (.+)/) qiita_id = m[1] patch = true else qiita_id = '' end case ARGV[1] when 'teams' qiita = 'https://nishitani.qiita.com/' access_token = ENV['QIITA_TEAM_WRITE_TOKEN'] private = false when 'open' qiita = 'https://qiita.com/' access_token = ENV['QIITA_WRITE_TOKEN'] private = false else qiita = 'https://qiita.com/' access_token = ENV['QIITA_WRITE_TOKEN'] private = true end params = { "body": lines.join, #"# テスト", "private": private, "title": title, "tags": tags } if patch path = "api/v2/items/#{qiita_id}" else path = 'api/v2/items' end p qiita+path uri = URI.parse(qiita+path) http_req = Net::HTTP.new(uri.host, uri.port) http_req.use_ssl = uri.scheme === "https" headers = {"Authorization" => "Bearer #{access_token}", "Content-Type" => "application/json"} if patch res = http_req.patch(uri.path, params.to_json, headers) else res = http_req.post(uri.path, params.to_json, headers) end p res.message res_body = JSON.parse(res.body) res_body.each do |key, cont| if key == 'rendered_body' or key == 'body' puts "%20s brabrabra..." % key next end print "%20s %s\n" % [key, cont] end system "open #{res_body["url"]}" qiita_id =res_body["id"] unless patch File.write(src,"#+qiita_id: #{qiita_id}\n"+$conts) endえっと,refactoringしてください.
課題
openとteamsで二箇所に出したいときは,どっちがどっちかわからなくなりますね.その辺り,自動で更新してくれるようにできんかな...
- 投稿日:2020-07-25T16:44:13+09:00
Active Admin 管理者画面からユーザー作成できない
経緯
rails g active_admin:resource userを実行し、
class DeviseCreateUsers < ActiveRecord::Migration[6.0] def change create_table :users do |t| t.string :email, null: false, default: "" t.string :encrypted_password, null: false, default: "" t.string :reset_password_token t.datetime :reset_password_sent_at t.datetime :remember_created_at t.timestamps null: false end add_index :users, :email, unique: true add_index :users, :reset_password_token, unique: true end endusersテーブルのカラムに合わせて
ActiveAdmin.register User do permit_params :email, :reset_password_token, :reset_password_sent_at, :remember_created_at endとpermit_paramsを書いて
フォーム入力後にユーザー作成ボタンを押したらユーザー作成できなかった。そこでadmin_users.rbにならってuser.rbを書き換えたところ
ActiveAdmin.register User do permit_params :email, :password, :password_confirmation index do selectable_column id_column column :email column :current_sign_in_at column :sign_in_count column :created_at actions end filter :email filter :current_sign_in_at filter :sign_in_count filter :created_at form do |f| f.inputs do f.input :email f.input :password f.input :password_confirmation end f.actions end end
- 投稿日:2020-07-25T14:45:13+09:00
チャットアプリ制作
個人の学習の知見を広げるため、チャットアプリを制作しました。
アプリの概要
・ユーザーの登録ができる
・ユーザーがグループを作成できる
・グループを指定して、メッセージを送ることができる使用技術
・Ruby
・Ruby on Rails
・JavaScript
・MySQL
・AWS
・nginx
・unicorn
・Capistrano本番環境のリンク
githubのリンク
https://github.com/mitsugu3/ChatSpace
感想
アプリ制作の流れを掴むことができた。
AWSで、本番環境にあげるのが
シークレットキーなどの知識が必要だったので難しく感じたが、
検索記事を参考に自走することができた。
- 投稿日:2020-07-25T14:32:54+09:00
slickでスライドショーをお洒落に実装したかった。
スライドショーを実装するためにslickを導入
詰まりまくったことを解決したので投稿
環境
rails : 6.0.3.2
ruby : 2.6.6
Docker, docker-compose参考URL
http://kenwheeler.github.io/slick/
先にできていること
jQueryの導入
slick導入編
slick本体をインストール
qiita.rb$ docker-compose run --rm web npm i slick-carousel なんやかんや 40 packages are looking for funding run `npm fund` for details found 0 vulnerabilitiesapplocation.html.erbのhead要素に追記
qiita.rb<link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/slick-carousel@1.8.1/slick/slick.css"/> <link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/npm/slick-carousel@1.8.1/slick/slick-theme.css"/> <script type="text/javascript" src="//cdn.jsdelivr.net/npm/slick-carousel@1.8.1/slick/slick.min.js"></script>jsファイル
slideの表示方法の設定については公式に書かれているので、一部だけ紹介。
slickの読み込みがどうもうまくいかなかったので、多分他の人とは違う書き方だと思う。slideshow.jsconst jQuery = require('jquery'); require('slick-carousel'); (function($) { $(function() { $('.theTarget').slick({ dots: true, autoplay: true, fade: true, autoplaySpeed: 3000 }); }) })(jQuery);viewにスライドショーで表示させたい画像の記述
show.html.erb<div class = "theTarget"> <%= image_tag 'abc.png' %> <%= image_tag 'def.png' %> <%= image_tag 'ghi.png' %> <%= image_tag 'jkl.png' %> <%= image_tag 'mno.png' %> </div> <%= javascript_pack_tag 'slideshow.js' %> #jsファイルの読み込みjsの読み込みのエラーが出た場合。
今回であれば、bin/webpackを実行してコンパイルすればエラーを解決できた。
webpackを理解できてないから、わざわざなんでこれをしないといけないのかが分からないqiita.rb% docker-compose run --rm web bin/webpack Version: webpack 4.43.0 Time: 15190ms Built at: 07/24/2020 11:18:43 PM
- 投稿日:2020-07-25T13:50:21+09:00
Active Admin リソースの削除
- 投稿日:2020-07-25T13:35:53+09:00
FizzBuzzを、やってみた。
概要
Rubyで,、FizzBuzz
1から100の変数を表示、その中の
3で割り切れる値には、文字列"Fizz"を
5で割り切れる値には、文字列”Buzz”を
表示し
3でも5でも割り切れる値には"FizzBuzz"を表示する。fizz_buzz.rb(1..100).each{|n| if n % 15 == 0 puts "FizzBuzz" elsif n % 3 == 0 puts "Fizz" elsif n % 5 == 0 puts "Buzz" else puts n end }コマンドで実行した結果
1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz 16 17 Fizz 19 Buzz Fizz 22 23 Fizz Buzz 26 Fizz 28 29 FizzBuzz 31 32 Fizz 34 Buzz Fizz 37 38 Fizz Buzz 41 Fizz 43 44 FizzBuzz 46 47 Fizz 49 Buzz Fizz 52 53 Fizz Buzz 56 Fizz 58 59 FizzBuzz 61 62 Fizz 64 Buzz Fizz 67 68 Fizz Buzz 71 Fizz 73 74 FizzBuzz 76 77 Fizz 79 Buzz Fizz 82 83 Fizz Buzz 86 Fizz 88 89 FizzBuzz 91 92 Fizz 94 Buzz Fizz 97 98 Fizz Buzzgithubのリンク
https://github.com/mitsugu3/FizzBuzz/blob/master/fizz_buzz.rb
感想
FizzBuzzを、やってみて
each文とelse if文とまとめてコードを書くことを学べたので
これからの作業を手早くできることと
知見が広がった。
- 投稿日:2020-07-25T05:19:03+09:00
hashのkeyとvalueのマッピングに関して
hashのvalueをうまく取得できないので調べてみたらちょっとした見落としだった。
hash1 = {key: "value"} #=> {:key=> "value"}と、
hash2 = {"key"=> "value"} #=> {"key"=> "value"}の違いを理解していなかった。
記述の仕方でkey名が変わるようだ。
上の例ではhash1["key"] #=> nil hash1[:key] #=> "value"になる。
- 投稿日:2020-07-25T00:11:05+09:00
RailsでGoogleMapsAPIを表示・ピン表示まで
はじめに
過去に自分のポートフォリオでGoogleMapsAPIを利用していましたが、流れを忘れていたのでリマインドです。
環境
rails 5.2.3
ruby 2.6.3今回すること
・現在地情報から経度緯度を取得しマーカーを表示する。
・取得した一覧情報をjson形式に変え、マーカーとして地図上に配置。
・地図の表示表示させるコントローラー作成、今回アクション名はsearchで。
spaces_controller.rbdef search @spaces = Space.all endモデルの作成、住所を入力後緯度経度を自動取得させる。
space.rbclass Space < ApplicationRecord geocoded_by :address after_validation :geocode, if: :address_changed? endschema.rbcreate_table "spaces", force: :cascade do |t| t.string "address" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.float "latitude" t.float "longitude" endMAPを表示させるscript
javascriptfunction initMap() //マップを表示させる箇所 var target = document.getElementById('gmap'); //マップ表示 var map = new google.maps.Map(document.getElementById('gmap'), { center: {lat: 35.681167, lng: 139.767052},//中心点設定 zoom: 8//mapの拡大率設定 }); //現在地マーカーの作成 //現在地取得できない場合 if(!navigator.geolocation){ infoWindow.setPosition(map.getCenter()); infoWindow.setContent('Geolocation に対応していません。'); infoWindow.open(map); } navigator.geolocation.getCurrentPosition(function(position) { //現在地の軽度緯度取得 var pos = { lat: position.coords.latitude, lng: position.coords.longitude }; var mark = new google.maps.Marker({ //ドロップダウンアニメーションの設定 animation: google.maps.Animation.DROP, position: pos, map: map, // 現在地ピンのアイコン作成。今回デフォルトのデザインは複数のマーカーに使用するので変更。 icon: { fillColor: "rgb(48, 255, 176)", fillOpacity: 1.0, path: google.maps.SymbolPath.BACKWARD_CLOSED_ARROW, scale: 4, strokeColor: "green", strokeWeight: 1.0 } }); }, function() { infoWindow.setPosition(map.getCenter()); infoWindow.setContent('Error: Geolocation が無効です。'); infoWindow.open(map); }); //複数マーカー //一覧のデータをjson形式に var spaces = #{raw @spaces.to_json}; var marker = []; var info; for(var i = 0; i < spaces.length; ++i) { //一覧から一つずつ経度緯度の情報を取り出してマーカー作成 spot = new google.maps.LatLng({lat: spaces[i].latitude, lng: spaces[i].longitude}); marker[i] = new google.maps.Marker({ position: spot, map: map, animation: google.maps.Animation.DROP }); markerEvent(i); } //複数マーカーのhover時イベント function markerEvent(i) { marker[i].addListener('mouseover', function() { var target = $('#' + (i + 1)); $(".highlight").removeClass("highlight"); target.addClass("highlight"); var position = target.offset().top - 280; $('body,html').animate({scrollTop:position}, 400, 'swing'); }); } //------------------------------------------------------------- } script src="https://maps.googleapis.com/maps/api/js?key=#{ENV[""]}&callback=initMap" async defer今回はテンプレートエンジンをslimにしてその中に直接書いているのでデータの変数格納のあたりが通常と違っているので注意。
gemのgeocoderを使用すると名前から経度と緯度を取得するのが非常に楽ですが、精度が悪く、番地単位まで表示してくれないので今回はGoogle Geocodingを使用しています。
- 投稿日:2020-07-25T00:05:18+09:00
超初心者向けGitHubの使い方(チーム開発)
自分自身が、GitHubの初心者なので
Rubyチーム開発の手順として、忘備録としてまとめます。
GitHubのアカウントを持っていて、GitHub Desktopもダウンロードしている
ことを前提としています。
もし、何か間違っていることがあれば教えていただきたいです。最初に、アプリの雛形を作成します(デプロイする人が作成をします)。
ターミナル
% rails _6.0.0_ new アプリ名 -d mysql # mysqlデータベースでの開発config/database.yml
default: &default adapter: mysql2 encoding: utf8 # encodingを変更。 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root password: socket: /tmp/mysql.sockターミナル
% rails db:create # データベースを作成これで、アプリの雛形が完成しました。
ここからは、GitHUbにデータを紐付ける作業をしていきます。
以下の手順で作業していきます。①GItHub Desktop から 先ほど作成したアプリのローカルリポジトリを作成。
左上の「Current Repository」→「Add」→「Add Existing Repository」を選択
②ターミナルから該当ディレクトリへ行き、「git init」コマンドを実行。
これをすることで、該当アプリがgit管理下に置くことができる。
③ターミナルより以下コマンドを入力git add 該当アプリ.rbこのコマンドを入力することで、インデックスに追加されることになリます。
念の為以下コマンドを入力% git status On branch master # git statusをすると、以下文が出たら、全てインデックスに移動済 No commits yet Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: 該当ファイル.rb Untracked files: (use "git add <file>..." to include in what will be committed) site/④GItHub Desktop から git-app のローカルリポジトリを作成。
左上の「Current Repository」→「Add」→「Add Existing Repository」を選択。
chooseから該当アプリを選択、「Add Repository」をクリック。
⑤ローカルリポジトリにある全てのファイルを選択してコミットする。
その際のコミットメッセージは、なんでも良いが、迷うのであれば「Initial commit」とする。
⑥リモートリポジトリと結びつける。
GitHubDesktopより[Publish repository]ボタンをクリックすると
GitHub のリモートリポジトリが作成される。
⑦ここで リモートのGitHub のトップページに移動。
GitHub の Your repositories の欄に 該当アプリ があれば成功。===========
ここまでで、アプリの雛形とGitHubへの紐付けが終了です。
次に、チームで開発するために、別のメンバーが作成していくを書いていきます。①別のメンバーは該当アプリをフォークして、クローンをする。
GitHub(リモート)の該当アプリのページへ飛び、URLをコピー。
右上にあるforkボタンを押す。→フォークされる。ターミナルでcloneしたいフォルダまで行き、以下のコマンドを実行。
git clone コピーしたアプリのURL →クローンされる。これで、アプリがクローンされる。
②コミットをする。
クローンした後、空のコミットをする。
しかし空のコミットは、GitHubデスクトップからコミットできないので
ターミナルから以下のコマンドを入力してコミットをする。git commit -m 'initial commit'必ず最初にコミットをしなければいけない訳ではないが、
この後、プルリクエストを出すにはコミットをしておかなければならない。
プルリクエストも別に出さなくても良いが、プルリクエストを出すことによって
別のチーム開発者に、今ここを実装しているといったアピールができるので
コンフリクトを減らすことができる。
つまり、コンフリクトを減らしたい→その為にプルリクエストを出しておきたい→その為に最初に
コミットを出しておく。③コミットをしたら、GitHubDesktopから、マスターブランチから新しくトピックブランチを切り
プルリクエストを出す。ブランチ名はこれから実装するであろう内容にする。
タイトルにWIP(作業中)をつける。
WHAT WHY で書くとわかりやすい。(マークダウンで書くのが望ましい)
プルリクエストを出すことで、他のメンバーに自分が実装している場所をアピールすることができる。
マスターブランチでプルリクエストを出さないように注意。④ トピックブランチから、開発を開始する。
⑤完成したら、GitHubデスクトップより、コミットをする。
⑥他のチームメンバーにLGTMをもらったら、WIPの記述をなくす。
もしくは、プルリクエストをクローズする。リモートの下の方にボタンがある。⑦プッシュする。
⑧アプリ開発者(デプロイする人)にマージしてもらう。
マージしたら、プルリクが溜まらないようにデリートするのがおすすめ。⑨ローカルリポジトリにプルしたいので、
GitHubデスクトップのブランチをマスターブランチに変更して、プルをおす。
こうすることで、最新版のデータを吸い上げることができる。⑩ローカルリポジトリが最新のデータになったので
再度、トピックブランチを切って、次の開発を進めていく。=======
GitHubは、最初はなかなか慣れない人が多いと聞きました。
順を追って確認しながら進めていくのがおすすめです。
みなさん、一緒に頑張りましょう!