- 投稿日:2019-10-20T23:25:30+09:00
AtCoder Beginner Contest 143
はじめに
Atcorder ABC143へ初参加。
結果は問A~問Cまでの3問のみ正答。
言語:ruby
Ver:Ruby 2.3.3
URL:https://atcoder.jp/contests/abc143/tasks143-A(Curtain)
・この問題は窓の幅とカーテンの1辺のサイズ×2と比較する問題
※ただし、値がマイナスにならないよう注意143-A.rbA,B = gets.split(' ').map(&:to_i) Num = A - B*2 if Num < 0 Num = 0 end p Num143-B(TAKOYAKI FESTIVAL 2019)
・たこ焼きの組み合わせの選び方の問題
1つ目のたこ焼きを限定して、2つ目のたこ焼きを選択143-B.rbN = gets.to_i takoyaki = gets.split(' ').map(&:to_i) taste_total = 0 a = 0 while a < N do taste = 0 b = a + 1 while b < N do taste = taste + takoyaki[a]*takoyaki[b] b = b + 1 end taste_total = taste_total + taste a = a + 1 end puts taste_total143-C(Slimes)
・隣接する文字列を判定する問題
・先頭から次の文字が同じかどうか比較し、異なるとスライムの総数を増加143-C.rbN = gets.to_i slime = gets.chomp slime_total = 0 slime.length.times do |num| if slime[num] != slime[num + 1] slime_total = slime_total + 1 end end p slime_total143-D(Triangles)
・解法を最適化する問題
1.すべての辺を1つずつ計算( 計算時間がO(N^3) )
※ 計算時間がかかりすぎるので改善
143-D.rbN = gets.to_i hen = gets.split(' ').map(&:to_i) hen.sort! triangle_total = 0 a = 0 while a < N - 2 do b = a + 1 while b < N - 1 do c = b + 1 while c < N do if hen[a] + hen[b] > hen[c] triangle_total += 1 c+= 1 else break end end b = b + 1 end a = a + 1 end p triangle_total2.解放を改善(計算時間がO(N^2 log2))
改善のポイント
- 143-Bの考え方を応用する
- 入力された数値がばらばらだと辺の大小関係が分かりにくい
- 入力された内容を昇順にソートする
- 三角形の成立条件は「最小の二辺が最大の辺より大きい」という条件に言い換えができる
・a < b + c
・b < c + a
・c < a + b- 最小の2辺を固定したうえで、最大の辺が条件を満たす組み合わせを考える
- 最小の2辺(a + b)で残りの1辺がどの値まで条件を満たすか(> c)を考える
- 1つずつ左から探索(線形探索)する場合は時間がかかる
- 2分木のソート方法を用いて、a + b に近似する値を探索する
https://qiita.com/ryosuketter/items/2798b09330e7102b6cfe143-D-2.rbN = gets.to_i hen = gets.split(' ').map(&:to_i) hen.sort! triangle_total = 0 a = 0 # aの候補の最大要素は配列数の2個前 while a < N - 2 do b = a + 1 # bの候補の最大要素は配列数の1個前 while b < N - 1 do check_num = hen[a] + hen[b] # a + b がソート対象の最小値以下の場合は三角形の成立条件を満たすものはなし if check_num <= hen[b + 1] # a + b がソート対象の最大値より大きい場合は全ての数値が三角形の成立条件を満たす elsif check_num > hen[N - 1] triangle_total = triangle_total + N - 1 - b # a + b がソート対象範囲内の数字 else # ソートの先頭と末尾を定義 head = b + 1 tail = N - 1 # ソート対象の中央値より上か下かで範囲を絞る while head <= tail center = (head + tail) / 2 if hen[center] >= check_num tail = center - 1 elsif hen[center] < check_num if check_num <= hen[center + 1] triangle_total = triangle_total + center - b break else head = center + 1 end end end end b = b + 1 end a = a + 1 end p triangle_total3.Rubyのライブラリを使用して改善
・bsearch_indexを使用して、探索用の処理に書き換える
https://docs.ruby-lang.org/ja/latest/method/Array/i/bsearch_index.html143-D-3.rbN = gets.to_i hen = gets.split(' ').map(&:to_i) hen.sort! triangle_total = 0 a = 0 while a < N - 2 do b = a + 1 while b < N - 1 do check_num = hen[a] + hen[b] if check_num <= hen[b + 1] elsif check_num > hen[N - 1] triangle_total = triangle_total + N - 1 - b else c = hen.bsearch_index { |x| x >= check_num } triangle_total = triangle_total + c - 1 - b end b = b + 1 end a = a + 1 end p triangle_total
- 投稿日:2019-10-20T22:48:56+09:00
インクリメンタルサーチについての復習
インクリメンタルサーチの復習
Ajaxの非同期通信を学習中で、前回はコメントの投稿をページの再読み込みなしで表示させました。
今回は文字を入力して検索する際、検索ボタンを押して再読み込みをさせずに非同期で検索結果を表示させるようにします。インクリメンタルサーチとは
そもそもインクリメンタルサーチとは、
Incremental Search
Incremental : 増加、増大する、追加する
Search : 検索
と単語の意味で考えると正直分かりませんが、IT用語で「文字入力するたびに自動的に検索が行われる検索方法」を指します。インクリメンタルサーチの実装
インクリメンタルサーチ実装の流れを復習していきます。
あくまでAjax、JavaScriptの流れを把握することが目的なので、HTMLなどの表記はある程度省略していきます。search.js$(function() { $(".search__form").on("keyup", function(){ var input = $(".search__form").val(); $.ajax({ type: 'GET', url: '/products/search', data: { keyword: input }, dataType: 'json' }) .done(function(products) { $(".検索結果表示クラス").empty(); if (products.length !==0) { $(".検索結果表示クラス").append("インクリメンタルサーチの結果を表示させる記述"); } else { $(".検索結果表示クラス").append("検索結果がない旨を表示させる記述"); } }) .fail(function(){ alert('映画検索に失敗しました'); })全体的な記述は上記のようになると思います。
細かい内容をおさらいしていきます。$(".search__form").on("keyup", function(){keyupイベントはキーボードのキーが上がった時に発火します。文字入力でキーを離したタイミングですね。
イベントの発火を検知する場所は、ここでは"search__form"クラスを持つ検索フォームが指定されています。var input = $(".search__form").val();検索フォームに入力されている値をinputに代入します。
$.ajax({ type: 'GET', url: '/products/search', data: { keyword: input }, dataType: 'json' })Ajaxで非同期通信を行う際に指定する内容を記述します。
URL、data内のkey名(keyword)はルーティングやインスタンス変数の定義により変わるので一例です。
今回の記述では、{ keyword: input }データを/products/searchパスにGETメソッドで送り、結果をJSON形式で返してもらいます。.done(function(products) { $(".検索結果表示クラス").empty(); if (products.length !==0) { $(".検索結果表示クラス").append("インクリメンタルサーチの結果を表示させる記述"); } else { "検索結果がない旨を表示させる記述"; } }) .fail(function(){ alert('映画検索に失敗しました'); })
.done
メソッドと.fail
メソッドは対で記述しておきましょう。そして.fail
メソッドはalert
で「エラーが発生しました」と表示される程度でいいかと思います。今回の
.done
メソッドでは、まず検索結果をproductsに代入します。
現在表示されている検索結果をempty
メソッドで消去します。
empty
メソッドは、その要素そのものではなく子要素を削除します。これで検索結果を表示させる箱は残しながら、中身を全て消してリセットしてしまいます。その後検索結果をリセットされた中身に追加して表示させるようにします。ifを使って場合分けを行います。検索結果の個数が0でなければその結果を表示させ、検索結果の個数が0の場合は検索結果がない旨の記述が適用されます。
結果
検索フォームに文字入力をすると、キーから指を離すたびにフォーム内の文字列が拾われて都度その文字列で検索をかけられます。
文字を入力する度に検索が実行されているわけですから、PC本体やネット回線のスペックがそれなりにないと負荷がすごいことになりそうですね。
ブロードバンドが普及する前にインクリメンタルサーチが使われていたら、どうなっていたのでしょうか?JavaScript(jQuery)の書き方にはまだ慣れませんが、書いている中身はなんとなく分かってきた気がします。一気に書くとさっぱり分かりませんが、一つ一つ読み解きながら進めていくとどうにか分かるようになってきました。
- 投稿日:2019-10-20T22:40:16+09:00
Rails初学者必見!クラスの作り方分かってないと色々やばい!
なぜ書こうと思ったか
Rails系プログラミングスクール卒業生に
クラスの定義に関して簡単な問題を出したところ、
絶望的にできなかった。その問題というのはこちら
「User.new(first_name: '太郎').first_name」で「太郎」を取得できるよう、クラス「User」を作成してください。
また、「User.new(first_name: '太郎', last_name: '田中').full_name」で「田中太郎」が取得できるよう、インスタンスメソッド「full_name」を定義してください。
答え書いた方がいいですか?
答え書いちゃうと巷のプログラミングスクールとおんなじのマニュアルお化けになっちゃうので、書きたくないです。
書き方は一つじゃないですし・・・。
頑張って調べて挑戦してみてください。終わりに
知ってたら5分かからないくらいで書けちゃうコードなんですよね。
Rails系のプログラミングスクールを卒業しても、戦力になっていない人が多いのは、
単純に、Rubyの最低限の基礎知識もわかってないからなんだろうなと、切に思います。
もし、あなたがプログラミングスクールを卒業しても、
この問題を5分足らずで書けないなら、Rubyの基礎をしっかり固める時期だと認識しましょう。
- 投稿日:2019-10-20T21:30:33+09:00
未経験がマッチングアプリを作ってみた話【Rails】
はじめに
未経験からのWeb系企業転職をするためのポートフォリオを作成しました。
マッチング機能を用いてエンジニアをつなぐサービスです。
8月から勉強をはじめ、10月から着手し完成まで至りました。(改修は随時行なっていきます。)なぜ作った?
私は現在地方で働いています。
だいぶ田舎にいるため、東京都比べてしまうとコミュニティが少ないです。というかありません。
このような壁があり、エンジニアとの繋がりが少ないのです。そこで、エンジニア向けのマッチングアプリがあればこの問題は解決できるのでは?というのが始まりです。
Twitterでよくない?という声が聞こえてきますが、Twitterではその人の得意な技術や好きな分野を調べなくてはなりません。
このサービスでは、「タグ機能」があり、その人の好きな分野をすぐに知ることができます。サービス紹介
【リンク】
https://engineer-link.herokuapp.com【Github】
https://github.com/kotaro-saitou/engineer-link-appEngineer Linkは、エンジニアとエンジニアが気軽にメッセージを送りあえるサービスです。
主な機能
・画像付きユーザー登録機能
・(ログイン時)フォロー/アンフォロー機能
・記事の投稿機能
・タグ(Ruby、Pythonなどの自分の好きな技術など)の画像付き投稿機能
・相互フォローのみリアルタイムメッセージ機能
・記事、タグ、ユーザー一覧でのページネーション機能技術
・Rails5.2.2
・Ruby2.5.4
・CircleCI
・Rspec
・Heroku
・AmazonS3(プロフィール画像、タグの画像)
・ActionCable(リアルタイムチャット)工夫
・CircleCIを用いて自動デプロイを実装
・Githubでissue管理を行なった参考にしたサイト
【Rails】Herokuで画像を投稿できるようにする方法(ActiveStorage + Amazon S3)
https://qiita.com/hmmrjn/items/479c9e9ce82771f1b6d7
Rails5.2から導入されたcredentials.yml.encを極める
https://qiita.com/yuuuking/items/53a37a2e998972be32b8
Rails 5 + ActionCableで作る!シンプルなチャットアプリ(DHH氏のデモ動画より)
https://qiita.com/jnchito/items/aec75fab42804287d71b
未経験がWeb系転職成功したいならgithubでissue管理して開発しよう
https://qiita.com/fukubaka0825/items/c7710b4e87d478c8ba3b
全てとても参考になりました!!
ありがとうございます!!!思ったこと
このサービスを開発するにあたり、以下の技術は勉強しながら実装しました。
・Rspec
・ActionCable
・CircleCIこの辺りのことを実装するにあたり、「手を動かしながら学ぶことの重要性」を感じました。(特にRspec)
Rspecの勉強はEveryday Railsが本当におすすめです!!
https://leanpub.com/everydayrailsrspec-jp
翻訳してくださっている方々に深く感謝しながら勉強しましょう。CircleCIに関しては、調べながらやっていけば比較的簡単に導入できます。
ポートフォリオを作成できていない未経験の方へ
Progateなどで基礎を勉強することは楽しいですし、素晴らしいことです。
しかし、勉強したことを元に物を作るのはもっと楽しいです!なんでもいいので、物を作り、そこに自分にとって未知の技術を取り入れることは、
勉強にもなり非常に楽しいです。最後に
これからは、この二ヶ月はサーバーサイドに偏りすぎていたので、フロントの勉強に力を入れつつ
引き続き頑張ります!
- 投稿日:2019-10-20T21:27:02+09:00
eachで回す時の<% %>と<%= %>の違い
eachで回していて、
なぜか、以下の画像のように出力されました。
[#<User id: 1, name: "aaaa", email: "aaaaa", created_at: "2019-10-19 12:10:03", updated_at: "2019-10-19 12:10:03">, #<User id: 2, name: "bbb", email: "bbbb", created_at: "2019-10-19 12:10:35", updated_at: "2019-10-19 12:10:35">]この部分いらないな。てか、なんで出てきたんだろう。今までこんな事なかったのに、、、
と思っていたところ、問題は、viewでした。index.html.erb<h1>Users#index</h1> <p>Find me in app/views/users/index.html.erb</p <div> <%= @user.each do |user| %> <p> <%= user.name %> <%= user.email %> </p> <% end %> </div><%= @user.each do |user| %>の=が問題でした。
<% @user.each do |user| %>とすると、いらない部分は消えました。
=をつけると、データ側も出力されるという新しい発見でした笑
- 投稿日:2019-10-20T20:53:18+09:00
Payjpを使って、商品購入機能を実装する【Rails】
概要
「payjp」というgemを使うことで、簡単にクレジットカード(以下CC)購入フォームと機能を作成することができます。
本記事では、某フリマアプリのクローンアプリを開発した際に購入機能を実装する上で、登録画面のマークアップからpayjp利用したサーバーサイドの実装までを紹介していきます。実装する機能
- Checkoutを利用した購入機能(この段階でのみCheckout利用)
- payjp.jsを利用した実装
- CC登録機能
- 登録したCCをユーザー情報と紐づけて表示させる
- CC削除機能
- 購入機能(再実装)
- ユーザー新規登録登録画面でもCC登録ができるようにする(+α)
バージョン情報や前提条件
- ruby 2.5.1
- payjp 5.2.3
- 前提条件
- hamlで記述
- sassで記述
- deviseを導入しており、ログイン機能が実装されている
実装
DB設計やルーティングの違いにより、実装する上で記述内容に差異が生じるかと思います。
適宜考えて実装していただけると幸いです。payjp gemをインストール
Gemfileに以下を記述して、bundle installします。
gem 'payjp'payjpのサイトにアカウント登録
payjpのサイトでアカウントを登録します。
https://pay.jp/APIキーを確認
登録が完了したら、payjpの管理画面でAPIキーを確認します。
今回確認するのは、テスト用の公開鍵(pk~)と秘密鍵(sk~)です。
こちらは後ほど使用するので、画面を残しておきましょう。
購入機能の実装(checkout利用)
続いて購入機能の実装です。
購入機能自体はpayjpで用意されているライブラリ 「Checkout」 を利用すれば、簡単に実装できます。1.ビューファイル編集
購入確認画面のビューファイル内の 「購入する」 の記述を、以下の記述と置き換えます。
app/views/transacts/buy.html.haml= form_with "パスを指定" do :plain %script{type: "text/javascript", src: "https://checkout.pay.jp", class:"payjp-button", "data-text": "購入する", "data-key": "公開鍵(pk_~)"}これだけで購入に関するフォームの記述は終了です。
置き換えた後に表示された「購入する」をクリックすると、CC登録フォームがモーダルで表示されます。
使用するカード情報
カード: 4242424242424242(Visaのテストカード)
有効期限: 現在より未来の期日
CVC番号: 3~4桁の任意の数字
名前: 任意の名前使用するカードはpayjpよりテストカードが用意されているので、そちらを使用しましょう。
https://pay.jp/docs/testcard2.コントローラ編集
app/controllers/transacts_controller.rbrequire 'payjp' def pay Payjp.api_key = "秘密鍵(sk_~)" Payjp::Charge.create( amount: 1100, # 決済する値段 card: params['payjp-token'], # フォームを送信すると生成されるトークン currency: 'jpy' ) end後は、ルーティングを設定すれば、購入できるようになります。
実際に購入できているのが確認できます。
再実装【payjp.jsを利用】
checkoutを利用することで、簡単に購入機能が実装できました。
しかし、現在の実装では実際の運用は難しいので、実際の運用を想定して実装し直します。実装条件
- ログインしているユーザーに紐づけてカード情報を登録する、削除もできる
- ユーザーは登録したCCを使用して、商品を購入できる
- 独自でCC登録フォームを作成する
1.テーブルの作成
マイグレーションファイルを作成し、テーブルの作成とカラムの紐付けを行います。
userは外部キーなので、references型で外部キー制約を指定しています。db/migrate/2019**********_create_cards.rbclass CreateCards < ActiveRecord::Migration[5.2] def change create_table :cards do |t| t.references :user, null: false, foreign_key: true t.string :customer_id, null: false t.string :card_id, null: false end end end記述したら、rake db:migare を行います。
なお、DBに顧客情報やカード情報そのものを保存することは禁止されているのでご注意ください。http://payjp-announce.hatenablog.com/entry/2017/11/10/182738モデルの紐付け
モデルファイルを作成し、編集します。
以下、カードに関する紐付けの記述のみ載せています。app/models/card.rbclass Card < ApplicationRecord belongs_to :user endapp/models/user.rbclass User < ApplicationRecord devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable has_many :cards # 追記する end2.クレジットカード登録フォームのマークアップ
続いて登録フォームを作成します。
今回は、某フリマアプリに寄せてています。
一つのファイルに以下の内容も記述すると、記述量が膨大になるため、部分テンプレートを採用しています。/_card_registration.html.haml.credit-update .credit-update__label クレジットカード情報入力 .card-form .card-form__box = form_tag(cards_path, method: :post, id: 'charge-form', name: "inputForm") do |f| .card-form__box__number %label{class:'box-group--label', for: 'card_number'} カード番号 %span.input-require 必須 = text_field_tag "number", "", class: 'card-number--input', type: "text", id: 'card_number', maxlength: "16", placeholder: "半角数字のみ" .registration-error{type: "hidden", value: "必須項目です"} %ul.card-list -# assets/imagesにimageを設置しており、それをimage_tagで呼び出しています。 %li.card-list--item{ style: "margin-left: 0;"} = image_tag "visa.svg", width:"49", height:"20" %li.card-list--item = image_tag "master-card.svg", width:"34", height:"20" %li.card-list--item = image_tag "saison-card.svg", width:"30", height:"20" %li.card-list--item = image_tag "jcb.svg", width:"32", height:"20" %li.card-list--item = image_tag "american_express.svg", width:"21", height:"20" %li.card-list--item = image_tag "dinersclub.svg", width:"32", height:"20" %li.card-list--item = image_tag "discover.svg", width:"32", height:"20" .card-form__box__expire %label.box-group--label 有効期限 %span.input-require 必須 .card-expire .card-expire__select-month %select#exp_month{name: "exp_month", type: "text"} %option{value: "1"}01 %option{value: "2"}02 %option{value: "3"}03 %option{value: "4"}04 %option{value: "5"}05 %option{value: "6"}06 %option{value: "7"}07 %option{value: "8"}08 %option{value: "9"}09 %option{value: "10"}10 %option{value: "11"}11 %option{value: "12"}12 %i.card-form-expire-icon = image_tag "arrow-bottom.png", size:"16x10",class:"arrow-bottom-icon5" %span{class: "month"} 月 .card-expire__select-year %select#exp_year{name: "exp_year", type: "text"} %option{value: "2019"}19 %option{value: "2020"}20 %option{value: "2021"}21 %option{value: "2022"}22 %option{value: "2023"}23 %option{value: "2024"}24 %option{value: "2025"}25 %option{value: "2026"}26 %option{value: "2027"}27 %option{value: "2028"}28 %option{value: "2029"}29 %i.card-form-expire-icon = image_tag "arrow-bottom.png", size: "16x10",class:"arrow-bottom-icon6" %span{class:"year"} 年 .card-form__box__security-code %label.box-group--label{for: "cvc"} セキュリティーコード %span.input-require 必須 = text_field_tag "cvc", "", class: 'payment__security-code', type: "text", id: "cvc", maxlength: "4" ,placeholder: "カード背面4桁もしくは3桁の番号" .question-form %span.question-form__mark ? %span.question-form__text カード裏面の番号とは? #card_token = submit_tag "追加する", class: "card-form__box__add", id: "token_submit", type: 'button'3.payjp.jsを編集
payjp.jsファイルを作成し、編集します。
checkoutを利用した場合、checkoutが簡単にトークンを作成してくれていましたが、それを利用しないのでpayjp.jsでトークンを生成する処理を記述する必要があります。app/assets/javascripts/payjp.js$(function(){ var submit = document.getElementById("token_submit"); submit.addEventListener('click', function(e){ // 追加するボタンが押されたらイベント発火 e.preventDefault(); // ボタンを一旦無効化 Payjp.setPublicKey("秘密鍵(pk_~)"); var card = { // 入力されたカード情報を取得 number: document.getElementById("card_number").value, exp_month: document.getElementById("exp_month").value, exp_year: document.getElementById("exp_year").value, cvc: document.getElementById("cvc").value }; if (card.number == "", card.exp_month == "1", card.exp_year == "2019", card.cvc == "") { alert("カード情報が入力されていません。"); // 送られた値がデフォルト値だった場合 } else { // デフォルト値以外の値が送られてきた場合 Payjp.createToken(card, function(status, response) { // トークンを生成 if (status === 200) { $("#card_number").removeAttr("name"); $("#exp_month").removeAttr("name"); $("#exp_year").removeAttr("name"); $("#cvc").removeAttr("name"); $("#card_token").append( $('<input type="hidden" name="payjp-token">').val(response.id) ); document.inputForm.submit(); // 生成したトークンを送信する準備を整える alert("登録が完了しました"); } else { alert("正しいカード情報を入力してください。"); } }); } false }); });4.payjp.jsを読み込めるようにする
application.haml.hamlに以下の内容を追記します。
%script{src: "https://js.pay.jp/", type: "text/javascript"}
%script{type: "text/javascript"} Payjp.setPublicKey('公開鍵(pk_~)');
app/views/layouts/application.html.haml%html %head %meta{content: "text/html; charset=UTF-8", http: { equiv: "Content-Type" }} %title FreemarketSample59a = csrf_meta_tags = csp_meta_tag = stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' = javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %script{src: "https://js.pay.jp/", type: "text/javascript"} %script{type: "text/javascript"} Payjp.setPublicKey('公開鍵(pk_~)'); %body = yield5.コントローラを編集
続いてコントローラを編集します。
先ほどはtransacts_controller(商品取引に関する)を編集しましたが、今回は新たにcards_controller(カードに関する)を作成し、それを編集します。app/controllers/cards_controller.rbclass CardsController < ApplicationController require 'payjp' before_action :set_card # 後ほど登録したクレジットの表示画面を作成します。 def index end # クレジットカード情報入力画面 def new if @card redirect_to card_path unless @card else render 'mypages/create_card' end end # 登録画面で入力した情報をDBに保存 def create Payjp.api_key = "秘密鍵(sk_~)" if params['payjp-token'].blank? render 'mypages/create_card' else customer = Payjp::Customer.create( # ここで先ほど生成したトークンを顧客情報と紐付け、PAY.JP管理サイトに送信 email: current_user.email, card: params['payjp-token'], metadata: {user_id: current_user.id} # 記述しなくても大丈夫です ) @card = Card.new(user_id: current_user.id, customer_id: customer.id, card_id: customer.default_card) if @card.save redirect_to cards_path else render 'mypages/create_card' end end end # 後ほど削除機能を実装します。 def destroy end private def set_card @card = Card.where(user_id: current_user.id).first if Card.where(user_id: current_user.id).present? end end秘密鍵を必ず設置するようにしましょう。
6.ルーティングを設定
ルーティングには今後実装するindex、destroyのアクションも記述します。
config/routes.rbresources :cards , only: [:new, :index, :create, :destroy]これでユーザーがクレジットカードを登録できるようになりました。
最後に
本記事の紹介は、一旦ここまでの実装で終わります。
また後日続きの実装を載せたいと考えているので、本記事を通して少しでも読者様の参考になれば幸いです。
また、学習期間3ヶ月の若輩者ですので、記事に多々不備があるかと思います。
ご意見やご質問がありましたらお気軽にご連絡ください。
- 投稿日:2019-10-20T18:15:55+09:00
Railsのmemberとcollectionについての備忘録
routes.rbの設定で使うmember,collectionの違い
Railsのルーターは受け取ったURLをコントローラーに割り当てる役割を持っている。
ルーターを設定する時に、member,collectionという機能について調べたため、備忘録として残す。memberの役割
memberは、特定のモデル(idで判別)に対するアクションを設定する時に使う。
ex)
routes.rbresources :users do member do get 'like' end endルーターの設定like_users GET /users/:id/like(.:format) users#likecollectionの役割
collectionは、全てのモデルに対するアクションを設定する時に使う。
ex)
routes.rbresources :users do member do get 'search' end endルーターの設定search_users GET /users/search(.:format) users#searchまとめ
RESTfulな7つのルーティング以外を設定したい場合、
特定のモデルに対してのアクション
→member
全てのモデルのアクション
→collection
で設定する。
- 投稿日:2019-10-20T17:42:13+09:00
CircleCIでbundler2のインストール時に実行ファイルの削除でYnの入力を求められるやつの対策
CircleCIでbundler2系を使いたいので以下のコマンドを実行するようにしていたが
- run: name: setup bundler 2 command: | sudo gem uninstall bundler sudo rm /usr/local/bin/bundle sudo rm /usr/local/bin/bundler sudo gem update --system sudo gem install bundler以下のログを出してタイムアウトすることがあった
Remove executables: bundler in addition to the gem? [Yn] Remove executables: bundler in addition to the gem? [Yn] Remove executables: bundler in addition to the gem? [Yn] context canceled要はユーザーからの入力を待ってタイムアウトしている。
対策
こうすればよかった
- run: name: setup bundler 2 command: | sudo gem update --system sudo gem uninstall -ax bundler sudo gem install bundle
gem uninstall
はaオプション(バージョン問わず該当するものを全て削除)とxオプション(インタラクティブに実行形式ファイルの削除を問わずアンインストールを続行する)を取れるので、それを指定すればよかった。rmコマンドとかいらない。yesコマンドを使ってもいいのでは?と思ったがなんか動かなかった。理由は調べてないのでわからん。
- 投稿日:2019-10-20T17:32:09+09:00
最近学習したrailsコマンド(Progateにて)
Progateにて最近学習した内容をアウトプッティングしてみた
1.アプリ作成
rails new アプリ名_app
例) rails new tweeeet_app2.機能追加(コントローラー作成)
rails g controller コントローラー名 アクション名
例) rails g controller image indexホームページ作成
例) rails g controller home top3. データベースの追加(テーブル作成)
rails g model テーブル名の単数形 カラム名:データ型
例) rails g model User name:string
※複数カラムを作成したい場合⬇︎
rails g model テーブル名の単数形 カラム名:データ型 カラム名:データ型•••
例) rails g model User name:string number: integer
rails db:migrate
例) rails db:migrate4. データベースに情報追加(カラム追加)
rails g migration データ名(add_カラム名_to _追加先のテーブル名)
例) rails g migration add_nickname_to_users
add_column :テーブル名, :カラム名, :データ型 (migrationファイルの”データ名”の中に記入)
例) add_column :users, :name, :string
rails d:b migrate
例) rails db:migrate〜追記〜
データ型は知る限り3種類あり
- string : 文字列(短い)
- text : 複数行にわたる場合
- integer : 数値
データの値の変換
- .to_s ••• 文字列へ
- .to_i ••• 数値へ
- 投稿日:2019-10-20T16:49:48+09:00
rubyで英語翻訳ごっこ!:正規表現で語順の違いを解決してみた
gsubメソッドで翻訳ごっこして遊んでみた
Rubyという言語には、文字列をお手軽に変換する「gsub」というメソッドがあります。
fruits.rbinput = "apple" input.gsub("apple","banana") #=>"banana"こんな感じで"apple"を"banana"に変えられます。
gsubメソッドを知ったとき、「これで翻訳できるんとちゃう…?」と思ったのでやってみました。
"I love you" を日本語に翻訳するコードを書いてみます。love.rbinput = "I love you" input_1 = input.gsub("I","私は") #=>"私は love you" input_2 = input_1.gsub("love","愛してる") #=>"私は 愛してる you" input_3 = input_2.gsub("you","あなたを") #=>"私は 愛してる あなたを""I love you" ⇒ 「私は 愛してる あなたを」
語順に違和感がありますが、すべての英語を日本語に変えることができました。
ちなみに、もっとコードを短くしたい場合はlove.rbinput = "I love you" input.gsub(/I|love|you/, "I"=>"私は","love"=>"愛してる","you"=>"あなたを") #=>"私は 愛してる あなたを"と書くこともできます。
さて、ここからが本題です。
違和感があるのは、日本語と英語では語順が違うため。
"I love you"で問題になるのは"love"と"you"の順番が逆
という点です。
汎用性も高めたいですね。"I tell you"や"I beg you"にも同じように対応したい。
つまり、「何らかの単語」(空白)"you" ⇒ "you" (空白)「何らかの単語」
に置き換えたい。
「youの前にある単語を、youの後ろにもってくる」コードを書いてみることにしました。
正規表現のキャプチャを使って語順を入れ替える
結論からいくと、こんなコードで出来ました。(実行環境はirb)
love.rb(追加部分)input = "I love you" if input =~ /([A-Za-z]+\s)you/ input.gsub(($1)+"you" , "you\s"+($1)) end #=>"I you love"正規表現っていきなり見ると少しびっくりする方もいると思うので(まさに私がそう)、ゆっくり説明しようと思います。
まずinputの文字列のなかから、「何らかの単語があって、そのあとに空白があって、そのあとにyouと書いてある」部分を探します。
そういう部分のことを正規表現で表すと
/([A-Za-z]+\s)you/ になるのです。
そして、「()」で括られた部分、([A-Za-z]+\s) は今後、($1)という名前でコード上で取り扱えるようになりました。
さて、if input =~ /([A-Za-z]+\s)you/ という処理によって、"I love you"のなかの"love you"というところが抜き出され、"love(空白)" の部分が($1)として扱えるようになりました。
あとは、"($1)+you" をgsubメソッドで変換して、 "you+ \s (空白) +($1)" に変形しました。
このコードで love you を you loveに。
love.rb(追加部分)input.gsub(($1)+"you" , "you\s"+($1))空白を入れないと "youlove" になってしまい、あとで日本語に変換できなくなってしまいます。空白は"\s"で表現できます。
引っかかった点としては、($1)を「""」で囲むと出力がうまくいかないということです。なので「+」を使って文字列を結合させています。
それでは、「"I love you"を正しい日本語の語順で翻訳する」作業をしてみます。
love.rb(追加部分)input = "I love you" if input =~ /([A-Za-z]+\s)you/ input = input.gsub(($1)+"you" , "you\s"+($1)) end #=> "I you love " input.gsub(/I|love|you/, "I"=>"私は","love"=>"愛してる","you"=>"あなたを") #=> "私は あなたを 愛してる "語順が正しくなりました!
私は正規表現がとても苦手なのですが、こういう風に遊んでみた結果ちょっとだけ親しめたよ、という話でした。
正規表現ってテキストやってるだけではとっつきにくいことこの上ないので、手を動かしてみると「意外と簡単じゃん」と思えるかもしれません。最後まで読んでくださった方、ありがとうございました。
間違っているところがあればご指摘ください。
- 投稿日:2019-10-20T16:42:45+09:00
法人番号APIをたたいて、RailsのDBに保存する(バルクインサートではないが。。。)
APIを叩く
法人番号API:
https://www.houjin-bangou.nta.go.jp/webapi/kyuusiyousyo.html上記サイトに記載されているが、利用にあたってアプリケーションIDの発行を申請する必要がある。
詳しくは、HPを。。。https://api.houjin-bangou.nta.go.jp/<バージョン番号>/diff?id=<アプリケーションIDを入れる>&from=2019-04-03&to=2019-04-03&type=12のように期間指定してあげて、URLを送ると
<updateDate>2019-04-03</updateDate> <changeDate>2015-10-05</changeDate> <name>法人番号株式会社</name> <nameImageId/> <kind>30124</kind> <prefectureName>東京都</prefectureName> <cityName>千代田区</cityName> <streetNumber>一番町99番地111</streetNumber> <prefectureCode>13</prefectureCode> <cityCode>1010</cityCode> <postCode>101010101</postCode> <successorCorporateNumber/> <changeCause/> <assignmentDate>2015-10-05</assignmentDate> <furigana>ほうじんばんごう</furigana> ---中略--- <updateDate>2019-04-03</updateDate> <changeDate>2017-10-19</changeDate> <name>HHH HOUJIN株式会社</name> <nameImageId/> <kind>301124</kind> <prefectureName>東京都</prefectureName> <cityName>千代田区</cityName> <streetNumber>大手町123丁目11番2321号大手町セカンドサーキュレートタワー4階</streetNumber> <addressImageId/> <prefectureCode>13</prefectureCode> <cityCode>1014</cityCode> <postCode>124124124</postCode> <assignmentDate>2017-02-28</assignmentDate> <furigana>トリプルエイチ</furigana>※数字は適当、&だいぶ省略してます。
のように返ってくるのでこれをJSON形式に変換して、DBにブッコム。データ保存 & 更新
コントローラーにメソッドを作って、viewから呼び出す。
コードはリファクタリングしてないので、いらないところとか、汚いところありますがご愛嬌でcorporation_number_controller.rbdef index # viewで"update_corp_num"とういparamsを送ってあげて、 # もしparamsの値がそれならupdate_corporate_numberメソッドを呼び出す if params[:update_corp_num] update_corporate_number(params[:q]) return end @q = CorporateNumber.all.order(corporate_number: :desc) -- 中略 -- endcorporation_numbers_controller.rbdef update_corporate_number(params_q) CorporateNumber.delete_all # どの期間で法人番号情報を取ってくるかを指定 # 日付指定が2桁で指定仕上げる必要があったので'%02' % ~ を入れている today = Date.today.months_ago(1) date = today.year.to_s + "-" + ('%02d' % today.month.to_s) + "-" + ('%02d' % today.day.to_s) from_date_i = from_date.year.to_s + "-" + ('%02d' % today.month.to_s) + "-" + ('%02d' % today.day.to_s) # APIをたたいて情報を取得 # APIを叩く = http://...形式でリクエストを送って「情報くれ」ってAPIサーバーに伝えること # (リクエストURIをchromeのURLの場所に貼り付け&Enterでリスポンスみれます) # 今回貼り付けたのは完璧なURIじゃないので見れませんが。。。 uri = URI.parse("https://api.houjin-bangou.nta.go.jp/<バージョン番号>/diff?id=<アプリケーションID>&from=#{date}&to=#{date}&type=12") resp = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http| # よくわからないが、下記二行はつけないとダメらしい(詳しくわかる方教えてください) http.verify_mode = OpenSSL::SSL::VERIFY_NONE http.get(uri) end # jsonの値がresultに入っている result = ActiveSupport::XmlMini.parse(resp.body) ary = [] result["corporations"]["corporation"].each do |item| cnum_company_name = item["name"].values.join cnum_company_prefecture = item["prefectureName"].values.join cnum_company_city = item["cityName"].values.join cnum_company_street = item["streetNumber"].values.join cnum_zipcode = item["postCode"].values.join.to_i cnum_corporate_num = item["corporateNumber"].values.join.to_i # 値がnilで入れられませんってエラーが出たので入れている # 今思えば、compactでやったほうがよかったのかも??。。。 next if cnum_company_name.nil? next if cnum_company_prefecture.nil? next if cnum_zipcode.nil? next if cnum_corporate_num.nil? # 上で作った配列にそれぞれ入れていく ary << CorporateNumber.new( corporate_number: cnum_corporate_num, company_name_jp: cnum_company_name, company_address_jp: cnum_company_prefecture + " " + cnum_company_city + " " + cnum_company_street, company_name_jp_kana: "ふりがな", insert_user_id: 1, update_user_id: 1, update_date: Time.now, insert_date: Time.now ) end CorporateNumber.import hoge redirect_to action: 'index' end今回のでは、一応データ更新はできたが、更新時間が長すぎてtimeoutでアプリケーションが見れなくなってしまう。
なので、リファクタリングで処理時間を短くする必要がある。例えば、今回のはSQL文が一回ごとに発行されてしまうので、バルクインサートを使って一括で入れてあげるとか、each_slice(1000)
&sleep(1)
を使って1000件づつ入れてあげるとか。
- 投稿日:2019-10-20T14:55:40+09:00
Ruby on Railsの基本的な仕組みってどうなってるの?(ルーティング、コントローラー、ビュー)
?? Ruby on Railsの基本的な仕組みってどうなってるの ??
◯ Ruby on Railsのやり始めるとき、大抵の人がビビる! ◯
Ruby on Railsを始めようとするとき、まずはインストールしてみると・・・ビビりました? ビビりますよね!?
私はもともとビビりなので、めちゃくちゃビビりました・・・
たくさんのフォルダ(ディレクトリ)が並んでいて何がなんのか全くわかりませんよね。
そこで、とにかく最初に紐解くべき事(1)が今回のテーマです。
Ruby on Railsをやっている方でしたら、Rubyはもう学習されているはずです。
1、コードを書く
2、ブラウザに結果を表示させる
HTMLやRubyでは、コードを書いたら即、表示を作ることができましたが、
Ruby on Railsでは、この基本的な作業を実行するためには、次の「3つ」を理解する必要があります。1、 ルーティング (routes)
2、 コントローラー (controller)
3、 ビュー (view) → HTML,Rubyで学んできた部分1、 まず、ブラウザを開く際には、そのページのアドレスが必要ですね。
「ルーティング」ではそのアドレスを指定します。2、 次に、1で指定したページのバックグラウンドで作業や設定などの複雑な計算をする部分(アクションと言います)を
「コントローラー」で指定します。3、 最後に、「ビュー」のファイルにHTMLやRubyで実際に表示されるコードを書きます。
ということで、ざっくり手間が「1」と「2」の二つ分増えるわけです。
Ruby on Rails は「ルーティング」や「コントローラー」、「ビュー」などのフォルダ(ディレクトリ)が
それぞれ繋がっていて、それぞれが反映されるようになっているので、離れているフォルダ(ディレクトリ)同士でも
勝手に連携してくれます。どこに何があるのか最初はわかりずらいですが、まずはこの三つの場所と上記のような関係を頭に入れましょう!
- 投稿日:2019-10-20T14:55:40+09:00
Ruby on Railsの基本、基礎的な仕組みが分からない!(ルーティング、コントローラー、ビュー編)
?? Ruby on Railsの基本的な仕組みってどうなってるの ??
◯ Ruby on Railsのやり始めるとき、大抵の人がビビる! ◯
Ruby on Railsを始めようとするとき、まずはインストールしてみると・・・ビビりました? ビビりますよね!?
私はもともとビビりなので、めちゃくちゃビビりました・・・
たくさんのフォルダ(ディレクトリ)が並んでいて何がなんのか全くわかりませんよね。
そこで、とにかく最初に紐解くべき事(1)が今回のテーマです。
Ruby on Railsをやっている方でしたら、Rubyはもう学習されているはずです。
1、コードを書く
2、ブラウザに結果を表示させる
HTMLやRubyでは、コードを書いたら即、表示を作ることができましたが、
Ruby on Railsでは、この基本的な作業を実行するためには、次の「3つ」を理解する必要があります。1、 ルーティング (routes)
2、 コントローラー (controller)
3、 ビュー (view) → HTML,Rubyで学んできた部分1、 まず、ブラウザを開く際には、そのページのアドレスが必要ですね。
「ルーティング」はそのアドレスを指定する所です。2、 次に、1で指定したページのバックグラウンドで作業や設定などの複雑な計算をする部分(アクションと言います)を
「コントローラー」で指定します。3、 最後に、「ビュー」のファイルにHTMLやRubyで実際に表示されるコードを書きます。
ということで、ざっくり手間が「1」と「2」の二つ分増えるわけです。
1ページだけのホームページなら、ルーティングやコントローラーは不要かもしれませんが、
複数のページが連携するようになってくると、1と2の作業が必要になってくるので、まずはここで理解に苦しみます。Ruby on Rails は「ルーティング」や「コントローラー」、「ビュー」などのフォルダ(ディレクトリ)が
それぞれ繋がっていて、それぞれが反映されるようになっているので、離れているフォルダ(ディレクトリ)同士でも勝手に連携してくれます。一つのホームページやシステムを作るのに欠かせない最低限の部分ですので、
どこに何があるのか最初はわかりずらいですが、まずはこの三つの場所と上記のような関係を頭に入れましょう!
- 投稿日:2019-10-20T14:55:40+09:00
〜ダレワカ〜Ruby on Railsの基本、基礎的な仕組みが分からない!(ルーティング、コントローラー、ビュー編)
?? Ruby on Railsの基本的な仕組みってどうなってるの ??
◯ Ruby on Railsのやり始めるとき、大抵の人がビビる! ◯
こんにちは。誰でも分かる 〜ダレワカ〜 のコムリンです。
Ruby on Railsを始めようとするとき、まずはインストールしてみると・・・ビビりました? ビビりますよね!?
私はもともとビビりなので、めちゃくちゃビビりました・・・
たくさんのフォルダ(ディレクトリ)が並んでいて何がなんのか全くわかりませんよね。
そこで、とにかく最初に紐解くべき事(1)が今回のテーマです。
Ruby on Railsをやっている方でしたら、Rubyはもう学習されているはずです。
1、コードを書く
2、ブラウザに結果を表示させる
HTMLやRubyでは、コードを書いたら即、表示を作ることができましたが、
Ruby on Railsでは、この基本的な作業を実行するためには、次の「3つ」を理解する必要があります。1、 ルーティング (routes)
2、 コントローラー (controller)
3、 ビュー (view) → HTML,Rubyで学んできた部分1、 まず、ブラウザを開く際には、そのページのアドレスが必要ですね。
「ルーティング」はそのアドレスを指定する所です。2、 次に、1で指定したページのバックグラウンドで作業や設定などの複雑な計算をする部分(アクションと言います)を
「コントローラー」で指定します。3、 最後に、「ビュー」のファイルにHTMLやRubyで実際に表示されるコードを書きます。
ということで、ざっくり手間が「1」と「2」の二つ分増えるわけです。
1ページだけのホームページなら、ルーティングやコントローラーは不要かもしれませんが、
複数のページが連携するようになってくると、1と2の作業が必要になってくるので、まずはここで理解に苦しみます。Ruby on Rails は「ルーティング」や「コントローラー」、「ビュー」などのフォルダ(ディレクトリ)が
それぞれ繋がっていて、それぞれが反映されるようになっているので、離れているフォルダ(ディレクトリ)同士でも勝手に連携してくれます。一つのホームページやシステムを作るのに欠かせない最低限の部分ですので、
どこに何があるのか最初はわかりずらいですが、まずはこの三つの場所と上記のような関係を頭に入れましょう!
- 投稿日:2019-10-20T14:18:56+09:00
Ruby on Railsにスタイルを反映させる手順
概要
Webアプリのscssファイルを更新しても本番環境に変更が反映されませんでした。
httpdリスタートしたりpassengerをリスタートしたりしま
したが変わらず。。。解決方法
何が問題なのかと調べた結果、こちらを参考にしました。
環境
ruby 2.3.3
rails 5.1.7
SAKURA VPS
CentOS 6手順
$ rm -rf public/assets $ rm -rf tmp/cache $ bundle exec rake assets:precompile $ sudo service httpd restart1,2行目:実行するプロジェクトのassets,cacheフォルダを削除
3行目:プリコンパイルを行う
4行目:httpdをリスタート以上の流れで、変更したscssファイルが反映されました。
私としては、アプリで利用するファイルの一部が残っていたので削除してもう一度作り直す、という理解になっています。何か違う!というのがあれば教えてください!!
- 投稿日:2019-10-20T13:11:25+09:00
Railsを5.0から6.0にアップデートしたらコンソールで日本語が使えなくなった問題の解決
コンソールで日本語を入力したらエラーで強制終了されてしまう
Railsプロジェクトのバージョンを5.0→6.0に上げたら、Rails cで立ち上がるコンソールで日本語を入力すると、
"\xE2" from ASCII-8BIT to UTF-8 (Encoding::UndefinedConversionError)
というエラーが発生し、強制終了するようになった。解決策
Gemfileのdevelopmentグループにある
gem 'rb-readline'
を削除し、$ bundle
を実行する。
これでエラーが発生しなくなりました。
なぜrb-readlineが問題だったのかわかる方、コメントお待ちしています、、、
- 投稿日:2019-10-20T12:27:39+09:00
gnuplotのmacosでaquaterm
gnuplot reinstall <2019-10-20 日>
結論 : 古いgnuplotを入れる.
brewのgnuplotのオプション指定ができなくなったので対処する
に従って.: brew tap ie-developers/ie
: brew install ie-developers/ie/gnuplot --with-cairo --with-aquaterm症状 :
- rubyでgnuplotがないと怒られた.
- gem install numo-gnuplot
- gnuplotがlibなしで動かない.
- brew install gnuplot --with-aquaterm
- したら,--with-aquatermがナイト..
- なしでinstallしたら,今度はnumo/gnuplotで
gnuplot.rb:307:in `run': (Numo::GnuplotError)
- 投稿日:2019-10-20T10:12:53+09:00
Capistranoを使ってRailsプロジェクトをデプロイ
自動化ツールは一度動き出すと便利なんですが、周辺環境の変化に都度追随するのが大変です。いっそherokuとかのPaaSに移ったほうが良いのかもしれませんが、柔軟性の高さが欲しい場合もあるので、もう少し自力で頑張る方向で。
macOSをCatalinaにアップデートしたら、
cap
コマンドが使えなくなっていたので、改めてgemをインストールします。sudo gem install capistrano-bundler capistrano-railsプロジェクト内のCapfileでは以下の3行をコメントアウトします。
capistrano/passenger
は何故か動かない(再起動に失敗する)のでそのまま無効化しています。require "capistrano/bundler" require "capistrano/rails/assets" require "capistrano/rails/migrations" # require "capistrano/passenger"
config/deploy.rb
は以下のように使っています(repo_treeやkeep_releasesは状況や好みによって変わると思いますが)。Rails5.2系になって一番の変化はmaster.key
です。これは git 管理しないことが推奨されているので、別の経路でサーバに転送しておく必要があります。sharedフォルダが(currentやreleasesと並んで)存在しているので、その中に設置しておいて、linked_files
の中に加えて上げると、各リリースの配備時にこのファイルのリンクを作ってくれます。前述したようにPassengerの再起動がうまくいかないので、ここでタスクを定義して配備完了後にApacheを再起動するコマンド(
apachectl restart
)を実行しています。set :application, "myapp" set :repo_url, "git@bitbucket.org:myrepo/myapp.git" set :repo_tree, 'railsapp' set :keep_releases, 3 append :linked_files, "config/master.key" namespace :deploy do after :publishing, :restart desc 'Restart application' task :restart do on roles(:app), in: :sequence, wait: 5 do execute :sudo, 'apachectl restart' end end end
- 投稿日:2019-10-20T01:08:54+09:00
ajaxを活用した非同期通信について
ajaxを使った非同期通信
10月19日現在、ajaxによる非同期通信を学習しているところですが、なかなか理解が追いつかないので自分なりにJavaScriptの復習をかねて中身を確認していきたいと思います。かなり自分向けに書いていますので、語弊がある部分もあるかもしれません。
今回は、ブログに対して投稿されるコメントが非同期通信にて行われるようにしていきます。
イベントの発火
まずは動作のきっかけ部分を記述します。きっかけはコメントを入力し、投稿ボタンをクリックした時です。
comment.js$(function(){ $('#newcomment').on('submit', function(e){ e.preventDefault(); var formdata = new FormData(this); }) })
$(function(){
jQuery(JavaScript)のコードが読み込まれる際に、まだHTMLが読み込まれていないとエラーが発生します。1行目、$(function(){
から書き始めることで、HTMLのページ情報が読み込み完了してからコードが実行されます。
ちなみにこのfunctionメソッド(書き方あっているのかな・・・)では引数は不要ですが、引数がない場合でも()括弧を書く必要があります。
$('#newcomment')
jQueryでどのボタンがトリガーになるかは、HTMLタブ内のclass
もしくはid
から探します。
2行目の$('#newcomment').
はHTML内のid
(newcomment)を探します。#はid
を探す書き方です。
$('.〜')といったように、.
を使うとclass
要素から探されます。
.on('submit', function(e){
イベントsubmit
が起こった際に以下の関数を実施する、という部分。
ちなみにfunction(e)のeはイベントの頭文字。
次の行のe.preventDefault
は実行されるべきイベントをキャンセルさせます。
var 〜〜 = 〇〇
変数〜〜
に〇〇
を代入します。
Rubyだと頭のvar
なんて要りませんでしたが、他のプログラム言語では必要な場合も多いようです。
new FormData(this)
フォームの情報を取得します。引数がthis
の場合、イベントが発生した部分、今回はコメント投稿の部分からの取得になります。コメントの保存
非同期通信の中で、入力したコメントがcreateメソッドで保存されるようにします。
comment.js$(function(){ $('#newcomment').on('submit', function(e){ e.preventDefault(); var formdata = new FormData(this); $.ajax({ url: $(this).attr('action'), type: "POST", data: formData, dataType: 'json', proseccData: false, contentType: false }) }) })
$.ajax({
ajaxで非同期通信をする際のオプションを記述します。
1.type HTTP通信の種類を記述。GETもしくはPOST。
2.url リクエスト送信先のURLを記述。
3.data 送信する値を記述。
4.dataType データの種類を記述。今は基本的にjson
5.processData
6.contentType データのファイル形式を指定。基本false
attr
要素が持つ属性から、指定した属性の値を返します。
今回では投稿ボタンを含むformタグの中からaction要素を探し、その値となるURLを取得するようにします。以上の記述で、ajaxで扱われるデータは
「json形式でテキストボックス内の文字をPOSTでコメント投稿のアドレスへ送信」
となります。すなわちコメントが投稿される形となります。返ってくる結果を受け取る
.doneメソッドで非同期通信の結果を受け取ります。
comment.js.done(function(data){ $('.comments').append(〜〜) $('.textbox').val('') }) .fail(function(){ alert('error') })
.done
メソッドで、受け取った結果を元に処理を行います。
comments
クラスの後ろに()内の記述を追加します。詳細は省略。
textbox
クラスの値を空にします。今回はフォームボックスの中をクリアします。
.fail
メソッドは、エラーが発生した時に表示させる処理です。
alert
メソッドはポップアップを表示させます。こんな感じなんでしょうか。
まだなんとなく程度の理解ですので、もっと精進していきます。
- 投稿日:2019-10-20T01:08:54+09:00
Ajaxを活用した非同期通信について
ajaxを使った非同期通信
10月19日現在、ajaxによる非同期通信を学習しているところですが、なかなか理解が追いつかないので自分なりにJavaScriptの復習をかねて中身を確認していきたいと思います。かなり自分向けに書いていますので、語弊がある部分もあるかもしれません。
今回は、ブログに対して投稿されるコメントが非同期通信にて行われるようにしていきます。
イベントの発火
まずは動作のきっかけ部分を記述します。きっかけはコメントを入力し、投稿ボタンをクリックした時です。
comment.js$(function(){ $('#newcomment').on('submit', function(e){ e.preventDefault(); var formdata = new FormData(this); }) })
$(function(){
jQuery(JavaScript)のコードが読み込まれる際に、まだHTMLが読み込まれていないとエラーが発生します。1行目、$(function(){
から書き始めることで、HTMLのページ情報が読み込み完了してからコードが実行されます。
ちなみにこのfunctionメソッド(書き方あっているのかな・・・)では引数は不要ですが、引数がない場合でも()括弧を書く必要があります。
$('#newcomment')
jQueryでどのボタンがトリガーになるかは、HTMLタブ内のclass
もしくはid
から探します。
2行目の$('#newcomment').
はHTML内のid
(newcomment)を探します。#はid
を探す書き方です。
$('.〜')といったように、.
を使うとclass
要素から探されます。
.on('submit', function(e){
イベントsubmit
が起こった際に以下の関数を実施する、という部分。
ちなみにfunction(e)のeはイベントの頭文字。
次の行のe.preventDefault
は実行されるべきイベントをキャンセルさせます。
var 〜〜 = 〇〇
変数〜〜
に〇〇
を代入します。
Rubyだと頭のvar
なんて要りませんでしたが、他のプログラム言語では必要な場合も多いようです。
new FormData(this)
フォームの情報を取得します。引数がthis
の場合、イベントが発生した部分、今回はコメント投稿の部分からの取得になります。コメントの保存
非同期通信の中で、入力したコメントがcreateメソッドで保存されるようにします。
comment.js$(function(){ $('#newcomment').on('submit', function(e){ e.preventDefault(); var formdata = new FormData(this); $.ajax({ url: $(this).attr('action'), type: "POST", data: formData, dataType: 'json', proseccData: false, contentType: false }) }) })
$.ajax({
ajaxで非同期通信をする際のオプションを記述します。
1.type HTTP通信の種類を記述。GETもしくはPOST。
2.url リクエスト送信先のURLを記述。
3.data 送信する値を記述。
4.dataType データの種類を記述。今は基本的にjson
5.processData
6.contentType データのファイル形式を指定。基本false
attr
要素が持つ属性から、指定した属性の値を返します。
今回では投稿ボタンを含むformタグの中からaction要素を探し、その値となるURLを取得するようにします。以上の記述で、ajaxで扱われるデータは
「json形式でテキストボックス内の文字をPOSTでコメント投稿のアドレスへ送信」
となります。すなわちコメントが投稿される形となります。返ってくる結果を受け取る
.doneメソッドで非同期通信の結果を受け取ります。
comment.js.done(function(data){ $('.comments').append(〜〜) $('.textbox').val('') }) .fail(function(){ alert('error') })
.done
メソッドで、受け取った結果を元に処理を行います。
comments
クラスの後ろに()内の記述を追加します。詳細は省略。
textbox
クラスの値を空にします。今回はフォームボックスの中をクリアします。
.fail
メソッドは、エラーが発生した時に表示させる処理です。
alert
メソッドはポップアップを表示させます。こんな感じなんでしょうか。
まだなんとなく程度の理解ですので、もっと精進していきます。
- 投稿日:2019-10-20T00:51:06+09:00
Rubyのシンタックス勉強用(組み込みクラス Fileクラス、Dirクラス)の挙動 [RUBY技術者認定試験...問題45,46,47,48,94,95,96,97,98]
基本説明
- Fileクラス:ファイル名の変更やコピーや削除、ファイル情報の取得などの機能がある
- Dirクラス:ディレクトリ情報の取得、ディレクトリ中のファイル一覧、ディレクトリの作成や削除の機能がある
組み込みクラス Fileクラス
File#dirname
File#dirnameは、最後のスラッシュの左側を文字列として返します。文字列にスラッシュがない場合は
.
を返します。p File.dirname('/hoge/fuga/test.txt') # => "/hoge/fuga" p File.dirname('$LIB') # => "."(RUBY技術者認定試験...問題45)
ファイルの読み書き
File.openのモード |
r+
| 読み書き両方 / ファイルの読み書き位置は先頭にセット
r
は読み出しだけFile.openのモード |
w+
| 読み書き両方 / オープン時にファイルがあれば内容を空にする
w
は書き込みだけ、あとは同じFile.openのモード |
a+
| 読み書き両方 / オープン時にファイルがあれば、ファイルの読み書き位置は末尾にセット
a
は書き込みだけ、あとは同じ(RUBY技術者認定試験...問題46)
RUBY技術者認定試験...問題47
以下のコードの実行結果は?的な問題があります。
File.open('foo.txt') do |io| while ! io.eof? # ファイルの終端に達した場合、true / そうでない場合 false print io.read(1) # 読み込む io.seek(1, IO::SEEK_CUR) # 現在の位置から1文字移動 end end# => 結果 acdfhjlnprtvxz
RUBY技術者認定試験...問題95
以下のコードの実行結果は?
file = File.open('foo.txt') file.seek(2) # ファイルポインタの位置が先頭から2バイト移動する print file.gets # 1行読み込んで表示# => 結果 cd
RUBY技術者認定試験...問題96
選択肢
- 1. gets - 2. readline - 3. readlines - 4. readファイルを1行ずつ読み込むメソッドでお馴染みなのは
gets
とreadline
です。両者の違いは、終端に達した時の挙動です。
- gets:これ以上読む行がない時は nil を返す
- readline:これ以上読む行がない時は 例外(EOFError) を返す
問題を見ると、レスキューでキャッチしているので、正解は2ですね。
RUBY技術者認定試験...問題97
以下の結果になるメソッドは?
選択肢
- 1. concat - 2. add - 3. join - 4. create_path正解は3なのですが、Fileクラスのメソッド
join
は、パス名の区切り文字(/
)を間に入れて文字列を連結します。URLを作成するときに使用します。組み込みクラス Dirクラス
カレントディレクトリ内の、特定のワイルドカードに一致するファイルの一覧を取得して表示するコードを2パターン書きます。
files = Dir.glob("*.rb") # files = Dir["*.rb"] files.each{ |file| p file }# files = Dir.glob("*.rb") files = Dir["*.rb"] files.each{ |file| p file }(RUBY技術者認定試験...問題48)
RUBY技術者認定試験...問題98
この中で、Dirクラスのクラスメソッドでないものは?
- 1. Dir.rmdir - 2. Dir.basename - 3. Dir.pwd - 4. Dir.extname - 5. Dir.getwd正解(Dirクラスのクラスメソッドでないもの)は、
2
、4
です。この2つは、Fileクラスのメソッドです。filename = '/hoge/fuga/test.txt' p File.basename(filename) # => "test.txt" p File.basename(filename, '.txt') # => "test" p File.dirname(filename) # => "/hoge/fuga" p File.extname(filename) # => ".txt" p File.split(filename) # => ["/hoge/fuga", "test.txt"]実行結果は以下でサクッと試せます
Online Ruby Editor and IDE - Fast, Powerful, Free - Repl.it
参考
- 日経BP SHOP|Ruby技術者認定試験 公式ガイド https://shop.nikkeibp.co.jp/front/commodity/0000/181950/
- class IO (Ruby 2.6.0) https://docs.ruby-lang.org/ja/latest/class/IO.html#I_EOF
- 投稿日:2019-10-20T00:49:17+09:00
本日の学び #4
配列に要素を追加する
ary.push("yey") ary << "yey"
Enumerable#max
,Enumerable#min
最大、最小の要素を返す。
改行なしで出力
numにnが含まれるかどうかの判別
num = 916 puts num.to_s.include?("1") #=> true2つの配列から重複を省いたり、重複を得たり
a = [1,2,3] b = [2,3,4] a - b #=> [1,4] a & b #=> [2,3]
Array#sort
ary = [2,3,6,4,8,9,5,7,1] p ary.sort #=> [1,2,3,4,5,6,7,8,9] p ary.sort { |a, b| b <=> a } #=> [9,8,7,6,5,4,3,2,1]
Float#floor
自身と等しいかより小さな整数のうち最大のものを返します。
(-1.2).floor #=> -2
case
のメリット
- 調べる値を範囲や配列や複数の値を指定できるので柔軟
- 複数の条件が分岐するとき見やすい
*Array
変数呼び出し時に引数に*をつけると配列を引数として渡すことができる
お世話になりました
・配列に要素を追加する
・複数の配列を比較し重複する値を取る
・ruby引数処理に使えるテクニック
・Array#sort
・Float#floor
・制御構造 case感想
paizaの使用する言語を毎回指定して、自動入力されるサンプルコードを消す作業が、非常にめんどくさい。
あと、終わった問題を解いた順に並べてほしい。
- 投稿日:2019-10-20T00:16:19+09:00
Ruby on Railsでログイン機能を作ろう2
前回ログイン機能を作った続き。
https://qiita.com/clipbord/items/0a716b797115f1368df1細かいところを整えたり、アクセス制限かけたりしています。主にリンクメモです。
空白入力時のエラーメッセージの日本語化
https://qiita.com/Ushinji/items/242bfba84df7a5a67d5bFlashメッセージ
https://pg-happy.jp/rails-flash-message.htmlbootstrap導入
https://qiita.com/tqkqt0/items/d9a3f3416c242ba48ba0text_fieldにclassを書く
https://qiita.com/KeyG/items/10691b0558ca0d0353b3バリデーションエラー時のレイアウト崩れ修正
https://blazing.hatenablog.com/entry/2018/12/07/093314ログイン・ログアウト判定
https://qiita.com/tobita0000/items/866de191635e6d74e392アクセス制限
ログインユーザのみ確認可application_controller.rbbefore_action :set_current_user def set_current_user @current_user = User.find_by(id: session[:user_id]) end def authenticate_user if @current_user == nil flash[:notice] = "ログインが必要です" redirect_to(users_login_path) end enduser_controller.rbbefore_action :authenticate_user, only: [:index,:show,:edit,:create,:update,:destroy]欄外
devise使用。
色々調べてたら、deviseを使ったログイン機能の作成というものが出てきたので、
新しくプロジェクト作ってやってみた。次作る時はこちらをベースにしようと思った。