- 投稿日:2020-07-30T22:11:19+09:00
Jekyllはカスタムプラグインを使うと色々できるよという話
この記事では、静的サイトジェネレーター「Jekyll」のカスタムプラグインで柔軟にサイトをいじる方法を紹介します。
もうちょっとピンポイントな記事もあります: JekyllでパーマリンクにFront Matterのカスタム変数を使う方法
そもそもJekyllとは?
Jekyllは、Ruby製のシンプルな静的サイトジェネレーターです。ブログなどを書けるような機能が備わっています(便利!)。.mdファイルや.htmlファイルなどを、Webサイトの表示に必要なファイル一式にして書き出してくれます。共通部分のレイアウトをまとめてかけたり、記事をマークダウン形式で書けたりと、そのままでもとても便利に使えます。
しかし、Rubyで書かれたプラグインを活用することで、さらに様々な実装ができます。
プラグインについて
プラグインは、gemやローカルの.rbファイルを読み込むことで、機能拡張ができるものです。
プラグインのインストール方法
プラグインのインストール方法(日本語)"jekyll-multiple-languages-plugin"(多言語対応に便利なプラグイン) や 公式の"jekyll-sitemap"(サイトマップ生成に便利なプラグイン)など、公開されているプラグインを使うことができます。
今回は、自分で実装する「カスタムプラグイン」について紹介します。
カスタムプラグインの動かし方
ルートディレクトリに、
_plugins
ディレクトリを作り、その下に.rb
(カスタムプラグインの中身)を置くことで使用できます。
※ちなみに、GitHub Pagesではカスタムプラグインが動きません orzカスタムプラグインの種類
Generators、Converters、Commands、Tags、Filters、Hooks の6つがあります。
種類 カスタムするところ Generators Webサイトのファイル一式を書き出す前の部分 Converters mdファイルなどを変換する部分 Commands Jekyllコマンドのサブコマンド Tags Liquidタグ Filters Liquidフィルタ Hooks Jekyllでサイトを生成する際の各プロセス Jekyllでは
{% if statement %}
のようにして生成処理時にLiquidタグを実行できます。また、{{ content | filter }}
のようにしてフィルターが使えます。各プラグインの詳しい書き方は公式サイトに載っているので参考にしてもらえればと思います。
実際に書いてみる
実際に、カスタムプラグイン(Hooks)を書いてみました。きれいなコードが書けなくてすみません(プルリクはこちらから)。https://mekurun.com/ という、子ども向けのプログラミング学習サイトを作る際に使用しているコードです。
ここでは、レンダリング後のimgタグのsrcを設定しています。今回は単純に正規表現でマッチした部分を置き換えているだけの単純な処理ですが、普通にRubyが書けるので様々な応用が効きそうです。
ちなみに、サイト高速化を目指しCloudinaryというCDNを利用するために、画像パスを場合に応じて置き換えているというコード内容になっています。
サイト高速化についての記事は、友人が書いたこちらの記事をぜひ: 【打倒!阿部寛のサイト】高校生が本気でサイト読み込み速度の最適化に取り組んでみた
要するに、各ページのレンダリング後のHTML(
doc.output
)を読んで、文字列の置き換え処理(素直にgsub
)をしています。Jekyll::Hooks.register [:pages, :documents], :post_render do |doc| # レンダリング後に実行 out = doc.output if ENV["JEKYLL_ENV"] == "production" #本番環境の場合 # 幅設定がないcloudinaryパス src = '\& src="https://res.cloudinary.com/nztm/image/fetch/c_fit,q_auto,f_auto/\1"' # 幅設定があるcloudinaryパス srcw = 'src="https://res.cloudinary.com/nztm/image/fetch/w_\2,c_fit,q_auto,f_auto,dpr_2/\1" \&' # data-srcをもとにパス設定 out.gsub!(/data-src=[\"|\'](.*?)[\"|\']/, src) out.gsub!(/data-src=[\"|\'](.*?)[\"|\'].*data-width=[\"|\'](.*?)[\"|\']/, srcw) else #本番環境ではない場合 src = '\& src="\1"' out.gsub!(/data-src=[\"|\'](.*?)[\"|\']/, src) end puts "#{doc.data["title"]}の画像パスを設定しました" doc.output = out end難しいところ
データ構造がわからないので、Jekyllのコードや他の方のプラグインを見ながら試行錯誤していました。今もあまり完全理解できていないため、ここでの説明は省かせていただきます。
まとめ
静的サイトジェネレーター「Jekyll」はRubyで様々な拡張ができて楽しいです。とはいえ、サイトビルド時のみいじれるので、インタラクティブなぬるぬるコンテンツは作れないです。そういう実装は素直にJavaScriptを触りましょう。
参考:
Jekyll
Jekyllで作るシンプルWebサイト 第1回 Jekyllとはなにか
Plugins | Jekyll
- 投稿日:2020-07-30T21:53:33+09:00
RSpecの単体テストにて"translation missing: ja.activerecord.○○"というエラーが出たときの対処法
Deviseを日本語化したときのエラー。エラー画面はこんな感じ。
◆原因
どうやらdeviseのエラーメッセージを日本語化したことによって
本来Deviseで用意されているエラー文(英語)
とテスト実行時のエラー文(devise.ja.yml)
に相違が出てしまい、エラーになってしまってるぽい。◆解決策
巷に落ちている
devise.ja.yml
の内容もそれぞれ引用元によって異なるため、このエラーが出た際にはdevise.ja.ymlに記述を追加する必要がある。実際に記述を追加していく。
今回の場合エラー分が
expected [translation missing: ja.activerecord.errors.models.user.attributes.name.blank] to include "can't be blank"
なのでconfig/locals/devise.ja.ymlja: activerecord: errors: models: user: attributes: name: blank: "が入力されていません"と追記してあげる。
これで無事にテストが通るように!
参考にした記事
・Devise日本語化後の「translation missing」に対処する
・Createの際のエラーUser translation missing: ja.activerecord.errors.models.company.attributes.user.required
- 投稿日:2020-07-30T21:43:35+09:00
Fabricateの使い方をまとめる
なんとなく使えてしまうFabricateですが、ふとしたきっかけでちゃんと理解したいなと思ったのでまとめました。
Fabricateとは
オブジェクト生成ライブラリです。
テストで使用するためのオブジェクトを簡単に作成できます。使い方
非常にシンプルで、モデルの属性に無難なデフォルト値を設定します。
サンプルでperson
というオブジェクトを定義しました。Fabricator(:person) do name "Niki" age 23 end生成メソッド
生成メソッドは3種類あります。よく使うのは
Fabricate.build
とFabricate
。Fabriate(:person) # newしてsaveしたものを返す Fabricate.build(:person) # newだけしてsaveはしない Fabricate.attributes_for(:person) # 属性のHashを返す一見
Fabricate.build
は必要なくない?となりますが、これは間違いです。
.build
を使うとインスタンスを保存しないので、specの処理時間の軽減につながります。なので、
.build
を使えない場合のみインスタンスを生成し、基本的には.build
を使うようにしています。属性の値を明示する
定義したオブジェクトの属性の値を変えたい場合は以下の様にします。
person = Fabricate(:person, name: "Peru") person.name = "Peru"また、関連しているデータを紐づけることも簡単にできます。
例えば、book
モデルがbelong_to
でperson
モデルに紐づいている場合は以下の様にしてFabricate
で表現できます。Fabricator(:book) do name "キングダム" price 1000 end book = Fabricate.build(:book, person: Fabricate.build(:person))これらは基本的な内容ですが、ちゃんと理解するとテストのコーディングスピードも上がると思います。他にも色々便利なメソッドがありますので暇があれば調べてみて下さい。
何かいいメソッドや書き方があれば、是非コメントください!
- 投稿日:2020-07-30T21:43:35+09:00
[Rspec]Fabricateの使い方をまとめる
なんとなく使えてしまうFabricateですが、ふとしたきっかけでちゃんと理解したいなと思ったのでまとめました。
Fabricateとは
オブジェクト生成ライブラリです。
テストで使用するためのオブジェクトを簡単に作成できます。使い方
非常にシンプルで、モデルの属性に無難なデフォルト値を設定します。
サンプルでperson
というオブジェクトを定義しました。Fabricator(:person) do name "Niki" age 23 end生成メソッド
生成メソッドは3種類あります。よく使うのは
Fabricate.build
とFabricate
。Fabriate(:person) # newしてsaveしたものを返す Fabricate.build(:person) # newだけしてsaveはしない Fabricate.attributes_for(:person) # 属性のHashを返す一見
Fabricate.build
は必要なくない?となりますが、これは間違いです。
.build
を使うとインスタンスを保存しないので、specの処理時間の軽減につながります。なので、
.build
を使えない場合のみインスタンスを生成し、基本的には.build
を使うようにしています。属性の値を明示する
定義したオブジェクトの属性の値を変えたい場合は以下の様にします。
person = Fabricate(:person, name: "Peru") person.name = "Peru"また、関連しているデータを紐づけることも簡単にできます。
例えば、book
モデルがbelong_to
でperson
モデルに紐づいている場合は以下の様にしてFabricate
で表現できます。Fabricator(:book) do name "キングダム" price 1000 end book = Fabricate.build(:book, person: Fabricate.build(:person))これらは基本的な内容ですが、ちゃんと理解するとテストのコーディングスピードも上がると思います。他にも色々便利なメソッドがありますので暇があれば調べてみて下さい。
何かいいメソッドや書き方があれば、是非コメントください!
- 投稿日:2020-07-30T21:43:35+09:00
[Rspec]Fabricateの基本的な使い方まとめ
なんとなく使えてしまうFabricateですが、ふとしたきっかけでちゃんと理解したいなと思ったのでまとめました。
Fabricateとは
オブジェクト生成ライブラリです。
テストで使用するためのオブジェクトを簡単に作成できます。使い方
非常にシンプルで、モデルの属性に無難なデフォルト値を設定します。
サンプルでperson
というオブジェクトを定義しました。Fabricator(:person) do name "Niki" age 23 end生成メソッド
生成メソッドは3種類あります。よく使うのは
Fabricate.build
とFabricate
。Fabriate(:person) # newしてsaveしたものを返す Fabricate.build(:person) # newだけしてsaveはしない Fabricate.attributes_for(:person) # 属性のHashを返す一見
Fabricate.build
は必要なくない?となりますが、これは間違いです。
.build
を使うとインスタンスを保存しないので、specの処理時間の軽減につながります。なので、
.build
を使えない場合のみインスタンスを生成し、基本的には.build
を使うようにしています。属性の値を明示する
定義したオブジェクトの属性の値を変えたい場合は以下の様にします。
person = Fabricate(:person, name: "Peru") person.name = "Peru"また、関連しているデータを紐づけることも簡単にできます。
例えば、book
モデルがbelong_to
でperson
モデルに紐づいている場合は以下の様にしてFabricate
で表現できます。Fabricator(:book) do name "キングダム" price 1000 end book = Fabricate.build(:book, person: Fabricate.build(:person))これらは基本的な内容ですが、ちゃんと理解するとテストのコーディングスピードも上がると思います。他にも色々便利なメソッドがありますので暇があれば調べてみて下さい。
何かいいメソッドや書き方があれば、是非コメントください!
- 投稿日:2020-07-30T20:48:01+09:00
【Sinatra】エラー解決 Rack::Flash::SessionUnavailable at /
はじめに
この記事の内容はSintaraでの開発中、rack-flash3を使ってフラッシュを表示させようとした時に発生した下記エラー、
Rack::Flash::SessionUnavailable at /
Rack::Flash depends on session middleware.
の解決方法について学んだ事を記しています。
解決への道のり
エラーを出したソースコードはこちら↓
require "rack-flash" use Rack::Flashエラー文はRack::Flashのセッションが利用できません、Rack::Flashはセッションミドルウェアに依存していますよ!ってな感じに訳せるかと思います。
という事でメンターさんにも聞いたりもしつつ、いろいろ調べて、READMEを見ていたら、ヒントがありました!
参考、引用)https://github.com/nakajima/rack-flash
If you're using Sinatra, you can use the flash hash just like in Rails:
(訳)Sinatraで使うとRailsと同じようにフラッシュハッシュを使えますよー、だと思う#省略 require 'rack-flash' #省略 enable :sessions use Rack::Flash #省略
enable :sessions
のところがセッションというワードが出てきてます、もしかしてこれ?
enable :sessions
とは、、、実はSinatraではデフォルトでRackのセッション機能は無効化されているらしいです、
そして、enable :sessions
はセッションを有効にするための指定らしいです!なるほどおお、絶対これだ!と思い、問題のコードに書き加えてページ更新してみました、、、がまたもエラー!
どうやら、、、
サーバーを再起動しないとなおりません!
この事に気づかず、僕はここからまた迷走してました笑
サーバーを再起動して無事解決〜♪
考察、学び
- おそらく、Rack-flashはセッションを使ってフラッシュを保存している
- Sinatraはセッション機能が無効化されていて、
enable :sessions
を書いてサーバーを再起動しないと有効化されない- 再起動をしてみる、という事の大事さ
勉強になりました!
- 投稿日:2020-07-30T20:17:25+09:00
コントローラーでのデータ検索等
データの絞り込み
データの絞り込みは下記の構成
例)Task.all.first
Task = 起点
all = 絞り込み条件
first = 実行部分起点
処理対象のモデルのクラス
絞り込み条件
メソッド 効果 where 特定のレコードの検索 order 検索結果の並び順を指定 joins 他のテーブルとのJOINを指定 group 指定したカラムの値を基準にデータをグループ化 select 指定したからむだけを属性として取得する limit 取得個数を制限する distinct 取得するカラムの値が一致しているデータは除外してデータを取得 all 全件取得 none 何もヒットさせない 実行部分
メソッド 効果 find idを指定して取得 ない場合は例外 Task.find(1) find_by 条件指定し取得 ない場合はnil Task.find_by(name:"mayu") なし 他のテーブルとのJOINを指定 first 検索条件に合う最初のレコードに対応するオブジェクトを取得 last 検索条件に合う最後のレコードに対応するオブジェクトを取得 exisit? 検索条件に合うレコードの有無を取得 count 取得するカラムの値が一致しているデータは除外してデータを取得 average COUNT関数を使って平均を取得 maximun AVG関数を使って最大値を取得 minimum AVG関数を使って最小値を取得 update_all 検索条件にあうレコードを全てインスタンス化せずに更新 delete_all 検索条件にあうレコードを全てインスタンス化せずに削除 destroy_all 検索条件にあうレコードを全てインスタンス化した上で削除 並び替え
tasks_controllerclass TasksController < ApplicationControlller def index @tasks = current_user.tasks #新しい順で検索するには① 古い順で検索するには② @tasks = current_user.tasks.order(created_at: :desc) #① @tasks = current_user.tasks.order(created_at: :asc) #② endscopeの活用
scopeを使い、クエリ用のメソッドの連続した呼び出し部分に名前をつけて、メソッドとして使用することができる
modelclass Task < ApplicationRecord scope :recent, -> {order(created_at: :desc)} #recentという名で定義 end #recentの使い方 tasks = Task.recent task = Task.recent.first task = Task.recent.last tasks = current_user.tasks.recent tasks = Task.where(user_id: [1,2,5]).recentフィルタ
同じコードを複数記述していると変更を行う必要があるときに重複箇所全てに対して変更を行わなければいけない。フィルタを使って重複を避けることを心がける
tasks_controllerclass TasksController < ApplicationController before_action :set_task, only: [:show, :edit, :update, :destroy] def show end def edit end def update end def destroy end private def set_task @task = current_user.tasks.find(params[:id]) end endURL表示
rails_autolinkと言うgemを使いURLを表示させる
gemfilegem 'rails_autolink'auto_link(simple_format(h(@task.description),{},sanitize: false, wrapper_tag: "div:))
- 投稿日:2020-07-30T18:38:21+09:00
Controllerを作成しよう
Controllerを作成する
コントローラでは、ユーザーのリクエストを受けてModelと連携したり、
どの画面(View)を表示するかを制御しています。
ユーザーがURLにアクセスしたときに、リクエストを最初に受け取るのがコントローラです。
受け取ったリクエストを元にして、Modelからのデータを、対応するViewに渡して画面を表示させます。具体的には、以下のような制御を行っています。
Modelとやり取りする
Viewに渡すインスタンス変数を定義する
表示するViewファイルを指定するcontrollerを作成するのは以下を実行するだけです。
gはgenerateの略称です。$ rails g controller コントローラ名ただ、一つだけ注意があります。
コントローラー名は複数形になります。こんな感じです。$ rails g controller homes成功するとこんな感じになります。
[vagrant@localhost sample_app]$ rails g controller homes Running via Spring preloader in process 29768 create app/controllers/homes_controller.rb invoke erb create app/views/homes invoke test_unit create test/controllers/homes_controller_test.rb invoke helper create app/helpers/homes_helper.rb invoke test_unit invoke assets invoke coffee create app/assets/javascripts/homes.coffee invoke scss create app/assets/stylesheets/homes.scss間違えてControllerを作成してしまったら?
コントローラー名などを間違えて作成した場合は、以下のコマンドで消しましょう。
勘の良い人はわかるかもしれませんが、
dはdestroyを意味します。[vagrant@localhost sample_app]$ rails d controller homes
- 投稿日:2020-07-30T18:17:49+09:00
MVC(Model View Controller)を理解しよう
MVC(Model View Controller)とは?
railsはMVCという考え方で構成されています。
全てのコードを同じ場所に書いてしまうと、コードが複雑になるため、
railsでは、保守性を維持するために、Model、View、Controllerの3つの処理パターンに分けて管理しています。model
データを扱う部分です。
データベースに対して、データの登録や取得、更新、削除などの処理を行います。view
PCの画面に関わる部分です。
HTMLを読み込み、ブラウザに表示させるためのものです。controller
modelとviewの中間に位置します。
ユーザーからのリクエストを受けて、Modelと連携したり、どの画面(View)を表示するのかといったことを制御します。
- 投稿日:2020-07-30T17:53:27+09:00
Railsでのアプリケーション作成
rails newで作成
railsで新規アプリケーションを作成するのは簡単です。
rails newコマンドだけで作成できてしまいます。$ rails new アプリケーション名もしアプリケーション名を間違えたら?
アプリケーション名を間違えて作成してしまっても安心です。
このコマンドでアプリケーションを消してしまいましょう。$ rm -rf アプリケーション名rmはremoveの略称です。
-rf remove recursively forceの略)はコマンドオプションの1つで、「フォルダ内のすべてのファイルとフォルダを削除する」を意味します。作成したアプリケーションを確認
rails newコマンドでアプリケーションの作成が完了すると以下のような画面が出ます。
この画面が出たら、成功です。[vagrant@localhost sample_app]$ rails new sample_app create create README.md create Rakefile create .ruby-version create config.ru create .gitignore create Gemfile run git init from "." Initialized empty Git repository in /home/ec2-user/environment/sample_app/.git/ create package.json create app create app/assets/config/manifest.js create app/assets/javascripts/application.js create app/assets/javascripts/cable.js create app/assets/stylesheets/application.css create app/channels/application_cable/channel.rb create app/channels/application_cable/connection.rb create app/controllers/application_controller.rb create app/helpers/application_helper.rb create app/jobs/application_job.rb create app/mailers/application_mailer.rb create app/models/application_record.rb create app/views/layouts/application.html.erb create app/views/layouts/mailer.html.erb create app/views/layouts/mailer.text.erb
- 投稿日:2020-07-30T17:23:42+09:00
[Ruby]Sheets API v4のupdate_spreadsheet_valueでNameErrorが出たときの対処方法(uninitialized constant ActiveSupport::JSON (NameError))
Rubyからスプレッドシートのセル情報を読み書きしたくて、まず公式が提供しているQuickstartを試してみました。
Ruby Quickstart | Sheets API | Google DevelopersQuickstartではシートのセル値を取得まであり、セルを更新(値を書き込む)は用意されておりませんでした。
なのでドキュメントやQiitaを参考に試したのですが、エラーが出たためその解決方法を書いていきたいと思います。
SheetsAPIの操作はQuickstartと同じ
google-api-ruby-client
を使用しています。
uninitialized constant ActiveSupport::JSON (NameError)
の対処方法
update_spreadsheet_value
にてセルの更新を行おうとしたときに、uninitialized constant ActiveSupport::JSON (NameError)
が発生しました。
google-api-client
の中でto_jsonメソッドが使用されているのですが、to_jsonメソッドはActiveSupportのメソッドであり、ActiveSupportが入っていないことが原因でした。Gemfileに
gem 'activesupport'
を追記し、update_spreadsheet_value
を使うファイルにrequire 'active_support'
を追記することでエラーを解消できました。Gemfile... gem 'google-api-client' gem 'activesupport'sample.rbrequire 'google/apis/sheets_v4' require 'active_support' # active_supportを読み込む def updated_cells(values) spreadsheet_id = 'xxxxxxxxx' value_range_object = Google::Apis::SheetsV4::ValueRange.new(values: values) range = 'sheet!D2:D' result = service.update_spreadsheet_value( spreadsheet_id, range, value_range_object, value_input_option: 'RAW' ) puts "#{result.updated_cells} cells updated." end実際のエラー内容
実際のエラーはこのような内容でした。
Traceback (most recent call last): 11: from main.rb:25:in `<main>' 10: from main.rb:12:in `main' 9: from /myapp/src/sheets.rb:32:in `write_price' 8: from /usr/local/bundle/gems/google-api-client-0.42.2/generated/google/apis/sheets_v4/service.rb:787:in `update_spreadsheet_value' 7: from /usr/local/bundle/gems/google-api-client-0.42.2/lib/google/apis/core/base_service.rb:360:in `execute_or_queue_command' 6: from /usr/local/bundle/gems/google-api-client-0.42.2/lib/google/apis/core/http_command.rb:99:in `execute' 5: from /usr/local/bundle/gems/google-api-client-0.42.2/lib/google/apis/core/api_command.rb:66:in `prepare!' 4: from /usr/local/bundle/gems/representable-3.0.4/lib/representable/json.rb:44:in `to_json' 3: from /usr/local/bundle/gems/multi_json-1.15.0/lib/multi_json.rb:139:in `dump' 2: from /usr/local/bundle/gems/multi_json-1.15.0/lib/multi_json/adapter.rb:25:in `dump' 1: from /usr/local/bundle/gems/multi_json-1.15.0/lib/multi_json/adapters/json_common.rb:19:in `dump' /usr/local/bundle/gems/activesupport-6.0.3.2/lib/active_support/core_ext/object/json.rb:42:in `to_json': uninitialized constant ActiveSupport::JSON (NameError)実際に使用したファイル
実際に使用したファイルを参考に載せておきます。
sheets.rbrequire "google/apis/sheets_v4" require "googleauth" require "googleauth/stores/file_token_store" require "fileutils" require 'active_support' class Sheets OOB_URI = 'urn:ietf:wg:oauth:2.0:oob'.freeze APPLICATION_NAME = 'Sample App'.freeze CREDENTIALS_PATH = 'credentials.json'.freeze TOKEN_PATH = 'token.yaml'.freeze SCOPE = Google::Apis::SheetsV4::AUTH_SPREADSHEETS SPREADSHEET_ID = 'xxxxxxxxxxxxxxxxxx'.freeze attr_reader :service def initialize @service = setup_service end def symbols range = 'sheet!C2:C' response = service.get_spreadsheet_values(SPREADSHEET_ID, range) puts 'No data found.' if response.values.empty? response.values.flatten end def update_price_cells(values) value_range_object = Google::Apis::SheetsV4::ValueRange.new(values: values) range = 'sheet!D2:D' result = service.update_spreadsheet_value( SPREADSHEET_ID, range, value_range_object, value_input_option: 'RAW' ) puts "#{result.updated_cells} cells updated." end private def setup_service service = Google::Apis::SheetsV4::SheetsService.new service.client_options.application_name = APPLICATION_NAME service.authorization = authorize service end def authorize client_id = Google::Auth::ClientId.from_file(CREDENTIALS_PATH) token_store = Google::Auth::Stores::FileTokenStore.new(file: TOKEN_PATH) authorizer = Google::Auth::UserAuthorizer.new(client_id, SCOPE, token_store) user_id = 'default' credentials = authorizer.get_credentials(user_id) if credentials.nil? url = authorizer.get_authorization_url(base_url: OOB_URI) puts 'Open the following URL in the browser and enter the ' \ "resulting code after authorization:\n" + url code = gets credentials = authorizer.get_and_store_credentials_from_code( user_id: user_id, code: code, base_url: OOB_URI ) end credentials end endまとめ
Railsを書いているときに何気なく書いていた
to_json
はActiveSupportのメソッドだということを知り勉強になりました。
ActiveSupportは様々なgemで使用されているようです。なにかわからない部分などありましたら、質問やコメント、Twitterにてお願いします。
- 投稿日:2020-07-30T16:22:37+09:00
Rubyで「ある期間の毎月1日」をDateオブジェクトの配列として取得する方法
Rubyの小ネタです。
お題
2020年4月1日から2021年3月1日まで、1年分の「xxxx年xx月1日」のDateオブジェクトを配列として取得するコードを書いてください。
イメージとしてはこんな感じです。
# 見やすいように文字列の配列にしていますが、本当はDateオブジェクトの配列を取得するのがゴールです [ "2020-04-01", "2020-05-01", "2020-06-01", "2020-07-01", "2020-08-01", "2020-09-01", "2020-10-01", "2020-11-01", "2020-12-01", "2021-01-01", "2021-02-01", "2021-03-01" ]解答例
こんな感じで書けます。
require 'date' start_date = Date.parse '2020/04/01' end_date = Date.parse '2021/03/01' (start_date..end_date).select{|d| d.day == 1} #=> [#<Date: 2020-04-01 ((2458941j,0s,0n),+0s,2299161j)>, #<Date: 2020-05-01 ((2458971j,0s,0n),+0s,2299161j)>, (中略), #<Date: 2021-03-01 ((2459275j,0s,0n),+0s,2299161j)>]Railsであれば
Date.parse
の代わりにto_date
が使えます。# Railsの場合 start_date = '2020/04/01'.to_date end_date = '2021/03/01'.to_date (start_date..end_date).select{|d| d.day == 1} #=> [Wed, 01 Apr 2020, Fri, 01 May 2020, (中略), Mon, 01 Mar 2021]むりやり1行で書くとこんな感じ。(可読性がイマイチなのであまりお勧めしませんが)
# Railsの場合 Range.new(*%w[2020/04/01 2021/03/01].map(&:to_date)).select{|d| d.day == 1} #=> [Wed, 01 Apr 2020, Fri, 01 May 2020, (中略), Mon, 01 Mar 2021]いったん335日分のDateオブジェクトの配列を作ってから、毎月1日のDateオブジェクトだけをselectするので若干処理効率が悪いところはありますが、何十年、何百年という期間を対象にしないのであれば、たぶん大きな問題にはならないんじゃないかなー、と思っています。
以上、Rubyの小ネタでした!
おまけ
Railsの
next_month
メソッドとRuby 2.7で導入されたEnumerator.produce
を使って、無駄なDateオブジェクトを作らない処理を考えてみました。これもなかなか良さそうです。# Rails + Ruby 2.7 start_date = '2020/04/01'.to_date end_date = '2021/03/01'.to_date Enumerator.produce(start_date, &:next_month).take_while{|d| d <= end_date} #=> [Wed, 01 Apr 2020, Fri, 01 May 2020, (中略), Mon, 01 Mar 2021]素のRubyでも
>> 1
を使えば1ヶ月後のDateオブジェクトが取得できるので、Ruby 2.7単体でこういう書き方もできます。# Ruby 2.7 require 'date' start_date = Date.parse '2020/04/01' end_date = Date.parse '2021/03/01' Enumerator.produce(start_date){|d| d >> 1}.take_while{|d| d <= end_date} #=> [#<Date: 2020-04-01 ((2458941j,0s,0n),+0s,2299161j)>, #<Date: 2020-05-01 ((2458971j,0s,0n),+0s,2299161j)>, (中略), #<Date: 2021-03-01 ((2459275j,0s,0n),+0s,2299161j)>]
- 投稿日:2020-07-30T12:58:32+09:00
Railsで開発中にLocalのMySQLのバージョンを8系から5.7に変更したらいろいろハマった
現在Railsでポートフォリオ作成中のたか(@ktkr7195)です。
Sequel Proを使ってDBの情報を参照しようとしたら、MySQL8系だと繋がらない問題に打ち当たり、バージョンを5.7にすれば治るらしいという記事を拝見し、変更したら事件が起きました。
環境
- Rails 5.2.4
- macOS 10.15.5
- MySQL 5.7
- ruby 2.5.1
状況
まずHomebrewで
brew install mysql
でMySQLをインストールしてローカルで開発をしていました。おそらく、バージョン指定しないと最新の8系がインストールされます。rails db:create
やrails db:migrate
等無事に成功し、アプリケーションが表示されるようになりました。開発を進めていく中でDBを参照することが多くなったのでSequel Proを使おとしたら弾かれてしまいこちらの記事を参考に修正したらrails db:migrate
ができなくなったのでMySQLのバージョンを落とすことに。手順
①Mac MySQLをきれいにする
まずはこちらの記事を参考にMySQLをきれいにして、インストールし直す。この際自分はこちらを見て5.7をインストールしました。②bundle doctorで原因を調べる
こちらの記事を参考に。感想
自分の場合は上の手順で解決しましたが、ここまで来るのに結構時間を使ってしまったので、同じような境遇の人がいたら参考になれば嬉しいです。
参考
- https://pqtomblog.com/2018/09/20/connecting_mysql_by_sequelpro/
- https://qiita.com/onoblog/items/4d67b3731debffcf6b2d
- https://qiita.com/renny1398/items/5df494a2b2f5d74b24f4
- https://qiita.com/hayte/items/cea0b7762d3adf096b8b
- https://qiita.com/SatoMaru/items/986aa0a63af28a8b6273
- https://www.takafumitaba.com/mysql-already-exists
- https://weblabo.oscasierra.net/mysql-57-homebrew-install/
- 投稿日:2020-07-30T12:17:48+09:00
Ruby on rails とは?
Ruby on railsとは
Ruby on railsはWebアプリケーションを開発するためのフレームワークです。
「フレームワーク」は「ひな形」のことで、アプリケーション開発に必要な機能を簡単な手順で
設定できるようになっています。
たとえば、Webサイトを制作する際、「ブログ」機能を使うと、HTMLやCSSを一つひとつ書かなくてもサイトが完成します。
ブログには、あらかじめ必要な機能が用意されているので、それに従ってテキストや画像を組み込むだけで完成できます。同様に、フレームワークでも必要な機能があらかじめ用意されているので、
ルールに従って記述していくだけで、プログラムを一つひとつ書くよりも効率的にWebアプリケーションを開発できます。
フレームワークは他にもありますが、Rubyでは、Ruby on Railsを利用するのが一般的です。Ruby on railsの特徴
1.生産性が高い
あらかじめ基本的な構造が組まれているので、必要最低限のプログラミングだけで済ませられます。
記述するコード量は、フレームワークを使わなかった場合とではまったく違います。よりコンパクトに記述できるので、機能開発の生産性も向上します。2.メンテナンスが容易
フレームワークには、記述ルールがありますので、
ルールに従ってコードを書くことで、一貫性を保ちやすくなります。Ruby on railsの設計理念
Ruby on railsには2つの設計理念があります。
1.DRY(don't repeat yourself)
DRYは「同じ記述を繰り返さない」を意味します。
同じコードや似たようなコードがあちこち散らばると、メンテナンスや修正がしにくくなります。2.CoC(Convention over Configuration)
Cocは「設定より規約」を意味します。
開発者が考えたり決定すべきことを極力少なくして、ロジックに集中させる思想のことです。
アプリケーションの設定を行うファイルや項目は、増えれば増えるほど仕組みが複雑化していきます。
CoCの思想を徹底することで、アプリケーションの実装に集中できるようになります。
- 投稿日:2020-07-30T09:33:09+09:00
プロを目指す人のためのRuby入門のためにRuby2.4.1をインストールする
はじめに
プロを目指す人のためのRuby入門を学習するためにRuby2.4.1を入れます。
環境
- macOS Catalina Version 10.15.6
- rbenv 1.1.2
- Ruby 2.4.1
条件
- rbenvがインストール済みあること
- 特定のフォルダのみRuby 2.4.1を有効にしたい場合
手順
- Ruby 2.4.1をインストールする
rbenv install 2.4.1
※結構時間がかかります。- Ruby 2.4.1を有効にしたいフォルダを作る (例)
touch ./ruby-book-codes
- フォルダに移動する (例)
cd ./ruby-book-codes
- Ruby 2.4.1を有効にする
rbenv local 2.4.1
Enjoy Ruby life!!
- 投稿日:2020-07-30T06:54:13+09:00
Kinx アルゴリズム - ハノイの塔
Kinx アルゴリズム - ハノイの塔
はじめに
「見た目は JavaScript、頭脳(中身)は Ruby、(安定感は AC/DC)」 でお届けしているスクリプト言語 Kinx。「プログラム=アルゴリズム+データ構造」。アルゴリズムの実装例をご紹介。
元ネタは「C言語による(30年経っても)最新アルゴリズム事典」。今回はライフゲームです。
- 参考
- 最初の動機 ... スクリプト言語 KINX(ご紹介)
- 個別記事へのリンクは全てここに集約してあります。
- リポジトリ ... https://github.com/Kray-G/kinx
- Pull Request 等お待ちしております。
最新アルゴリズム事典にはこういうのも結構載ってる。パズル的な。
Kinx では最初のころにこのサンプルコードを書いて、再帰関数の確認に使った。良いテストになった。
ハノイの塔
Wikipedia より
以下のルールに従ってすべての円盤を右端の杭に移動させられれば完成。
- 3本の杭と、中央に穴の開いた大きさの異なる複数の円盤から構成される。
- 最初はすべての円盤が左端の杭に小さいものが上になるように順に積み重ねられている。
- 円盤を一回に一枚ずつどれかの杭に移動させることができるが、小さな円盤の上に大きな円盤を乗せることはできない。
ソースコード
function movedisk(n, a, b) { if (n > 1) movedisk(n - 1, a, 6 - a - b); System.println("円盤 %d を %d から %d に移す" % n % a % b); if (n > 1) movedisk(n - 1, 6 - a - b, b); } const N = 4; System.println("円盤 %d 枚を柱 1 から柱 2 に移す方法は" "次の %u 手です." % N % ((1 << N) - 1)); movedisk(N, 1, 2);結果
円盤 4 枚を柱 1 から柱 2 に移す方法は次の 15 手です. 円盤 1 を 1 から 3 に移す 円盤 2 を 1 から 2 に移す 円盤 1 を 3 から 2 に移す 円盤 3 を 1 から 3 に移す 円盤 1 を 2 から 1 に移す 円盤 2 を 2 から 3 に移す 円盤 1 を 1 から 3 に移す 円盤 4 を 1 から 2 に移す 円盤 1 を 3 から 2 に移す 円盤 2 を 3 から 1 に移す 円盤 1 を 2 から 1 に移す 円盤 3 を 3 から 2 に移す 円盤 1 を 1 から 3 に移す 円盤 2 を 1 から 2 に移す 円盤 1 を 3 から 2 に移すおわりに
こちらも C 言語版ほぼそのままです。GitHub は英語基準なのでこれまで文言を英語に直していましたが、一応日本語でも動くので、今回の上記のソースコードは日本語のままにしました。ただし GitHub に例としてコミットしているものは英語にしてあります。
ではまた、次回。
- 投稿日:2020-07-30T00:03:53+09:00
Rubyで外部コマンドを実行する
概要
Rubyで外部コマンドを実行するときの関数について、それぞれ実行して試しました。
自分用メモです。動機
安全なWebアプリケーションの作り方 のOSコマンド・インジェクションの項で、
Rubyの場合どうなるか興味を持った実行環境
Ruby2.5.1
試してみた
- Kernel.#system
systemはsystem(コマンド)のように直接コマンドを打つことと、
system(コマンド, パラメータ)のように指定することができる子プロセスが終了ステータス 0 で終了すると成功とみなし true を返します。それ以外の終了ステータスの場合は false を返します。コマンドを実行できなかった場合は nil を返します。
引数のコマンドをサブプロセスで実行するのが特徴。
$system("echo test") test => true $system("echo test ; echo test2") test test2 => true$system("/bin/echo","test") test => true $system("/bin/echo","test; echo test2") test; echo test2 => true後者の場合、パラメータ内のセミコロンが文字列として処理されている。
OSコマンドインジェクションの対策に有効。
- Kernel.#exec
systemと似ている。
プロセスの実行コードはそのコマンド(あるいは shell)になるので、起動に成功した場合、このメソッドからは戻りません。
こちらは実行中のプロセスが置き換わるので、返り値を持たない。
$exec("echo test ; echo test2") test test2$exec("/bin/echo","test; echo test2") test; echo test2外部コマンドが実行できる(できてしまう)例
他の関数で外部コマンドを実行することはあるのだろうか?
- Kernel.#open
$open('|/bin/echo test;').read => "test\n"このように、引数の中にパイプを組み込むことで外部コマンドを実行できてしまう。
File.openを使えばエラーが出る。
$File.open('|/bin/echo test;').read Errno::ENOENT: No such file or directory @ rb_sysopen - |/bin/echo test;まとめ
systemやexecといった関数を使うときはOSコマンドインジェクションに配慮して実装をする
→外部から入力された文字列をコマンドラインのパラメータに渡さない
→system関数に第二引数を追加するopen関数は外部コマンドを実行される危険があるので、File.openに置き換えるのが望ましい
参考ページ
Ruby リファレンスマニュアル
https://docs.ruby-lang.org/ja/latest/doc/index.htmlRails セキュリティガイド
https://railsguides.jp/security.html
- 投稿日:2020-07-30T00:02:11+09:00
Rubyとは?
Rubyとは?
Rubyは「Webアプリケーション」を作るためのプログラミング言語です。
ここでWebアプリケーションとWebサイトの違いが分からない人向けに説明しておくと、
Webサイトとは、訪問者が見ることしかできないものです。
俗に言う、ホームページと言うやつですね。
WebサイトはHTML,CSSを用いて作られます。一方で、Webアプリケーションは訪問者が見る+操作(検索や登録など)できます。
例えば、Amazonでユーザー情報を登録したり、商品を検索したりしますよね。
それをできるものがWebアプリケーションです。Rubyの特徴とは?
1.スクリプト言語である
スクリプト言語とは、簡単に言うと、記述したプログラムをすぐに実行して、
動きを確認できる言語です。Ruby以外のプログラミング言語(例えば、JavaやCなど)は、
プログラミングを実行するには、コンパイルする必要があります
(コンパイルとは、人間が書いたソースコードを、機械が読み取れるように変換する作業)。
Rubyは、記述したコードをすぐに実行・確認できるので、
円滑にプログラミングを進められます。2.記述がシンプルである
Rubyは、可読性(読みやすさ)を重視しています。そのため、Javaなどに比べて、
シンプルにプログラミングを行えます。
実際のコードで、JavaとRubyのコードを比較してみましょう。◆JAVA
public class Main { public static void main(String[] args){ System.out.println("Hello World"); } }◆Ruby
puts "Hello World"Rubyの方が圧倒的にコードの量が少ないことがわかると思います。
このようにRubyはシンプルで書きやすい言語なのです。3.日本語の文献が多い
Rubyは日本人によって作られたプログラミング言語なので、国内でも非常に人気のある言語となっています。
そのため、エラーなどが出ても、google先生に聞くと、大体は出てきます。
しかし、本当にたまに何も出てこない時があります。
そのときは、誰かに聞くしかありません(笑)