20201227のRubyに関する記事は30件です。

Ruby on Rails でnewコマンドにてアプリを作成するとbundler: failed to load command: spring (/Users/ユーザー名/アプリを作成するディレクトリ名/アプリ名/vendor/bundle/ruby/2.6.0/bin/spring)と出た話

こんばんは。Miyayanと申します。今回初めてQiitaにて記事をあげます。
ゆえに拙い部分もあるかと存じますが、どうぞよろしくお願いいたします。

目次

  • 環境
  • 参考記事
  • 概要
  • 仮説
  • 試したこと
  • 解決方法
  • まとめ

環境

OS : macOS Big Sur ver.11.1
Ruby : 2.6.5p114
Rails : 6.0.0
bundler : 2.1.4, default: 1.17.2
gem : 3.0.3

参考記事

【Rails6】rails new で bundler: failed to load command: spring が出た。問題はbundler2.1.4かRuby2.7にあるようだが.....

bundler: failed to load command: spring が出た。。

「gem update --system」と「gem update」の違い

概要

railsにてnewコマンドを用い、アプリケーションの作成を試みました。

rails _6.0.0_ new アプリ名 -d mysql

すると、下記文面が赤色で表示されるではないですか!

bundler: failed to load command: spring (/Users/ユーザー名/アプリを作成したいディレクトリ/アプリ名/vendor/bundle/ruby/2.6.0/bin/spring)

どうもエラーのようでエラーっぽくないと言いますか、正直プログラミング初学者の私からしたらイマイチ何が起きているのかもパッとしない状況・・・。
しかし赤文字ってだけで何かムズムズしてしまう。
どうにかしてこの警告のような文面が出ることなくアプリケーションを作成できないものだろうか・・・。

仮説

文面から見るにSpringというものがうまくいってないように感じます。
しかしながら、インストールされているGemを見ると、

Installing spring 2.1.1

と緑色で表示があり、Springは入っている。正直この警告は無視しても良さそうな感じがします。
参考記事を見てみると、バージョンが2.1.4となっているbundlerが悪さをしているのかと書かれております。

では、bundlerをいじってみましょうか。

試したこと

まずbundlerのバージョンを確かめてみます。

% gem list bundler

*** LOCAL GEMS ***

bundler (2.1.4, default: 1.17.2)

参考記事の方々と同じ2.1.4です。
これをアンインストールし、バージョンを再度確認。

% gem uninstall bundler
Successfully uninstalled bundler-2.1.4

% gem list bundler     

*** LOCAL GEMS ***

bundler (default: 1.17.2)

そしてさらに、最新バージョンのbundlerを入れてみます。

% gem install bundler

ここで再度bundlerのバージョンを確かめてみましょう。

% gem list bundler   

*** LOCAL GEMS ***

bundler (2.2.3, default: 1.17.2)

bundlerが2.2.3にアップグレードされました。
これでnewコマンドでアプリを作成してみましょう!!!

bundler: failed to load command: spring (/Users/ユーザー名/アプリを作成したいディレクトリ/アプリ名/vendor/bundle/ruby/2.6.0/bin/spring)

出るんかい!!!
どうもbundlerではなさそう。あるいは2.2.3でもSpringの警告文は出るのかもしれない。

gemそのもののバージョン・・・?

解決方法

こちらは私の場合、解決した方法です。あくまでご参考程度にしていただけると幸いです。

gemのバージョンを確認してみる。

% gem -v
3.0.3

gemのアップデートを試みる。

% gem update --system

再度gemのバージョンを確認する。

% gem -v             
3.2.3

アップデートが完了したようです。
流石にこれで解決するのかなーと半信半疑でしたが、ここで一旦bundlerのバージョンも確認してみます。

% gem list bundler

*** LOCAL GEMS ***

bundler (default: 2.2.3)

ん?ちょいと表記が違いますね。
先程は

bundler (2.2.3, default: 1.17.2)

こういう表示だったのが、gem自体のアップデートを行なったことによりbundlerのdefaultがカチッと最新バージョンになったようです。

ここでrails newコマンドで再度アプリを作成すると、
無事警告が出ることなく作成完了しました!!!

まとめ

結論、なぜ解決したのかパッとしませんが、
①bundlerのdefaultバージョンが1.17.2より現行最新である2.2.3へと切り替わったことで解決した。
②gemのバージョンが3.0.3から3.2.3になったことで解決した。

以上2パターンかなぁと感じております。

あくまで私の環境下での解決方法ではありましたが、同様に
bundler: failed to load command: spring
が出た方のご参考になれば幸いです。

ご覧いただきありがとうございました!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsチュートリアル 14章 FactoryBotでRelationshipのテストデータの作成

はじめに

Railsチュートリアルをrspecに対応させながら取り組んでいたところ、14.2.3のリスト14.28のユーザのRelationshipテストデータをFactoryBotで作ろうとしたときにハマってしまったので、備忘録として投稿します。

環境

  • ruby 2.7.2
  • rails 6.0.3
  • factory_bot_rails 6.1.0
  • rspec-rails 4.0.1

やりたいこと

①下記ようにrelationshipのテストデータを作成するfixtureをFactoryBotで定義する。
②userのテストデータも同時にFactoryBotの定義内で作成する。

test/fixtures/relationships.yml(リスト14.28)
one:
  follower: michael
  followed: lana

two:
  follower: michael
  followed: malory

three:
  follower: lana
  followed: michael

four:
  follower: archer
  followed: michael

解決方法

試してみて、採用した解決方法を記載します。

その1 Relationshipのテストデータを作成するFactoryを定義(①のみ解決)

一番素直な方法です。follower_idとfollowed_idを持つRelationshipクラスのファクトリーを作成します。ただ、この方法でassociationをうまく設定することができなかったので、userのテストデータを別途作成しました。

spec/factories/relationships.rb
 factory :relationship, class: Relationship do
    follower_id { follower.id }
    followed_id { followed.id }
  end
spec/models/relationship_spec.rb
RSpec.describe Relationship, type: :model do
  let(:follower) { create(:user) }
  let(:followed) { create(:user) }
  let(:relationship) { create(:relationship, follower: follower, followed: followed) }

  it { expect(relationship).to be_valid }
end

その2 Relationshipを持つuserのテストデータを作成するFactoryBotを定義(①②の両方解決?)

2つめの方法は、Relationshipを持つuserのテストデータを作成する方法です。userのテストデータはすべてのテストでRelationshipを持っている必要はないので、traitで必要に応じて設定できるようにしています。この方法だと、userとrelationshipのテストデータをそれぞれ作成しなくても良くなりました。しかし、この方法はあくまでuserのテストデータを作成する方法で、relationshipを呼び出すにはuserを通す必要があるので、relationshipのテストには向いていなさそうです。

spec/factories/users.rb
factory :user do
  .
  .
  .
  trait :has_followed do
    after(:create) do |user|
      followed = create(:user)
      user.follow(followed) 
    end
  end
end
spec/models/relationship_spec.rb
RSpec.describe Relationship, type: :model do
  let(:user) { create(:user, :has_followed) }

  it { expect(user.actve_relationships).to be_valid }
end

終わりに

結局①②を完全に達成する解決方法を見つけられなかったので、relationshipのテストはその1の方法で、relationshipを持つuserのテストはその2で書くことにしました。

参考文献

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

rubyでapplication/pdfのレスポンスをFileで扱う

外部APIのレスポンスがapplication/pdfだったときの対応

response = http_client.get url
response.headers
# {
#  "content-type"=>"application/pdf",
# }

# シンプルに書き込めばok
file = ::File.open("path/to/pdf", "wb") do |f|
  f.write resp.body
  f
end

# AWS::S3.upload file.path
# みたいな
$ file path/to/pdf
# path/to/pdf: PDF document, version 1.4
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rubyのネイティブ拡張でメソッド呼び出しをキャッシュさせる簡単な方法

概要

RustのHashMapをRubyから使えるようにしてみたが…… の続きです。

前回、以下のように書いた。

ハッシュ値を取得するのに、Rubyのメソッドが動的に呼び出され、Rustのhash関数も実行されている。
さらに Eqの時もRubyのメソッドが動的に呼び出されている。
Rubyからメソッド呼び出しする場合は普通はメソッドをキャッシュしておくので次の呼び出しは速くなるが、CやRustから呼ばれる場合は毎回メソッドテーブルから探しに行く必要があって、とても遅い。

今回、メソッドをキャッシュさせることで find, insert, delete が速くなることを確認できた。

結果

before:

$ ruby benchmark.rb --rust --seed 1
Hash: Rust
Seed: 1
       user     system      total        real
values  1.896433   0.152249   2.048682 (  2.049503)
keys    1.589012   0.118299   1.707311 (  1.708012)
find   11.612382   0.002426  11.614808 ( 11.617854)
insert 15.397090   0.012138  15.409228 ( 15.413532)
delete  7.581418   0.001750   7.583168 (  7.585473)

after:

$ ruby benchmark.rb --rust --seed 1
Hash: Rust
Seed: 1
       user     system      total        real
values  1.924479   0.166750   2.091229 (  2.092445)
keys    1.514441   0.112787   1.627228 (  1.628187)
find    8.677083   0.001990   8.679073 (  8.681669)
insert 12.661791   0.010463  12.672254 ( 12.678383)
delete  5.908580   0.001670   5.910250 (  5.912530)

insertは標準のHashクラスより37%も速くなっている。やったね

やったこと

これまで、hash関数は以下のように実装していた。

    fn hash<H: Hasher>(&self, state: &mut H) {
        let val = ruby::fun_call(self.0, "hash", &[]);
        val.to_raw().hash(state);
    }

Rustから呼び出すと毎回テーブルを引く必要があるが、Rubyから呼び出せばいい感じにキャッシュされる。
つまりRubyを経由して呼び出せばよい。というわけで

pub static mut M_HASH: Value = NIL;
// ...
    let sym_hash = module_eval(klass, "def self.value_hash(val); val.hash; end");
    M_HASH = obj_method_by_symbol(klass, sym_hash);

eval を作ってRubyの関数を定義する。

    fn hash<H: Hasher>(&self, state: &mut H) {
        let method = unsafe { crate::hashmap::M_HASH };
        let val = ruby::method_call(method, &[self.0]);
        val.to_raw().hash(state);
    }

hash関数では、インスタンスメソッドを呼ぶ代わりにこのキャッシュされた Method 呼び出しを行う。

extern "C" fn mark(ptr: *const ffi::c_void) {
   gc_mark(unsafe { M_HASH });

この Method のインスタンスがGCで回収されないように注意(これが原因で時々SEGVが出てデバッグが辛かった)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby】「オブジェクトへの参照」と「変数の中身」

はじめに

Rubyを使用していると、「オブジェクトへの参照」という概念が出てくると思います。

例えば、以下のようなコードがあったとします。

sample.rb
# 渡された文字列を破壊的に大文字に変換するメソッドを定義する
def replace!(str)
  str.upcase!
end

str = 'sample'
# 変数strにreplaceメソッドを適用する
replace!(str) #=> "SAMPLE"

この時、replaceメソッドの引数であるstrに渡されたのは、「変数strに格納されているStringオブジェクト'sample'への参照である」いうような説明がよくされると思います。

しかし、この説明を聞いても

  • 「オブジェクトへの参照とはそもそも一体どういうことなのか?」
  • 「変数に格納されているオブジェクトへの参照とはどういうこと?」

と思っている人は多いのではないでしょうか?

今回はそのような方へ向けて、

  • オブジェクトへの参照
  • 変数の正体
  • 参照の値渡し

といったことをわかりやすく説明していきます。

ぜひ最後までご覧になってください。

対象読者

  • Rubyを学び始めた人
  • プログラミング始めたての人
  • 「オブジェクトへの参照」がよくわからない人

本記事の内容

1. オブジェクトへの参照とは?
2. 変数の正体
3. メソッドの引数へ渡されるもの
4. まとめ
5. 最後に
6. 参照サイト

1. オブジェクトへの参照とは?

「オブジェクトへの参照」とは簡単にいうと「オブジェクトの居場所にアクセスする」ことを指しています。

まず、Rubyはオブジェクト指向言語であるため、配列や文字列はもちろん、数値であったり、nilも含め、全ての値がオブジェクトとして扱われます。

そしてこのようなオブジェクト指向言語では、あるオブジェクトを定義すると、それと同時にオブジェクトを記憶するためのメモリ領域というものが定められます。

簡単に言うと、各オブジェクトに住所が定められるというようなイメージです。

# String(文字列)オブジェクトの'Hello'を生成
'Hello'

# オブジェクトの「住所」はobject_idメソッドで調べられる
'Hello'.object_id #=> 260

image.png

そして、こうして定められたオブジェクトの住所にアクセスすることを「オブジェクトへの参照」と呼ぶのです。

もっとわかりやすくざっくり言うと、「オブジェクトへの参照=オブジェクトの居場所」のことだと思ってもらうとわかりやすいかもしれません。

2. 変数の正体

次に、先ほど出てきたメモリ領域と変数との関係性について考えていきます。

例えば、以下のような状況を考えてみます。

# 変数aに'test'を代入する
a = 'test'

# 'test'と変数aのメモリ領域(住所)を確認
'test'.object_id #=> 260
a.object_id #=> 280

この時、裏側では次のようなことが起こっているということになります。

① String(文字列)オブジェクトが作成される(中身は'test')
② その住所(メモリ領域)が変数aに格納される

image.png

つまり、変数の実体とは「メモリ領域」であり、さらにその変数に入っている値は実は「変数に格納されているオブジェクト(ここでは'test')の住所」であるということが言えます。

変数aの中には、文字列オブジェクトそのものが入っていないということをちゃんと押さえておきましょう。

3. メソッドの引数へ渡されるもの

ではここから、この変数をメソッドの引数に渡す場面を考えてみましょう。

一番最初に挙げた例を元に考えてみましょう。

sample.rb
# 渡された文字列を破壊的に大文字に変換するメソッドを定義する
def replace!(str)
  str.upcase!
end

str = 'sample'

# 'sample'とstrのメモリ領域(住所)を確認
'sample'.object_id #=> 320
str.object_id #=> 340

# 変数strにreplaceメソッドを適用する
replace!(str) #=> "SAMPLE"

この時、何が起こっているのでしょうか?

まず、最初に「replace」メソッドが定義されていますが、このメソッド内に含まれる引数「str」も当然変数なので、先ほど述べたように当然メモリ上に領域が確保されます。
(この領域は固定された場所ではなく、メソッドが呼ばれると確保され、メソッドの実行が終わると解放されます。

そして、メソッドが定義された時点ではこの引数は仮のものなので(仮引数)、その中にはまだ何も入っていません。
ここではあくまで「メモリ上に領域を確保しただけ」という状態です

そして次に、先ほどと同様に文字列「sample」と変数strがセットされます。

ここまでをまとめると以下のようになります。

image.png

次にsample.rbにおいて、「replace!メソッド」を呼び出した直後の状態を図で表して見ると、以下のようになります。

image.png

ここでのポイントは

  • 変数(実引数)strの値は、文字列オブジェクトへの参照であり、それがそのまま引数(仮引数)strにコピーされる

ということです。

そしてこのように、「変数に格納されているオブジェクトへの参照」が引数として渡されることを「参照の値渡し」と呼びます。

この参照の値渡しが行われると、当然ですが変数strと引数strは同じオブジェクトを共有していることになります。

そのため、引数strの値が変更されると、連動してその引数の値の住所に住んでいるオブジェクトの中身も変更されることになります。
(専門的な言い方をすれば、引数strの参照先であるオブジェクトが変更される

今回の場合だと、「replace!メソッド」の中身である「str.upcase!」が実行されると以下のようになります。

image.png

これを見ると、引数strの値は変わっていませんが、その引数が指し示すオブジェクトの中身がしっかりと変更されていることがわかると思います。

4. まとめ

  • オブジェクトへの参照とは「オブジェクトの居場所にアクセスする」こと
  • 変数の実体は「その変数に格納されているオブジェクトへの参照」
  • 参照の値渡しとは「変数に格納されているオブジェクトへの参照がそのまま引数に渡される」こと

5. 最後に

本記事の内容がみなさんの参考になれば嬉しいです。

最後までご覧いただきありがとうございました。

6. 参考文献

Qiita記事: 【Ruby】メソッドの引数は値渡し?参照渡し?
Qiita記事: Rubyの破壊的メソッドと参照の値渡し
Rubyist Magazine: 値渡しと参照渡しの違いを理解する

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby の attr_accessor はアクセッサーじゃない

Ruby の初心者向け記事の定番間違いの一つに,attr_accessor のことを「アクセッサー」と呼ぶ,というものがあります。
単に言葉の表現が間違っているだけの場合と,そもそも正しく理解していない場合とがあるように思われます。

Ruby の場合,アクセッサーというのは,

  • インスタンス変数の値を読み出すためのメソッド(ゲッターと呼ぶ)
  • インスタンス変数に値をセットするメソッド(セッターと呼ぶ)

の総称です。
以下の典型的な例を見ましょう

class Person
  def name
    @name
  end

  def name=(name)
    @name = name
  end
end

a_person = Person.new
a_person.name = "Kaoru"
puts a_person.name # => "Kaoru"

二つのメソッドを定義していますが,name がゲッターで,name= がセッターです。この二つを合わせてアクセッサーと呼ぶわけです。
慣習として,

  • ゲッターのメソッド名はインスタンス変数名から @ を除いたもの
  • セッターのメソッド名はインスタンス変数名から @ を除いたものの末尾に = を付加したもの

とします(ルールではなく慣習です)。

名前の末尾が = であるようなメソッドは「代入メソッド」と呼ばれ,Ruby の構文上,ちょっぴり特別扱いされます。
上の例で

a_person.name = "Kaoru"

と書いたように,メソッド呼び出しの際に = の前にスペースを入れても構わないのです。
上のコードは代入式の一種です1

それだけではありません。代入メソッドを使った自己代入式も書けます。
以下のコードを見ましょう(クラス定義は先ほどのとおりだとします)。

a_person = Person.new

# (1)
a_person.name ||= "Kaoru"
puts a_person.name # => "Kaoru"

# (2)
a_person.name ||= "Haruka"
puts a_person.name # => "Kaoru"

(1) では,インスタンス変数 @name にまだ値がセットされていない(読み出すと nil になる)状態で自己代入演算子 ||= を使っているので,@name の値が "Kaoru" になります。

しかし,(2) では,@name に文字列オブジェクトが代入された状態で実行されるので代入は起こりません。そのため,a_person.name の返り値は "Haruka" ではなく "Kaoru" になっています。

前ふりが長くなりました。ここから本題に入りましょう。
先ほどのクラス定義を見ると,ゲッター,セッターの定義で(単純とはいえ)それぞれ 3 行も費やしています。
インスタンス変数が 5 個あって,それぞれゲッターもセッターも定義するとなると,30 行も必要になります。これは馬鹿馬鹿しいですね。

そこで,このような単純なゲッター,セッターを定義するなら2

class Person
  attr_accessor :name
end

と書けば済むようになっています。

この attr_accessor のことを「アクセッサー」と書いている記事をよく目にします。
しかし,attr_accessor はアクセッサーを定義してくれるものであって,これ自体がアクセッサーなのではありません。
おそらく名前の一部に「accessor」と付いているのに引きずられて「アクセッサー」と思い込んでしまうのでしょう。

ところで,attr_accessor というのは一体何者でしょうか?
他言語から来た方は,Ruby のクラス定義構文の一部分と思うかもしれませんが,そんな文法はありません。
attr_accessor はただのメソッドです。
参考:Module#attr_accessor (Ruby 3.0.0 リファレンスマニュアル)

つまり,

attr_accessor :name

は,:name というシンボルを引数として,attr_accessor というメソッドを呼び出しているだけなのです。
こうすることで,クラスにアクセッサーが定義されます。
attr_accessorメソッドを定義するメソッドなわけです。

少し補足すると

  • クラスもまたオブジェクトである
  • クラス定義式(class Personend)の中では,そのクラスが self となる
  • つまり,クラス定義式内でレシーバーをあらわに書かないメソッド呼び出しを行うと,当該のクラスがレシーバーとなる

ということです。
最後の点を確認するコードを以下に示します。

class Hoge
  p name # => "Hoge"
end

このコードで,name はローカル変数ではありません。この箇所以前に name への代入式が存在しないので,ローカル変数ではありえないのです。
とすると,メソッド呼び出しのはずです。
このメソッド呼び出しにはレシーバーが書かれていません。
ここはクラス定義式の中ですから,name のレシーバーは Hoge クラスです。
HogeClass というクラスのインスタンスですから,name はクラス名・モジュール名を返すメソッドです。だから "Hoge" が表示されます。
参考:Module#inspect (Ruby 3.0.0 リファレンスマニュアル)

以上が理解できると,

class Person
  attr_accessor :name
end

class Person
end

Person.attr_accessor(:name)

と書くのと同じであることが分かるでしょう。


  1. Ruby の代入式は,変数への代入だけではないってことですね。 

  2. 「単純な」と書いたのは理由があります。単純でないアクセッサーを定義したいこともあるからです。とくにセッターの場合,与えられた引数に何らかの正規化(全角/半角の統一とか余計なスペースの削除とか)を施してからインスタンス変数に代入したいことがあります。こういう場合,attr_accessor は使えません。 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby 3でRBS、TypeProf、Steep(型注釈・型検査)を体験してみる!

Ruby3がリリースされました。
Rubyコミッターの皆さん、お疲れ様です。

待ち望んでいた、Rubyの型注釈をやってみる!!

Ruby3をインストール!

rbenvをインストールする。

brew install rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
source ~/bash_profile

rbenvからRuby3をインストールする。
インストールできるリストを確認すると、3.0.0があるのを確認。

% rbenv install --list
2.5.8
2.6.6
2.7.2
3.0.0
jruby-9.2.14.0
mruby-2.1.2
rbx-5.0
truffleruby-20.3.0
truffleruby+graalvm-20.3.0

Only latest stable releases for each Ruby implementation are shown.
Use 'rbenv install --list-all / -L' to show all local versions.

Ruby3.0.0をいよいよインストール。

 rbenv install 3.0.0 
 rbenv global 3.0.0

やったー。

% ruby -v               
ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin19]

Rubyの型注釈をやってみる

適当なディレクトリにRubyのコードを書いてみる。
app.rbというファイルに書いてみた。

def plus(x, y)
  x + y
end

puts plus(1,1)

必要なツールをインストールする。
型検査をしてくれるsteepというgemを使う。

gem install steep

Steepfileという設定ファイルを自動生成してもらう。

steep init

Steepfileが生成された。

# target :lib do
#   signature "sig"
#
#   check "lib"                       # Directory name
#   check "Gemfile"                   # File name
#   check "app/models/**/*.rb"        # Glob
#   # ignore "lib/templates/*.rb"
#
#   # library "pathname", "set"       # Standard libraries
#   # library "strong_json"           # Gems
# end

# target :spec do
#   signature "sig", "sig-private"
#
#   check "spec"
#
#   # library "pathname", "set"       # Standard libraries
#   # library "rspec"
# end     

Steepfileを書き換える。

target :lib do
  signature "sig"
  check "app.rb"
end

試しに、型検査をしてみる。

steep check   
app.rb:5:5: NoMethodError: type=::Object, method=plus (plus(1,1))

まだ型注釈を書いてないので、NoMethodErrorとなる。

型注釈を書く

次は、sigディレクトリ以下に型注釈を入れていく。
型注釈は.rbsという拡張子で記述する。

TypeProfというRuby3に付いているツールで自動で生成できる。

typeprof app.rb -o sig/app.rbs

sig/app.rbsが生成された。以下のようになる。

# Classes
class Object
  private
  def plus: (Integer x, Integer y) -> Integer
end

この状態で型検査してみる。

steep check    

すると、何も表示されなかったので型検査が通りました?

試しに、IntegerをStringにしてみる。

# Classes
class Object
  private
  def plus: (Integer x, Integer y) -> String
end

すると、このようなエラーとなる。

steep check
app.rb:1:0: MethodBodyTypeMismatch: method=plus, expected=::String, actual=::Integer (def plus(x, y))
  ::Integer <: ::String
   ::Numeric <: ::String
    ::Object <: ::String
     ::BasicObject <: ::String
==> ::BasicObject <: ::String does not hold

まとめ

待ち望んでいた、Rubyの型を体験できてよかった。
TypeProfなどで自動で解析して型注釈を書いてくれるのは独自な機能だし、Matzさんの思想が反映されているのかなぁと感じた。

参考文献

https://qiita.com/scivola/items/ac83d8275ace1b4ed123

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Java ~真偽値~】勉強メモ2

Java学習中。
復習に見返せるようにメモしていきます。
ほぼ自分の勉強メモです。
過度な期待はしないでください。

真偽値

  • 真偽値とは

真偽値とは、「true」と「false」という2つの値がある。
trueは真(正しい)、falseは偽(間違っている)を意味する。
真偽値のデータ型はboolean型です。

  • 比較演算子

比較演算子とは、値を比較するための記号で、比較した結果は真偽値(trueかfalse)になる。
「x == y」は、xとyが同じかどうかを比較し、同じであればtrue、違っていればfalseとなる。
また「x != y」はその逆になる。

// ①「==」を用いて、値を比較した結果を出力
System.out.println(12 / 4==3);

// ②「!=」を用いて、値を比較した結果を出力
System.out.println(12 / 4!=3);

// boolean型の変数boolを定義し、「3 * 9 == 27」を代入
boolean bool = 3 * 9 == 27;

// ③変数boolの値を出力してください
System.out.println(bool);
出力結果
①true

②false

③true


  • 比較演算子/大小比較

<, >という記号は数学でも用いる大小比較の記号です。
x < yはxがyより小さければtrue, 大きければfalseを返します。x > yはその逆となる。

// 8と5を比較し、falseとなるように出力
System.out.println(8 < 5);

// 3と2を比較し、trueとなるように出力
System.out.println(3 >= 2);


  • 論理演算子

論理演算子は、「かつ」「または」「~でない」を表現する記号。

-「かつ」は、&& で表現し、「条件1 && 条件2」は「条件1がtrueかつ条件2もtrue」であれば結果もtrueになり、
どちらか一方でもfalseであれば結果はfalseになる。

System.out.println(8 < 5 && 3 >= 2);
// 出力結果 → false


-「または」は、| | で表現し、「条件1 || 条件2」は、「条件1または条件2のどちらか一方でもtrue」であれば
結果はtrueになる。

System.out.println(8 < 5 || 3 >= 2);
// 出力結果 → true


-「~でない」は、! を用いると表現できます。
例えば、!(x >= 30)は「xが30以上でない(つまり30より小さい)」ときtrueになり、「xが30以上」のときfalseになる。

System.out.println(!(8 < 5));
// 出力結果 → true


過去投稿記事

【Java~変数の定義、型変換について~】勉強メモ

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby】便利なやつだよ 〜before_action編〜

コントローラー内の記述でかぶっているものについてまとめてくれる、そんな素晴らしいコマンド「before_action」編です。

class ItemsController < ApplicationController

  def index
    @items = Item.order('created_at DESC')
  end

  def new
    @item = Item.new
  end

  def create
    @item = Item.new(item_params)
    if @item.save
      redirect_to root_path
    else
      render :new
    end
  end

  def show
    @item = Item.find(params[:id])
  end

  def edit
    @item = Item.find(params[:id])
    redirect_to root_path unless current_user.id == @item.user_id
  end

  def update
    @item = Item.find(params[:id])
    @item.update(item_params)
    if @item.save
      redirect_to root_path
    else
      render :edit
    end
  end

end

アクション内でかぶっている記述がありますね。
上から順番に

show
edit
update


以上3つの「@item = Item.new(item_params)」という記述です。

これをbefore_actionを使ってまとめてみます。

class ItemsController < ApplicationController
before_action :find_item ⬅️❶まずこれを記述して

〜略〜

  def show
    @item = Item.find(params[:id])     ⬅️❷これを消してく
  end

  def edit
    @item = Item.find(params[:id])     ⬅️❷これを消してく
    redirect_to root_path unless current_user.id == @item.user_id
  end

  def update
    @item = Item.find(params[:id])      ⬅️❷これを消してく
    @item.update(item_params)
    if @item.save
      redirect_to root_path
    else
      render :edit
    end
  end

  private                     ⬅️❸privateメソッドにして


  def find_item                 ⬅️❹find_itemという名前のメソッドを定義して、中身はかぶっている記述をIN
    @item = Item.find(params[:id])
  end


そしてページ更新!

はい!エラーになりました!笑
定義したfind_itemメソッドは、かぶっていて記述を削ったアクションにだけ必要になっている。
つまりshoweditupdateの3つにだけ適用したい。
そんな時はonlyアクションでしたね。しぼっちゃいましょう。

class ItemsController < ApplicationController
before_action :find_item, only: [:show, :edit, :update] ⬅️❶ここに追加
〜略〜

  def show
  end

  def edit
    redirect_to root_path unless current_user.id == @item.user_id
  end

  def update
    @item.update(item_params)
    if @item.save
      redirect_to root_path
    else
      render :edit
    end
  end

  private

  def find_ite
    @item = Item.find(params[:id])
  end

だいぶスッキリしました。
ずっと同じファイルで記述しているとこういうことが起きやすいのかなと思いました。
コードが増えてきたら一度整理&確認してみることが大事ですね。
今日も良い経験になりました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby】便利なやつだよ〜before_action編〜

コントローラー内の記述でかぶっているものについてまとめてくれる、そんな素晴らしいコマンド「before_action」編です。

class ItemsController < ApplicationController

  def index
    @items = Item.order('created_at DESC')
  end

  def new
    @item = Item.new
  end

  def create
    @item = Item.new(item_params)
    if @item.save
      redirect_to root_path
    else
      render :new
    end
  end

  def show
    @item = Item.find(params[:id])
  end

  def edit
    @item = Item.find(params[:id])
    redirect_to root_path unless current_user.id == @item.user_id
  end

  def update
    @item = Item.find(params[:id])
    @item.update(item_params)
    if @item.save
      redirect_to root_path
    else
      render :edit
    end
  end

end

アクション内でかぶっている記述がありますね。
上から順番に

show
edit
update


以上3つの「@item = Item.new(item_params)」という記述です。

これをbefore_actionを使ってまとめてみます。

class ItemsController < ApplicationController
before_action :find_item ⬅️❶まずこれを記述して

〜略〜

  def show
    @item = Item.find(params[:id])     ⬅️❷これを消してく
  end

  def edit
    @item = Item.find(params[:id])     ⬅️❷これを消してく
    redirect_to root_path unless current_user.id == @item.user_id
  end

  def update
    @item = Item.find(params[:id])      ⬅️❷これを消してく
    @item.update(item_params)
    if @item.save
      redirect_to root_path
    else
      render :edit
    end
  end

  private                     ⬅️❸privateメソッドにして


  def find_item                 ⬅️❹find_itemという名前のメソッドを定義して、中身はかぶっている記述をIN
    @item = Item.find(params[:id])
  end


そしてページ更新!

はい!エラーになりました!笑
定義したfind_itemメソッドは、かぶっていて記述を削ったアクションにだけ必要になっている。
つまりshoweditupdateの3つにだけ適用したい。
そんな時はonlyアクションでしたね。しぼっちゃいましょう。

class ItemsController < ApplicationController
before_action :find_item, only: [:show, :edit, :update] ⬅️❶ここに追加
〜略〜

  def show
  end

  def edit
    redirect_to root_path unless current_user.id == @item.user_id
  end

  def update
    @item.update(item_params)
    if @item.save
      redirect_to root_path
    else
      render :edit
    end
  end

  private

  def find_ite
    @item = Item.find(params[:id])
  end

だいぶスッキリしました。
ずっと同じファイルで記述しているとこういうことが起きやすいのかなと思いました。
コードが増えてきたら一度整理&確認してみることが大事ですね。
今日も良い経験になりました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ファイル生成を抑えた最低限のRails

はじめに

新しくRailsでアプリを作ろうとした際に、余計なファイルが生成されてしまうのが気になったので、今回は自分に必要な最低限のファイル生成でrails newをする方法、設定を書きます。

Rails newのオプション

rails newにオプションをつけることで、指定した関連のファイルを生成しないでアプリを作ってくれます。
以下によく使いそうなオプションをいくつか上げていきます。中にはファイル生成以外の物も含まれています。

使用データベースの指定

rails new sample_app --database=mysql

--database=(任意のDB)で最初から指定したDBでアプリを作ってくれます。指定しない場合はsqliteになるはずです。勿論DBは後から変更することはできますが、少々面倒なので使用DBが決まっている場合は先に指定してしまいましょう。

minitestの除外

rails new sample_app --skip-test

rails標準搭載のminitestを生成しなくなります。Rspecを使用する際には確実に使うオプションです。skipオプションは他にもあります。

turbolinksの除外

rails new sample_app --skip-turbolinks

ページ遷移をAjaxに置き換え、JavaScriptやCSSのパースを省略して高速化させるturbolinksを取り込まなくなります。turbolinksはreadyが発火しないなどの問題もありますので、除外する方もいるみたいです。

.gitignoreの除外

rails new sample_app --skip-git

デフォルトのgitignoreを生成しなくなります。予めpushしないファイルを決めてgitignoreを用意している場合に使います。

APIモード

rails new sample_app --api

アプリをAPIとして作成する際の小さな構成で作ってくれます。MVCのVがなくなった感じです。デフォルトのgemもかなり削減されます。詳しくは最後に参考記事を載せますので、そちらをご参照ください。

Rails new後の設定

rails generateを使用することで簡単にコントローラーやモデルを作成できますが、同時に要らないhelperやtestが生成されてしまうことがあります。そういった場合はconfigのapplication.rbにgenerateコマンドの設定を記述します。

config/application.rb
module Sample
  class Application < Rails::Application
    config.generators do |g|
      g.stylesheets false #stylesheetsが自動生成されなくなる
      g.helper false #helperが自動生成されなくなる
      g.test_framework false #test及びfixtureが生成されなくなる
    end
  end
end

これはあくまで一例ですが、こういった設定をすることでファイル量をかなり減らすことができます。

終わりに

簡単なオプションを付け加えるだけでしたが、快適な開発を進める上でかなり役立ちました。

参考にさせていただいた記事

Rails 5 の API モードを触ってみる
rails generate で余分なファイルが生成されないようにする

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby の && や || は条件演算子じゃない

Ruby の初心者向け記事で &&|| を「条件演算子」と書いているものをときどき目にします。
おそらく条件式で使うのでそう呼んでしまっているのだろうと思いますが,これらは「論理演算子」です。

一方,条件演算子というのは,

(1..9).each do |n|
  puts "#{ n } is #{ n.odd? ? "odd" : "even" }"
end

に出てくる式

n.odd? ? "odd" : "even"

? : という二つの記号で表される演算子のことです。
三つの項を取るので「三項演算子」とも呼ばれます(Ruby では条件演算子以外に三つの項を取る演算子はありません)。
演算子式 (Ruby 3.0.0 リファレンスマニュアル)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Gemfile.lock にはインストールされている gem のバージョンが書かれている,わけじゃない

Ruby の初心者向け記事を眺めていると,Gemfile.lock について誤解していると思われる記述が目につきます。
そんなアレコレをこの記事では見ていきます。

最初に,Gemfile と Gemfile.lock についておさらいをしておきましょう。

まず,Gemfile はそのプロジェクトで使用する gem を指定するものでしたね。
gem の名前だけでなくバージョンも指定することができます。「○○以上」「○○未満」のような幅をもった指定もできます。また,

gem "hoge", "~> 3.5.2"

と書けば,hoge gem で,「3.5.2 以上,3.6.0 未満」という意味の指定になるのでした。

一方,Gemfile.lock は,Bundler によって生成されるファイルでした。
Gemfile.lock がまだ存在しない状態で,

bundle install

とすると,Bundler は Gemfile の記述を元に gem をインストールしていくのですが,さきほどの記述を例に取ると,hoge gem の「3.5.2 以上,3.6.0 未満」を満たすバージョンのうち,実際に存在している最も高いバージョンの gem を選びます。そしてそのバージョンを Gemfile.lock に記録し,まだインストールされていない場合はインストールします。

ここで以下のような誤解が生じます。

  • Gemfile.lock にはインストールされている gem のバージョンが書かれている。

確かに上述の状況ではそのようになります。
しかし,Gemfile.lock が生成されたあとで当該の gem をアンインストールすることができます。
また,チーム開発などでは,誰かの環境で作られた Gemfile.lock が Git 管理されて自分の手元にやってくることもありますね。この場合,そこに書かれた gem はこちらではまだインストールされていないかもしれません。
それに,Gemfile.lock に書かれていないバージョンの gem もインストールされているかもしれません。

こうしてみると,Gemfile.lock の記述と(あなたの環境に)インストールされている gem(のバージョン)は無関係と言えることが分かります。
Gemfile.lock は,「そのプロジェクトにおいて現時点で使うことになっている gem(のバージョン)」が記述されている,と考えればいいと思います。

次に,よくある誤解が

  • Gemfile.lock が存在する場合,bundle install すると,Gemfile.lock に従って gem がインストールされる。

です。
わりと正しいのですが,既にインストールされている場合はインストールは行われませんし(当たり前),Gemfile.lock に従わないケースすらあります。
それは Gemfile.lock に書かれたバージョンが Gemfile に書かれたバージョンの条件を満たさない場合です。
例えば,Gemfile.lock が 1.0.3 となっているときに,Gemfile のほうを >= 1.1 と書き換えたら,bundle install では 1.0.3 は採用されず,>= 1.1 を満たすバージョンが選ばれ,Gemfile.lock は書き換えられることになります。

Gemfile と Gemfile.lock の関係はちょっぴりだけ複雑です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[wip] Ruby メモ

csv

raw_data = File.read('')

# RFC4180準拠のパース(rubyの標準ライブラリのCSVパーサー仕様)で不正となるcsvも適切にパースする
parsed_csv = CSV.parse(raw_data, col_sep: "\t", liberal_parsing: true)

参考

文字コード

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

google recruit

Mac OS X-10.15.7 ruby-2.7.1p83

google recruit

課題

自然対数eの値で連続10桁の数のうち、最初の素数を出力する以下をexp.txtとして入力として使用する

2.71828182845904523536028747135266249775
7247093699959574966967627724076630353547
5945713821785251664274274663919320030599
2181741359662904357290033429526059563073
81323286279434907632338298807531952510190

解答

コード

def prime?(num)
 if (number < 2) return false;
 elsif (number == 2  && num == 3) return true;
 elsif (number % 2 == 0) return false;
 end

sqrt_num = Math.sqrt(num);
3.step(sqrt_num,2) do |i|
 if num % i == 0
  return false
 end
end

 return true
end

def read_exp
 exp = gets.to_s.chomp
end

exp = read_exp()
for i in 0..(exp.length - 10)
 num = exp[i..(i+9)].to_i
 prime = prime?(num)
 if prime 
  puts(num)
  break
 end
end

結果

7427466391

  • source ~/grad_members_20f/members/wjswnsrud12/gool.org
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ギリギリでRuby Silverに受かるために

はじめに

RubySilverに合格しました。
点数は76点と、本当にギリギリでした。
今回はギリギリですがSilverに受かった私の勉強内容を記事にします。

自己紹介

2020/3月からプログラミングスクールにて4ヶ月間学び、8月よりRailsの自社/SESの会社に就職しました。
プログラミングスクールではRailsを学びましたが、Rubyを勉強したことはほとんどなく、メソッドや配列、ハッシュの細かいところなどは知らなかった私です。

受けようと思ったきっかけは
今は自社コンテンツを触っている状況ですが、いずれSESで外に出ることが確定しているということで、出向先の会社の面接の合格率が上がるんでは無いかと思ったからです。
業務にも役に立ちそうとも思いました。

勉強してみての感想

先に結論?みたいなのを言ってしまうと、勉強してみて本当に良かったとしみじみ感じています。
先輩方が書いたコードを読むところから開発、改修が始まっていくわけで。
すると、なんだろこのメソッド。
なんだろこのコードみたいなのがたくさんありました。

きっと優秀と言われる人は改修に関係がなくてもそれを調べたりするわけじゃないですか。
でも私は今回の改修に関係なかったとしたらスルーしてしまうんですね笑
まあわかんないけど動いているし、自分より優秀な人が書いたコードだから大丈夫だろ、みたいな。

ダメな新人エンジニアです。笑

このままだと一生分からないままになるところだったのですが、
今回Silverを勉強してみて今まで読めなかったコードを確実に読めるようになり、
さらに先輩方のコードを改良することも出来るようになったので、勉強の価値ありだと思います!!

勉強期間

およそ2ヶ月
10月と12月ですね。
毎日大体30分から1時間くらいは勉強したと思います。
通勤の電車の中で問題をひたすら問いていました。

後述するRexの模擬問題では最終的に100点か98点しか取らなくなるような状態でした。

受験に向けて使用した書籍、サイトなど

1:Rex
https://www.ruby.or.jp/ja/certification/examination/rex
こちらは実際の試験を想定した問題を解くことができます。
ほとんど毎日2回は模擬問題を解き続けました。

2:スマホで1問1答
https://ruby1mon1tou.com/
こちらもRexに似ていますが、問題のバリエーションは少なめです。
ただ回答した時に答えをすぐに確認出来るのはおすすめです。

3:たのしいRuby 第6版
正規表現や例外処理、あとはRuby全般に関して細かく書いてある入門書です。

4:Ruby 技術者試験合格教本 Version2.1
公式テキストのようです。
参考書としても使えるようですが、結構難しくてほとんど読んでいません。
巻末の模擬問題は実試験でも何問かは同じ問題が出るのでおすすめです。

実際の試験を受けてみて

模擬問題だけをひたすらやっていたとしても恐らく5割は解けるような感覚を受けました。
まさに私のような人間ですね笑
半分は模擬問題の類似問題、もしくは全く同じ問題が出ます。

正直問題内容はよく覚えていないのですが、
個人的に大事だと思うことが

・破壊的メソッドと非破壊的メソッドの種類(!が無いのに破壊的なものとか)
clear update concat delete delete_ifとかがそれにあたります。

・引っ掛け問題が多い
模擬問題をやっていれば恐らく引っかかることは無いです。
例えば

test.rb
ary = [apple,apple,apple]
ary[0].upcase
p ary #=> [apple,apple,apple]

のような問題ですね。
upcaseメソッドは破壊的メソッドでは無いので[0]はappleのままです。

・Fileクラス
実務ではほとんど触らないので、r、r+、a、,a+、w、w+のモードがそれぞれどういう挙動をするかを確かめておく必要があります。
またrewindやIO.seekなどの使い方も知っておいた方が良いです。

・Dirクラス
これは今回の試験ではあまりなかったです。
模擬問題で多いのが、どれがDirのクラスメソッドなのかを選ぶような問題でした。
確か今回の試験もそういう問題だったと思います。

・Hash
これがなかなか私の頭を悩ませました。
模擬問題だとHash[]で新しいハッシュを作成することが出来るが正解なのですが、どなたかの記事を読んだところこちら2.1だと非対応とのこと。

一体どっちなんだろうと調べる間もなく試験にこれが出てしまう悪夢を経験しました。

Hashに関するメソッドも作成方法を始め一通り覚えておく必要があります。

・Array
map collect select find detect reject find_all
zip transpose productなどなど。

それぞれがどのような挙動をし、どのメソッドと同じなのか(map と collectは同じ)
は覚えておかないといけません。
これは恐らく試験に出ます。

・String

test.rb
str = "abcdefghr"
p str[2,4] #=> "cdef"
p str[0,3] #=> "abc"
p str[1..3] #=> "bcd"
p str[1...3] #=> "bc"
p str[1..-2] #=> "bcdefgh"

このような取り出し系の問題は必ず出ます。

また、chop chomp stripなどのメソッドの出題も多いです。

・その他
joinやsplitメソッドの使い方の問題もありました。
splitに引数を渡さないとどういう挙動をするかのような。
残念ながら私はわかりませんでしたが、笑

eachに関してもeach doだけでなくeach_with_index、each_charなども出ます。

また、二進数、八進数、十六進数に関する問題も出ます。
ただこれに関しては模擬問題でも必ずやるのでそこで覚えれば問題なく解けるはずです。

それと簡単な正規表現に関する問題や例外処理に関する問題も出ます。

時刻の変換であるstrftimeに関しても%Y%m%dだけでなく他にも色々あるので%xと%Fくらいは覚えておいた方が良さそうです。

まとめ

上記以外にも絶対にやっておいた方がいいこと

実際にローカル環境のバージョンを2.1にして、模擬問題のコードを検証する!!!

なぜなら、本やネットの模擬問題の回答が間違っているケースがあるからです(衝撃)

これも試験直前に知りました。

全てのコードを貼り付けて動作を確認するぐらいの方がきっといいと思います。

また、間違った回答に関してもそれが何故ダメなのかというところを抑えておかないと
私の二の舞になります。笑

駆け足で書いてしまったので内容がスカスカになってしまいました、すみません。

またこの記事に肉付けをしていきます。

皆さんの合格を願っています。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

deviseを用いたユーザー認証機能の作成

アプリケーションに"devise"を読み込ませる

Gemfile
:
gem 'devise' #追加
terminal
$ bundle install

deviseコマンドでモデル、ビュー、コントローラを作成

terminal
$ rails g devise:install
$ rails g devise User name:string #モデルの作成
$ rails db:migrate
$ rails g devise:views users #ビューの作成
$ rails g devise:controllers users #コントローラの作成

rails g devise "model名"で作成したモデルには初期値ではnameカラムが存在しない為、上記のようにカラムを同時に作成するか、migrationファイルに記述してテーブルに反映させる。

・作成されたモデル

app/models/user.rb
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable
end

デフォルトの機能

  • database_authenticatable(パスワードの正確性を検証)
  • registerable(ユーザー登録や編集、削除)
  • recoverable(パスワードをリセット)
  • rememberable(ログイン情報を保存)
  • validatable(emailのフォーマットなどのバリデーション)

ルーティングの変更

config/routes.rb
...編集
devise_for :users # devise機能の使用の際にURLにusersを含むことの宣言

devise_for :users, controllers: {
  sessions: 'users/sessions',
  registrations: 'users/registrations'
}

ビューページの編集

新規登録画面に名前の入力フォームを追加

app/views/users/registrations/new.html.erb
... +の部分を追加
+ <div class="field"> 
+  <%= f.label :name %><br />
+  <%= f.text_field :name, autofocus: true, autocomplete: "name" %>
+ </div>

<div class="field">
  <%= f.label :email %><br />
  <%= f.email_field :email, autofocus: true, autocomplete: "email" %>
</div>
:

ログイン画面の入力フォームをemailからnameに変更
これによりemailでのログイン認証へと変更させる

app/views/users/sessions/new.html.erb
...編集
:
 <div class="field">
   <%= f.label :email %><br />
   <%= f.email_field :email, autofocus: true, autocomplete: "email" %>
 </div><div class="field">
   <%= f.label :name %><br />
   <%= f.text_field :name, autofocus: true, autocomplete: "name" %>
 </div>
:

コントローラの編集

app/controllers/application_controller.rb
...追加
before_action :configure_permitted_parameters,if: :devise_controller? 

protected

def configure_permitted_parameters
  devise_parameter_sanitizer.permit(:sign_up,keys:[:name])
end

devise利用の機能(ユーザ登録、ログイン認証など)が使われる場合、その前にconfigure_permitted_parametersが実行

devise_parameter_sanitizer.permit(:sign_up,keys[:name])
= ユーザ登録(sign_up)の際のユーザ名(name)のデータ操作を許可

Strong Parametersと同様の機能
・private = 自分のコントローラ内のみで参照
・protected = 呼び出された他のコントローラからも参照可能

ログアウト機能の実装

app/views/layouts/application.html.erb
...+部分の追加
  <body>
+   <% if user_signed_in? %>
+     <%= link_to "ログアウト", destroy_user_session_path, method: :delete %>
+   <% else %>
+     <%= link_to "新規登録", new_user_registration_path %>
+     <%= link_to "ログイン", new_user_session_path %>
+   <% end %>
:

以上

記載内容に間違い等ございましたらご指摘頂けると幸いです。
ご連絡お待ちしております。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

hidden_field_tagの使い方

はじめに

Railsアプリ作成時にhidden_field_tagを使ったので、その時の内容のメモ書きになります。
検索機能を使った時にパラメータが飛ばなかったのでhidden_field_tagを使用し対応した時の内容になります^^

使用方法

hidden_fieldhidden_field_tagは用途は似ているが使い方が違う。
hidden_fieldform_forform_withの中で使用するに対し、

hidden_field_tagは一つだけで使用でき単体でパラメーターを渡したいときに使用する。
form_for内でも使用はできます。

作業内容

このように検索窓のソースがあります。

app/views/texts/index.html.erb
<%= search_form_for @eq do |f| %>
      <div class="d-flex">
        <div class="form-group flex-grow-1">
          <%= f.search_field :title_cont, placeholder: "教材を探す", class: "form-control" %>
        </div>
        <div> 
        <%= f.submit "検索", class: "btn btn-primary ml-1" %>
        </div>
      </div>
    <% end %>

viewの表示はこのようにコントローラーで指示をしています。

app/controllers/texts_controller.rb
def index
    if params[:genre].nil? 
      @eq = Text.where(genre: ["Ruby on Rails", "Git","Basic","Ruby"]).ransack(params[:q])
    else
      @eq = Text.where(genre: params[:genre]).ransack(params[:q])
    end
      @texts = @eq.result.order(:id)
  end

そこで
indexアクションに記述してある
if params[:genre].nil?はパラメータが空ならtureで以下実行するという記述です。

一部ページのパスにgenre:を埋め込んでいます。

<%= link_to " Ruby/Rails教材", texts_path, class: "dropdown-item" %>
<%= link_to "動画教材", movies_path, class: "dropdown-item" %>
<%= link_to "PHP教材", texts_path(genre: "PHP"), class: "dropdown-item" %>
<%= link_to "プログラミング勉強会", movies_path(genre: "Live"), class: "dropdown-item" %>
<%= link_to "質問集", questions_path, class: "dropdown-item" %>
.
.
.
.

表示するページ事に[:genre]を付けて色分けしています。
なのでリンクからの表示なら問題は無いのです。

が、

今回は検索して表示が目的なので、

このままだと
キーワード検索してもgenreのparamsに値が無いのでtrueで表示されます。

app/views/texts/index.html.erb
<%= f.search_field :title_cont, placeholder: "教材を探す", class: "form-control" %>

↑今のままだと検索かけたとしてもユーザーが記入した文字列しか飛ばしていません。

ターミナル
           部分一致検索→"p"→検索
 Parameters: {"q"=>{"title_cont"=>"p"}, "commit"=>"検索"}
  User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 3], ["LIMIT", 1]]

From: /Users/ikedakeigo/Desktop/gyakuten_clone_group27/app/controllers/texts_controller.rb:4 TextsController#index:

     2: def index
     3:   binding.pry
 =>  4:   if params[:genre].nil? 
     5:     @eq = Text.where(genre: ["Ruby on Rails", "Git","Basic","Ruby"]).ransack(params[:q])
     6:   else
     7:     @eq = Text.where(genre: params[:genre]).ransack(params[:q])
     8:   end
     9:     @texts = @eq.result.order(:id)
    10: end

[1] pry(#<TextsController>)> params[:genre]
=> nil ⇦:genreに値が入っていない。

そこでhiddenfield_tagの出番です!
:genreを単体で送り込みましょう。

app/views/texts/index.html.erb
  <%= search_form_for @eq do |f| %>
      <div class="d-flex">
        <div class="form-group flex-grow-1">
          <%= f.search_field :title_cont, placeholder: "教材を探す", class: "form-control" %>
        </div>
        <div> 
        <%= hidden_field_tag(:genre, "Php")%> ⇦追加
        <%= f.submit "検索", class: "btn btn-primary ml-1" %>
        </div>
      </div>
    <% end %>

このように記述すると検索キーワードと:genreを飛ばすことができます!
が、
このままだと常に中身がPhpfalseが返され特定の物しか検索できない形になります。

そこで条件分岐を付けて上げて柔軟に対応するようにします。

app/views/texts/index.html.erb
  <%= search_form_for @eq do |f| %>
      <div class="d-flex">
        <div class="form-group flex-grow-1">
          <%= f.search_field :title_cont, placeholder: "教材を探す", class: "form-control" %>
        </div>
        <div>               
        <%= hidden_field_tag(:genre, params[:genre]) if params[:genre].present? %> ⇦追加
        <%= f.submit "検索", class: "btn btn-primary ml-1" %>
        </div>
      </div>
    <% end %>

present?メソッドは 「〜が存在するとき」の条件分岐

表示しているページによって:genreに値を付けているので、
それで判断させています。

これでページ事のキーワード検索ができました!^^

おわりに

コード書いていると極々普通なことかもしれませんが、
悩んでいたことが、上手くできると
「ん?いや、普通に考えたらわかるやん!」っておわりに気づくことがあります^^笑

なんでも諦めないことですね!^^

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

resources & resource

resources

Ruby on Railsでルーティングを行う際に必ずと行っていいほど頻出であるresources
resourcesはモデルに対してアプリケーションにおける基本メソッド7つを自動的にルーティングしてくれます。

例えばUserモデルに対してresourcesを使ってルーティングを記載した場合

config/routes.rb
Rails.application.routes.draw do
  resources :users
end

$ rails routesでルーティングを表示させると以下のようになります。

$ rails routes
   Prefix Verb   URI Pattern               Controller#Action
    users GET    /users(.:format)                    users#index                                               
          POST   /users(.:format)                    users#create                                                     
 new_user GET    /users/new(.:format)                users#new                                                  
edit_user GET    /users/:id/edit(.:format)           users#edit                                                   
     user GET    /users/:id(.:format)                users#show                                                 
          PATCH  /users/:id(.:format)                users#update                                           
          DELETE /users/:id(.:format)              users#destroy

このようにして、たった1行記載するだけで、簡単にルーティイングをしてくれます。

resourcesが使われるのは基本的にモデルに複数のリソースがある時です。
例えば、Userモデルにはアプリケーションのユーザのモデルがたくさん登録されると思います。
他にも、ユーザの投稿モデルであるPostモデルも、アプリケーション内に複数の投稿が存在するので、resourcesを使用することができます。

resource

では、複数リソースに対してではなく単数のリソースにルーティングする場合はどうでしょうか?

単数のリソースとはつまり、アプリケーション内のページにおいて、ログインユーザだけが使用するリソースです。
例えば、Instagramの設定にあるプロフィールページは自分だけが使用できますよね?
他の人はあなたのプロフィール設定ページににアクセスすることはできません。(できたらアカウントが乗っ取られています笑)

そのような単一リソースに対してルーティングを設定する際はresourcesではなく、単数形resourceを使います。
例えば、プロフィール画面をルーティングするとしましょう。

config/routes.rb
Rails.application.routes.draw do
  resources :users
  # 追記
  resource :profile
end
$ rails routes
      Prefix Verb   URI Pattern               Controller#Action
 new_profile GET    /profile/new(.:format)             profiles#new
edit_profile GET    /profile/edit(.:format)            profiles#edit
     profile GET    /profile(.:format)                 profiles#show
             PATCH  /profile(.:format)                 profiles#update
             DELETE /profile(.:format)                 profiles#destroy
             POST   /profile(.:format)                 profiles#create

resourcesと何かが違いますね、、。

①indexアクションがない

なぜ?、と思うかもしれませんが、これはよくよく考えてみると簡単です。

上述したように、resourceを使用する場合、単一リソースが使用対象をなることを説明しました。
しかし、indexアクションはモデルのリソース全てを表示することを意図しています。
結果、単一リソースであるプロフィール画面を扱う際に複数を表示するindexアクションは不要となるわけです。

②:idがない
4つのアクション(edit、show、update、destroy)から:idという部分が消えています。

実はこれもindexアクションがない理由と同じになります。

resourcesにおいて4つのアクションに:idが必要だった理由は、複数あるリソースの中からどのリソースかを指定するためです。
例えば、自分の投稿を編集する場合、どのidの投稿かを指定しないと、どの投稿を編集していいのかがわかりません。投稿の詳細閲覧、投稿の更新、投稿の削除も同様に、どの投稿であるかを指定しないといけません。

しかし、プロフィール設定画面はどうでしょうか。
単一リソースであるプロフィールは、指定せずとも一つしかないのだからわかるという仕組みです。
ですので、idを指定する必要がそもそもないという理由で:idが消えています。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby on Rails ✕ Docker 開発中のアプリにDocker導入(MySQL)

はじめに

はじめてのDocker導入だと、何から手を付けたら良いのかわからない、ということがよくありますが、まさに自分がそれでした...

本記事では開発途中・完成したRailsアプリケーション(DB: MySQL)にDockerを導入する方法・流れを解説していきます。
参考までに自分は6時間位かけてローカルに導入できました。その苦労を忘れないようにしっかりアウトプットしていこうと思います(笑)
間違っていたら指摘してくださると幸いです!

Dockerの導入

1)Dockerのインストール

まずMacにDockerのアプリをインストールしてください
それに関しては以下の記事がわかりやすいです!
DockerをMacにインストールする

インストールできたらターミナルで以下コマンドを実行しましょう!

ターミナル
~ % docker run -d -p 80:80 docker/getting-started

2)インストールの確認

ターミナル
~ % docker -v

以下のように出力されたらインストール成功です。
Docker version 20.10.0, build 7287ab3

ターミナル
~ % docker-compose -v

こちらも同じようにdocker-compose version 1.27.4, build 40524192と出力されたら成功です。

3)開発中・完成済みのアプリでDockerファイルの作成

次にDockerを導入するためにDockerファイルを作成し、設定を記述していきます。
テキストエディタでも可能ですが、自分の場合はターミナルから入力して方がエラーもなくスムーズだったため、そちらの方法を記載していきます。

①Dockerfileの作成

まずアプリのルートディレクトリにDockerfileを作成して、記述していきます。
ルートディレクトリというのは以下の図のようにアプリ直下のディレクトリを表します。

dock_app ----|-- app
            |-- bin
            |-- config
            |-- db
            ・・・・・・
       ・・・・・・
            |-- Gemfile
            |-- Gemfile.lock
            |-- package.json
            |-- Rakefile
            |-- README.md
            |-- Dockerfile  ←「Dockerfile]
            |-- docker-compose.yml  ←[docker-compose.yml]

手順としては以下の順に進んでいきます。

ターミナル
 ~ % cd Dockerを導入したいアプリのパス

 アプリ名 % vi Dockerfile
 #ファイルを開いたら「i」でインサートモードにして以下記述
FROM ruby:2.6.5 #アプリのRubyバージョン

RUN apt-get update -qq && \
    apt-get install -y build-essential \
                       libpq-dev \
                       nodejs

RUN mkdir /アプリ名
WORKDIR /アプリ名

ADD ./Gemfile /アプリ名/Gemfile
ADD ./Gemfile.lock /アプリ名/Gemfile.lock

RUN gem install bundler #bundlerをインストールしないとエラーが出る
RUN bundle install
ADD . /アプリ名

 #記述ができたら「escキー」を押して「:wq」で保存

②docker-compose.ymlファイルの作成

ターミナル
 アプリ名 % vi docker-compose.yml

 docker-compose.ymlに以下記述

 #「i」と入力しインサートモードで記述

version: '3'
services:
  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: 'password' # このままpasswordとしても問題なく動く
    ports:
      - "4306:3306" #DockerコンテナとSequelpro接続の為に必要な設定

  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/アプリ名
    ports:
      - "3000:3000"
    depends_on:
      - db
 #記述が終了したら「escキー」を押して「:wq」で保存

4)config/database.ymlファイルの編集

(テキストエディタ)
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: password # passwordの設定がなければ、このままで良い
  socket: /tmp/mysql.sock
  host: db

development:
  <<: *default
  database: アプリ名_development

追加されたのはpassword: passwordhost: dbの2つのみ。

5)docker-compose buildでコンテナ作成

ターミナル
アプリ名 ~ % docker-compose build

上記コマンドを実行してコンテナを作成しましょう。※時間がかかることがあります

以下のように出力されれば成功です。

ターミナル
Removing intermediate container dac250609513
 ---> f0ba8d685e44
Step 9/9 : ADD . /tumlog
 ---> f50cb7681119

Successfully built f50cb7681119
Successfully tagged tumlog_web:latest

ちなみに初心者の方だとコマンド実行中に赤字でdebconf: delaying package configuration, since apt-utils is not installedと表示されますが、自分の調べた範囲では特に気にするようなこともない?出力のようです。

6)コンテナ上でDB作成・migrationの実行

コンテナが作成できたらコンテナ上でDBを作成していきます。

ターミナル
アプリ名  % docker-compose run web bundle exec rake db:create

Rails6だとこのコマンドを実行すると

========================================
  Your Yarn packages are out of date!
  Please run `yarn install --check-files` to update.
========================================


To disable this check, please change `check_yarn_integrity`
to `false` in your webpacker config file (config/webpacker.yml).

このように出力されることがあります。
このように出力されたら、エラー分通りconfig/webpacker.ymlファイルの記述を以下のように編集しましょう。

webpacker.yml
# Verifies that correct packages and versions are installed by inspecting package.json, yarn.lock, and node_modules
  check_yarn_integrity: true

 # check_yarn_integrity: true を falseに変えましょう → check_yarn_integrity: false

これでエラーは解決できると思うので、記述を変更したら、もう1度DB作成のコマンドを実行しましょう。

ターミナル
Created database 'アプリ名_development'
Created database 'アプリ名_test'

#上記のようにcreatingがcreated...doneとなったら成功

続いてmigrationを実行しましょう。

ターミナル
アプリ名  % docker-compose run web bundle exec rake db:migrate


== 20201222010929 Createテーブル名: migrating ====================================
-- create_table(:テーブル名)
   -> 0.0095s
== 20201222010929 Createテーブル名: migrated (0.0096s) ===========================

# 上記のようにrails db:migrateを実行したときのようにマイグレーションが実行されれば成功です

7)コンテナの起動

最後にコンテナを起動して無事、アプリがブラウザで表示されるか確認しましょう。

コンテナの起動コマンドを実行しましょう。

ターミナル
アプリ名 % docker-compose up 

# 起動していれば以下の様の出力が出る

db_1   | 2020-12-27T06:45:52.494912Z 0 [Note] Event Scheduler: Loaded 0 events
db_1   | 2020-12-27T06:45:52.497330Z 0 [Note] InnoDB: Buffer pool(s) load completed at 201227  6:45:52
db_1   | 2020-12-27T06:45:52.497669Z 0 [Note] mysqld: ready for connections.
db_1   | Version: '5.7.32'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server (GPL)
web_1  | => Booting Puma
web_1  | => Rails 6.0.3.4 application starting in development 
web_1  | => Run `rails server --help` for more startup options
web_1  | Puma starting in single mode...
web_1  | * Version 3.12.6 (ruby 2.6.5-p114), codename: Llamas in Pajamas
web_1  | * Min threads: 5, max threads: 5
web_1  | * Environment: development
web_1  | * Listening on tcp://0.0.0.0:3000
web_1  | Use Ctrl-C to stop

コマンドを実行し、サーバーが起動したらローカル環境にアクセスしてみましょう
http://localhost:3000/
無事に表示・挙動が確認できれば開発環境にDockerを導入できたということになります。

自分はこれだけで6時間くらいかかったので、ぜひ皆さんは本記事を活用して、さくさく進めていってください!!

本記文献

『さわって学ぶクラウドインフラ docker基礎からのコンテナ構築』
既存のrails6のアプリにMySQLでDockerを導入する。
Ruby on Rails 「途中まで作ったアプリにDockerを導入したい」に挑戦してみる(MySQL / Sequel Pro)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby】eachの入れ子

論理的思考強化の為、ドリルの復習をしています。
初学者のため、何かお気づきの点がありましたらご教示いただけますと幸いです。

問題

以下の配列を用いて、果物の名前とそれぞれの合計額が出力されるコードを記述してください。

fruits_price = [["banana", [160, 100, 220]], ["kiwi", [100, 250, 80]], ["strawberry", [700, 680]]]

#出力
bananaの合計金額は480円です。
kiwiの合計金額は430円です
strawberryの合計金額は1380円です

解答

fruits_price = [["banana", [160, 100, 220]], ["kiwi", [100, 250, 80]], ["strawberry", [700, 680]]]

fruits_price.each do |fruit|   #①
  sum = 0
  fruit[1].each do |price|    #②
    sum += price
  end
  puts "#{fruit[0]}の合計金額は#{sum}円です"   #③
end

解説

①fruits_priceから["apple", [200, 250, 220]]を取り出す
eachは、配列内の要素全てを分解して取り出すのではなく、eachにかけた配列内で次に小さな塊で取り出してくれます。

今回の場合、
[["banana", [160, 100, 220]], ["kiwi", [100, 250, 80]], ["strawberry", [700, 680]]]から
1回目→["banana", [160, 100, 220]]
2回目→["kiwi", [100, 250, 80]]
3回目→["strawberry", [700, 680]]
の順に取り出しています。

②["banana", [160, 100, 220]]から[160, 100, 220]を取り出して計算する

変数の中身の値は添字で表すことができます。
例えば、fruit = [banana, kiwi, strawberry]だった場合は以下の通りです。
fruit[0] = banana
fruit[1] = kiwi
fruit[2] = strawberry

今回は配列内に配列がある為、難しく考えてしまいがちですが考え方は同じです。
現在["banana", [160, 100, 220]]は、fruitという変数に格納されているので以下のようになります。
fruit[0] = banana
fruit[1] = [160, 100, 220]

fruit[1]にeachをかけると数値を一つ一つ取り出し、自己代入しながら数値を足していきます。


③putsで出力する
②で述べたように、果物名はfruit[0]で取り出すことができます。
そして合計金額を格納している変数はsumも合わせて、式展開で出力します。

おまけ

以下は私のミスです。

fruit[1].each do |price|
  sum += price
  puts "#{fruit[0]}の合計金額は#{sum}円です"  
end

このようにputsをfruit[1].eachのブロック内に入れてしまうと
計算途中の金額も毎回出力されてしまうので誤りとなります。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RailsチュートリアルでRuby3.0.0をインストールしたらbundle updateとbundle installができなかったときの解決法

あいさつ

知っている人はこんにちは!知らない人ははじめまして!
独学でプログラミングを極める変態中学生のAtieです!
今回は約3日間格闘し続けたエラーの解決法がわかったのでここに記録を残します
これでやっとRailsチュートリアルを進めることができます

結論から言うと...

Rubyの最新版(3.0.0)をインストールしてしまって依存関係が解決できずに動かなかった!
ということのせいで動きませんでした
なのでRailsチュートリアルと同じバージョンのRuby2.6.3をインストールしてGlobalに2.6.3を設定することで動きました!

開発環境

Ruby 3.0.0
Rails 6.0.3.4
Gemfile.lock は削除済み
Gemfileの内容(名前は「Gemfile」ですがRubyのコードで記載されていてわかりやすいようにわざと.rbの拡張子をつけています本番環境では.rbはついていません以下Gemfileを表示するときは.rbを拡張子としてつけています)

Gemfile.rb
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

gem 'rails',      '6.0.3'
gem 'puma',       '4.3.6'
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]

エラーの内容

まずはbundle installを行うと以下のようなエラーが出てきました

$ bundle install
Fetching gem metadata from https://rubygems.org/............
Fetching gem metadata from https://rubygems.org/.
You have requested:
  listen = 3.1.5

The bundle currently has listen locked at 3.3.3.
Try running `bundle update listen`

If you are updating multiple gems in your Gemfile at once,
try passing them all to `bundle update`

エラーの内容は「バージョンがロックされているからbundle updateでアップデートしてね!」という内容です

$ bundle update
Fetching gem metadata from https://rubygems.org/............
Fetching gem metadata from https://rubygems.org/.
Resolving dependencies...
Bundler found conflicting requirements for the Ruby version:
  In Gemfile:
    Ruby armv7l-linux-eabihf

    capybara (= 3.28.0) armv7l-linux-eabihf was resolved to 3.28.0, which depends on
      Ruby (>= 2.4.0) armv7l-linux-eabihf

    listen (= 3.1.5) armv7l-linux-eabihf was resolved to 3.1.5, which depends on
      Ruby (>= 2.2.3, ~> 2.2)

    puma (= 4.3.6) armv7l-linux-eabihf was resolved to 4.3.6, which depends on
      Ruby (>= 2.2) armv7l-linux-eabihf

    selenium-webdriver (= 3.142.4) armv7l-linux-eabihf was resolved to 3.142.4, which depends on
      Ruby (>= 2.3) armv7l-linux-eabihf

内容は「競合が発生しているよ!」という内容です

ググってみると依存関係がどうのこうのだと...
あれ?ちょっと待てよRubyのバージョンってRailsチュートリアルのバージョンと一緒なのか?
という疑問が頭の中をよぎりました
そのときにぴーんと来ました!
なのでまずはRailsチュートリアルのRubyのバージョンを調べました
Railsチュートリアルの初期の状態のGemfileは以下のようになっていました

Gemfile.rb
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '2.6.3'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 6.0.3'
# Use sqlite3 as the database for Active Record
gem 'sqlite3', '~> 1.4'
# Use Puma as the app server
gem 'puma', '~> 3.11'
# Use SCSS for stylesheets
gem 'sass-rails', '~> 5'
# Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker
gem 'webpacker', '~> 4.0'
# Turbolinks makes navigating your web application faster.
# Read more: https://github.com/turbolinks/turbolinks
gem 'turbolinks', '~> 5'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.7'
# Use Redis adapter to run Action Cable in production
# gem 'redis', '~> 4.0'
# Use Active Model has_secure_password
# gem 'bcrypt', '~> 3.1.7'

# Use Active Storage variant
# gem 'image_processing', '~> 1.2'

# Reduces boot times through caching; required in config/boot.rb
gem 'bootsnap', '>= 1.4.2', require: false

group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a
  # debugger console
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
end

group :development do
  # Access an interactive console on exception pages or by calling 'console'
  # anywhere in the code.
  gem 'web-console', '>= 3.3.0'
  gem 'listen', '>= 3.0.5', '< 3.2'
  # Spring speeds up development by keeping your application running in the
  # background. Read more: https://github.com/rails/spring
  gem 'spring'
  gem 'spring-watcher-listen', '~> 2.0.0'
end

group :test do
  # Adds support for Capybara system testing and selenium driver
  gem 'capybara', '>= 2.15'
  gem 'selenium-webdriver'
  # Easy installation and use of web drivers to run system tests with browsers
  gem 'webdrivers'
end

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

Railsチュートリアルのバージョンが2.6.3で自分の環境が3.0.0...
違いすぎるだろ!!それじゃ動くわけねぇよ!(3.0.0に至ってはメジャーアップデートでそこそこ大幅に改良されてたし... 詳しくはここへ)
そうですバージョンが大幅に違いました
あるあるです
特にLinuxを使っているとプログラムなどを動かそうとしてもライブラリなどのバージョンどうのこうのの依存関係のせいで動かないのがよくあります(自分が使っているFedoraなどは特にそう)

はぁはぁはぁ...疲れた...やっと動く...(フラグじゃないよ\(^o^)/)

ということで動きました!

最後に

今回はかなり解決に時間がかかったエラーでした
今回のことを経験することができそのおかげで一回りはプログラマーとして成長できたと思います
エラーの原因を探したり解決するのもプログラマーの必須スキルであったりします
そして今回は依存関係などのバージョンの大切さを非常に学ぶことができました
もしこの記事が皆さんのエラー解決に少しでも役に立てたら光栄です
最後まで読んでいただきありがとうございました
ではまた次回の記事で!
AtieのTwitter

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

signup後の画面で、profile,logoutを表示されない問題を解決した。

発生した問題

ブログの完成に向けて、ログインシステムを構築する過程でエラーが発生した。
http://localhost:3000/users/new
において、Signupを実行後、UserのProfile画面にリダイレクトはできただが、ページ上部にProfileとLogoutが表示されず、代わりにSignUpとLoginが表示されてしまう。
signup_error.gif

当初考えられた原因

 (1)app/helpers/sessions_helper.rbで定義し、layouts/application.html.erbに記述した”logged_in?”が有効でない。
 ・・・しかし、コードの記述自体に誤りは見られず、条件分岐もlogged_in?メソッド(※)も発火している。

logged_in?メソッドを格納しているapp/helpers/sessions_helper.rb
module SessionsHelper
  def current_user
    @current_user ||= User.find_by(id: session[:user_id])
  end
  def logged_in?
    current_user.present?
  end
end

 (2)そもそも、”rails g controller sessions new”実行時に、sessions_helper.rbが生成されなかった。
 ・・・これは「- CSS、JavaScript、Helperのファイルをrails g コマンドで自動生成しない設定を記述して、これらの余分なファイルができない」ようにするため、”config/application.rb”に下記の記述をしたことで、意図的に自動生成せず、代わりに自分でsessions_helper.rbファイルを作成した。

config/application.rb
require_relative 'boot'
require 'rails/all'
Bundler.require(*Rails.groups)
module HogehogeAppli
  class Application < Rails::Application
  #省略
    config.generators do |g|
      g.assets false
      g.helper false
    end
  end
end

 おそらく、上記(2)が原因で上手くlogged_in?が発火していないと予想していた。しかし、
http://localhost:3000/sessions/new
(Loginページ)でログインした場合は、正常にProfileとLogoutが表示されるため、なぜlogged_in?が発火しないのかが分からない。
 SignUp後に、ProfileとLogoutを表示させるためにはどうしたらよいのか、悩んでしまった。

解決法

 logged_in?メソッドは何の問題も発火しているため、問題点は違うところにあった。

 そもそもログイン状態とは、ユーザーのブラウザ内のcookiesに暗号化されたユーザーIDを付与することをログインといい、それが保持され続けていることをログイン状態という。(ブラウザとサーバ間で同一のユーザIDが突合し合えている状態)をいい、その仕組みはcreate時にsessionメソッドを使ってcookiesにユーザIDを持たせることでログイン状態が実現できる。
 
 Login(=ドメイン名/sessions/new)後には正常にProfileとLogoutを表示させられて、Signup(=ドメイン名/users/new)では表示されず代わりにSignupとLoginが表示されてしまう…。

 この違いについて焦点を当てることが解決につながると考え、users_controller.rb内のcreateアクションでログイン状態を作れていないことが判った。

app/controllers/users_controller.rb
def create
    @user = User.new(user_params)
    if @user.save
      #下記1行を追記し、ユーザーのブラウザ内のcookiesに暗号化されたユーザーIDが自動で生成されるようにした。
      session[:user_id] = @user.id
      redirect_to user_path(@user.id)
    else
      render :new
    end
  end

 結果として、別添画像のとおりSignup後の画面でProfileとLogoutを表示させることに成功した。
signup_correct.gif

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Google Recruit

Google Recruit

過去に出題された Google のリクルート問題を解いていく.

問題は次の通り.

Google Recruit Problem

e(自然対数の底)の値で連続する10桁の数のうち,最初の素数をrubyで求めよ.ただし,e(自然対数の底)は以下の200桁までとする.

2.71828182845904523536028747135266249775
7247093699959574966967627724076630353547
5945713821785251664274274663919320030599
2181741359662904357290033429526059563073
81323286279434907632338298807531952510190

解法

それでは実際に解いていく.まずはじめに方針を決める必要があるので,タスクをまとめてみると

  1. 数値ファイルを読み込む.
  2. 10桁の数を取り出す.
  3. 素数を判定する.

これらを順に実装していこう.

ファイルの読み込み

まずは 200 桁のe(自然対数の底)を exp.txt に保存し,ファイルを読み込む.標準入力から読み込む場合,

exp = gets.to_s.chomp.delete(".") 

のように実装できるがこの場合,実行時に

$ ruby google_recruit.rb < exp.txt

とリダイレクトで exp.txt を指定しなければならない.

今回はexp.txt を変更することはないので,コマンドではなくプログラム内でファイルを参照することにする.ruby では File クラスの read メソッドを使うことでファイルを読み込むことができる.

exp = File.read('exp.txt').delete(".")

読み込んだデータを格納した変数 exp を出力すると

2.71828182845904523536028747135266249775
7247093699959574966967627724076630353547
5945713821785251664274274663919320030599
2181741359662904357290033429526059563073
81323286279434907632338298807531952510190

改行されて出力される.これはexp.txt の中身自体が改行されているため,読み込まれたものも改行されてしまっている.

改行をなくすには delete メソッドで改行コードを指定すればよい.

exp = File.read('exp.txt').delete(".").delete("\n")
2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274274663919320030599218174135966290435729003342952605956307381323286279434907632338298807531952510190

問題なくファイルを読み込むことができた.

連続する 10 桁の数の取り出し

先ほど読み込んだデータを格納した変数 exp について,先頭から順に連続する 10 桁を取り出したい.変数 exp は文字列として扱えば各桁を指定することができるので each を用いて 10 桁ずつ取り出す.

exp = File.read('exp.txt').delete("\n").delete(".")

[*0..exp.length-10].each do |i|
  x_digits = exp[i..i+10-1].to_i
  puts xdigit
end

実行してみると

2718281828
7182818284
.
.
.
1952510190

問題なく先頭から順に連続する 10 桁を取り出すことができた.

素数判定のメソッド

今回のメインになる素数判定について見ていく.引数が素数であれば true, 素数でなければ false を返す is_prime メソッドを実装する.

素数とは自身の数 n と 1 以外で割り切れない数字なので,n を 2 ~ n-1 で順に割っていき,割り切れたら false を返すようにする.プログラムは以下のとおり.

def is_prime(num)
  [*2..num-1].each do |i|
    return false if num%i == 0
  end
  return true
end

しかし,実際に実行してみると1つの10桁の数に対して愚直に数十万回比較するので,自然対数の底 e の 200 桁の実行時間はとてつもなくかかってしまう.

何か上手い方法はないのか?

これは以下のように変更することで解決できる.

def is_prime(num)
  [*2..Math::sqrt(n).to_i+1].each do |i|
    return false if num%i == 0
  end
  return true
end

n-1Math::sqrt(n).to_i+1 に書き換えるだけでできる.これは素数でない合成数の性質を上手に利用している.

その性質とは 合成数 x は p ≦ √x を満たす素因子 p をもつ .わかりやすく説明すると x が合成数の場合,√x 以下の約数を持つ ということ.これで最高 100 万回近く比較していたものも 1000 回程度で済むようになる.

完成プログラム

上記を組み合わせたものは,以下のとおり.

# coding: utf-8
def is_prime(num)
  # 愚直に 1 ずつ比較する場合
  # [*2..num-1].each do |i|

  # 
  [*2..Math::sqrt(num).to_i+1].each do |i|
    return false if num%i == 0
  end
  return true
end

exp = File.read('exp.txt').delete("\n").delete(".")

[*0..exp.length-10].each do |i|
  x_digits = exp[i..i+10-1].to_i
  if is_prime(x_digits)
    print("[", i,", ", x_digits,", true]")
    break
  end
end

実行すると,

$ ruby google_recruit.rb
[99, 7427466391, true]

99 桁目から連続する 10 桁の 7427466391 が最初の素数であることがわかった.

発展問題

先ほどの問題の続きとして,

f(1)=7182818284
f(2)=8182845904
f(3)=8747135266
f(4)=7427466391
f(5)=__________

f(5) に入る数字を求める問題が出題される.これについて考察し,実行してみる.

素数とか完全数ではなさそう.共通点は 10 桁であることくらい.Google Recruit Problem の続きなのでネイピア数には関係していると考えて,ネイピア数の小数点を見ていくと f(1)=7182818284 が小数点の 1 桁目から 10 桁目であることがわかる.その他はどうなのか続きを見てみると f(2) は 5 桁目から 14 桁目,f(3) は 23 桁目から 32 桁目,f(4) は 99 桁目から 108 桁目であった.数列のようでもないし手がかりがない.

8 が多いけど偶数とか奇数とか関係あるのかなーと悩んでいると,10 桁の総和が49 になることを発見した.

これは各桁の総和が 49 になる 10 桁を求めるメソッドを作成し,先ほどのプログラムに組み込めば良い.作成したものは以下のとおり.

def is_49(num)
  sum = 0
  [*0..9].each do |i|
    sum += num[i].to_i
  end
  return true if sum == 49
  return false
end

exp = File.read('exp.txt').delete("\n").delete(".")

[*0..exp.length-10].each do |i|
  x_digits = exp[i..i+10-1]
  if is_49(x_digits)
    print("[", i,"~", i+9,": ", x_digits,"]\n")
  end
end

実行すると

$ ruby google_recruit2.rb
[1~10: 7182818284]
[5~14: 8182845904]
[23~32: 8747135266]
[99~108: 7427466391]
[127~136: 5966290435]
[145~154: 2952605956]

200 桁のe(自然対数の底)の中で連続する10桁の総和が49 になるものは 6 つあり, f(5) = 5966290435 であることがわかった.

参考ページ

今回参考にしたページはこちら.

Google recruit problem, exp and prime

【Ruby】ファイル読み込みメソッドまとめ

【Ruby】よく使うFileクラスを使ったファイル読み込み処理


  • source ~/grad_members_20f/members/e79a93e5b7b1/posts/class/google-recruit.org
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rubyで日付のデータを取得する方法

Dateクラスに対しクラスメソッドを使用

Rubyでは日付を扱うクラスとしてDateクラスが用意されており、これを使用することによりうるう年やひと月ごとの日数、曜日などの管理といった単なる数字のみでは正確に算出することが困難なデータを簡単に取得することが可能となる。
日付以外にも時間を管理するクラスや、日付と時間の両方を扱うクラスが存在する。

日付や時間に関する主なクラス

クラス名 管理可能なデータ   
Dateクラス   日付     
Timeクラス 時間
Datetimeクラス 日付と時刻の双方

Dateクラスを使う前準備(require)

Dateクラスを使用する際には、Rubyのコード上に"Date"ライブラリーを呼び込む必要がある。
その役割を果たすのがrequireメソッドであり、これにより外部ファイルを参照して、そこで定義されているクラスを取得することが可能となる。
※Railsのアプリケーションの場合はクラスはどのファイルにおいても参照できる為、require "~"の記述は不要

・具体的な使用方法

require "date"
#日付に関わるライブラリ"date"を取り込む
:
:

Dateクラスのインスタンス(オブジェクト)を取得する主な方法

  • todayメソッド(今日の日付を自動で算出してDateオブジェクトを作成)
require "date"
today = Date.today
#今日の日付を自動で算出してDateオブジェクトを作成
  • parseメソッド(引数で渡した文字列をDateオブジェクトに変換して作成)
require "date"
today_str = 2020-12-30
Date.parse(today_str)
#2020年12月30日のDateオブジェクトが作成される
  • newメソッドによる作成(引数で渡した整数を元にDateオプジェクトを作成)
require "date"
today = Date.new(2020, 12, 30) 
#2020年12月30日のDateオブジェクトが作成される

作成したDateオブジェクトから年や月などを取得する

上記の方法で作成したDateオブジェクトから特定の情報を取得する場合は、以下のようなコードを使用する。

require "date"
today = Date.today
today.year # 作成したDateオブジェクトから年を取得
today.mon # 作成したDateオブジェクトから月を取得
today.mday # 作成したDateオブジェクトから日を取得
today.wday # 作成したDateオブジェクトから曜日を数字として取得

記載内容に間違い等ございましたらご指摘頂けると嬉しいです。
ご連絡お待ちしております。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Ruby]色々なeachの種類

はじめに

勉強していると色々な種類のeachが出てきたので
忘れないように記していきます。:sunny:

eachメソッド

1 . 配列や範囲オブジェクトなどに用意されているメソッドです。
オブジェクトに含まれている要素を取り出します。

fruits = [ "apple", "orange","banana"]

fruits.each do |fruit|
  p fruit
end

#=>"apple"
#  "orange"
#  "banana"

2 . 配列のkeyとvalueを同時に取り出して使用したい場合は変数を2つ設定します。

fruits = { apple: 100, orange: 200, banana: 300}

fruits.each do |key, value|
  puts "#{key}の値段は#{value}円です。"
end

#=>"appleの値段は100円です。"
#  "orangeの値段は200円です。"
#  "bananaの値段は300円です。"

下記のように記述することもできます。
(お好みで。長いブロックを書くときは前のような記述は⇧、コンパクトに書きたい場合は⇩)

fruits = { apple: 100, orange: 200, banana: 300}

fruits.each { |key, value| puts "#{key}の値段は#{value}円です。"}

#=>"appleの値段は100円です。"
#  "orangeの値段は200円です。"
#  "bananaの値段は300円です。"

each_keyメソッド

keyのみを取り出したい場合に使用します。

fruits = { apple: 100, orange: 200, banana: 300}

fruits.each_key {|key|  p "#{key}の値段" }

#=>"appleの値段"
#  "orangeの値段"
#  "bananaの値段"

each_valueメソッド

valueのみを取り出したい場合に使用します。

fruits = { apple: 100, orange: 200, banana: 300}

fruits.each_value { |value| p "#{value}円"}

#=>"100円"
#  "200円"
#  "300円"

each_with_indexメソッド

1 . 配列の要素意外にindexの数字を使用したい場合に使用します。

fruits = [ "apple", "orange","banana"]

fruits.each_with_index do |a,i|
  p "#{i}個の#{a}があります。"
end

#=>"0個のappleがあります。"
#  "1個のorangeがあります。"
#  "2個のbananaがあります。"

2 . 引数にindexの初期値を設定して開始する数値を指定できます。
   (◯番から始めたいんだよなぁっていうとき。)

fruits = [ "apple", "orange","banana"]

fruits.each.with_index(5) do |a,i|
  p "#{i}個の#{a}があります。"
end

#=>"5個のappleがあります。"
#  "6個のorangeがあります。"
#  "7個のbananaがあります。"

each_sliceメソッド

引数に数を指定します。そうすることで名前の通り指定した数をsliceして要素を取り出すことができます。

fruits = [ "apple", "orange", "banana", "lemon","lime"]

fruits.each_slice(2) do |fruit|
  p fruit
end

#=>["apple", "orange"]
#  ["banana", "lemon"]
#  ["lime"]

each_lineメソッド

改行部分で分けて取り出すことができます。

fruits = "apple\norange\nbanana\nlemon"
fruits.each_line {|line| p line.chomp }

#=>[:apple, :orange, :banana, :lemon]

each_with_objectメソッド

引数のオブジェクトと要素を評価して最後に引数のオブジェクトを返します。

arr = [1, 2, 3]

result = arr.each_with_object({}) do |item, memo|
  memo[item] = item + 1
end

p result
#=>{1=>2, 2=>3, 3=>4}

こちらはさらに深堀として。。

まとめ

eachの仲間も色々な種類があるのがわかりました。
少しずつ覚えてできる範囲を広げて行こう・・・!!:fire:

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

google recruit

Ubuntu-20.04.1 ruby-2.7.1p83

お題

テキストで読み込ませたe(自然対数の底)で連続する10桁の数のうち、最初の素数を求めよ

方針

やることはシンプルだ。文字列を読み込ませ、文字列を前から10桁ずつ切り出して素数かどうかを判定していく。

まず動くやつを作る

テキストを読み込む

まずは200桁までのeが記述されたテキスト(exp.txt)を作っておいて、それを読み込ませる。

def read_exp
  exp1=gets.to_s.chomp
end
exp1 = read_exp()

これでexp1に文字列が配列として読み込まれたようだ。試しに

puts exp1[0..9]

として、配列の0番目から9列目を出力させると

> ruby google_recruit.rb exp.txt
> 2.71828182
#+end_src ruby
あ、なるほど、2とかピリオドも配列に入ってるから、それを考慮してプログラムを書いていかないといけないな<br>
ちなみに僕は一つ上のディレクトリにいる状態で実行しようとしたら、ちゃんとexp.txtまでの相対パスを指定したのに「exp.txtなんてありません」とか言われてムカついて作業が3日止まりました。カレントディレクトリ基準で相対パスまで指定したのにそんなことある?と思ったけど謎
#+begin_src ruby
for i in 0..189
  num = exp1[2+i..11+i].to_i
    puts num
  end
end

初期値は配列の2~11番目を出力、以降それを190回繰り返して10桁ずつ取り出せる。実際に取り出してみるとちゃんと頭から10桁ずつ出力されてた。とりあえず10桁ずつ切り出すことはできたので、次はこれが素数であるかを判定していく

素数を判定する

素数の定義に従って、つまり自分の数字以外で2から順に割っていって、割り切れずに最後まで到達すればそいつが答えだ

def prime?(num)
  (2..num-1).each do |i|
    if num % i == 0
      puts i
      return false
    end
  end
  return true
end

each doで2から自分-1の数字まで順に割っていき、どこかで割り切れたタイミングがあればそこでfalse=素数じゃない判定を返す。全く割り切れずに終わったらtrueを返す。こういう関数を作っておいて、10桁の数字ごとに呼び出していくという地道な方法を取って、とりあえず動くものを作る

for i in 0..189
  num = exp1[2+i..11+i].to_i
  answer = prime?(num)

  if answer == true
    puts num
    break
  end
end

基礎的ではあるけど、exp1には文字列が格納されてるので、to_iを付けて整数にしないとprime?に渡したときに計算できなくて困ったことになる。僕はそれに気づくのに1時間かかって詰まりました。断続的に作業をしないと効率悪いって分かってんのに没頭しちゃうんだよねえ
あとはanswerにprime?の戻り値を入れて、それがtrue=素数であるなら表示するというだけ

> ruby google_recruit.rb exp.txt 
> 2.71828182

どうやら正解が導かれたらしい。
しかしこの2行の間には、実はとてつもなく長い時間が含まれている。時間がかかるのは分かってたけど、進行状況を出力しつつ動かしたら15分もかかりやがった。コンピュータの感覚で時間がかかるのかと思ったらマジモンの「時間がかかる」だった。
はっきり言って素数かどうかを判断するだけで「終了まで結構時間がかかりますのでその間にお茶でもどうぞ」状態では困る。なので高速化を試みる。

素数判定高速化事業

教科書によると高速化をするには。prime?のループの範囲を2..Math::sqrt(n).to_i+1とすると良いらしい

def prime?(num)
  (2..Math::sqrt(num).to_i+1).each do |i|
    if num % i == 0
      return false
    end
  end
  return true
end

これだけで今まで15分かかってたのが一瞬で答えが出るようになった。なんでやろなあ

たとえばnum=400だとしたらループ範囲は2..21となる。従来2..399だったのが平方根を取ることで約1/20になる。同様に

  • 100000 : 2..317 -> 約0.3%
  • 50000000 : 2..7072 -> 約0.1%
  • 3000000000 : 2..54773 -> 約0.002%

という感じで、numが大きくなればなるほど短縮度合いは大きくなる。これによって大幅な高速化が可能になったと考えられる。
なお、ループ範囲がnumの平方根まででいい理由は、numはn×mとするとnもしくはmが必ずnumの平方根の切り上げ以下となるため。こういうことじゃないでしょうか?
というわけでgoogleは私に内定をください。もしくは給料だけをください。

参考記事


  • source ~/MasahiroOba/grad_members_20f/members/MasahiroOba/codes/../google_recruit.org
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

日時の文字列を、Time.zone.parseしてRailsに認識させる方法

Time.zoneが一致しなくて検索できなかった問題

筆者がRailsのアプリを開発している時に、
日付を一致させる時にひと悶着あったので、備忘録として残しておきます。

今回使用する例

productsテーブル

id date (datetime型)
1 2020-11-01 15:00:00
2 2020-11-02 00:00:00

DBの時刻はUTCとします。

問題

下記の例がtrue or falseを返す理由が説明できるでしょうか?
RailsアプリのTime.zoneは次の状態だとします。

[*] pry(#<ProductsController>)> Time.zone
=> #<ActiveSupport::TimeZone:0x000055cc45b31408
 @name="Tokyo",
 @tzinfo=#<TZInfo::DataTimezone: Asia/Tokyo>,
 @utc_offset=nil>

例題

[1] pry(#<ProductsController>)> 
Product.find(1).date == "2020-11-01 15:00:00"
=> true

[2] pry(#<ProductsController>)> 
Product.find(1).date == "2020-11-02 00:00:00"
=> false

[3] pry(#<ProductsController>)> 
Product.find(1).date == Time.zone.parse("2020-11-01 15:00:00")
=> false

[4] pry(#<ProductsController>)> 
Product.find(1).date == Time.zone.parse("2020-11-02 00:00:00")
=> true

[5] pry(#<ProductsController>)> 
Product.find(2).date == "2020-11-01 15:00:00"
=> false

[6] pry(#<ProductsController>)> 
Product.find(2).date == "2020-11-02 00:00:00"
=> true

[7] pry(#<ProductsController>)> 
Product.find(1).date == Time.zone.parse("2020-11-01 15:00:00")
=> false

[8] pry(#<ProductsController>)> 
Product.find(1).date == Time.zone.parse("2020-11-02 00:00:00")
=> false

[9] pry(#<ProductsController>)> 
Product.find(1).date == Time.zone.parse("2020-11-02 09:00:00")
=> true


回答

[1] pry(#<ProductsController>)> 
Product.find(1).date == "2020-11-01 15:00:00"
=> true
# 文字列で検索した場合、DBのレコードと一致するものを検索します。
# つまり、2020-11-01 15:00:00という値が一致するのでtrueとなります。

[2] pry(#<ProductsController>)> 
Product.find(1).date == "2020-11-02 00:00:00"
=> false
# 純粋な文字列を比較してるので、
# 2020-11-01 15:00:00 == 2020-11-02 00:00:00はfalseとなります。

[3] pry(#<ProductsController>)> 
Product.find(1).date == Time.zone.parse("2020-11-01 15:00:00")
=> false
# 今回のRailsアプリのTime.zoneはTokyoでした。
# Time.zone.parseとは、文字通りアプリのタイムゾーンに合わせて変換することです。
# UTCとTokyoの時間は9時間ずれてる(Tokyoが遅れてる)
# DBにsaveする時、2020-11-02 00:00:00 ➡️ 2020-11-01 15:00:00に変換されます。
# RailsがDBからレコードを取り出す時、+9時間して返します。

[4] pry(#<ProductsController>)> 
Product.find(1).date == Time.zone.parse("2020-11-02 00:00:00")
=> true
# 上記で説明したとおり、Railsのタイムゾーンと同じ値を検索&parseしたので、trueを返します。

[5] pry(#<ProductsController>)> 
Product.find(2).date == "2020-11-01 15:00:00"
=> false
# 文字列で検索した場合、DBと一致する値を返すため

[6] pry(#<ProductsController>)> 
Product.find(2).date == "2020-11-02 00:00:00"
=> true
# 文字列で検索した場合、DBと一致する値を返すため

[7] pry(#<ProductsController>)> 
Product.find(1).date == Time.zone.parse("2020-11-01 15:00:00")
=> false
# parseした後はDBの値 - 9 されるためfalse
# parseした後は、2020-11-01 06:00:00になる

[8] pry(#<ProductsController>)> 
Product.find(1).date == Time.zone.parse("2020-11-02 00:00:00")
=> false 
# parseした後はDBの値 - 9 されるためfalse
# parseした後は、2020-11-01 15:00:00になる

[9] pry(#<ProductsController>)> 
Product.find(1).date == Time.zone.parse("2020-11-02 09:00:00")
=> true
# parseした後は、2020-11-02 00:00:00になるのでtrue

言いたかったこと

今回のRailsのTime.zoneはTokyoなので、
バックエンドのデータに-9時間してsaveしてる。

それに合わせて、Time.zoneをTokyoにparseしたら、
欲しかった情報を取得できました!

参考

ようやく:こうしきよめ
https://api.rubyonrails.org/classes/ActiveSupport/TimeZone.html

助けられたteratail
https://teratail.com/questions/148819

RubyとRailsにおけるTime, Date, DateTime, TimeWithZoneの違い
https://qiita.com/jnchito/items/cae89ee43c30f5d6fa2c

おまけ

ふと疑問に思ったので、
ransackのコード見たら、Time.zone.parseしてました。

def cast_to_time(val)
  if val.is_a?(Array)
    Time.zone.local(*val) rescue nil
  else
    unless val.acts_like?(:time)
      val = val.is_a?(String) ? Time.zone.parse(val) : val.to_time rescue val
    end
    val.in_time_zone rescue nil
  end
end
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[個人開発]経験を共有するWebアプリ作ってみた!

新しいwebアプリ開発しました。「Elder」という人生経験を募集、公開、評価できるサイトです。今回は作ったwebアプリの紹介、サービスのネタの考え方、herokuの無料プランでスリープにさせない方法など書いていきます。今回は前回みたいなヘマしないように頑張ります(^^♪

今回作ったWebアプリはこちら

紹介

Elder-top.png

↑トップページ
人生経験を共有するコミュニティサイトです。
人生経験の募集、エッセイ、一言だけ投稿、などができます。
現在技術系の記事ばかりですが、分野は問いません。

募集中のところはスライドショーになっていて動きます。一か所でも動くところがあると凝ったサイト感が出ます。
イメージカラーはを選びました。
使ってみた感想として、いろんな色とは合わないけどその代わりたくさん使っても不自然になりにくいと感じました。
普通、同じ色ばっかり使うとそれはそれで変な感じになるんですがね。

なぜつくったか

人生経験ってなかなか聞く機会も話す機会もなく、もっと共有したほうがいいと思ったから。

今回使った技術

gem
rails6
ruby2.7
postgresql
heroku free
Logo Garden
gem 'ridgepole'
gem 'slim-rails'
gem 'html2slim'
gem 'pry-rails'
gem "devise"
gem 'devise-i18n'
gem 'devise-i18n-views'
gem 'rails-i18n'
gem 'carrierwave'
gem "kaminari"
gem 'ransack'

Logo Gardenとはロゴ制作サイトです。地味に今回はじめてちゃんとしたロゴを作りました。
Elder.png

ちょい粗いですがこれが完全無料で作れるんですよ。すごいなー(感心)。もっと凝ったものも作れたんですけどシンプルが一番かなーと。
https://www.logogarden.com/

あと、bootstrapは使ってません。

サービスのネタの決め方(個人開発)

なんでサービスを作りたいのか。

  • サービスを届けたい人は本当に喜ぶ?
  • 本当にそのアプリで問題解決することができる?。
  • 有料でも使いたいか(無料で出すとしても)
  • お金を扱わない
  • 初期費用がいらない
  • 個人で管理できる
  • ほぼコンテンツがいらない or 自分でコンテンツが作れる
  • 幸福になりたいのだったら、人を喜ばすことを勉強したまえ。

こんなもんだと思います。まだ成功するかわからないのにこんなこと書くのはあれですが間違ったことも言ってないと思います。
一時的に当たるネタというのはこれのどれかが抜けていると思います。

あと、一応保険かけときます。※個人の意見です

herokuの無料プランで運用

herokuの無料プランで一番きついのは、30分ごとのスリープだと思います。
これがなかったら無料プランで全然いいという方も多いと思います。

僕がやったのはのはHeroku Schedulerです。
10分ごとに自動でサーバーになにかさせるというものです。

 heroku addons:create scheduler:standard
 heroku addons:open scheduler 

ブラウザが開いたらadd jobをクリックして
Run Commandを

$ curl サイトのURL

ScheduleはEvery 10 minutesにして保存。

これでスリープしなくなります。ただバグがあったりするらしいので注意してくださいねー。

参考:
https://casualdevelopers.com/tech-tips/how-to-prevent-idling-of-free-dyno-on-heroku/#HerokudynoHeroku_Scheduler

振り返り

よかったこと

  • 完全無料で作れた(人件費抜き)
  • ロゴも作れた
  • railsコードの再利用ができた

悪かったこと

  • 途中でなんかいもあきらめそうになった

個人でやるとモチベーション管理が一番むずいです...
なにあともあれ使ってくみてださいね(^^♪

https://e-elder.herokuapp.com/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

人生経験を共有するコミュニティサイト作ってみた! & サービスの考え方

新しいwebアプリ開発しました。「Elder」という人生経験を募集、公開、評価できるサイトです。今回は作ったwebアプリの紹介、サービスのネタの考え方、herokuの無料プランでスリープにさせない方法など書いていきます。今回は前回みたいなヘマしないように頑張ります(^^♪

今回作ったWebアプリはこちら

紹介

Elder-top.png

↑トップページ
人生経験を共有するコミュニティサイトです。
人生経験の募集、エッセイ、一言だけ投稿、などができます。
現在技術系の記事ばかりですが、分野は問いません。

今回使った技術

gem
rails6
ruby2.7
postgresql
heroku free
Logo Garden
gem 'ridgepole'
gem 'slim-rails'
gem 'html2slim'
gem 'pry-rails'
gem "devise"
gem 'devise-i18n'
gem 'devise-i18n-views'
gem 'rails-i18n'
gem 'carrierwave'
gem "kaminari"
gem 'ransack'

Logo Gardenとはロゴ制作サイトです。地味に今回はじめてちゃんとしたロゴを作りました。
Elder.png

ちょい粗いですがこれが完全無料で作れるんですよ。すごいなー(感心)。もっと凝ったものも作れたんですけどシンプルが一番かなーと。
https://www.logogarden.com/

サービスのネタの決め方(個人開発)

なんでサービスを作りたいのか。

  • サービスを届けたい人は本当に喜ぶ?
  • 本当にそのアプリで問題解決することができる?。
  • 有料でも使いたいか(無料で出すとしても)
  • お金を扱わない
  • 初期費用がいらない
  • 個人で管理できる
  • ほぼコンテンツがいらない or 自分でコンテンツが作れる
  • 幸福になりたいのだったら、人を喜ばすことを勉強したまえ。

こんなもんだと思います。まだ成功するかわからないのにこんなこと書くのはあれですが間違ったことも言ってないと思います。
一時的に当たるネタというのはこれのどれかが抜けていると思います。

あと、一応保険かけときます。※個人の意見です

herokuの無料プランで運用

herokuの無料プランで一番きついのは、30分ごとのスリープだと思います。
これがなかったら無料プランで全然いいという方も多いと思います。

僕がやったのはのはHeroku Schedulerです。
10分ごとに自動でサーバーになにかさせるというものです。

 heroku addons:create scheduler:standard
 heroku addons:open scheduler 

ブラウザが開いたらadd jobをクリックして
Run Commandを

$ curl サイトのURL

ScheduleはEvery 10 minutesにして保存。

これでスリープしなくなります。ただバグがあったりするらしいので注意してくださいねー。

参考:
https://casualdevelopers.com/tech-tips/how-to-prevent-idling-of-free-dyno-on-heroku/#HerokudynoHeroku_Scheduler

振り返り

よかったこと

  • 完全無料で作れた(人件費抜き)
  • ロゴも作れた
  • railsコードの再利用ができた

悪かったこと

  • 途中でなんかいもあきらめそうになった

個人でやるとモチベーション管理が一番むずいです...
なにあともあれ使ってくみてださいね(^^♪

https://e-elder.herokuapp.com/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む