- 投稿日:2019-11-28T22:44:26+09:00
Ruby技術者認定試験対策 | 破壊的メソッド一覧(!がつくメソッドのみ)
Class.instance_methods(false).grep(/.*!/)これを各クラスに行いビックリマークがつく破壊的メソッドを全て取得して、以下に一覧としてまとめておきます。
それぞれのメソッドにリファレンスのリンクを付与しています。
(非公式ですがAmiWikiのほうが自分はわかりやすいと思ったのでAmiWikiをチョイスしています。AmiWikiにないものは、るりまサーチにしています。)Array
=> [:reverse!, :rotate!, :sort!, :sort_by!, :collect!, :map!, :select!, :reject!, :slice!, :uniq!, :compact!, :flatten!, :shuffle!]
- reverse!
- rotate!
- sort!
- sort_by!
- collect!
- map!
- select!
- reject!
- slice!
- uniq!
- compact!
- flatten!
- shuffle!
Hash
=> [:select!, :reject!, :merge!]String
=> [:succ!, :next!, :scrub!, :upcase!, :downcase!, :capitalize!, :swapcase!, :reverse!, :sub!, :gsub!, :chop!, :chomp!, :strip!, :lstrip!, :rstrip!, :tr!, :tr_s!, :delete!, :squeeze!, :slice!, :encode!]
- 投稿日:2019-11-28T22:40:33+09:00
Rubyの数値について少し詳しく備忘録
10進数以外の整数リテラル
2進数の場合は0b、8進数の場合は0xを先頭につけると、それぞれ10進数以外の整数値を作成することができる!
10進数以外の整数リテラル# 2進数 0b11111111 #-> 255 # 8進数 0377 #->255 # 16進数 0xff #->255数値クラス
Ruby2.3までの整数は、Bignum、Fixnumクラスに別れていましたが、Ruby2.4以降は全てIntegerクラスにまとめられた!
この他にも有理数を表すRationalクラスや、複素数を表すComplexクラスがある。
有理数と複素数# 有理数 r = 2 / 3r r #->(2/3) r.class #->Rational # 複素数 c = 0.3 - 0.5i c #->(0.3-0.5i) c.class #->Complex小数クラスのFloatクラスも含め、数値クラスは全てNumericクラスのサブクラス!
あたいの種類によってクラスが異なるので、メソッドの使い方をAPIドキュメントで調べたりする場合は、適切なクラスのAPIドキュメントを参照するように注意!
- 投稿日:2019-11-28T21:35:14+09:00
コードを和訳する②(chomp,function,def)
はじめに
前回の記事が思いのほか書くのが楽しかったので、続けざま書いてみます。
実行
まずはRubyの次のコードです。
num = gets.chomp.to_i入力した数字をnumに代入するコードです。
このうちgets
は理解する、入手する
といった意味があります。
そしてchomp
はむしゃむしゃ食べる
という意味があります。
このコードは、言ってみれば人間の言葉を機会の言葉に翻訳する処理とも言えるので、
入力された人間の言葉を咀嚼して、機械にも理解できるようにする
という意味合いだと予想できます。続いては、JavaScriptの関数に使われている
function
です。function Say(Hello){ console.log(Hello); }といった具合に使われます。
functionはそのまま
関数、機能
という意味があるので、特に解釈の必要はなさそうです。ではRubyの方で関数定義するときに使う
def
はどうでしょうか?def Say(Hello){ puts Hello endという風に使われます。
def
自体の意味はすばらしい
という意味で、このままイマイチしっくりこないので、defで始まる単語の略であるという説をもって検索してみます。
するとdefinite :確定する
という単語が見つかりました。
ここから解釈すると、前述の関数はSayは~という処理と決める
という意味合いだと想像できます。結果
def
などは若干無理矢理感がありましたが、実際に単語の意味を調べてみると自分なりに理解ができそうです。
まだ短いコードでしか和訳を試していたないので、いずれはもっと長いコードの和訳に挑戦してみたいです。
- 投稿日:2019-11-28T20:33:50+09:00
コードを和訳する①(Hello World)
はじめに
プログラミング言語というのは大体英語です。
こういう記事(Qiita外記事)があるくらい、とにかく英語で書かれています。
割と簡単な単語もあれば、辞書を引かないとわからないような単語もあります。
そして、実際に意味を調べると、コードの意味がよくわかることもあります。本記事では、過去の記事で書いたコードにある英単語を和訳してみて、解りやすくなるのか…わけがわからなくなるのか…それとも笑える感じになるのか、そういったことを試してみます。
実行
どんなプログラムでも最初に勉強することは
Hello World
と出力することですが、RubyとJavaScriptではそれぞれ次のようにコードを書きます。puts "Hello World"console.log(Hello World)まず
puts
の方ですが、goo辞書で調べてみると暴動、反乱
といった単語がでます。
明らかに違います
そこで、putの複数形でputsという説を立て再調査してみると、置く、移動する、言う、表現する etc
という意味が出てきます。
この中では言う、表現する
あたりがしっくりきます。同じように
console.log
の方を調べてみます。
console
の方は、動詞だと慰める
、名刺だと端末
といった意味が出てきました。
このままではピンとこないので、log
も調べてみます。
log
の意味は色々ありますが記録
に関する意味があるようです。これらをふまえて、前述のコードを翻訳してみると、
言う "Hello World"端末の記録(Hello World)rubyの方は
Hello Worldと言う
という風に解釈できそうです。
JavaScriptの方は端末(=()の中身)の記録を出す
とかなり強引にに解釈できそうです。結果
JavaScriptの方はかなり強引になってしまいましたが、Rubyの方は割としっくりくる感じです。
Rubyは日本人が作った言語というのも、こういう結果に影響しているのかもしれません。
JavaScriptの方は英語ではないのでは?という疑念が沸々と湧いています。
- 投稿日:2019-11-28T20:08:10+09:00
[ruby2.5~] 文字列中の先頭, 末尾から特定文字を一つだけ消す
特定の文字を先頭から見つかった最初だけ、末尾から見つかった一つだけ消したいニーズがあった
gsubやdeleteだと下記の様に見つかった全部の文字を消してしまうので使えない'中野区東中野'.gsub('中野', '') => "区東" '中野区東中野'.delete('中野') => "区東"地味に面倒な記憶があったけれど、ruby2.5から
delete_suffix
,delete_prefix
というメソッドが追加されていた'中野区東中野'.delete_prefix('中野') => "区東中野" '中野区東中野'.delete_suffix('中野') => "中野区東"破壊的メソッドも用意されているらしい。便利!
参考
https://docs.ruby-lang.org/ja/latest/method/String/i/delete_suffix.html
https://docs.ruby-lang.org/ja/latest/method/String/i/delete_prefix.html
- 投稿日:2019-11-28T19:31:20+09:00
サクッと高機能なWebスクレイピングを実現できるRubyGem「Kimurai」
はじめに
Ateam cyma Advent Calendar 2019 の 6日目です。
本日の担当はエイチームのEC事業本部でWebアプリケーションエンジニアをしている@hibiheionです。
業務では主に自転車ECサイトcymaのバックエンドの機能をRailsで書いています。
今年のアドベントカレンダーでは2日目と3日目に続いての登場です。本題
WebスクレイピングはWebページの情報を自動的に取得する手法です。
RubyはCapybara(※1)やNokogiri(※2)といったRubyGemのおかげでわりと簡単にWebスクレイピングを実現できます。
ですが、夜間に自動でスクレイピングするという場合などには「Webページから情報を取得する」という本来やりたいこと以外にエラーハンドリングやログの出力といったことに手間をかける必要がでてきます。
そういった手間をかけずに高機能なWebスクレイピングを実現できるすばらしいRubyGemがあります。
それが今回ご紹介するKimuraiです。※1:CapybaraはWebページを操作するためのRubyGem
※2:NokogiriはWebページの要素を解析するためのRubyGemKimuraiとは
Kimuraiの公式ドキュメントはこちら
https://github.com/vifreefly/kimuraframework概要
- Webスクレイピングを目的としたRubyGem
- Webスクレイピングフレームワークという立ち位置で、Kimuraiを入れることでWebスクレイピングに必要な機能がまとめて手に入る
- PythonにScrapyという有名なWebスクレイピングフレームワークがあるのですが、GithubのタグにScrapyが入っているなどRuby版Scrapyを目指しているように感じます
- CapybaraやNokogiriといったRubyでのWebスクレイピングでは定番のRubyGemを使用している
- この記事を公開した2019年12月の時点ではマイナーな存在
- RubyGemsのダウンロード数は9,500くらい
- Githubのスター数は470くらい
- Kimuraiの由来は公式ドキュメントで言及されていないのですが、クモの一種の学名「Heptathela kimurai」ではないかと推測しています
特徴
以下のリストは公式ドキュメントのFeaturesの日本語訳(意訳)です。
https://github.com/vifreefly/kimuraframework#features
- JavaScriptで表示するWebサイトもスクレイピングできる
- ヘッドレスChrome、ヘッドレスFirefox、PhantomJS、HTTPリクエスト(mechanize gem)をドライバとして使用できる
- スクレイピングのコードを書いてから使用するドライバを変更できる
- Capybaraのすべての機能を使用できる
- 次のような項目を設定できる
- デフォルトのヘッダー
- クッキー
- リクエスト間の待ち時間
- プロキシやユーザーエージェントのローテーション
- 以下のようなスクレイピングを簡単にするための機能が備わっている。
- save_to : 結果をJSONやCSVで保存できる
- unique? : 同じデータをスキップする
- リクエストエラーを自動的にハンドリングする
- メモリやリクエストの上限に達したときに自動的にリスタートしてスクレイピングを継続する
- wheneverを使って定期的に実行できる
- (訳注)wheneverは定期的にジョブを実行するRubyGem
- 「in_parallel」というシンプルなメソッドでスクレイピングを並列実行できる
- 2つのモードがある
- 単一ファイルのシンプルなスパイダー
- Scrapyのようなプロジェクト形式
- コンソールでの開発モード・色付けされたロガー・デバッカーといった便利な機能が備わっている。これらはPryやByeBugに対応している。
- ubunt18.04での実行環境の自動セットアップ、Ansibleでのコマンドを使用したデプロイが可能
- コマンドラインからすべてのプロジェクトのスパイダーを動かすことができる。スパイダーはひとつずつ動かすことも並列して動かすこともできる。
Webスクレイピングにあたってあるとうれしい機能が盛りだくさんです。
Kimuraiを導入すると、自分ではほとんど手を動かさずにこれらの機能が手に入るのです。
実に素晴らしいと思いませんか?使い方
ここからはKimuraiの使い方を説明します。
特徴のところで書いたように2つのモード(単一ファイルとプロジェクト形式)があるのですが、ここでの説明は単一ファイルのモードについてのみです。準備
Kimuraiを使用するためには次のような準備が必要です。
- ruby2.50以降のインストール
- Kimuraiのインストール(gemをインストールするだけ)
- ブラウザと対応したWebドライバーのインストール
公式ドキュメントにインストール手順がコマンドと一緒に載っているのでそちらを参考にしてください。
https://github.com/vifreefly/kimuraframework#installationスクレイピングの実行
作成したプログラムをrubyコマンドから動かすだけです。
ruby spider.rbサンプルコード
Kimuraiを使用しない場合と使用した場合の2パターンでサンプルコードを作成しました。
サンプルコードでは弊社の自転車ECサイトcymaをスクレイピングして自転車の情報を取得しています。
具体的には次のようなことをしています。
- トップページに訪れる
- ナビゲーションからカテゴリページのリンクを取得する
- カテゴリページに移動する
- カテゴリページで商品名、最低価格、最高価格を取得する
- 4で取得した情報をCSVファイルに出力する
サンプルコードの途中でCSSセレクタが出てきますが、それぞれ下記の位置を示しています。
■カテゴリページの「#cy-products .cy-product-list .product」
なお、記事の公開時点ではサンプルコードの動作を確認していますが、サイトの変更により今後動かなく可能性があります。
Kimurai未使用
まずはKimuraiを使用しないプログラムです。
Webスクレイピングを実行するCapybaraSpiderクラスでスクレイピングの入り口になるメソッドはcrawl!
です。# 動作確認する際は以下のRubyGemのインストールが必要 require "capybara" require "nokogiri" require "selenium-webdriver" require "csv" # Webスクレイピング実行クラス class CapybaraSpider # トップページのURL CYMA_HOME = "https://cyclemarket.jp".freeze # ドライバの接続情報 @session = nil # ドライバを初期化する def initialize Capybara.register_driver :selenium do |app| Capybara::Selenium::Driver.new(app, browser: :chrome, desired_capabilities: Selenium::WebDriver::Remote::Capabilities.chrome( chrome_options: { args: %w(headless disable-gpu window-size=1280,800), } ) ) end Capybara.javascript_driver = :selenium @session = Capybara::Session.new(:selenium) end # スクレイピングを実行する def crawl! # トップページからカテゴリページへのリンクを取得する categories = parse_top_page sleep 2 # カテゴリページから商品情報を取得する products = [] categories.each do |category| products += parse_category_page(category) sleep 2 end # CSV出力 CSV.open("results.csv", "wb") do |csv| csv << %w[name category_name min_price max_price] products.each { |product| csv << [product[:name], product[:category_name], product[:min_price], product[:max_price]] } end end private # トップページを解析する # @return [Array] カテゴリページへのリンク def parse_top_page # トップページを訪問し、HTMLを解析する @session.visit CYMA_HOME response = Nokogiri::HTML.parse(@session.html) categories = [] # CSSセレクタを使ってヘッダのナビゲーションを取得する response.css("#nav-global ul li a").each do |menu| # HTMLのクラスを見てカテゴリページ以外は除外する next if menu[:class].include?("outlet") || menu[:class].include?("parts") # ナビゲーションからカテゴリページへのリンクを取得する category_name = menu.css(".caption").text category_url = "#{CYMA_HOME}#{menu[:href]}" categories << { category_name: category_name, category_url: category_url } end categories end # カテゴリページを解析する # @param [Array] category カテゴリページへのリンク # @return [Array] 商品情報 def parse_category_page(category) # カテゴリページを訪問し、HTMLを解析する @session.visit category[:category_url] response = Nokogiri::HTML.parse(@session.html) products = [] response.css("#cy-products .cy-product-list .product a").each do |product| # CSV出力のために1件ごとにハッシュに入れる row = {} row[:name] = product_name(product.css(".body .title").text.strip) row[:category_name] = category[:category_name] row[:min_price] = product.css(".min-price").text.strip.delete("^0-9") row[:max_price] = product.css(".max-price").text.strip.delete("^0-9") products << row end products end # 商品名にメーカー名がついている場合はメーカー名を取り除く # @param [String] base_name 元の商品名 # @return [String] メーカー名を取り除いた商品名 def product_name(base_name) base_name.include?("\n") ? base_name.split("\n")[1].strip : base_name end end # スクレイピングを開始する spider = CapybaraSpider.new spider.crawl!Kimurai使用
次にKimuraiを使用したプログラムです。
説明のためにプログラム中のコメントを多めにしています。
基本的な使い方はこのサンプルコードで書いた内容で十分だと思います。
Webスクレイピングを実行するKimuraiSpiderクラスは以下の手順でスクレイピングを開始します。
- 継承しているKimurai::Baseクラスの
crawl!
メソッドを呼び出すcrawl!
メソッドからKimuraiSpiderクラスのparse
メソッドを呼び出すrequire "kimurai" # Webスクレイピング実行クラス # Kimurai::Baseを継承する class KimuraiSpider < Kimurai::Base # 名前 @name = "kimurai_spider" # スクレイピングに使用するドライバ @engine = :selenium_chrome # 最初に訪れるURL。配列で複数設定することも可能。 @start_urls = ["https://cyclemarket.jp"] @config = { # ユーザーエージェント user_agent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36", # ページを開く前に2秒待つ before_request: { delay: 2 } } # starts_urlsのページを解析する # 継承しているKimurai::Baseのcrawl!メソッドから呼ばれる # @param [Nokogiri::HTML::Document] response 対象ページを対象としたNokogiri::HTML.parseの結果 # @param [String] url 対象ページのURL # @param [Hash] data 前ページからの引数 def parse(response, url:, data: {}) # CSSセレクタを使ってヘッダのナビゲーションを取得する # 項目の取得には「css」や「xpath」といったNokogiriの検索系メソッドが使用できる response.css("#nav-global ul li a").each do |menu| # HTMLのクラスを見てカテゴリページ以外は除外する # ノードのアクセスでもNokogiriと同じメソッドを使用できる next if menu[:class].include?("outlet") || menu[:class].include?("parts") # ナビゲーションからカテゴリページの情報を取得する category_name = menu.css(".caption").text category_url = absolute_url(menu[:href], base: url) # 「request_to」メソッドでカテゴリページに移動し、カテゴリページを解析する。引数は下記の通り。 # ・第1引数は移動先のページの解析に使うメソッド # ・キーワード引数の「url」は移動先のページのURL # ・キーワード引数の「data」は移動先のページの解析に使うメソッドへの引数 request_to :parse_category_page, url: category_url, data: { category_name: category_name } end end # カテゴリページを解析する # @param [Nokogiri::HTML::Document] response 対象ページを対象としたNokogiri::HTML.parseの結果 # @param [String] url 対象ページのURL # @param [Hash] data 前ページからの引数 def parse_category_page(response, url:, data: {}) # 商品情報を取得する response.css("#cy-products .cy-product-list .product a").each do |product| # CSV出力のために1件ごとにハッシュに入れる row = {} row[:name] = product_name(product.css(".body .title").text.strip) row[:category_name] = data[:category_name] row[:min_price] = product.css(".min-price").text.strip.delete("^0-9") row[:max_price] = product.css(".max-price").text.strip.delete("^0-9") # CSVファイルに出力する save_to "results.csv", row, format: :csv end end private # 商品名にメーカー名がついている場合はメーカー名を取り除く # @param [String] base_name 元の商品名 # @return [String] メーカー名を取り除いた商品名 def product_name(base_name) base_name.include?("\n") ? base_name.split("\n")[1].strip : base_name end end # スクレイピングを開始する KimuraiSpider.crawl!こちらはドライバの初期化などが不要なのでスッキリして見えると思います。
ソースコードが短いほど良いというものでもないですが、コメントと空行を除いた行数を比較するとKimurai未使用が67行、Kimurai使用が33行とほぼ半減しています。所感
実際の運用ではここに書いたサンプルコードよりいくらか複雑なことをしています。
その中で感じた良かった点と気になった点は下記の通りです。良かった点
- 「Webページから情報を取得する」という本来やりたいことに集中できる
- エラーハンドリングやCSVファイルの制御などを書かなくても良い
- CapybaraやNokogiriのメソッドをそのまま使うことができる
- すでにRubyでWebスクレイピングを行っている場合、慣れ親しんだ仕組みを活用できるので移行しやすい
- 別ページに移動する際に
request_to
メソッドを呼ぶ必要があるため、HTMLを解析するメソッドが自然とページごとに分かれる
- ページの構成が変わったときの影響が限定されるので良い設計だと思う
- 公式ドキュメントが充実している
- まだ有名ではないRubyGemだとソースコードを見ないと使い方がわからないことも珍しくないが、Kimuraiは公式ドキュメントだけで使い方を理解できた
気になった点
- Kimuraiの想定から外れた使い方はしにくい
- スタート地点にあたるstart_urlsからWebページをたどっていくような使い方を想定している
- start_urlsを変更する仕組みが公式にはないため、商品コードのリストをもとにURLのリストを組み立てて特定の商品ページだけから情報を取得するいうことはやりにくい
- できないわけでなくて、今の運用では下記のようなメソッドをクラス内に書いてstart_urlsを動的に書き換えている
def self.build_start_urls start_urls = [] %w[1 2 4 8 16 32 64].each { |n| start_urls << "https://cyclemarket.jp/product/category_#{n}/" } @start_urls = start_urls end
- 今の段階だと日本語の情報がないに等しい
- とはいえ、公式ドキュメントの英語はわかりやすい
まとめ
Kimuraiの基本的な使い方を身に付けるのはそれほど難しくなく、使い方を身に付ければ効率良くWebスクレイピング機能を実装できます。
この記事で少しでもKimuraiに興味を持っていただければうれしいです。最後になりましたが、開発者のVictor Afanasevさん、素晴らしいRubyGemを作っていただきありがとうございます!
次回予告
Ateam cyma Advent Calendar 2019 の 6日目の記事は以上です。
7日目はエンジニアの@namedpythonさんが担当します。
内容はPythonに関するもの、ではなくデータの可視化に関するものです。さいごに
株式会社エイチームでは、一緒に働けるチャレンジ精神旺盛な仲間を募集しています。
エンジニアで興味を持った方はcymaのQiita Jobsをご覧ください。
そのほかの職種は、エイチームグループ採用サイトをご覧ください。
- 投稿日:2019-11-28T18:58:43+09:00
【Rails】CSVファイルからデータをインポート
簡単なTODOアプリに、CSVファイルからタスクを追加する機能を実装します。
手順は以下の記事で説明されているものとほとんど同じです。めちゃくちゃ参考になりました。
【Ruby on Rails】CSVインポート実装
タスク追加、編集、削除機能、ログイン機能などを持つTODOアプリにCSVアップロード機能を実装して行きます。
Ruby on Railsで簡単なアプリを作成
【Rails】ログイン機能を実装するrubyの標準ライブラリ
csv
を追加/config/application.rbrequire 'csv'
roo
というgemを追加csvファイルを読み込むためのgem
roo
を追加します。Gemfilegem 'roo'terminal$ bundle installタスク一覧画面にcsvアップロード用のフィールドを追加
/app/views/tasks/_logged_in.html.erb<%= form_tag import_tasks_path, multipart: true do %> <%= file_field_tag :file %> <%= submit_tag "インポート" %> <% end %>コントローラーにアクションを追加
Task.import(params[:file])
で使われているimport
メソッドは後ほど定義します。/app/controllers/tasks.controller.rbdef import Task.import(params[:file]) redirect_to root_url endルーティングを設定
collection {post :import}
と書き込むことで、resources :tasks
で作成されるルーティング以外の、tasksコントローラーのアクションへのルーティングを追加することができます。/config/route.rbresources :tasks do collection {post :import} endterminal$ rails routes . . import_tasks POST /tasks/import(.:format) tasks#import . .
import_tasks
という名前付きルートが追加されました。モデルにCSV読み込み、登録処理を実装
/app/models/task.rb#importメソッド def self.import(file) CSV.foreach(file.path, headers: true) do |row| # IDが見つかれば、レコードを呼び出し、見つかれなければ、新しく作成 task = find_by(id: row["id"]) || new # CSVからデータを取得し、設定する task.attributes = row.to_hash.slice(*updatable_attributes) task.save end end # 更新を許可するカラムを定義 def self.updatable_attributes ["title", "user_id"] end動作確認
以下のようなファイルを用意します。
taskForTodoApp.csvtitle,user_id パンを買う,2 筋トレ,2 メルカリの発送,8 ティッシュを交換する,2ハマったポイント
・CSVファイル内にuser_idを記載しておらず、データベースへの登録時にエラーが発生していたところで少しハマりました。
TODO
・TSVファイルも取り込めるようにする
参考
- 投稿日:2019-11-28T18:56:18+09:00
さくらVPSでCentOS7 10.Ruby On Railsインストール
はじめに
自由にテスト出来るLinuxのサーバーがほしくて、さくらVPSで構築してみました。
順次手順をアップしていく予定です。今回は、Ruby On Railsをインストールします。
どういった構成が正解かは判断がつきかねているのですが、今のところこんな感じです・・(^^;目次
- 申し込み
- CentOS7インストール
- SSH接続
- Apache・PHPインストール
- MariaDBインストール
- FTP接続
- sftp接続
- phpMyAdminインストール
- 環境のバックアップ
- Ruby On Railsインストール
10.Ruby On Railsインストール
必要パッケージインストール
Node.jsインストール
Node.jsのバージョンを管理する「n」パッケージをインストールします。
鶏と卵のような話ですが、「n」パッケージインストールにはnpmが必要で、npmにはNode.jsが必要ということで、Node.jsをインストールする為にまずnpmとNode.jsをインストールします。npmインストール
$ sudo yum install epel-releasenode.jsインストール
$ sudo yum install nodejs npm「n」パッケージインストール
$ sudo npm install -g n「n」パッケージを使ってNode.jsをインストール
最新版は「latest」、安定版は「stable」でインストールできます。
$ sudo n latest $ node -v v11.13.0$ sudo n stable $ node -v v10.15.3「n」パッケージの使い方
コマンド 内容 n インストールしているバージョンの表示やバージョンを切り替える n ls すべてのバージョンを表示する n --latest 最新バージョンを表示する n --lts 安定バージョンを表示する n latest 最新バージョンをインストールする n stable 安定バージョンをインストールする n [version] 指定したバージョンをインストールする n rm [version] 指定したバージョンを削除する n prune すべてのバージョンを削除する その他もろもろインストール
$ sudo yum -y install gcc make openssl openssl-devel gcc-c++ mysql-devel readline-devel libxml2-devel libxslt-devel git bzip2 zlib-devel sqlite-devel$ sudo npm install yarn -gRubyインストール
rbenvインストール
rbenvは、複数のRubyのバージョンを管理し、プロジェクトごとにRubyのバージョンを指定して使うことを可能としてくれるツールです。
まずこれをインストールします。$ cd /usr/local $ sudo git clone https://github.com/rbenv/rbenv.git $ sudo mkdir rbenv/plugins && cd rbenv/plugins $ sudo git clone git://github.com/sstephenson/ruby-build.gitログイン時にrbenvを使えるようにする初期化スクリプトを記述します。
$ sudo vi /etc/profile.d/rbenv.sh以下を追加
export RBENV_ROOT="/usr/local/rbenv" export PATH="${RBENV_ROOT}/bin:${PATH}" eval "$(rbenv init -)"パーミッションの変更
$ sudo chmod -R 777 /usr/local/rbenv設定を反映させるために、ここで一度ログアウトして再ログインします。
再ログインしたら、確認。$ rbenv install -l 2.6.5Rubyインストール
rbenvを使ってRubyをインストールします。
インストール可能なRubyバージョン一覧を表示します。$ rbenv install -lバージョン2.6.5のRubyをインストールします。
$ rbenv install 2.6.5全体で使用するRubyのバージョンを指定
$ rbenv global 2.6.5確認
$ ruby --version ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-linux]Rails環境構築
GemとBundler
GemはRubyGems(Ruby用のパッケージ管理ツール)で管理されるrubyのアプリケーションやライブラリです。
Bundlerは、gem動詞の互換性を保ちながらパッケージの種類やバージョンを管理するツールです。gem
確認
$ which gem /usr/local/rbenv/shims/gem最新版にアップデート
$ gem update --systemバージョン確認
$ gem -v 3.0.6bundlerインストール
システムのgemにはbundlreのみインストールし、bundler以外のものはプロジェクトのvendor/bundleに格納します。
ので、ここではbundlerのみインストール。$ gem install bundlerプロジェクトのフォルダ
以前、4. Apache・PHPインストールでApacheをインストールした時に作成した、/var/www/の中にappというフォルダを作成し、その中にプロジェクトを作っていきます。
フォルダ作成
$ mkdir /var/www/appWebコンテンツに複数のユーザが操作出来るように作成したグループに権限を与えます。
$ sudo chown root:webadmin /var/www/app/ $ sudo chmod 2775 /var/www/app/ -R「bundle exec」の省略設定
railsコマンドをプロジェクト内のvendor/bundleに格納すると、railsコマンド呼出時に、「bundle exec rails server」のように「bundle exec」を付けて呼び出す必要があります。
このbundle execを省略できるように設定します。
この設定は、各ユーザーごとに必要です。スクリプトをダウンロード
$ cd $ curl -L https://github.com/gma/bundler-exec/raw/master/bundler-exec.sh > ~/.bundler-exec.shbundler-exec.shを編集
$ vi ~/.bundler-exec.shリストにrailsを追記(下の方にあります)
・ ・ (省略) ・ ・ unicorn unicorn_rails wagon rails }" define-bundler-aliases unset -f define-bundler-aliases反映させます。
$ source ~/.bashrc利用可能なRailsのバージョンの確認
$ gem query -ra -n "^rails$"現時点で最新は6.0.1でしたが、以下のプロジェクトでは5.2.4を使います。
プロジェクト作成
プロジェクト用フォルダ
bundlerを利用する為、「rails new 」する前に、フォルダを作成します。
$ mkdir /var/www/app/HelloWorld $ cd /var/www/app/HelloWorldローカルのrubyのバージョンを指定。
$ rbenv local 2.6.5確認
$ rbenv version 2.6.5 (set by /var/www/app/HelloWorld/.ruby-version)Gemfile
Gemfileの雛形作成
$ bundle init riting new Gemfile to /var/www/app/HelloWorld/GemfileGemfileの編集
$ vi Gemfilerailsのバージョン5.2.4を使用できるように下記のように修正します。
# frozen_string_literal: true source "https://rubygems.org" git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } # コメントを外し、バージョンを記述 gem "rails", "5.2.4"gemのインストール
$ bundle install --path vendor/bundleインストールのメッセージが流れ、無事に終わるかと思ったのですが、こんなメッセージが・・・
HEADS UP! i18n 1.1 changed fallbacks to exclude default locale. But that may break your application. Please check your Rails app for 'config.i18n.fallbacks = true'. If you're using I18n (>= 1.1.0) and Rails (< 5.2.2), this should be 'config.i18n.fallbacks = [I18n.default_locale]'. If not, fallbacks will be broken in your app by I18n 1.1.x. For more info see: https://github.com/svenfuchs/i18n/releases/tag/v1.1.0「i18nの設定方法が変わったので気を付けなさい」ということみたいです。
だだ、今回はRailsのバージョン5.2.4にしていますので、I18n (>= 1.1.0) and Rails (< 5.2.2)の条件には引っ掛からないので大丈夫だと思います。新規プロジェクト作成
これでやっとrailsコマンドが使えるようになりましたので、プロジェクトを作成します。
フォルダは作成済みですので、プロジェクト名の指定は不要です。$ rails new ..ruby-versionを上書きしますか?と聞いてきますのでYを入力。
Overwrite /var/www/app/HelloWorld/.ruby-version? (enter "h" for help) [Ynaqdhm]YGemfileを上書しますか?と聞いてきますのでYを入力。
Overwrite /var/www/app/HelloWorld/Gemfile? (enter "h" for help) [Ynaqdhm]Y順調に行くと思いきや、以下のメッセージが出ました。
The dependency tzinfo-data (>= 0) will be unused by any of the platforms Bundler is installing for. Bundler is installing for ruby but the dependency is only for x86-mingw32, x86-mswin32, x64-mingw32, java. To add those platforms to the bundle, run `bundle lock --add-platform x86-mingw32 x86-mswin32 x64-mingw32 java`. Fetching gem metadata from https://rubygems.org/............ Fetching gem metadata from https://rubygems.org/. Resolving dependencies... Bundler could not find compatible versions for gem "sprockets": In snapshot (Gemfile.lock): sprockets (= 4.0.0) In Gemfile: sass-rails (~> 5.0) was resolved to 5.1.0, which depends on sprockets (>= 2.8, < 4.0) rails (~> 5.2.4) was resolved to 5.2.4, which depends on sprockets-rails (>= 2.0.0) was resolved to 3.2.1, which depends on sprockets (>= 3.0.0) Running `bundle update` will rebuild your snapshot from scratch, using only the gems in your Gemfile, which may resolve the conflict. run bundle exec spring binstub --all bundler: command not found: spring Install missing gem executables with `bundle install`依存関係に問題があるから、「bundle lock --add-platform x86-mingw32 x86-mswin32 x64-mingw32 java」を実行しろということのようです。
あと、「bundle update」を実行すると、スナップショットを最初から再構築します、と。
なので、やってみます。$ bundle lock --add-platform x86-mingw32 x86-mswin32 x64-mingw32 java Fetching gem metadata from https://rubygems.org/............ Fetching gem metadata from https://rubygems.org/. Resolving dependencies...... Bundler could not find compatible versions for gem "sprockets": In snapshot (Gemfile.lock): sprockets (= 4.0.0) In Gemfile: sass-rails (~> 5.0) was resolved to 5.1.0, which depends on sprockets (>= 2.8, < 4.0) rails (~> 5.2.4) was resolved to 5.2.4, which depends on sprockets-rails (>= 2.0.0) was resolved to 3.2.1, which depends on sprockets (>= 3.0.0) Running `bundle update` will rebuild your snapshot from scratch, using only the gems in your Gemfile, which may resolve the conflict.$ bundle update The dependency tzinfo-data (>= 0) will be unused by any of the platforms Bundler is installing for. Bundler is installing for ruby but the dependency is only for x86-mingw32, x86-mswin32, x64-mingw32, java. To add those platforms to the bundle, run `bundle lock --add-platform x86-mingw32 x86-mswin32 x64-mingw32 java`. ・ ・ (以下略) ・ ・と、同じようなメッセージが・・・
とりあえず、再度「bundle lock --add-platform x86-mingw32 x86-mswin32 x64-mingw32 java」して、「bundle update」すると、「Bundle updated!」と出たので、とりあえずOKかなと。サーバー起動
3000のポートを開ける
ファイアウォールを使っている場合
ポートを開ける
$ sudo firewall-cmd --permanent --add-port=3000/tcp $ sudo firewall-cmd --reload![2019-11-28.png](https://qiita-image-store.s3.ap-northeast-さくらVPSのパケットフィルタを使っている場合
- さくらVPSコントロールパネルにログインし、サーバーを選択
- [パケットフィルタ]-[パケットフィルタ設定へ>]を選択
- [+任意の解放ポート設定を追加する]ボタンをクリック
- [TCP][3000]を設定
- [設定]ボタンをクリック
サーバー起動
$ rails server -b 0.0.0.0 => Booting Puma => Rails 5.2.4 application starting in development => Run `rails server -h` for more startup options Puma starting in single mode... * Version 3.12.1 (ruby 2.6.5-p114), codename: Llamas in Pajamas * Min threads: 5, max threads: 5 * Environment: development * Listening on tcp://0.0.0.0:3000 Use Ctrl-C to stop無事起動しました。
ブラウザで確認
次回
次回は、Pythonのインストールの予定です。
- 投稿日:2019-11-28T18:32:34+09:00
RailsのDM一覧に最後のメッセージを表示させる方法
はじめに
記事①と記事②を参考にDM機能を作らせていただきました。投稿してくださった方々に深く感謝いたします。
以下は記事①の通りにDM機能を作成した前提で進めます。やりたいこと
TwitterやLINEのようにメッセージの一覧に最後のメッセージを表記させる。
実装
記事①通りに進めるとメッセージ一覧はrooms#indexに表示させることになると思うので、以下のようにすればユーザ間の最後のメッセージを引っ張ってくることができます。
まず、記事②を参考にroomsコントローラ側に
@anotherEntries
を定義します。roomsコントローラーdef index @currentEntries = current_user.entries myRoomIds = [] @currentEntries.each do | entry | myRoomIds << entry.room.id end @anotherEntries = Entry.where(room_id: myRoomIds).where('user_id != ?', @user.id) endそして、
@anotherEntries
にはuser_idが自分のidではない相手の情報が配列として入っているので、以下のようにすればやりとりした最後のメッセージを引っ張ってこられます。rooms#index<% @anotherEntries.each do |e| %> <%= Message.find_by(id: e.room.message_ids.last).content %> <% end %>上はただ表記させただけなので、あとは自分好みにリンクにしたり字数に制限をかけたりしてみてください。
また、ここでは最後のメッセージを表示させましたが、上記のcontent
の部分をuser.name
にすれば最後にメッセージを送ったユーザ(自分か相手)の名前を引っ張ってくることもできます。
- 投稿日:2019-11-28T18:30:19+09:00
has_many_attachedなActiveStorageに属性を付与する
とあるModelに複数のファイルをAttachさせるときに、
ActiveStorage
のhas_many_attached
を使うことはよくあると思いますが、
このとき、
- ファイルに属性を付与したい
- 同じ属性のファイルが既にあるなら削除したい
的な感じの気持ちが溢れ出ると思います。
ので、やります。
class Foo < ApplicationRecord has_many_attached :bars endこのクラスで何かをattachします
class Foo < ApplicationRecord has_many_attached :bars def attach_bars bar = 'something' #何らか適当なファイル的なやつ bars.attach( io: StringIO.new(bar), filename: 'なんらかてきとうなふぁいるめい.txt', content_type: 'text/plain', metadata: { bar_type: 'something' } ) end end
metadata: { bar_type: 'something' }
の部分が何かいい感じのやつで、これでactive_storage_blobs.metadata
に"bar_type": "something"
な感じでデータが保持されるようになります。やったね。これで属性付与できたので、
bars
の中でbar_type == 'something'
なattachmentを削除したい場合は、foo = Foo.find(xxx) foo.bars.select {|bar| bar.metadata[:bar_type] == 'something' } .each {|bar| bar.purge }みたいな感じでpurgeすることはできるんですが、仮に
bars
が100件とか200件とかなってきたらウザウザなので、事前にクエリで絞り込む的なことがしたくなりました。というわけで、しました。
foo.bars.joins(:blob).where( "`active_storage_blobs`.`metadata`->>'$.bar_type' = ?", 'something' ).each { |bar| bar.purge }やったね!
- 投稿日:2019-11-28T18:16:43+09:00
コメントの削除も非同期で対応する
コメント投稿の非同期は成功しました。
そこで、コメント削除も非同期にて対応しようと思い。
クロームの検証画面でエレメントコピーして修正して下記コードを追加しました。
削除コメントして即削除でActiveRecord::RecordNotFound in TweetsController#destroyが出ます。
一度リロードをすれば問題なく削除できているので
非同期部分で引っかかっているのは確認済みです。どうすればいいのでしょうか?
コメント投稿と削除で別々の
コードがいるのでしょうか?
記載をするべきでしょうか?
何かファイルを増やしてそこに記載がいるのでしょうか?$(function(){ function buildHTML(comment){ var html = `<p> <strong> <a href=/users/${comment.user_id}>${comment.user_name}</a> : </strong> ${comment.text} <a class="comment-delete" rel="nofollow" data-method="delete" href="/tweets/${comment.tweet_id}">削除</a> </p>` return html; } $('#new_comment').on('submit',function(e){ e.preventDefault(); console.log(this) var formData = new FormData(this); var url = $(this).attr('action') $.ajax({ url: url, type: "POST", data: formData, dataType: "json", processData: false, contentType: false }) .done(function(data){ var html = buildHTML(data); $('.comments').append(html); $('.form_message').val(''); $('.form__submit').prop('disabled', false); }) .fail(function(){ alert('error'); }) }) })
- 投稿日:2019-11-28T16:43:13+09:00
RailsとLaravelの比較
はじめに
この記事はRailsとLaravelを比較分析してみた記事です.
Railsは以前から勉強していて,新たにLaravelを使ってみました.
Railsの勉強にはRuby on Rails 5 超入門と改訂4版 基礎 Ruby on Rails (IMPRESS KISO SERIES)を使いました.
Ruby on Rails 5 超入門についてはチュートリアル形式で一見わかりやすいのですが,誤植などが多いのとレベルが優しすぎるのであまりオススメしません.Laravelの勉強はPHPフレームワーク Laravel Webアプリケーション開発 バージョン5.5 LTS対応を使いました.買う前に中身を確認しなかった僕が悪いのですが,本の厚さの割に内容が薄いです.また辞書的に使う分には良いのですが,チュートリアル形式で作っていく感じではないので,フレームワークを使ったことのない人などにはオススメ出来ません.
RailsとLaravelの基本情報
*以下,2019/11/28現在の情報
Rails Laravel 言語 Ruby PHP 初リリース 2004年 2011年 github https://github.com/rails/rails https://github.com/laravel/framework github start数 44.6K 19.5K githubのstart数ではrailsの方がLarvelの倍くらいの数になっています.Railsはいま流行りと個人的に思っていたりするのですが,リリースからはもう10年以上経過していました.
Googleトレンドで調べてみた
Googleトレンドでは検索のトレンドを調べて,検索キーワードで比較したりできるサービスです.Googleは面白いサービスを作っていますね.
これを使ってRailsとLaravelについて調べてみました.すべての国
https://trends.google.co.jp/trends/explore?date=all&q=Rails,Laravel
日本
https://trends.google.co.jp/trends/explore?date=all&geo=JP&q=Rails,Laravel
Laravelはリリースが2011年なので,2012年頃まではほぼ0です.
全ての国
の場合ではLaravelがRailsをやや追い越したくらいになっています.日本
の場合ではまだRailsを追いかけていますが,このままの状態が続くと追い越しそうです.個人的分析
ここからはRailsとLaravelを使ってみた感想になります.
本,参考資料などの多さは? 勝者:Rails
Railsの方がネットでググったときなどの参考になる記事などが多いです.それはRailsで使われている言語のRubyの開発者が日本人(まつもとゆきひろ氏)なのでRubyの日本語資料がそもそも多いという点と,Laravelより7年早くリリースしているからかなと思っています.
*IT分野の中で日本発祥の技術はRubyと深層学習のChainerくらいしか知らない(他にあったらコメントください)のでRubyは本当すごいです.
勉強のしやすさは? 勝者:Rails
難易度的にもRailsとLaravelは遜色ないですが,やはり本や参考資料などが多い方が勉強しやすいです.以前Go言語のフレームワークのGinを使う機会があったのですが,公式以外のドキュメントが少なくて開発しにくかったことがあります.
使いやすさは? 同じ
- railsには
scaffold
という色々必要なものを一発で作ってくれるコマンドがあるのですが,Laravelは標準でサポートしていません(あるけど,githubの更新も止まっているのでバージョンに寄っては今後使えなくなるかも).- Laravelは比較的命名規則などが緩いので,ネットで調べても色々な書き方をしているのでわかりにくいです.
- 逆にRailsは規則が厳しいのですが,厳しいが故に,変数名などを修正するのが億劫になります.
- Laravelはデフォルトでログイン認証などが入っているので,インストールなどの手間が省けます.
RailsとLaravelのどっちがいいの? 若干Laravelかな
ここまで読んだ人にはRailsの方が良い感じに見えますが,他のエンジニアの人の意見を聞くと
「Railsは比較的開発が速くできるからスタートアップに多いが,保守・運用や難しい機能にはRailsは向いておらず,JavaやPHPのフレームワークの方が開発が容易」
という意見が多かったです(社会人になって1ヶ月くらいなのでこの辺は自分の中で不確定要素).確かに求人とか見てるとPHPとかJavaの募集の方が多いなという印象を持ったのでLaravelとしました.
まとめ
Railsが最強(僕の大学の教授)という人もいれば,Railsはオワコンと言っている人もいますのでどうなんですかね...
僕の周囲ではRailsの方がよく耳にします.
Rails,LarvelはRubyとPHPという言語の違いは多少ありますが,考え方や使い方はほとんど同じです.個人的には勉強のしやすいRailsを最初にやってMVCの基礎を勉強して,Laravelとかに移ればいいかなと思います.
- 投稿日:2019-11-28T15:58:39+09:00
【Rails】もっと早く知りたかったデバッグ用gem 'better_errors','binding_of_caller'
はじめに
先日伊藤さんのこちらの動画(↓)を見ました。
プログラミング初心者歓迎!「エラーが出ました。どうすればいいですか?」から卒業するための基本と極意 - YouTube「いや、なんでもっと早く見なかった!」と思うくらい具体的なデバッグ手法が諸々解説されています。
そこで出てきたgem
better_errors
&binding_of_caller
の導入方法と見方について簡単にまとめます。今まで
puts デバッグ
binding.pry
rails serverのログ
を使ってエラーと闘っていましたが、この2つのgemはもっと早く知りたかったです
この記事が役に立つ方
- エラーに苦しんでいるRails初心者
この記事のメリット
- デバッグの効率が上がる
環境
- macOS Catalina 10.15.1
- zsh: 5.7.1
- Ruby: 2.6.5
- Rails: 5.2.3
- Docker: 19.03.5
better_errors
とは?デフォルトのエラー画面をわかりやすく整形してくれるgem。
binding_of_caller
とは?上記
better_errors
と一緒に使うことで、ブラウザ上でirb
を使えるようになるgem。
※本記事では使用方法について触れていません。導入方法
Gemfilegroup :development do gem 'better_errors' gem 'binding_of_caller' endGemfileに上記追記し、
bundle install
で完了。簡単!
※Dockerを使用している場合はもうひと手間必要
app/config/environments/development.rbBetterErrors::Middleware.allow_ip! "0.0.0.0/0"仮想環境を使っている方は、うまく動作しないようです。
私はDockerを使っていますが、上記コードを追記してサーバー再起動で動作しました。
Gem 『Better errors』が動かないとき | HippoBlog使用例
ArgumentErrorが出ていた場合
form_with
を使おうとしたらエラーが出た場合を例にします。エラーメッセージが最上部にあるのは変わりませんが、
その下に2つタブがあります。これが超便利。
- Application Frames
- All Frames
1. Application Frames
最初はApplication Framesが表示されています。
ここでは、自分の書いたコードを対象にエラーに関係する箇所を明示してくれています。
2. All Frames
次に、All Framesをクリックすると、自分が書いた箇所以外(gemやActiveSupportなど)まで踏み込んでエラーに関係する箇所が表示されます。
それぞれクリックしていくとコードが表示されます。
例えば今回は、
form_with
のソースコードまで表示してくれます。
↓
form_with
の最初の1行を抜き出すとこんな感じです。def form_with(model: nil, scope: nil, url: nil, format: nil, **options, &block)これで指定すべき引数がわかり、今回は
「いけね!そういえば
model:
って書き忘れた!」と気づくことが出来ます。便利!
その他、
NoMethodError
で~ for nil:NilClass
とか出ていたら、ブラウザでそのまま変数の中身を確認したり出来て非常に便利です。
※画像最下部がコンソールになっています。おわりに
最後まで読んで頂きありがとうございました
デバッグ手法は学び始めの段階でなるべく多くリストアップしておいたほうが効率がいいと思いますが、
better_errors
はもっと早く導入していたかったです伊藤さんのYoutube、非常に勉強になるのでまた他の動画も見させて頂きます。
参考にさせて頂いたサイト(いつもありがとうございます)
プログラミング初心者歓迎!「エラーが出ました。どうすればいいですか?」から卒業するための基本と極意 - YouTube
プログラミング初心者歓迎!「エラーが出ました。どうすればいいですか?」から卒業するための基本と極意(解説動画付き) - Qiita
Gem 『Better errors』が動かないとき | HippoBlog
【Rails】better_errorsとbinding_of_callerで自分でエラーを解決できるようになろう【初心者向け】 - Qiita
- 投稿日:2019-11-28T15:04:38+09:00
Webエンジニア業界に感じた違和感
私は18年間ほど企業向け製品開発の世界(SIer含む)にいました。
メインで使っていた言語はC++とC#です。2014年にウェブスタートアップを数カ月手伝う経験があり、
フロントエンドの技術やWebフレームワークに興味を持ち、ウェブ系のカンファレンスに行くようになりました。ウェブの技術は大変面白かったのですが、そこである大きな違和感を感じもしました。
カンファレンスで発表する人の中にはその道の有名人みたいな人がいて、ブログやTwitter、Githubなどで沢山フォロワーがついています。
常に数字や営業的な雰囲気に包まれている企業向け製品開発にはない、純粋に技術を楽しむ雰囲気がとても楽しかったです。
ですが、よくよく観察しているとWeb業界には「何が凄いのかよくわからないけど有名な人」もいました。
はっきり言ってしまえば、「ただツールやライブラリの使い方を紹介するだけで有名人になっている人達がいる」ように見えてきたのです。
Webカンファレンスのほとんどの発表内容は、ツールやライブラリの構造上の理解や仕組み、またはそれによる営利的なメリットではなく、「このツールを使えばこんなことができる」という使い方の説明であり、多少の業務経験がある人が英語リファレンスを読み解けば、比較的容易に発表できてしまう内容が多かったです。
さらに業界を観察していると「新しい技術を紹介したもの勝ち」的な雰囲気が蔓延しており
目的を見失ってそのスピードの速さ、紹介するレトリックの巧みさが競われているような文化さえ感じたのです。そして周囲から有名になると、まるで芸能人のように祭り上げられます。(それが業界の面白さや楽しさでもあるのは理解してます)
世の中に何かをアウトプットできる
インフルエンサーとしての能力を持っているこれは素晴らしいことですし、その能力を持っていない人より持っている人は優れていると思います。
しかしそれがイコールその人の技術者としての技術力ではないはずです。ツールやライブラリをスクラッチで自作した本人じゃなければ評価されちゃいけないと言ってるわけではないです。
ですが、Web業界では「ライブラリを作った人」より「上手く紹介した人」の方が有名になっている、といった違和感を感じました。
技術とその価値は「具体的な成果物を出して世の中にどれだけの影響を与えたか?」ではないでしょうか?
その成果物は技術の紹介ブログ記事やTwitterやカンファレンスの発表やQiitaのGood数やGitHubのスターの数ではなく、「直接、あるいは間接にでも売上に貢献した目に見えるプロダクト」であるべきです。
極端かもしれませんが、これが基準にならなければ評価の基準も曖昧になります。
最後に、私はWeb業界の雰囲気が嫌いではありません。
Qiitaを見ていると新しいことを学ぶモチベーションが高まります。ですが、Qiitaやブログの記事を一つ読むにしても、その人は「本当に価値のあるアウトプット」をしている人なのかを考えながら接する必要があると思っています。
- 投稿日:2019-11-28T15:02:25+09:00
openssl1.0系がbrewから消えたことでrailsでエラーが発生する時の対処法
openssl1.0系がbrewから消えたことでrailsでエラーが発生する時の対処法
次のようなエラーが発生する場合の対処法です。
Library not loaded: /opt/local/lib/libssl.1.0.0.dylib (LoadError)
openssl1.1系にアップデートされた状態で、postgresqlのバージョンが古いとエラーが発生します。
対処法としては、
brew upgrade postgresql
でpostgresqlをアップデートしたら直りました。参考までに、openssl1.0系がbrewから消えた原因のHomebrewのコミットはこれです。
https://github.com/Homebrew/homebrew-core/commit/0349a7ca76f483483c6d5c1d4cfe6b458dee2665
- 投稿日:2019-11-28T14:10:22+09:00
Ruby on Rails のselectメソッドで生成されるoptionタグにdisabled属性を追加する
- 投稿日:2019-11-28T12:06:37+09:00
ABC085B - Kagami Mochi
問題
https://atcoder.jp/contests/abs/tasks/abc085_b
1回目
回答
重複削除のメソッドあるかな!って調べたらあったので一瞬で終わった。
N = gets.to_i D = N.times.map{gets.to_i} puts D.uniq.size結果
2回目
回答
せっかくなので自力で重複削除してみた
N = gets.to_i D = N.times.map{gets.to_i} for i in 0..(D.size-2) (D.size-1).step(i+1, -1) do |j| if D[j] == D[i] D.delete_at(j) end end end puts D.size結果
- 投稿日:2019-11-28T11:51:52+09:00
投稿できるかテスト
- 投稿日:2019-11-28T09:29:41+09:00
Rubyでブラックジャックのアプリを作った
プログラミング初学者がたどり着く定番のブラックジャックを作ってみました。
ちょっと雑感もあるし、いかにも初学者らしい感じのコーディングになっている気がするので、もう少しクラスを意識したり、可読性を良くしたり、効率の良い感じを検討して改修しようかな。
仕様要件
・ジョーカーなしの1〜13×4種の構成。
・相手が先に山札から引き、17以上になるまで引く。但し、1枚目しか数字がプレイヤーには見えない。
・プレイヤーは初期に2枚引き、ヒットがスタンドを選択する。ヒットならば1枚引き、スタンドならば現在の手札で勝負する。
・JQKは10として扱い、Aは1もしくは11として扱う。
・手札の合計値が21で勝利した場合はブラックジャックという結果が出る。実際に書いてみた
blackjack.rb# Card judgement def card_judge(i) # mark judgement mark_no = (i % 13 == 0) ? (i / 13) - 1 : i / 13 # Mark no: 0 SPADE / 1 HEART / 2 DIAMOND / 3 CRAB card_mark = case mark_no when 0 then "♠️" #SPADE when 1 then "♥️" #HEART when 2 then "♦️" #DIAMOND when 3 then "♣️" #CRAB end # number judgement card_no = i - ( 13 * mark_no ) # display judgement disp_list = %w(A 2 3 4 5 6 7 8 9 10 J Q K) disp_num = disp_list[(card_no - 1)] # return: card number / mark / display number return card_no, card_mark, disp_num end # card deisplay def disp_card(n) puts "#{card_judge(n)[1]} #{card_judge(n)[2]}" end # hand deisplay dealer def disp_hand_dealer(p) puts "\nhand list(#{p.length}):" p.each{|i| case i when p[0] disp_card(p[0]) else puts "Reverse" end } end # hand deisplay def disp_hand(p) puts "\nhand list(#{p.length}):" p.each{|i| disp_card(i) } end # Draw action def card_draw # Deck to hand draw_card = DECK.shift(1) # Card number return draw_card[0] end # Deck shuffle def deck_shuffle DECK.shuffle! end # Number sum def card_sum(m,o) if card_judge(m)[0] > 10 return 10 elsif card_judge(m)[0] == 1 if o + 11 < 21 return 11 else return 1 end else return card_judge(m)[0] end end def duel_judge(d_score, p_score) puts "Dealer's score:#{d_score}" puts "Player's score:#{p_score}" if p_score == d_score return "\nIt' draw." elsif p_score == 21 return "\nYou win. It's blackjack." elsif d_score == 21 return "\nYou lose. It's blackjack." elsif p_score > 21 return "\nYou lose. Player's burst." elsif d_score > 21 return "\nYou win. Dealer's burst." elsif p_score > d_score return "\nYou win." elsif p_score < d_score return "\nYou lose." end end # First setup # Dealer DEALER_HAND = [] dealer_score = 0 #Player PLAYER_HAND = [] player_score = 0 # Deck TRASH = [] card_max = 52 # Deck setup DECK = [*(1..(card_max))] # Deck shuffle puts "Shuffle the desk.\n" deck_shuffle # Dealer's turn puts "The dealer draws the card." while dealer_score <= 17 do DEALER_HAND.push(card_draw) dealer_score += card_sum(DEALER_HAND[-1], dealer_score) end disp_hand_dealer(DEALER_HAND) # Player's turn puts "\nThe player draws the card." 2.times{ PLAYER_HAND.push(card_draw) player_score += card_sum(PLAYER_HAND[-1], player_score) } disp_hand(PLAYER_HAND) puts "\nPlayer's score:#{player_score}" # Hit or Stand loop { puts "\nhit or stand [H/S]" case gets when /^[hH]/ puts "Hit" PLAYER_HAND.push(card_draw) player_score += card_sum(PLAYER_HAND[-1], player_score) disp_hand(PLAYER_HAND) puts "\nPlayer's score:#{player_score}" if player_score >= 21 break end when /^[sS]/ puts "Stand" break end } # Duel puts "\nDuel!" puts duel_judge(dealer_score, player_score) exitソースコードで使用したもの
後でまとめます
- 投稿日:2019-11-28T08:49:03+09:00
Railsで開発環境のURLをlocalhost:3000ではなくa.example.comとかにする方法
/etc/hosts
ファイルをsudoで編集します。Linuxでも同様に動きます。127.0.1.1 a.example.com 127.0.1.1 b.example.comこれで、アプリを起動させて、ブラウザーをそれらのいずれかに向けると、動作するはずです。次に、Railsアプリのサーバーを起動します。
rails s rails s -p 3001最後に、ブラウザで次を指定します。
foo.example.com:3000 bar.example.com:30013000番とかを消したい場合
80番ポートで起動させてください
sudo rails server --port=80参考
- 投稿日:2019-11-28T08:31:17+09:00
【Rails】モデルの関連付けを行う
関連付けとは
Railsでは、モデルやテーブル同士の関係を設定することができます。
例えばUserモデルとTaskモデルの関係などを定義します。
(この場合、1人のユーザーが複数のタスクを持っている)何がうれしいのか
必要な記述が少なく、シンプルになります。
TODOアプリを例に説明すると、以下のように記述が簡素化します。タスク作成時
Task.create(title: "パンを買う", user_id: @user.id)↓
@user.tasks.create(title: "パンを買う")ユーザー削除時
@tasks = Task.where(user_id: @user.id) @tasks.each do |task| task.destroy end @user.destroy↓
@user.destroyその他、以下のようなメソッドが使えるようになります。
メソッド 用途 task.user Micropostに紐付いたUserオブジェクトを返す user.tasks Userのタスクの集合を返す user.tasks.build(arg) userに紐付いた新しいTaskオブジェクトを返す user.tasks.find_by(id: 1) userに紐付いていて、idが1であるタスクを検索する 実装してみる
簡単なTODOアプリを例に、UserモデルとTaskモデルの関連付けをします。
Ruby on Railsで簡単なアプリを作成
【Rails】ログイン機能を実装するtasksテーブルに
user_id
を追加
$ rails g migration Addカラム名Toテーブル名 カラム名:データ型
でカラムを追加するマイグレーションファイルを作成できます。$ rails g migration AddUserToTasks user:references
作成されるファイル
[timestamp]add_user_to_tasks.rbclass AddUserToTasks < ActiveRecord::Migration[5.1] def change add_reference :tasks, :user, foreign_key: true end endここでは外部キー制約を持った
reference型
のuser_id
というカラムを追加し、user_id
にはusersテーブルのidカラム
に入っているデータだけを許可します。
(データベース上には、usersテーブルのidカラムの型であるinteger型
として登録されます。)
外部キー (foreign key)とは|「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典$ rails db:migrate
has_many
、belongs_to
で関連付けTaskモデルに
belongs_to
、Userモデルにhas_many
を記述し、関連付けを行います。
その他default_scope
で取り出す時の順番を指定したり、dependent: :destroy
でユーザーが削除された時にそのユーザーの持つタスクを全て削除するように設定できます。/app/model/task.rbclass Task < ApplicationRecord belongs_to :user default_scope -> { order(created_at: :desc) } . . end/app/model/user.rbclass User < ApplicationRecord has_many :tasks, dependent: :destroy . . endタスク登録処理を修正
これまで
Task.new
で取得していたタスクオブジェクトをcurrent_user.tasks.build
で書き換えます。
(このアプリではcurrent_userという関数で現在ログイン中のユーザーオブジェクトを返すことができます。). . def create # @task = Task.new(task_params) @task = current_user.tasks.build(task_params) if @task.save flash[:success] = "タスクを追加しました。" . .まだこのアプリにはユーザー削除の機能がないので、削除時の動作の実装は割愛しますが、
@user.destroy
でユーザーに紐づいた全てのタスクを削除できます。参考
- 投稿日:2019-11-28T02:08:28+09:00
カレンダーを表示する (たのしいRuby 練習問題)
はじめに
以下の問題を解いている記事を読んで、自分もやってみようと思いました。
たのしいRuby 第5版から引用
[第20章 TimeクラスとDateクラス 練習問題]
Date クラスを使って、今月の1日と月末の日付と曜日を求め、次のような形式でカレンダーを表示させてください
April 2015 Su Mo Tu We Th Fr Sa 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30私の場合は以下のように回答しました。
require "date" today = Date.today # header puts "#{Date::MONTHNAMES[today.month]} #{today.year}".center 21 puts ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].map{|d| "%3s"%d}.join # body current_day = today - today.day + 1 row = [nil] * current_day.wday loop do row << current_day.day current_day = current_day + 1 if current_day.wday == 0 puts row.map{|n| "%3s"%n }.join row.clear end if current_day.month != today.month break end endNovember 2019 Su Mo Tu We Th Fr Sa 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30参考
たのしいRuby 第5版
たのしい Ruby 第2版 第17章 Time クラスと Date クラス 練習問題(3)
カレンダー整形問題を色々なパターンで解いてみた
- 投稿日:2019-11-28T00:48:45+09:00
Ruby で平仮名を打つとエラーが発生した!!
rubyで平仮名を打つとエラーが発生していろんなことをしてみたが解決できなくて、
which ruby
をしてみると、
/usr/bin/ruby
とのことだった。
echo $PATH
をした後に
open ~/.bash_profile
をしまして、
下記2つのがあれば良いらしいが、よくないことに、全然違うことが書いてあった。
①export PATH="$HOME/.rbenv/bin:$PATH"
②eval "$(rbenv init -)".bash_profileの中身を削除して上記のものを書いて保存をした後に、
$ source ~/.bash_profile
をして反映させる。
which ruby
をしてみると、
/Users/自分の名前/.rbenv/shims/ruby
と言う感じでいけた。
ruby --version
をするとしっかりと反映されていた。
参考にした記事
https://qiita.com/SAYJOY/items/be06302ae8a2fac7f0c4めちゃくちゃわかりやすかったです、ありがとうございましたww