- 投稿日:2020-09-24T23:47:03+09:00
Ruby on Rails 〜MVCとルーターの基礎〜
はじめに
本記事では、MVC(Model(モデル)、View(ビュー),Controller(コントローラー)とRouter(ルーター)の関連を確認しながら、用語について解説していきます。
Router(ルーター)とは
RouterはHTTPリクエストがあったURLに対して、アプリケーション内のどの機能を結びつけるを決める役割を果たします。そして次に説明するControllerに1つのメソッドを割り当てます。
Controller(コントローラー)
"Controller"はMVCパターンの司令塔的役割を果たします。
これは、ユーザから送られてきたHTTPリクエストの処理を担当します。そのHTTPリクエストはRouterからControllerの1つメソッドと結びつきます。
そしてControllerはHTTPリクエストに対応したModelの作成や取得、取得した値をViewに渡して処理を行わせる、というようなことを行います。
つまりModelやViewに命令を出すことがControllerの仕事です。Model(モデル)
"Model"はデータとやりとりをしてくれる存在です。
Controllerからの命令に従い、データベースから情報を取得したり、データを更新したり、書き込んだり、データを消去したりします。
データベースと直接やりとりできるのはModelだけです。View(ビュー)
ViewではControllerから渡されたデータを、HTMLページでどのように表示するかを定義します。最終的にHTTPレスポンスとして返すWebページです。
Viewでは見た目の部分だけでなく、Controllerによって選択された適切なModelが埋め込まれます。まとめ
これを一連の流れにしてまとめます。
RouterはHTTPリクエストを受け取り、適切なアクションとひも付けます。
Controllerはそのアクションを実行してModelやVeiwに指示を出して、ViewをHTTPレスポンスとして返すと行ったところでしょうか。
- 投稿日:2020-09-24T23:44:00+09:00
【Rails】ページの上部に戻るボタン
はじめに
・Railsを使用してアプリケーションを開発
・viewsの下部地点から上部に戻るボタンを設置するRuby 2.5.7
Rails 5.2.4.4流れ
・
gem 'jquery-rails'
を導入
・アクションを起こすボタンを用意(画像でなく文字やfont-awesome等でも代用可能)
・viewにボタンを記載しcss及びjavascriptへ追記ボタン画像
適当に準備します・・・
画像ファイルをapp/assets/images配下に格納
viewsへ追加
<span id="top-btn"> <a href="#"> <%= image_tag asset_path('top_btn.png'), class: 'top-btn' %> </a> </span>・asset_path('~~') は、app/assets/images配下の画像を読み込む
css 及び jsファイルへ追記
.top-btn { position: fixed; right: 30px; bottom: 40px; } .top-btn a { width: 50px; height: 50px; }$(function() { $('#top-btn a').on('click',function(event){ $('body, html').animate({ scrollTop:0 }, 1000); event.preventDefault(); }); });初期状態(ページの上部)では表示したくない場合?
$(function() { var topBtn = $('#top-btn a'); topBtn.hide(); $(window).scroll(function(){ if ($(this).scrollTop() > 100) { topBtn.fadeIn(1000); } else { topBtn.fadeOut(); } }); topBtn.click(function () { $('body, html').animate({ scrollTop:0 }, 1000); event.preventDefault(); }); });fadeIn 及びfadeOut のif文にてボタンの表示を設定しています・・
終わり
上記記載内容で、実装できるはず・・・
不明点及び説明がずれている(誤っている等)ございましたら、コメントにてにてお伝えいただければありがたいです。以上、ご参考になれば幸いです。
- 投稿日:2020-09-24T23:15:49+09:00
再帰処理の流れについて基本的な理解を目指す
「自分自身を呼び出す」再帰的関数に関するコード記述を読んでも、なかなか理解が追い付かずに折れかけたので、自戒を込めて「再帰処理の流れについて基本的な理解を目指す」をテーマに記事を書いてみたいと思います。
下記のシンプルなコードを用いてどのような流れで関数が実行されているか、考えてみます。再帰的関数
1 def recursive(n) 2 p 'a' 3 p n 4 return 1 if n == 0 5 p n 6 n * recursive(n - 1) 7 p 'b' 8 p n 9 end 10 11 p recursive(5)初見、なぜ数字が0から増えていくのかがまったく分からずに混乱しました。
「関数が関数を内包している」様子をイメージしながら、再帰的関数の仕組みについて、下記のように自分なりにかみ砕いてアウトプットしてみます。おおまかな流れ
(1)引数として5が与えられて関数実行
→(2)p "a"から5行目のp nまでが実行される(※当然、後置if文returnは実行されない)
→(3)6行目で、自身の関数recursive(4)が実行される。
→(4)ループのように、上記(2)から(3)が、recursive(0)まで実行される。(※この時点で、「(省略)..."a", 1 , 1」まで処理されている」)
→(5)recursive(0)実行時、 p "a"から3行目のp nまでが実行されたのち、後置if文 returnが実行される。returnにより、recursive(0)関数処理が終了。
→(6)ここからは、巻き戻し?逆行?の様な状態になる。
実行場面がrecursive(1)に戻り、7行目の"b"、8行目のp n(※nは1)が実行され、recursive(1)終了。
→(7)実行場面がrecursive(2)へ戻り、7行目の"b"、8行目のp n(※nは2)が実行され、recursive(2)終了。
→(recursive(4)まで省略)
→(8)実行場面がrecursive(5)へ戻り、7行目の"b"、8行目のp n (※nは5)が実行され、recursive(5)が終了しすべての関数が完結。
→(9)最後に、p recursive(5)(p nと同義で)5が出力され、終了。(※仮にpメソッドを除くと、最後の5は出力されない。)・・・個人的に再帰的関数はかなり理解が難しいです。
場数をこなして慣れていくのがいいのかなと少し頭を悩ませつつ、筆をおきます。
- 投稿日:2020-09-24T23:05:37+09:00
単体テスト時、ActiveRecordの暗黙的型変換でハマった話
事象
以下の単体テストコードが失敗してしまう。
item_spec.rbit 'priceが半角数字でなければ保存できないこと' do @item.price = '1000' @item.valid? expect(@item.errors.full_messages).to include('Price Half-width characters.') end原因
integer型の項目「price」への文字列「1000」代入時、
暗黙的型変換が行われ、priceには数値「0」が代入されたため。↓暗黙的型変換が行われる様子をコンソールで確認↓
irb(main):002:0> @item.price = '1000' => "1000" irb(main):003:0> @item.price => 0文字列「1000」を代入した後のpriceの値は数値「0」となります。
これはRails 5から追加された「ActiveRecord Attributes API」という機能によるものです。
暗黙的型変換は裏で以下のようなセッターが動いているイメージです。
to_iしているところがポイントです。# セッター def price=(price) @price = price.to_i end結論
Itemモデルに以下の記述をすることで解決
item.rbclass Item < ApplicationRecord attr_accessor :price【解説】
attr_accessorは項目に対してセッター・ゲッターの処理を実現できるメソッドです。
以下の記述と「attr_accessor :price」は同じ意味です。# セッター def price=(price) @price = price end # ゲッター def price @price endつまり、これで純粋なセッター(to_iしない)が呼び出されることによって、
to_iされない文字列をpriceに代入できるようになります。irb(main):002:0> @item.price = '1000' => "1000" irb(main):003:0> @item.price => "1000"【参考リンク】
「ActiveRecord Attributes API」の仕組みについては、以下の記事を参考にさせていただきました。
https://www.wantedly.com/companies/wantedly/post_articles/31132
- 投稿日:2020-09-24T23:01:34+09:00
Rails APIモード キーワード複数検索機能を配列と繰り返し処理を使って実装してみた。
機能として成り立つ前
def keyword if params[:keyword] keywords = params[:keyword].split(/[[:blank:]]+/).select(&:present?) keywords.each do |keyword| offices = Office.where('name LIKE ? OR address LIKE ? OR near_station LIKE ? OR introduction LIKE ? OR company LIKE ?',"%#{keyword}%", "%# {keyword}%", "%#{keyword}%", "%#{keyword}%", "%#{keyword}%") end else pagy, offices = pagy(Office.all) pagy_headers_merge(pagy) end render json: offices, each_serializer: OfficeIndexSerializer, include: '**' endこのような記述で彷徨っていた。理由としては、1単語では検索可能だが、複数キーワード(例えば,「東京 福岡」のような検索方法では、福岡という文字だけでしか検索できないような状態だった。
気になっていた点
- each文を使って繰り返し処理を書いているが、これがそもそも機能していないっぽい。
- where句の中身の記述があっているのか自信がない・・・。
最終的なコード
def keyword if params[:city_id] offices = Office.where(city_id: params[:city_id]) elsif params[:keyword] keywords = params[:keyword].split(/[[:blank:]]+/).select(&:present?) offices = [] keywords.each do |keyword| offices += Office.where('name LIKE (?) OR address LIKE (?) OR near_station LIKE (?) OR introduction LIKE (?) OR company LIKE (?)',"%#{keyword}%", "%#{keyword}%", "%#{keyword}%", "%#{keyword}%", "%#{keyword}%") end else pagy, offices = pagy(Office.all) pagy_headers_merge(pagy) end render json: offices end変わった点としては、
offices = []
を加えた。キーワードを格納する箱を作るイメージ。
そして、office += Office.where
と、where句内の?に()を加えた。これにより、「東京」というような1単語のみのキーワード検索のみならず、「東京 福岡 千葉」というような複数キーワードに関しても検索機能として成り立たせることができた。
- 投稿日:2020-09-24T22:02:21+09:00
[Rails][jQuery] remote:trueとjs.erbを使って非同期のいいね機能実装
概要
Railsプロジェクトで掲示板サイトを作成中、
remote:true
とjs.erbファイル
を用いた非同期のいいね機能を実装する機会がありました。
備忘録としてここに手順を残しておきます。前提
Rails 5.0
favorites_tableの作成
とモデルのアソシエーションを定義
は既にされているものとします。アソシエーション:
users - has_many :posts, has_many :favorites
posts - belongs_to :user, has_many :favorites
favorites - belongs_to :user, belongs_to :post
jQueryの準備
Rails内でjQueryを使えるように準備します。
まずはgemの導入します。Gemfilegem 'jquery-rails'ターミナルで
bundle install
します。
そしてapplication.js
に記述を追加します。application.js# Rails5.1より前の場合 //= require jquery //= require jquery-ujs # バージョンがRails5.1以降の場合 //= require jquery //= require rails-ujs今回は、Rails 5.0 を使っているので
jquery_ujs
をrequire
してあげてください。
この場合、必ずjqueryを先にrequireするようにしてください。ちなみに
rails-ujs
はRails5.1
よりデフォルトで搭載されているので、application.jsにてrequireしてあげるだけで大丈夫です。ルーティングの設定
createアクションをpostメソッド、destroyアクションをdeleteメソッドを使ってルーティングを記述します。
オプションでas:を記述することでPrefixの名前を指定できます。routes.rbpost '/favorite/:post_id' => 'favorites#create', as: 'like' delete '/favorite/:post_id' => 'favorites#destroy', as: 'unlike'favorites_controllerの作成
いいねのcreateとdestroyを定義します。
app/controllers/favorites_controller.rbclass FavoritesController < ApplicationController before_action :set_post def create @favorite = Favorite.create(user_id: current_user.id, post_id: @post.id) end def destroy @favorite = Favorite.find_by(user_id: current_user.id, post_id: @post.id) @favorite.destroy end private def set_post @post = Post.find(params[:post_id]) end end部分テンプレートでviewを作成
使い回ししやすいように、部分テンプレート化しています。
app/views/users/show.html.erb<%= render 'posts/posts', posts: @posts %>app/views/users/_post.html.erb<% posts.each do |post| %> <div id="favorite-<%= post.id %>"> <%= render partial: "favorites/favorite", locals: { post: post } %> </div> <% end %>jsでイベントを発火させるためには、idまたはclassでセレクタを指定しますが、今回はどのpostに対するいいねなのかを判別するために、id内にそのpostのidを含める必要があります。
上のように書くことによって、id="post-1"のようなidを指定することができます。app/views/favorites/_favorite.html.erb<% if Favorite.find_by(user_id: current_user.id, post_id: post.id) %> <%= link_to "いいね", unlike_path(post.id), method: :delete, remote: true, class: "btn btn-default" %> <% else %> <%= link_to "いいね", like_path(post.id), method: :post, remote: true, class: "btn btn-success" %> <% end %> <%= post.favorites.length %>いいねボタンのlink_toにremote: trueを追加します。
この記述により、通常であれば、link_toで呼ばれるアクションに対応するhtml.erbファイルを呼び出すところ、js.erbファイルを呼び出せるようになります。
なのでページ遷移を行わず非同期で通信が行われるようになります。
最後にいいね数を<%= post.favorites.length %>
で表示しています。js.erbファイル作成
まずはcreateとdestroyそれぞれのアクションに対応するjs.erbファイルを作成します。
app/views/favorites/create.js.erb
app/views/favorites/destroy.js.erb
app/views/favorites/create.js.erb$("#favorite-<%= @post.id %>").html("<%= j(render partial: 'favorites/favorite', locals: { post: @post }) %>");app/views/favorites/destroy.js.erb$("#favorite-<%= @post.id %>").html("<%= j(render partial: 'favorites/favorite', locals: { post: @post }) %>");まずはセレクタの指定ですが、
id="favorite-<%= post.id %>
に対応するように指定します。
そして、jQueryのhtml()メソッドで、指定したセレクタのhtmlを置き換えます。置き換える内容が
"<%= j(render partial: 'favorites/favorite', locals: { post: @post }) %>"
の部分で、部分テンプレートの_favorite.html.erb
を呼び出しています。
(renderの前にあるjは、escape_javascriptのエイリアスで、改行と括弧をエスケープしてくれるメソッドです。)これで非同期のいいね機能実装完了です!
最後に
ここまで読んでいただきありがとうございます。
間違っている点などがありましたらご指摘いただきますよう、よろしくお願いいたします。
- 投稿日:2020-09-24T21:30:39+09:00
2020年で最も需要のあるプログラミング言語
本記事はMost in-demand programming languages in 2020の日本語訳です。翻訳元に報告していますが、もし苦情が来たら消します。
翻訳は不慣れなので変なところもあると思いますが、ご容赦ください。
ソフトウェア開発業界は絶えず変化しており、それは開発者の能力に対する企業のニーズも変化していることを意味します。そのため、あなたが想像できるように、Webアプリケーション、ゲーム、アルゴリズムなどのあらゆる側面の開発をカバーするために、選択できるプログラミング言語はたくさんあります。その上で、私たちは2020年で最も需要のあるプログラミング言語とその主な特徴について触れます。
- JavaScript (回答者の71%がこのスキルに関する求職者を探している)
- Java (57%)
- C# (53%)
- Python (51%)
- PHP (40%)
- Ruby (15%)
JavaScript
JavaScriptが2020年で最も需要のあるプログラミング言語リストのトップであることは全く不思議ではありません。
今日では何らかの方法でJavaScriptを使用することなしに開発者になることは不可能です。調査の回答者の71%以上がJavaScriptでコードを書ける開発者を探しており、JavaScriptが最も人気のあるプログラミング言語のうちの一つであることが想像できます。また、JavaScriptはWebにおける偏在性と私たちのインターネットへの重い依存のため、非常に人気があります。Twitter、Facebook、YouTubeなどの最も人気のあるサイトの多くは、JavaScriptを使ってインタラクティブなWebページを生成したり、コンテンツを動的にユーザに表示したりしています。
JavaScriptはコア言語があり、追加の開発ツールによって柔軟性が保たれています。JavaScriptは寛大で柔軟な構文を持ち、全てのメジャーなブラウザで動作するため、初学者にとって最も簡単なプログラミング言語の一つです。今日、JavaScriptは世界中で広く使用されているプログラミング言語であり、あらゆるところで動作します:コンテナ、マイクロコントローラ、モバイル端末、クラウド、ブラウザ、サーバなど。
主な特徴
- JavaScriptはここ数年で大規模な現代化と徹底的な点検を経てきました。ES5、ES6といったJavaScriptのメジャーなリリースはいくつかのモダンな機能が追加され、今日のJavaScriptは過去10年間のJavaScriptとは完全に別物です
- Node.jsのおかげでJavaScriptはイベント駆動なプログラミングを提供し、特にI/Oの複雑なタスクに適しています。今日では、Node.jsとJavaScriptは、サーバとモバイル端末を含めてほとんど全てのプラットフォームで動作します
- JavaScriptはブラウザプログラミングにおいて、議論の余地のない王様です。今日、Web開発は主にVue.js、Angular、ReactといったJavaScriptベースのSPAフレームワークによって支配されています
Java
Javaは2020年で最も需要のあるプログラミング言語リストで2位の座を手にしています。
Javaは、ビジネスでは最も人気のモバイルコンピューティングプラットフォームであるAndroidのネイティブ言語であることから人気のあるプログラミング言語です。
Javaは過去数年の間に、非常にユーザに優しいモダンな言語にビジネスの一部を奪われました。
Javaは欠陥の改善に取り組んでおり、GraalVMアクションを介してクラウドにフィットさせる努力をしています。Javaはまだエンタープライズではナンバーワンのプログラミング言語です。Javaは誕生してからずっとトップクラスの需要があるプログラミング言語です。大企業の多数がバックエンドWebシステムやデスクトップアプリケーションのためにJavaを使っているため、もし開発者がJavaを知っていれば、その開発者は継続的に需要が高い状態になるでしょう。Javaは静的型付けの言語で、そのためバグが少なく、メンテナンスを速く行えて管理しやすいです。
主な特徴
- Javaはマルチパラダイムを提供し、強力で、多機能で、柔軟な学習曲線と高い生産性を持つインタプリタ型のプログラミング言語です
- Javaは厳格な後方互換性を持ち、これはビジネスアプリケーションにとって重要な要件です。JavaではScalaやPythonのようなメジャーな破壊的変更が取り入れられたことはありません。その結果、Javaはいまだにビジネスにとってナンバーワンの選択肢です
- JavaのランタイムであるJVMはソフトウェア工学の結晶で、ビジネスにおいて最高の仮想マシンの一つです。何年もの技術革新とエンジニアリングの職人技により、JVMは素晴らしい機能と性能をJavaに提供します。JVMはいくつかの優秀なガベージコレクションもJavaに提供しています
C#
C言語は、移植性と、AppleやMicrosoftのような巨大なIT企業から早期に採用されたことのおかげで最も古くて最も人気のあるプログラミング言語のうちの一つとなった言語です。1
C-sharpとしても知られるC#は、2000年にMicrosoftによって開発された言語のスピンオフです。C#はオブジェクト指向言語で、アクションの代わりにオブジェクトを中心に、ロジックの代わりにデータを中心に構築されます。C#の特徴はJavaと似ており、Windowsのデスクトップアプリケーションとゲームを開発するのに特に有効です。しかし、C#はWebアプリケーションとモバイルアプリケーションを開発するのにも使えます。C#はC++のようなC派生の言語に似た構文を使っており、あなたがCファミリーの中の別の言語から来たのであれば簡単に習得できます。C#は銀行のトランザクション処理のような大企業のアプリケーションの開発にしばしば使われます。C#は人気のUnityゲームエンジンを使った2Dや3Dのビデオゲームを作るために推奨される言語です。今日では、C#はWindowsプラットフォームにおいてだけでなくLinuxプラットフォームやiOS/Androidプラットフォームでも幅広く使用される、マルチパラダイムな言語です。
主な特徴
- C#はプラットフォーム非依存でもあり、Linux、Windows、モバイル端末で動作します
- Microsoftの後ろ盾があり、長年に渡り業界にいるC#はライブラリとフレームワークの大きなエコシステムがあります。ASP.NETはWebアプリケーション開発に使われます(主にWindows上での)
- 開発者体験という面では、C#はJavaよりはるかに優れています
Python
Pythonはおそらくこのリストの中で最もユーザに優しいプログラミング言語です。Pythonの構文は明確で、直感的で、ほとんど英語だとよく言われ、初学者にとって本当に良い選択肢です。Pythonは高レベルで、汎用性が高く、Webアプリケーションやデータ解析、アルゴリズムの開発などに使われます。Pythonは、科学計算やエンジニアリング、数学といったフィールドで頻繁に使われるSciPyやNumPyのようなパッケージも持っています。
Pythonはスクレイピングにしばしば使われ、PHPでコーディングするのに何時間もかかるものが、Pythonだと数分しかかかりません。Pythonは、あなたの時間を消費する日々のタスクを含む特定の作業を自動化するためにも使うことができます。もしバックエンドのWeb開発の例に興味があれば、オープンソースの(Pythonで書かれた)Djangoフレームワークは人気で、学ぶのが簡単で、多機能です。そしてJavaのように、Pythonには多様なアプリケーションがあり、あなたのユースケースのために最も良いプログラミング言語を選択する時に、多様で強力な選択肢となります。今日、Pythonは広く行き渡り、ソフトウェア開発の多くの分野で使用され、そしてその勢いが衰えるようには見えません。
主な特徴
- Pythonには非常に活発なコミュニティとサポートがあります。たとえあなたがデータサイエンス、業務アプリケーション、AIのどれで働いているのだとしても、常に十分なPythonの組織2やフレームワークが見つかります
- Pythonには第一級のC++/Cとの統合機能があり、CPU負荷の高いタスクをシームレスにC++/Cにオフロードすることができます。Pythonは、SciPy、Pandas、NumPyなど、統計、Scikit-Learn3、数学、および計算科学のための素晴らしいツールセットも提供します。 結論として、Pythonは機械学習/ディープラーニング/データサイエンスの状況やその他の科学的な領域を支配しています
- Pythonのウリはその言語設計にあります。それは生産性が高く、エレガントで、シンプルで、その上強力です。Pythonは開発者経験という面で黄金律を設定し、Julia、Goといったモダンな言語に対して多大な影響を与えました
PHP
たとえ多くの論争があるとしても、PHPは2020年で最も需要のあるプログラミング言語リストに入っています。
PHPは幅広く使用されているオープンソースの汎用スクリプト言語で、典型的にはWebアプリケーション開発に適しています。たとえ以前ほどではないとしても、PHPは依然として世界中で最も用いられているプログラミング言語のうちの一つです。PHPはFacebookやYahoo!といった多数の大きな会社によって使用されています。PHPは汎用的で、動的な、基本的にはサーバサイドのWebアプリケーションの開発のために使用されているプログラミング言語です。
PHPはJavaScriptのような新しいWeb言語が実現するまでずっと、ほとんど全てのモダンなWebサイトを構築可能にしました。いくつかの調査によると、PHPがWebの3分の1を支えているとのことです。たとえPHPが以前ほどは注目されていないとしても、PHPは今後何年にもわたって進化を継続し、最も人気のあるプログラミング言語のうちの一つとしての地位を維持するでしょう。
主な特徴
- 多くの大きな会社がPHPを使用しており、そのための素晴らしいツールのサポートに繋がっています
- PHPはWebアプリケーション開発に過去25年4に渡って使用されており、強力で安定したPHPフレームワークが数多く市場に存在します
- PHPは非常に生産性が高いサーバサイドWeb開発プログラミング言語のうちの一つです。結果として、Webアプリケーションを素早く開発するために、IT業界で広く使われています。最も有名なSNSの一つであるFacebookはPHPで開発されました
Ruby
特に、Rubyは人気のあるRuby on Rails Webアプリケーションフレームワークのための基盤として使われます。RubyはC言語で実装され、ガベージコレクタがあります。Rubyは90年代半ばに作られましたが、ここ10年ほどの間に人気を獲得しました。Rubyは非常に動的で、オブジェクト指向言語で、プログラマーが使うための様々な機能を持っています。Rubyの経験が6年以上ある開発者は、現在の採用状況では2倍の面接依頼を受けることが期待できます。
Twitter、Shopify、そして多くのスタートアップがいずれかの段階でRuby on Railsを使ってWebサイトを構築しています。Rubyはまた、素晴らしいハイテク企業との関連性のために選び出すには本当に良い言語です。5
Pythonのように、Rubyは開発者の生産性と幸福を非常に重視しています。Rubyは新しい開発者にとって学習曲線がフラットになる非常に優れた言語でもあります。主な特徴
- RubyはTwitter、GitHub、Airbnbのような最大級のソフトウェアプロジェクトで使われ、そして素晴らしいツールとフレームワークの支援があります
- Rubyそれ自体は破壊的ではありませんが、RubyのWeb開発フレームワークであるRuby on Railsはおそらく最も破壊的で、影響力のあるサーバサイドWeb開発フレームワークです
- Rubyはプログラミング言語の最高の機能のうちのいくつかをうまく利用してきました: 簡潔さ、動的、ガベージコレクタのあるオブジェクト指向、そして関数型です
- 投稿日:2020-09-24T18:47:05+09:00
【Rails】ドット(.)とか、コロン(:)とは一体
::
とか、.
とかよくお見かけします。
これはメソッドの呼び出しの違いで、表記が変わるという種明かしなんです。ドット記法
class User def method puts "Hello" end end> user = User.new > user.method Hello => nilコロン記法
class User def method puts "Welcome" end end> user = User.new > user::method Welcome => nilドット記法とコロン記法の違い
ドット記法とコロン記法の違いは、
定数を呼び出せる
かどうか。
記法 メソッドの呼び出し 定数の呼び出し ドット記法 ○ × コロン記法 ○ ○ Rubyでは、クラスやモジュールも定数として扱われる。
require 'uri' require 'net/http' url = URI.parse("http://yahoo.co.jp") http = Net::HTTP.start(url.host, url.port)> document = http.get(url.path) > puts document.body # ドキュメントを表示まとめ
このようにコロン記法だと、指定した別ファイルのクラス内やモジュール内のアイテムにアクセスすることができる。
- 投稿日:2020-09-24T18:40:31+09:00
Rails6のマルチDBの自動切換(ActiveRecord::Middleware::DatabaseSelector)の実装を読んでみる
概要
Rails6.0より実装された複数DB対応に関して、自身のプロジェクトに適用できるか?という判断のために実装を追ってみますRailsガイドでの記載
https://railsguides.jp/active_record_multiple_databases.html#コネクションの自動切り替えを有効にする
自動切り替え機能によって、アプリケーションはHTTP verbや直近の書き込みの有無に応じてprimaryからreplica、またはreplicaからprimaryへと切り替えます。
アプリケーションがPOST、PUT、DELETE、PATCHのいずれかのリクエストを受け取ると、自動的にprimaryに書き込みます。書き込み後に指定の時間が経過するまでは、アプリケーションはprimaryから読み出します。アプリケーションがGETリクエストやHEADリクエストを受け取ると、直近の書き込みがなければreplicaから読み出します。HTTPメソッドによる判定 + 書き込みからの時間による判定 の2種類にて行われているという記載になっている
設定方法としては下記の記載config.active_record.database_selector = { delay: 2.seconds } config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Sessionコードリーディング
まずはミドルウェアの適用部分から追ってみる
Railtieでのミドルウェアの適用部分
activerecord-6.0.3.2/lib/active_record/railtie.rb
class Railtie < Rails::Railtie # :nodoc: config.active_record = ActiveSupport::OrderedOptions.new initializer "active_record.database_selector" do if options = config.active_record.delete(:database_selector) resolver = config.active_record.delete(:database_resolver) operations = config.active_record.delete(:database_resolver_context) config.app_middleware.use ActiveRecord::Middleware::DatabaseSelector, resolver, operations, options end end
database_selector
が設定されていれば実行されるdatabase_resolver
とdatabase_resolver_context
はただ渡されるようになっている続いてミドルウェア部分の実装を追っていく
[補足] OrderedOptionsとは?
https://api.rubyonrails.org/classes/ActiveSupport/OrderedOptions.html
Hashをドットでアクセスできるようにしている機構
deleteで設定されていない場合はnilが返るRuby2.6.5 pry(main)> x = ActiveSupport::OrderedOptions.new => {} Ruby2.6.5 pry(main)> x.delete(:hoge) => nilDatabaseSelectorの実装内容
activerecord-6.0.3.2/lib/active_record/middleware/database_selector.rb
module ActiveRecord module Middleware class DatabaseSelector def initialize(app, resolver_klass = nil, context_klass = nil, options = {}) @app = app @resolver_klass = resolver_klass || Resolver @context_klass = context_klass || Resolver::Session @options = options end attr_reader :resolver_klass, :context_klass, :options def call(env) request = ActionDispatch::Request.new(env) select_database(request) do @app.call(env) end end
database_resolver
が設定されていない場合はDatabaseSelector::Resolver
が設定されるdatabase_resolver_context
が設定されていない場合はDatabaseSelector::Resolver::Session
が設定される続いて重要そうな
#select_database
を見てみるDatabaseSelector#select_database
module ActiveRecord module Middleware class DatabaseSelector private def select_database(request, &blk) context = context_klass.call(request) resolver = resolver_klass.call(context, options) if reading_request?(request) resolver.read(&blk) else resolver.write(&blk) end end def reading_request?(request) request.get? || request.head? end end end end
context
が先に実行され、それをもとにresolver
が作られているため、まずはcontext
のほうを確認してみるResolver::Session.call
class Resolver # :nodoc: class Session # :nodoc: def self.call(request) new(request.session) end def initialize(session) @session = session end attr_reader :session
.call
は#new
しているだけで、ここではActionDispatch::Request
のsessionをセットしているのみ
なので続いてはResolverの.call
を確認Resolver.call
class Resolver # :nodoc: SEND_TO_REPLICA_DELAY = 2.seconds def self.call(context, options = {}) new(context, options) end def initialize(context, options = {}) @context = context @options = options @delay = @options && @options[:delay] ? @options[:delay] : SEND_TO_REPLICA_DELAY @instrumenter = ActiveSupport::Notifications.instrumenter end attr_reader :context, :delay, :instrumenterここでもnewしているだけなので、元の
DatabaseSelector#select_database
をもう少し読み進めていく
※ちなみにinstrumenterは通知の仕組み(購読すれば通知を受け取れる)HTTPメソッドの判断部分
def select_database(request, &blk) context = context_klass.call(request) resolver = resolver_klass.call(context, options) if reading_request?(request) resolver.read(&blk) else resolver.write(&blk) end end def reading_request?(request) request.get? || request.head? endここではGETかHEADの場合 => read
それ以外の場合 => write
としてresolverの処理を実行している(Resolverがさらに判定を行っているっぽいまずはreadから見てみる
Resolver#read
class Resolver # :nodoc: def read(&blk) if read_from_primary? read_from_primary(&blk) else read_from_replica(&blk) end end private def read_from_primary(&blk) ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role, prevent_writes: true) do instrumenter.instrument("database_selector.active_record.read_from_primary") do yield end end end def read_from_replica(&blk) ActiveRecord::Base.connected_to(role: ActiveRecord::Base.reading_role, prevent_writes: true) do instrumenter.instrument("database_selector.active_record.read_from_replica") do yield end end endroleをどちらにするかとinstrumentにより通知を行ったうえで処理を進めているよう。
では続いて#read_from_primary?
にて何をどう判定しているのか?private def read_from_primary? !time_since_last_write_ok? end def send_to_replica_delay delay end def time_since_last_write_ok? Time.now - context.last_write_timestamp >= send_to_replica_delay end
context
いわゆるsessionの#last_write_timestamp
というものが、
最初のconfig.active_record.database_selector = { delay: 2.seconds }
のdelay分だけ経過していなかった場合はprimaryにして、
delay分経過している場合はreplicaを見るようになっているということでsessionの
#last_write_timestamp
を確認class Session # :nodoc: # Converts milliseconds since epoch timestamp into a time object. def self.convert_timestamp_to_time(timestamp) timestamp ? Time.at(timestamp / 1000, (timestamp % 1000) * 1000) : Time.at(0) end def last_write_timestamp self.class.convert_timestamp_to_time(session[:last_write]) endただ
sesion[:last_write]
をtimeオブジェクトに直しているのみ
readはこれで終わりなので続いてwriteResolver#write
class Resolver # :nodoc: def write(&blk) write_to_primary(&blk) end private def write_to_primary(&blk) ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role, prevent_writes: false) do instrumenter.instrument("database_selector.active_record.wrote_to_primary") do yield ensure context.update_last_write_timestamp end end endこれはただただ書き込みのroleにて書き込んでいるのみ
class Session # :nodoc: def self.convert_time_to_timestamp(time) time.to_i * 1000 + time.usec / 1000 end def update_last_write_timestamp session[:last_write] = self.class.convert_time_to_timestamp(Time.now) endそして、
session[:last_write]
に現在のタイムスタンプを付与まとめ
さすがRailsですね。とても分かりやすく作られていました。
結局はActionDispatch::Requestをもとに処理されているだけで、かつResolverの
#read
と#write
を両方書き換えれば
GETとHEADに限らず好きに書くことができそうでした。ヘッダーやIPアドレス、localhostなどによる判定も、Requestが持っている情報なので使えますし
できることはかなり多いと思いました。
- 投稿日:2020-09-24T18:33:32+09:00
組み合わせ爆発ハラスメントの処方箋
プログラミング初学者向けの内容です。
今のところ Golang, Ruby, Python, JavaScript, TypeScript による処方箋のみ掲載しています。ある日のこと
知人「店長からさぁ、
『うちはメニューの数が少ないから、
コンビ・メニュー作ることにした』『とりあえず、
今あるメニューを組み合わせて、
単品から全部入りまで
すべての組み合わせのリスト作ってくれ!』って、言われたんだけど…」
俺「え? それって、
???があるとしたら、
↓みたいなやつ?」1:?
2:?
3:? ?
4:?
5:? ?
6:? ?
7:? ? ?知人「そう。そう。それ!それ!」
俺「作れるけど、、
きっとものすごい数になるよ。
単品メニューって何種類くらいあんの?」知人「20種類くらいかなぁ。。
物好きな店長でしょ?!
めんどくせぇ。。」俺「…」
俺「あのさぁ、、
面倒くさいとかの次元じゃないんだけど。。」俺「0.1 mm 厚の紙を 26 回折ったら
富士山より高くなるって知ってる?」\begin{align} 0.1mm\times2^{26} &= 6,710,886.4 mm\\ &\fallingdotseq 6.7 km \end{align}知人「あ、なんか聞いたことあるかも。。」
俺「それと同じなんだけど、、」
\begin{align} 2^{20} - 1 &= 1,048,575 通り\\ &\fallingdotseq 105万通り \end{align}俺「105万通りは、
さすがにメニュー充実しすぎだろ(笑)」知人「へ〜、そんなになるんだぁ!」
俺「…」
Golang による処方箋
取り急ぎ Golang で書いてみます。
menu.gopackage main import ( "flag" "fmt" "strings" ) func comball(in []string) [][]string { n := 1 << len(in) out := make([][]string, n) for i := 0; i < n; i++ { ss := make([]string, 0, len(in)) for j := 0; j < len(in); j++ { if 1<<j&i != 0 { ss = append(ss, in[j]) } } out[i] = ss } return out } func main() { flag.Parse() args := flag.Args() for i, ss := range comball(args) { fmt.Printf("%d:%s\n", i, strings.Join(ss, " ")) } }Go のバージョンです。
version$ go version go version go1.15.2 linux/amd64
実行してみます。
実行$ go run menu.go ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? > menu.txtGolang はコンパイルも実行も速くていいですね。
Generics をサポートしていないので string 型専用の関数になってしまい、そこが残念ポイントですが、LL のような感覚で気軽にいろいろ試せます。
(Generics は来年サポートされるようですね)プログラムは標準出力へ書き出すようにしましたが、そのまま出力するとたぶん大変なことになるので menu.txt という名前のファイルへリダイレクトしました。
ファイルの先頭を見てみます。
ファイルの先頭$ head menu.txt 0: 1:? 2:? 3:? ? 4:? 5:? ? 6:? ? 7:? ? ? 8:? 9:? ?最初の行に「なし」を出すようにしてます。
今度は末尾を見てみます。
ファイルの末尾$ tail menu.txt 1048566:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048567:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048568:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048569:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048570:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048571:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048572:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048573:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048574:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048575:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ?1行目の「なし」を除いて、ちゃんと 104 万 8,575 行あります。
ファイルサイズが 56.4 MiB もありますが、、(笑)
(圧縮して 4 Mib くらい)
ひとまず、これで大丈夫そうです。あと、 Golang はサクッとクロスコンパイルしてシングルバイナリが作れるのがいいですね!
とりあえず、AMD64 互換 の linux と Mac と Windows 用を用意して持ち帰ってもらうことにました。build.shGOOS=linux GOARCH=amd64 go build -o ./linux-amd64/menu menu.go GOOS=darwin GOARCH=amd64 go build -o ./darwin-amd64/menu menu.go GOOS=windows GOARCH=amd64 go build -o ./windows-amd64/menu.exe menu.goでも、、
せっかくプログラムを書いてあげたのに、結局、彼は「店長に怒られそう…」という理由で、これを使ってくれませんでした。
遠い昔を思い出す
知人は採用してくれませんでしたが、これってテストデータの生成(フラグの組み合わせとか)にも応用できますよ。
昔、入社 1 年目のとき、まるで野球部の球拾いのごとくテスターをやらされた日々を思い出します。
ある日、明確なテスト仕様書もない中で、先輩 SE から無茶振りされました。
「可能な組み合わせを全部テストするなんて当たり前なの!お前バカなの!?」
と怒鳴られました。
遠い昔のことなので、細かいことはあまり良く覚えてませんが、同期の仲間と計算してみると、1 個 1 分でやったとしても、寝ずにやって何十年かかるとか、そんな途方もないオーダーでした。
現実的な解が思い浮かばなかったので、もっと上の先輩に相談しました。
すると、即答で「バカは相手にしなくていいから(笑)!」と言ってくれ、あっさりとこの問題は解決してしまいました。今考えると完全にパワハラでした。
2〜3日、真剣に悩みましたから(笑)無茶ぶりした先輩 SE はその後しばらくして会社を辞めていきました。
でも、マシンが高速化し自動テストがあたりまえになった現代では、当時できなかったいろんなことができるようになりました。
あのとき、もし今の環境が手元にあったら、この程度の簡単な処方箋であっさりと解決していたのかも。。
そう考えると感慨深いものがあります。先輩 SE が後輩を馬鹿呼ばわりすることもなく、彼がさらに上の先輩から馬鹿呼ばわりされることもなかったかもしれません。
ということで、他の言語の例もいくつか載せておきます。
Ruby で調合する
Ruby はあまり書いたことがないので、らしいコードじゃないかもしれません。
プログラムをみる
menu.rbdef comb(arr) out = [] n = 1 << arr.size n.times do |i| a = [] arr.size.times do |j| if 1 << j & i != 0 a << arr[j] end end out << a end out end comb(ARGV).each.with_index(0) do |a, i| puts i.to_s + ":" + a.join(" ") end実行$ ruby --version ruby 2.7.0p0 (2019-12-25 revision 647ee6f091) [x86_64-linux] $ ruby menu.rb ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? > menu.txt $ tail menu.txt 1048566:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048567:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048568:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048569:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048570:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048571:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048572:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048573:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048574:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048575:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ?まあ、Ruby の場合は組み込み関数を使えば、↓これでもいけますね。
出力順が違いますけど。。menu2.rbdef comball(arr) out = [[]] arr.each_with_index { |s, i| out += arr.combination(i+1).to_a } out end comball(ARGV).each.with_index(0) do |a, i| puts i.to_s + ":" + a.join(" ") endRuby って、書く順番がなんか他の言語と違いますよね。
この感覚が気持ちよくて好きです。。Python で調合する
プログラムをみる
menu.pyimport sys def comball(arr): out = [] n = 1 << len(arr) for i in range(n): a = [] for j in range(len(arr)): if 1 << j & i != 0: a.append(arr[j]) out.append(a) return out arr = sys.argv arr.pop(0) for i, a in enumerate(comball(arr)): s = ' '.join(a) print('{0}:{1}'.format(i, s))実行$ python3 --version Python 3.6.8 $ python3 menu.py ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? > menu.txt $ tail menu.txt 1048566:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048567:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048568:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048569:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048570:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048571:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048572:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048573:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048574:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048575:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ?end や } が必要ない分、関数本体が短く書けますね。
JavaScript で調合する
プログラムをみる
menu.jsfunction comball(arr) { const out = [] const n = 1 << arr.length for (let i = 0; i < n; i++) { const a = [] for (let j = 0; j < arr.length; j++) { if ((1 << j & i) != 0) { a.push(arr[j]) } } out.push(a) } return out } const arr = process.argv.slice(2) comball(arr).forEach((a, i) => console.log(i + ":" + a.join(" ")) )実行$ node --version v12.16.1 $ node menu.js ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? > menu.txt $ tail menu.txt 1048566:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048567:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048568:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048569:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048570:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048571:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048572:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048573:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048574:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048575:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ?JavaScript って & より != の方が演算子の優先順位が高いんですよね。
だから括弧が付いてます。
なんか理由があるんですかね。。TypeScript で調合する
プログラムをみる
menu.tsfunction comball<T>(arr: T[]): T[][] { const out: T[][] = [] const n = 1 << arr.length for (let i = 0; i < n; i++) { const a: T[] = [] for (let j = 0; j < arr.length; j++) { if ((1 << j & i) != 0) { a.push(arr[j]) } } out.push(a) } return out } const arr: string[] = process.argv.slice(2) comball(arr).forEach((a, i) => console.log(i + ":" + a.join(" ")) )実行$ npx ts-node --version v8.10.1 $ npx ts-node menu.ts ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? > menu.txt $ tail menu.txt 1048566:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048567:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048568:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048569:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048570:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048571:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048572:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048573:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048574:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ? 1048575:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ☕ ?TypeScript は関数シグネチャを見れば何をしそうか分かるところが良いですね。
あと、Generics 使っています。
でも、トランスパイルが遅いところが玉に瑕です。あとがき
本稿で扱ったプログラミング言語は演算子の使い方もほとんど同じなので、みんな似たコードになりましたが、それでも言語の個性が出ている部分もあって面白かったです。
後で他の言語も追記するかもしれません。
要望があればプログラムの解説も付けるかもしれません。あと、各言語のエキスパートの方で、もっとカッコいい書き方を知ってるよ! という人は是非教えてください。
それでは!
- 投稿日:2020-09-24T17:57:33+09:00
CodeWarでの勉強
この記事について
最近始めたCodewarを通じて学べたことを少しずつアウトプット
学び① joinメソッド
Write a function that accepts an array of 10 integers (between 0 and 9), that returns a string of those numbers in the form of a phone number.
#僕の回答 def createPhoneNumber(numbers) return "(#{numbers[0]}#{numbers[1]}#{numbers[2]}) #{numbers[3]}#{numbers[4]}#{numbers[5]}-#{numbers[6]}#{numbers[7]}#{numbers[8]}#{numbers[9]}" end #理想の回答 def createPhoneNumber(str) "(#{str[0..2].join}) #{str[3..5].join}-#{str[6..10].join}" end解説
https://docs.ruby-lang.org/ja/latest/method/Array/i/join.html
僕が書いたコードでは配列のデータをバカ丁寧に一つ一つ文字展開をしている
理想のコードではstr[0..2]
のようにまとめてやって、尚且つその配列の要素を結合して一つの文字列に変換するためにjoinメソッド
を使用している。
- 投稿日:2020-09-24T16:46:19+09:00
Railsでログイン機能をシンプルに名前とパスワードだけで実装する(3)
前回の続き
概要
前回まででログイン機能はできたものの、現在の状態ではどのユーザーがログインしているか分からず、またログインしなくても一覧ページにアクセスできるという欠陥が残っている。それに対処していく
手順
- current_roomメソッド。現在のログインしているユーザーを表示するヘルパーメソッドを追加する
app/helpers/sessions_helper.rb# ログインしているユーザーがいたら、ユーザーを代入する def current_room if session[:room_id] @current_room ||= Room.find_by(id: session[:room_id]) end end
- 今回はページに共通した部分がないので、不要ですが、必要ならログインしているかどうかを判断するヘルパーメソッドを定義します。
app/helpers/sessions_helper.rb# ログインしているかどうか判断する def logged_in? !current_room.nil? end
- ログアウトメソッドを 2か所に書きます。
app/helpers/sessions_helper.rbdef log_out session.delete(:room_id) @current_room = nil endapp/controllers/sessions_controller.rbdef destroy log_out redirect_to login_path end
- あとは以下のようにログインユーザーの表示とログアウト用リンクを追加します。
ログイン制御したページ~ <div class="header-title"> <div class="header-title">受付一覧: <%= current_room.name %> <%= link_to "Logout", logout_path, method: :delete %> </div> </div> ~
- 最後に一覧画面へアクセスする前にログイン制御したいので、プライベートメソッド内に定義します。
app/controllers/receptions_controller.rbclass ReceptionsController < ApplicationController before_action :logged_in_room, only: [:index] ~ private def logged_in_room unless logged_in? flash[:alert] = "ログインが必要です" redirect_to login_path end end ~これで一覧ページへのログイン機能が簡単にですが完成しました。
- 投稿日:2020-09-24T16:34:30+09:00
Ruby_work 基礎問題
模範解答
work.rb##### 問題1(四則演算とif文の復習) ##### # 以下のif文の後にコードを記述して、正しい表示がされるようにしてください number = 5 if number % 2 == 0 puts "偶数です" else puts "奇数です" end ##### 問題2(式展開の復習) ##### # 以下の表示がされるよう、コードを記述してください name = "小松原" # ご自身の名前を代入してください # 「私は●●です」と表示されるよう記述してください puts "私は#{name}です" ##### 問題3(配列の復習) ##### # 以下の①から④についてコードを記述してください # ①"田中","佐藤","山田"という名前が3つ入ったstudentsという配列を定義してください。 students = ["田中", "佐藤", "山田"] # ②①でつくった配列に"鈴木"を追加してください。 students << "鈴木" # ③②でつくった配列をターミナルに出力してください puts students # ④配列の中から番号を指定して"佐藤"を取り出し、ターミナルに出力してください puts students[1] ##### 問題4(ハッシュの復習) ##### # 以下の①から②についてコードを記述してください # ①下記のsasakiというハッシュの中から、"東京"を取り出してターミナルに出力してください sasaki = {from: "東京", age: 30} puts sasaki[:from] # ②sasakiというハッシュにjob:というキーで"teacher"というバリューを追加してください sasaki[:job] = "teacher" # ③②で追加したjobというキーのバリューをターミナルに出力してください puts sasaki[:job]
- 投稿日:2020-09-24T15:48:26+09:00
未経験者が自社開発企業に就職するためのREADME書き方
はじめに
こんにちは!
先月、無事にエンジニアデビューした1年目の者です。
私は某プログラミングスクールに3ヶ月間お世話になり、卒業後、3週間で自社開発企業に転職することができました。
この経験を生かして、私が意識してきたことを伝えていければと思います。まず、前提として転職では見せ方が最も重要だと考えています。
例えば、職務経歴書、面接対策、wantedlyのプロフィールなどなど、、
この記事では、その中でも重要なことの一つである、ポートフォリオの見せ方について共有します。記事の対象者
・未経験からエンジニア転職を考えていて、ポートフォリオを作成している方
・ポートフォリオのREADMEにて書く内容で迷っている方ポートフォリオの見せ方とは
エンジニアの方々は、忙しいので、書類選考の段階で、ソースを細かく見たりサイトを触って見たりしてくれるとは限りません。
ここで活躍するのが、READMEです。
私は、多くの転職成功された方々のREADMEを見て、自分なりの最適解を見つけました。
共通点は、端的でわかりやすく、視覚的に訴えていることでした。
この共通点からREADMEを使ってわかりやすく、視覚的に伝えられるようにすることが大事だと思います。
この記事では内容についてフォーカスしているので、書き方については他の方の記事を参考にしてください。READMEの構成
⬇️私の転職活動時に使用していたREADMEを元に説明していきます。
https://github.com/sora-uzu/The-View/blob/master/README.md書くことは、主に4つです。
1, タイトルと概要、URL
2, 使用技術
3, AWS(インフラ)構成図
4, 機能、非機能一覧1, タイトルと概要、URL
まずは、タイトル、URLはそのままの意味なので、概要について説明します。
概要は、以下の3点を一言で書いてください。
・どういうサイトか
・何ができるのか
・アピールポイントこれがかけたら、あとはサイトの分かりやすい画像を載せます。
載せ方は、癖があるので、
github readme 画像
などでググってください。2, 使用技術
ここには、使用言語や、インフラ周りで使用しているサービスを書きます。
バージョンも書いていると良いです。3, AWS(インフラ)構成図
インフラ周りで力を入れている方や、AWSを使っている方は、draw.ioを使ってインフラ構成図を作成してください。
各サービスの画像は、ググると公式サイトなどから転載可能な画像が取得できます。
インフラ周りでアピールポイントがあればここに記載すると良いと思います。
私の場合は、CircleCIでやっていることを書いています。
4, 機能、非機能一覧
機能と使用したgemを記載します。細かく書くというよりは、主な機能とそれに付随した機能を簡単に書いてください。
次に、非機能一覧では、なにでテストをしたか、何のテストをどのファイルで行っているかを書いてください。
最後に
以上が私が転職活動時にReadmeにおいて意識していたポイントです。私自身も多くの方のポートフォリオを参考にこういった構成になったので、皆さんも一つの参考にしていただけると嬉しいです。
ご覧いただきありがとうございました!会社の紹介
私は現在、株式会社ダイアログという物流×ITの会社に勤務しております。
2020年9月現在、エンジニアの募集はしていませんが、他にも様々な職種を募集しているので、Wantedlyのページをご覧ください。
- 投稿日:2020-09-24T14:38:32+09:00
Catalinaにアップグレード後のbundle installでエラー
エラー内容
$ bundle install Gem::Ext::BuildError: ERROR: Failed to build gem native extension. (省略) An error occurred while installing ffi (1.13.0), and Bundler cannot continue. Make sure that `gem install ffi -v '1.13.0'` succeeds before bundling. In Gemfile: guard-rspec was resolved to 4.7.3, which depends on guard was resolved to 2.16.2, which depends on listen was resolved to 3.2.1, which depends on rb-inotify was resolved to 0.10.1, which depends on ffi試したこと
$ gem install ffi -v '1.13.0' Building native extensions. This could take a while... ERROR: Error installing ffi: ERROR: Failed to build gem native extension. ...エラーの通りにコマンドを実行するもエラー
$ xcode-select --install xcode-select: error: command line tools are already installed, use "Software Update" to install updates既にinstallされていた。
解決策
$ sudo xcodebuild -license acceptを実行したところ解決。
- 投稿日:2020-09-24T14:26:48+09:00
(Ruby on Rails6) 投稿内容を編集する機能を作る
まえがき
こちらでは、投稿ページ制作後を前提に"投稿内容を編集"の作業を忘却録として残します。
投稿内容を編集する機能を作る
編集ページの作成
routes・controllers・view の3点に、編集ページを新規作成してください
また、ページ作成には・コントローラー名→ form
・アクション名→ Editで設定してます。
(例)
config/routesRails.application.routes.draw do get '/' => 'form#index' get '/form' => 'form#form' post "form/create" => "form#create" get "form/:id/edit" => "form#edit" ⇦これ get "form/:id" => "form#post" # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html endapp/views/任意.html.erb<h1>編集ページ</h1>app/controllers/任意.controller.rbclass FormController < ApplicationController def index @forms = Form.all @forms = Form.all.order(created_at: :desc) end def post @forms = Form.find_by(id: params[:id]) end def form @forms = Form.find_by(id: params[:id]) end def create @forms = Form.new(content: params[:content]) @forms.save @forms = Form.new(title: params[:title]) @forms.save redirect_to("/") end def edit ←ここから end ←ここまで endroutesのpostは、フォームデータの取得を行う時に使います。
新規ページ作成ではgetで設定してください。エラーの原因になってしまいます。編集ページでの初期値設定(textarea・input)
controllers
app/views/任意.html.erb・ ・ ・ def edit @forms = Form.find_by(id: params[:id]) ←ここ endeditアクションに @forms = Form.find_by(id: params[:id]) を設定して、URLと同じidのデータを取得させます。
views
app/views/任意.html.erb<h1>編集ページ</h1> <div class="form"> <div> <textarea><%= @forms.content %></textarea> ←ここ <input type="submit" value="保存"> </div> </div><%= @forms.content %> により、入力の初期値を設定しています。
編集内容の保存
コントローラーにアクションの追加
フォームから値を受け取るので、routesでは get ではなく post で実行してください。
config/routes.rbpost "form/:id/new" => "form#new"リダイレクトの設定
アクションにフォームから値を受け取る準備をしたら、submitを押した後にリダイレクトさせる必要があります。
app/views/任意.controllers.rbdef new redirect_to("/") endredirect_to("/") を利用してリダイレクト設定を行います。 / は私が任意で設定しているので個人でアレンジしてください。
Viewsで送信先の指定する
先により フォームからの値の取得・リダイレクト を行いました。
ここでは、Viewsで送信先を指定します。app/views/任意.controllers.erb<h1>編集ページ</h1> <%= form_tag("/posts/#{@post.id}/new") do %> ←ここ <div class="form"> <div> <textarea><%= @forms.title %></textarea> <textarea><%= @forms.content %></textarea> <input type="submit" value="保存"> </div> </div> <% end %> ←ここ↓ 詳細
app/views/任意.html.erb<%= form_tag("/posts/#{@post.id}/new") do %> フォームタグ <% end %>↑により、送信先が指定されます。
投稿内容の更新を行う
データーベースからデータを取得する必要があります。
取得アクションは、アクション・name属性の追加で行えるので、実行しましょう。Viewでname属性を指定する
app/views/任意.html.erb<h1>編集ページ</h1> <%= form_tag("/posts/#{@post.id}/new") do %> <div class="form"> <div> <textarea name="content"><%= @forms.content %></textarea> ←ここ <input type="submit" value="保存"> </div> </div> <% end %>コントローラーで params と save で指定
params では、送られてきたデータを保持するオブジェクトを作成できます。
app/controllers/任意.controller.rbdef update @forms = Form.find_by(id: params[:id]) @forms.content = params[:content] @forms.save redirect_to("/") endあとがき
ここまで読んでいただき、ありがとうございました。
初期値の設定などの処理が理解できるまで、少し時間がかかりそうですが地道に理解を深めたいと思います。
また、ここの紹介だけでは"投稿ページへのリンク"など詳細を省いてしまってるので、自作されるかたは設定することをおすすめします。参考リンク
Myリンク
また、Twitter・Portfolio のリンクがありますので、気になった方は
ぜひ繋がってください。プログラミング学習を共有できるフレンドが出来るととても嬉しいです。
- 投稿日:2020-09-24T12:35:53+09:00
Railsでログイン機能をシンプルに名前とパスワードだけで実装する(2)
前回 の続き。ここからログイン画面とログイン処理を実装していく
手順
- Sessionコントローラを作成する
MacBook % rails g controller Sessions new
- 以下のようにroutesファイルを編集
config/routesRails.application.routes.draw do get '/login', to: 'sessions#new' post '/login', to: 'sessions#create' delete '/logout', to: 'sessions#destroy' ~
- 次にログインフォームを作っていく。今回はBootstrapなどをつかってない直書き。
app/views/sessions/new.html.erb<body> <h1>Login</h1> <%= form_for(:session, url: login_path) do |f| %> <div class="input-name"> <%= f.label :password, '部屋の名前' %> <%= f.text_field :name, placeholder: "部屋の名前を入力してください" %> </div> <div class="form-group"> <%= f.label :password, 'パスワード' %> <%= f.password_field :password, placeholder: 'パスワードを入力してください' %> <%= f.submit 'ログイン' %> </div> <% end %> </body>
- フォームをつくり、http://localhost:3000/login にアクセスし確認
- 確認できたら、次にコントローラのアクションにcreateとdestroyアクションを追加する
app/controllers/sessions_controller.rbclass SessionsController < ApplicationController def new end def create room = Room.find_by(name: params[:session][:name]) if room && room.authenticate(params[:session][:password]) else end end def destroy end end
- createアクションのログイン失敗時の処理を書いていく。(bootstrapなど使われていない)
app/controllers/sessions_controller.rb~ def create room = Room.find_by(name: params[:session][:name]) if room && room.authenticate(params[:session][:password]) else flash[:alert] = '名前かパスワードが違います' redirect_to '/login' end end ~
- ブラウザを閉じると自動的に有効期限が切れるsessionhelperの追加
app/controllers/application_controller.rbclass ApplicationController < ActionController::Base include SessionsHelper end
- ヘルパーメソッド、log_inメソッドを定義する
app/helpers/sessions_helper.rbmodule SessionsHelper #ブラウザ内の一時cookiesに暗号化済みのroomIDを格納 def log_in(room) session[:room_id] = room.id end end
- これによってログインできるようになったので、createアクションを定義する
/app/controllers/sessions_controller.rb~ def create room = Room.find_by(name: params[:session][:name]) if room && room.authenticate(params[:session][:password]) log_in room redirect_to receptions_path else flash[:alert] = '名前かパスワードが違います' redirect_to '/login' end end ~ブラウザの画面からログインができるようになりました。
続き [Railsでログイン機能をシンプルに名前とパスワードだけで実装する(3)]
- 投稿日:2020-09-24T11:21:32+09:00
Ruby on Rails チュートリアル 第一章
はじめに
自分がRailsを勉強するときに、簡単にまとめたやつがあったらいいのにと思ったので学習しながら編集しました。
自分の勉強用です。
AWSでのCloud9の設定はとばします。1.2.2 Railsをインストールする
ターミナル$ echo "gem: --no-document" >> ~/.gemrcRubyドキュメントをインストールしないよう.gemrcファイルを設定する
.gemrcって言うのはgemの設定ファイル
設定は「gemのインストールやアップデートの際にドキュメントファイル生成しない」的な感じ
ドキュメントとは、説明書のこと。
Gemを使うに当たって絶対必要ではなく、サイズも大きくなるし時間もかかるからスルーしますというやつ。
ターミナル$ gem install rails -v 6.0.3 $ rails -v $ ruby -vRailsのインストールとバージョン確認をする。
ターミナル$ source <(curl -sL https://cdn.learnenough.com/yarn_install)JavaScriptの依存関係を管理するYarnというプログラムをインストールする。
1.3 最初のアプリケーション
ターミナル$ cd ~/environment $ rails _6.0.3_ new hello_apprais newを実行する(バージョン番号を指定)
並び順は rails バージョン指定 new アプリ名
Gemfilesource 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } gem 'rails', '6.0.3' gem 'puma', '4.3.4' gem 'sass-rails', '5.1.0' gem 'webpacker', '4.0.7' gem 'turbolinks', '5.2.0' gem 'jbuilder', '2.9.1' gem 'bootsnap', '1.4.5', require: false group :development, :test do gem 'sqlite3', '1.4.1' gem 'byebug', '11.0.1', platforms: [:mri, :mingw, :x64_mingw] end group :development do gem 'web-console', '4.0.1' gem 'listen', '3.1.5' gem 'spring', '2.1.0' gem 'spring-watcher-listen', '2.0.1' end group :test do gem 'capybara', '3.28.0' gem 'selenium-webdriver', '3.142.4' gem 'webdrivers', '4.1.2' end # Windows ではタイムゾーン情報用の tzinfo-data gem を含める必要があります gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]Gemfileを書き換える。
ターミナル$ cd hello_app/ $ bundle installgemをインストールする。
ここでエラーが出てしまったのでbundle uddateする。ターミナル$ bundle uddate再度bundle installする。
ターミナル$ bundle install1.3.2 rails server
config/environments/development.rbRails.application.configure do . . . # Cloud9 への接続を許可する config.hosts.clear endWebサーバーへの接続を許可が必要らしいので、config/environments/development.rbを開いて2行足す。
ターミナル$ cd ~/environment/hello_app/ $ rails server実行したままにしたいので、もう1つターミナルを開いてRailsサーバーを実行する。
ブラウザを開いて、ヾ(´∀`)ノYay! You’re on Rails!ヾ(´∀`)ノわーい みたいのが出たらOK。1.3.4 Hello, world!
ここからMVCモデルに入る。
ターミナル#app/controllers/の中にある〇〇controller.rbと言うファイルは? $ ls app/controllers/*_controller.rb #結果 app/controllers/application_controller.rbファイルを調べる。まずは第一章ではまずコントローラから。
app/controllers/application_controller.rbclass ApplicationController < ActionController::Base #helloアクション def hello render html: "hello, world!" #HTMLで表示したい:"表示したい内容" end end3行追加する。これでこの後のルーティングを設定すると"hello, world!"が表示できるようになるらしい
config/routes.rbRails.application.routes.draw do root 'application#hello' end#root(一番上、/)では'application_controller'のhelloアクション'を実行するという意味。
'application_controller'のhelloアクション'というのは1個前に設定したやつ。ここでエラーが出てしまった。エラーの内容は読み込み中がすごい長いというもの。
Rails sを再起動しようと思ってRails sを実行しているターミナルを見ると、終了できなくなってしまっていた。ターミナル$ ps aux | grep [p]uma $ kill -9 <出てきたプロセス番号>これでもう一度Rails sを再起動できた。
ブラウザに、Hello,world!と表示されればOK。1.4 Gitによるバージョン管理
ターミナル$ git config user.name #登録されていればここに表示される $ git config user.email #登録されていればここに表示される #登録されていなければ下記コマンドで登録 $ git config --global user.name "Your Name" $ git config --global user.email your.email@example.comgit configで設定。
ターミナル$ sudo ln -sf `which nano` /usr/bin $ git config --global alias.co checkoutGitで使うデフォルトのエディタを設定。
git coをcheckoutのエイリアスに設定。これから'git checkout' を'git co'と省略できる。
ターミナル$ cd hello_app #アプリのルートディレクトリに移動する $ git init #リポジトリの初期化 $git add -A #すべての更新ファイルをステージに移動 $git status #ステージングの状況を確認 #現状ではすべての更新ファイルがステージングされて緑で表示 $git commit -m "Initialize repository" #メッセージを追加するcommitのコマンド メッセージ→"リポジトリを初期化" $ git log #ログ表示 「q」で終了git initでセットアップする。
1.5.1 Herokuのセットアップ
gemfileを書き換える。
Gemfilesource 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } gem 'rails', '6.0.3' gem 'puma', '4.3.4' gem 'sass-rails', '5.1.0' gem 'webpacker', '4.0.7' gem 'turbolinks', '5.2.0' gem 'jbuilder', '2.9.1' gem 'bootsnap', '1.4.5', require: false group :development, :test do gem 'sqlite3', '1.4.1' gem 'byebug', '11.0.1', platforms: [:mri, :mingw, :x64_mingw] end group :development do gem 'web-console', '4.0.1' gem 'listen', '3.1.5' gem 'spring', '2.1.0' gem 'spring-watcher-listen', '2.0.1' end group :test do gem 'capybara', '3.28.0' gem 'selenium-webdriver', '3.142.4' gem 'webdrivers', '4.1.2' end group :production do gem 'pg', '1.1.4' end # Windows ではタイムゾーン情報用の tzinfo-data gem を含める必要があります gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]Herokuではsqlite3は使えない。PortgreSQLを使う。
本番(production)環境にpg gemをインストールしてRailsがPostgreSQLと通信できるようにする。
sqlite3 gemが本番環境に導入されないようにしておく。ターミナルbundle install --without production本番用以外のgemをインストールする。
ターミナル$ heroku --versionHerokuがインストールされているか確認する。されていなかった。
ターミナル$ source <(curl -sL https://cdn.learnenough.com/heroku_install)Herokuをインストールする。
ターミナル$ heroku --version確認。OK。
ターミナル$ heroku login --interactiveherokuにログインする。 --interactiveはブラウザを開かないようにするやつ。
ターミナル$ heroku createHerokuに新しいアプリケーションを作成する。
ターミナル$ git push heroku masterHerokuにリポジトリをPUSHする。
heroku createの時に出てきたURLを開くとデプロイ完了が確認できる。ターミナル$ rails webpacker:installwebpackerがないと怒られたとき。
- 投稿日:2020-09-24T11:12:10+09:00
【Ruby on Rails】デバック(binding.pry)
目標
binding.pryの使い方をマスターする
開発環境
ruby 2.5.7
Rails 5.2.4.3
OS: macOS Catalina前提
※ ▶◯◯ を選択すると、説明等が出てきますので、
よくわからない場合の参考にしていただければと思います。今回は投稿に対するコメント機能まで実装している例を参考に解説していきます。
流れ
1 デバックとは?
2 gem 'pry-byebug'のインストール
3 controllerで使用
4 viewで使用デバックとは?
エラーの原因(エラーが出ない場合もあります)を調査して、
理想の動作を実現させるために行うことをデバッグと言います。アプリケーションがエラーを起こした際には、
基本的にエラーメッセージが出力されるようになっています。
そのエラーメッセージを確認し、デバッグを行い、エラー原因を解決していきます。今回はその方法の一つでもあるbinding.pryをご紹介します。
gem 'pry-byebug'のインストール
gemfilegem 'pry-byebug'ターミナル$ bundle install
補足【pry-byebug】
記述を加えた場所でプログラムの処理を止め、
その時の状態を確認することができるgemです。controllerで使用
処理を止めたい場所で下記を記述。
binding.pry実際の使用例①
ターミナルdef show @post = Post.find(params[:id]) @comment = Comment.new @comments = @post.comments end上記のような記述があった場合、下記のように追加します。
ターミナルdef show binding.pry @post = Post.find(params[:id]) @comment = Comment.new @comments = @post.comments endその後railsサーバーを立ち上げてください。
すると記述したページに遷移すると画面がフリーズするはずです。
その状態のまま、ターミナルに戻ってください。すると下記のようになっています。ターミナル31: def show => 32: binding.pry 33: @post = Post.find(params[:id]) 34: @comment = Comment.new 35: @comments = @post.comments 36: end [1] pry(#<PostsController>)>この状態で[1] pry(#)> の後ろにparamsと入力後、Enterを押してみてください。
postのパラメーターとしてid=32が取得出来ていることがわかります。ターミナル31: def show => 32: binding.pry 33: @post = Post.find(params[:id]) 34: @comment = Comment.new 35: @comments = @post.comments 36: end [1] pry(#<PostsController>)> params => <ActionController::Parameters {"controller"=>"posts", "action"=>"show", "id"=>"32"} permitted: false> [2] pry(#<PostsController>)>次にcontroller通りの記述をしてみます。
するとid=32のデータを取得出来ました。ターミナル[1] pry(#<PostsController>)> params => <ActionController::Parameters {"controller"=>"posts", "action"=>"show", "id"=>"32"} permitted: false> [2] pry(#<PostsController>)> Post.find(params[:id]) Post Load (3.4ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" = ? LIMIT ? [["id", 32], ["LIMIT", 1]] ↳ (pry):2 => #<Post:0x00007f16b08cfeb0 id: 32, user_id: 2, title: "test", body: "test", created_at: Tue, 08 Sep 2020 06:36:21 UTC +00:00, updated_at: Tue, 08 Sep 2020 06:36:21 UTC +00:00, post_image_id: nil> [3] pry(#<PostsController>)>続けてこの投稿に対してのコメントを見る場合、下記のように記述します。
するとid=32に紐づくコメント情報を取得できました。ターミナル[3] pry(#<PostsController>)> Post.find(params[:id]).comments CACHE Post Load (0.0ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" = ? LIMIT ? [["id", 32], ["LIMIT", 1]] ↳ (pry):3 Comment Load (2.6ms) SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = ? [["post_id", 32]] ↳ app/controllers/posts_controller.rb:32 => [#<Comment:0x00007f16b0af5398 id: 9, user_id: 2, post_id: 32, comment: "", created_at: Thu, 17 Sep 2020 09:52:01 UTC +00:00, updated_at: Thu, 17 Sep 2020 09:52:01 UTC +00:00, score: 1>] [4] pry(#<PostsController>)>求めていたパラメーターが返ってきたら成功です。
もし返ってこなければ、記述が間違えているため、見直しが必要です。
※終了する場合は exit と入力後、Enterです。実際の使用例②
①では一番上にしましたが、今度は一番下にしてみます。
ターミナルdef show @post = Post.find(params[:id]) @comment = Comment.new @comments = @post.comments binding.pry endその後railsサーバーを立ち上げてください。
すると記述したページに遷移すると画面がフリーズするはずです。
その状態のまま、ターミナルに戻ってください。すると下記のようになっています。ターミナル31: def show 32: @post = Post.find(params[:id]) 33: @comment = Comment.new 34: @comments = @post.comments => 35: binding.pry 36: endそこで@postを記述すると、上記Post.find(params[:id])の記述と同じ結果が返ってきます。
ターミナル[1] pry(#<PostsController>)> @post => #<Post:0x00007fc2b06fc870 id: 32, user_id: 2, title: "test", body: "test", created_at: Tue, 08 Sep 2020 06:36:21 UTC +00:00, updated_at: Tue, 08 Sep 2020 06:36:21 UTC +00:00, post_image_id: nil> [2] pry(#<PostsController>)>このようにbinding.pryを置く場所によって調べたい項目を変更できるため、
色々試してみるのもおすすめです。
※終了する場合は exit と入力後、Enterです。実際の使用例③
binding.pryはif文などでも使えます。
[2] pry(#)> if @post.nil? と入力すると
[2] pry(#)* と表示が変わるため、
1行づつif文の中身を記述していきます。[2] pry(#<PostsController>)> if @post.nil? [2] pry(#<PostsController>)* redirect_to new_post_path [2] pry(#<PostsController>)* else [2] pry(#<PostsController>)* @post [2] pry(#<PostsController>)* end => #<Post:0x00007fc2b06fc870 id: 32, user_id: 2, title: "test", body: "test", created_at: Tue, 08 Sep 2020 06:36:21 UTC +00:00, updated_at: Tue, 08 Sep 2020 06:36:21 UTC +00:00, post_image_id: nil> [3] pry(#<PostsController>)>※終了する場合は exit と入力後、Enterです。
※表示が多い場合は途中まで表示されますが、Enterで取得していくことができ、
取得を終了する場合はqを押すことで終了します。viewで使用
viewで使用する場合は、調べたい箇所で下記のように記述します。
<% binding.pry %>使い方に関してはcontrollerと同様です。
使うタイミングはeach文の中身を確認するときなどで使います。まとめ
binding.pryは使い方次第で開発スピードを格段に早めてくれます。
とくに初学者の方にとっては早めに学ぶことができれば、理解もしやすくなるので
早めの学習をおすすめします。
- 投稿日:2020-09-24T11:01:46+09:00
小数点以下を切り捨てたい
【概要】
1.結論
2.どのように使うのか
3.ここから学んだこと
1.結論
floorメソッドを使う!
2.どのように使うのか
def cal_points(point) if point < 6000 cal_point = points * 0.05 else cal_point = points * 0.1 end puts "ポイントは#{cal_point.floor}点です" end上記ではif条件式の中で小数点が入った計算を#{cal_point.floor}を小数点以下を切り捨てています。
式展開にfloorメソッドを適用しています。参考URL:
Rubyで数値の切り捨て・切り上げ・四捨五入する
3.ここから学んだこと
他にもroundメソッド(四捨五入),ceilメソッド(切り上げ)があります。また、.round(1)とすることで"小数点第1位まで四捨五入"や.round(-1)とすることで1の位を四捨五入できます。
ex)1.23.round(1) #1.2 ex)123.round(-1) #120
- 投稿日:2020-09-24T00:57:13+09:00
【Ruby】セキュアなパスワードポリシー設定のための正規表現
1.はじめに
Webアプリケーション作成の際に特に意識をしないとならない箇所はセキュリティ面です。パスワードに関しては慎重に取り扱わなければいけません。
この記事ではパスワードポリシー設定の際に正規表現を使うことが有用という話を聞きましたので、パスワードと正規表現について考察してみました。2.正規表現とはなにか
初心者歓迎!手と目で覚える正規表現入門・その1「さまざまな形式の電話番号を検索しよう」によると
「パターンを指定して、文字列を効率よく検索・置換するためのミニ言語」
ということみたいです。
実際にRuby用の正規表現エディタのRubularというWebサイトを使用して、正規表現がどういったものか見ていきます。
例えば下記のようなテキストがあります。8月30日学習時間:1時間 8月31日学習時間:3時間 9月1日学習時間:2時間 9月2日学習時間:4時間 9月3日学習時間:6時間 9月4日学習時間:10時間この中で9月の学習時間の数字だけ正規表現を使って抽出します。
正規表現を使うと下記のような文字列になります。
^9.*:(\d*)時間$
^
や.
や*
などの正規表現で使用する特別な文字を「メタ文字」と呼びます。
ここでのメタ文字の意味は後述するとしてRubularで検証していきます。
Rubularの「Your test string」に検証したいテキストを、「Your regular expression」に正規表現を入力していきます。
そうすると下記のような結果になります。
「Match result」の水色の部分が検索して見つかった部分です。
「Match groups」がキャプチャされた部分です。ここで学習時間を抽出します。
こうやって正規表現を使用して文字列を検索していきます。3.この記事で使用する正規表現のメタ文字
参考にしました→基本的な正規表現一覧
メタ文字 意味 ^ 文頭を表す $ 文末を表す [] いずれか1文字を表す文字クラスを作る - []内で使われる文字の範囲を示す . 任意の1文字を表す ? 直前の文字やパターンが1回、もしくは0回現れる * 直前の文字やパターンが0回以上連続する。条件に合う最長の部分に一致 *? 直前の文字やパターンが0回以上連続する。条件に合う最短の部分に一致 + 直前の文字やパターンが1回以上連続する。条件に合う最長の部分に一致 () 内部でマッチした文字列をキャプチャもしくはグループ化する {n,m} 直前の文字やパターンがn回以上、m回以下連続する \ メタ文字をエスケープしたり、\dや\wといった他のメタ文字の一部になったりする \d 1個の半角数字(0123456789) \w 半角英数字とアンダースコア'_' (?=x) xの「直前の位置」を表す(肯定先読み)
4.どういったパスワードポリシーを設定すればよいのか
コンピュータの性能は日進月歩で向上しているため、パスワードの暗号解読(例えば総当り攻撃)のスピードは年々上がっていっています。それに伴いパスワードの複雑化が求められています。
2020年3月31日発行の内閣サイバーセキュリティーセンター「インターネットの安全・安心ハンドブック Ver.4.10」のP30によると、パスワードの安全性を高めるためのポリシーとして「英大文字+英小文字+数字+記号混じりで10桁以上」を推奨しています。
ここではハンドブックに則ったパスワードポリシーを正規表現にて作成していきます。5.パスワードポリシー設定のための正規表現
ここでは段階的にそれぞれの正規表現を考えていきたいと思います。
(1) 10桁以上40桁以下の半角英数記号
(2) 英大文字1桁以上+英小文字1桁以上の条件追加
(3) 数字1桁以上の条件追加
(4) 記号1桁以上の条件追加すべてのパターンを網羅できているわけではありませんが、上から
・9桁の文字
・10桁の英小文字
・10桁の英大文字+英小文字
・10桁の英大文字+英小文字+数字
・10桁の英大文字+英小文字+数字+記号
・41桁の文字で下記のテキストで検証をしていきます。
Aaaaaaa1? aaaaaaaaaa Aaaaaaaaaa Aaaaaaaaa1 Aaaaaaaa1? Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1?(1) 10桁以上40桁以下の半角英数記号
正規表現で使用する文字についてはASCIIコードを使用して指定ができます。ここでの半角英数字記号はASCIIコード表の
!
から~
までですので、下記のようになります。Ruby^[!-~]{10,40}$(2) 英大文字1桁以上+英小文字1桁以上の条件追加
理解するのに時間がかかりましたが、段階を踏んで説明します
a.肯定的先読み
(?= )
を使用して、条件の順序の依存をなくす
b.条件の前の文字は、任意の1文字.
を最短一致で0回以上連続*?
する
c.条件を設定する[A-Z][a-z]
参考にしました→パスワード向け正規表現 /^(?=.?[a-z])(?=.?\d)[a-z\d]{8,100}$/i を解読する
Ruby^(?=.*?[A-Z])(?=.*?[a-z])[!-~]{10,40}$成功しました。
(3) 数字1桁以上の条件追加
(2)に数字0-9の条件
\d
を追加しました。Ruby^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?\d)[!-~]{10,40}$成功しました。
(4) 記号1桁以上の条件追加
ASCIIコードを確認して記号を指定しました。
記号とメタ文字がかぶる箇所については、エスケープ\
をしました。Ruby^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?\d)(?=.*?[!-\/:-@\[-`{-~])[!-~]{10,40}$成功しました。
記号確認用にテキストを追加しました。6.まとめ
正規表現は理解するのに骨が折れる部分がありました。パスワードポリシー設定以外にも色々使わせていただきます。