- 投稿日:2020-12-27T23:48:37+09:00
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.3gemのアップデートを試みる。
% 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
が出た方のご参考になれば幸いです。ご覧いただきありがとうございました!
- 投稿日:2020-12-27T23:39:16+09:00
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.rbfactory :relationship, class: Relationship do follower_id { follower.id } followed_id { followed.id } endspec/models/relationship_spec.rbRSpec.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.rbfactory :user do . . . trait :has_followed do after(:create) do |user| followed = create(:user) user.follow(followed) end end endspec/models/relationship_spec.rbRSpec.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で書くことにしました。
参考文献
- 投稿日:2020-12-27T23:36:42+09:00
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
- 投稿日:2020-12-27T23:31:37+09:00
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が出てデバッグが辛かった)
- 投稿日:2020-12-27T22:52:00+09:00
【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そして、こうして定められたオブジェクトの住所にアクセスすることを
「オブジェクトへの参照」
と呼ぶのです。もっとわかりやすくざっくり言うと、
「オブジェクトへの参照=オブジェクトの居場所」
のことだと思ってもらうとわかりやすいかもしれません。2. 変数の正体
次に、先ほど出てきたメモリ領域と変数との関係性について考えていきます。
例えば、以下のような状況を考えてみます。
# 変数aに'test'を代入する a = 'test' # 'test'と変数aのメモリ領域(住所)を確認 'test'.object_id #=> 260 a.object_id #=> 280この時、裏側では次のようなことが起こっているということになります。
① String(文字列)オブジェクトが作成される(中身は'test')
② その住所(メモリ領域)が変数aに格納されるつまり、変数の実体とは
「メモリ領域」
であり、さらにその変数に入っている値は実は「変数に格納されているオブジェクト(ここでは'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がセットされます。
ここまでをまとめると以下のようになります。
次にsample.rbにおいて、「replace!メソッド」を呼び出した直後の状態を図で表して見ると、以下のようになります。
ここでのポイントは
- 変数(実引数)strの値は、文字列オブジェクトへの参照であり、それがそのまま引数(仮引数)strにコピーされる
ということです。
そしてこのように、
「変数に格納されているオブジェクトへの参照」が引数として渡されることを「参照の値渡し」と呼びます。
この参照の値渡しが行われると、当然ですが変数strと引数strは同じオブジェクトを共有していることになります。
そのため、引数strの値が変更されると、連動してその引数の値の住所に住んでいるオブジェクトの中身も変更されることになります。
(専門的な言い方をすれば、引数strの参照先であるオブジェクトが変更される)今回の場合だと、「replace!メソッド」の中身である「str.upcase!」が実行されると以下のようになります。
これを見ると、
引数strの値は変わっていませんが、その引数が指し示すオブジェクトの中身がしっかりと変更されていることがわかると思います。
4. まとめ
- オブジェクトへの参照とは
「オブジェクトの居場所にアクセスする」
こと- 変数の実体は
「その変数に格納されているオブジェクトへの参照」
- 参照の値渡しとは
「変数に格納されているオブジェクトへの参照がそのまま引数に渡される」
こと5. 最後に
本記事の内容がみなさんの参考になれば嬉しいです。
最後までご覧いただきありがとうございました。
6. 参考文献
Qiita記事: 【Ruby】メソッドの引数は値渡し?参照渡し?
Qiita記事: Rubyの破壊的メソッドと参照の値渡し
Rubyist Magazine: 値渡しと参照渡しの違いを理解する
- 投稿日:2020-12-27T22:46:37+09:00
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 Person
〜end
)の中では,そのクラスがself
となる- つまり,クラス定義式内でレシーバーをあらわに書かないメソッド呼び出しを行うと,当該のクラスがレシーバーとなる
ということです。
最後の点を確認するコードを以下に示します。class Hoge p name # => "Hoge" endこのコードで,
name
はローカル変数ではありません。この箇所以前にname
への代入式が存在しないので,ローカル変数ではありえないのです。
とすると,メソッド呼び出しのはずです。
このメソッド呼び出しにはレシーバーが書かれていません。
ここはクラス定義式の中ですから,name
のレシーバーはHoge
クラスです。
Hoge
はClass
というクラスのインスタンスですから,name
はクラス名・モジュール名を返すメソッドです。だから"Hoge"
が表示されます。
参考:Module#inspect (Ruby 3.0.0 リファレンスマニュアル)以上が理解できると,
class Person attr_accessor :name endは
class Person end Person.attr_accessor(:name)と書くのと同じであることが分かるでしょう。
- 投稿日:2020-12-27T22:42:26+09:00
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_profilerbenvから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 steepSteepfileという設定ファイルを自動生成してもらう。
steep initSteepfileが生成された。
# 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" # endSteepfileを書き換える。
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さんの思想が反映されているのかなぁと感じた。参考文献
- 投稿日:2020-12-27T22:39:25+09:00
【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
過去投稿記事
- 投稿日:2020-12-27T22:29:29+09:00
【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メソッドは、かぶっていて記述を削ったアクションにだけ必要になっている。
つまりshow、edit、updateの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だいぶスッキリしました。
ずっと同じファイルで記述しているとこういうことが起きやすいのかなと思いました。
コードが増えてきたら一度整理&確認してみることが大事ですね。
今日も良い経験になりました。
- 投稿日:2020-12-27T22:29:29+09:00
【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メソッドは、かぶっていて記述を削ったアクションにだけ必要になっている。
つまりshow、edit、updateの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だいぶスッキリしました。
ずっと同じファイルで記述しているとこういうことが起きやすいのかなと思いました。
コードが増えてきたら一度整理&確認してみることが大事ですね。
今日も良い経験になりました。
- 投稿日:2020-12-27T22:26:33+09:00
ファイル生成を抑えた最低限の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-testrails標準搭載の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.rbmodule 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これはあくまで一例ですが、こういった設定をすることでファイル量をかなり減らすことができます。
終わりに
簡単なオプションを付け加えるだけでしたが、快適な開発を進める上でかなり役立ちました。
参考にさせていただいた記事
- 投稿日:2020-12-27T21:44:01+09:00
Ruby の && や || は条件演算子じゃない
Ruby の初心者向け記事で
&&
や||
を「条件演算子」と書いているものをときどき目にします。
おそらく条件式で使うのでそう呼んでしまっているのだろうと思いますが,これらは「論理演算子」です。一方,条件演算子というのは,
(1..9).each do |n| puts "#{ n } is #{ n.odd? ? "odd" : "even" }" endに出てくる式
n.odd? ? "odd" : "even"の
? :
という二つの記号で表される演算子のことです。
三つの項を取るので「三項演算子」とも呼ばれます(Ruby では条件演算子以外に三つの項を取る演算子はありません)。
演算子式 (Ruby 3.0.0 リファレンスマニュアル)
- 投稿日:2020-12-27T21:29:02+09:00
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 の関係はちょっぴりだけ複雑です。
- 投稿日:2020-12-27T20:55:37+09:00
[wip] Ruby メモ
- 投稿日:2020-12-27T20:31:47+09:00
google recruit
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
- 投稿日:2020-12-27T20:20:38+09:00
ギリギリで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.rbary = [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.rbstr = "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にして、模擬問題のコードを検証する!!!
なぜなら、本やネットの模擬問題の回答が間違っているケースがあるからです(衝撃)
これも試験直前に知りました。
全てのコードを貼り付けて動作を確認するぐらいの方がきっといいと思います。
また、間違った回答に関してもそれが何故ダメなのかというところを抑えておかないと
私の二の舞になります。笑駆け足で書いてしまったので内容がスカスカになってしまいました、すみません。
またこの記事に肉付けをしていきます。
皆さんの合格を願っています。
- 投稿日:2020-12-27T20:05:57+09:00
deviseを用いたユーザー認証機能の作成
アプリケーションに"devise"を読み込ませる
Gemfile: gem 'devise' #追加terminal$ bundle installdeviseコマンドでモデル、ビュー、コントローラを作成
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.rbclass 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> :ログイン画面の入力フォームを
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]) enddevise利用の機能(ユーザ登録、ログイン認証など)が使われる場合、その前に
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 %> :以上
記載内容に間違い等ございましたらご指摘頂けると幸いです。
ご連絡お待ちしております。
- 投稿日:2020-12-27T20:01:24+09:00
hidden_field_tagの使い方
はじめに
Railsアプリ作成時に
hidden_field_tag
を使ったので、その時の内容のメモ書きになります。
検索機能を使った時にパラメータが飛ばなかったのでhidden_field_tag
を使用し対応した時の内容になります^^使用方法
hidden_field
とhidden_field_tag
は用途は似ているが使い方が違う。
hidden_field
はform_for
やform_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.rbdef 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を飛ばすことができます!
が、
このままだと常に中身がPhp
でfalse
が返され特定の物しか検索できない形になります。そこで条件分岐を付けて上げて柔軟に対応するようにします。
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
に値を付けているので、
それで判断させています。これでページ事のキーワード検索ができました!^^
おわりに
コード書いていると極々普通なことかもしれませんが、
悩んでいたことが、上手くできると
「ん?いや、普通に考えたらわかるやん!」っておわりに気づくことがあります^^笑なんでも諦めないことですね!^^
- 投稿日:2020-12-27T19:03:54+09:00
resources & resource
resources
Ruby on Railsでルーティングを行う際に必ずと行っていいほど頻出である
resources
。
resources
はモデルに対してアプリケーションにおける基本メソッド7つを自動的にルーティングしてくれます。例えば
User
モデルに対してresources
を使ってルーティングを記載した場合config/routes.rbRails.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.rbRails.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
が消えています。
- 投稿日:2020-12-27T17:17:06+09:00
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-started2)インストールの確認
ターミナル~ % 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: password
とhost: 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:createRails6だとこのコマンドを実行すると
======================================== 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)
- 投稿日:2020-12-27T16:15:14+09:00
【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のブロック内に入れてしまうと
計算途中の金額も毎回出力されてしまうので誤りとなります。
- 投稿日:2020-12-27T15:50:25+09:00
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.rbsource '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.rbsource '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
- 投稿日:2020-12-27T13:06:34+09:00
signup後の画面で、profile,logoutを表示されない問題を解決した。
発生した問題
ブログの完成に向けて、ログインシステムを構築する過程でエラーが発生した。
http://localhost:3000/users/new
において、Signupを実行後、UserのProfile画面にリダイレクトはできただが、ページ上部にProfileとLogoutが表示されず、代わりにSignUpとLoginが表示されてしまう。
当初考えられた原因
(1)app/helpers/sessions_helper.rbで定義し、layouts/application.html.erbに記述した”logged_in?”が有効でない。
・・・しかし、コードの記述自体に誤りは見られず、条件分岐もlogged_in?メソッド(※)も発火している。logged_in?メソッドを格納しているapp/helpers/sessions_helper.rbmodule 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.rbrequire_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.rbdef 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
- 投稿日:2020-12-27T11:13:56+09:00
Google Recruit
Google Recruit
過去に出題された Google のリクルート問題を解いていく.
問題は次の通り.
Google Recruit Problem
e(自然対数の底)の値で連続する10桁の数のうち,最初の素数をrubyで求めよ.ただし,e(自然対数の底)は以下の200桁までとする.
2.71828182845904523536028747135266249775 7247093699959574966967627724076630353547 5945713821785251664274274663919320030599 2181741359662904357290033429526059563073 81323286279434907632338298807531952510190解法
それでは実際に解いていく.まずはじめに方針を決める必要があるので,タスクをまとめてみると
- 数値ファイルを読み込む.
- 10桁の数を取り出す.
- 素数を判定する.
これらを順に実装していこう.
ファイルの読み込み
まずは 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-1
をMath::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】よく使うFileクラスを使ったファイル読み込み処理
- source ~/grad_members_20f/members/e79a93e5b7b1/posts/class/google-recruit.org
- 投稿日:2020-12-27T10:58:57+09:00
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オブジェクトから曜日を数字として取得記載内容に間違い等ございましたらご指摘頂けると嬉しいです。
ご連絡お待ちしております。
- 投稿日:2020-12-27T10:47:29+09:00
[Ruby]色々なeachの種類
はじめに
勉強していると色々な種類のeachが出てきたので
忘れないように記していきます。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の仲間も色々な種類があるのがわかりました。
少しずつ覚えてできる範囲を広げて行こう・・・!!
- 投稿日:2020-12-27T10:32:44+09:00
google recruit
お題
テキストで読み込ませた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 endeach 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
- 投稿日:2020-12-27T09:55:27+09:00
日時の文字列を、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
orfalse
を返す理由が説明できるでしょうか?
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/148819Rubyと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
- 投稿日:2020-12-27T09:29:33+09:00
[個人開発]経験を共有するWebアプリ作ってみた!
新しいwebアプリ開発しました。「Elder」という人生経験を募集、公開、評価できるサイトです。今回は作ったwebアプリの紹介、サービスのネタの考え方、herokuの無料プランでスリープにさせない方法など書いていきます。今回は前回みたいなヘマしないように頑張ります(^^♪
紹介
↑トップページ
人生経験を共有するコミュニティサイトです。
人生経験の募集、エッセイ、一言だけ投稿、などができます。
現在技術系の記事ばかりですが、分野は問いません。募集中のところはスライドショーになっていて動きます。一か所でも動くところがあると凝ったサイト感が出ます。
イメージカラーは紫を選びました。
使ってみた感想として、いろんな色とは合わないけどその代わりたくさん使っても不自然になりにくいと感じました。
普通、同じ色ばっかり使うとそれはそれで変な感じになるんですがね。なぜつくったか
人生経験ってなかなか聞く機会も話す機会もなく、もっと共有したほうがいいと思ったから。
今回使った技術
gemrails6 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とはロゴ制作サイトです。地味に今回はじめてちゃんとしたロゴを作りました。
ちょい粗いですがこれが完全無料で作れるんですよ。すごいなー(感心)。もっと凝ったものも作れたんですけどシンプルが一番かなーと。
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 サイトのURLScheduleはEvery 10 minutesにして保存。
これでスリープしなくなります。ただバグがあったりするらしいので注意してくださいねー。
振り返り
よかったこと
- 完全無料で作れた(人件費抜き)
- ロゴも作れた
- railsコードの再利用ができた
悪かったこと
- 途中でなんかいもあきらめそうになった
個人でやるとモチベーション管理が一番むずいです...
なにあともあれ使ってくみてださいね(^^♪
- 投稿日:2020-12-27T09:29:33+09:00
人生経験を共有するコミュニティサイト作ってみた! & サービスの考え方
新しいwebアプリ開発しました。「Elder」という人生経験を募集、公開、評価できるサイトです。今回は作ったwebアプリの紹介、サービスのネタの考え方、herokuの無料プランでスリープにさせない方法など書いていきます。今回は前回みたいなヘマしないように頑張ります(^^♪
紹介
↑トップページ
人生経験を共有するコミュニティサイトです。
人生経験の募集、エッセイ、一言だけ投稿、などができます。
現在技術系の記事ばかりですが、分野は問いません。今回使った技術
gemrails6 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とはロゴ制作サイトです。地味に今回はじめてちゃんとしたロゴを作りました。
ちょい粗いですがこれが完全無料で作れるんですよ。すごいなー(感心)。もっと凝ったものも作れたんですけどシンプルが一番かなーと。
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 サイトのURLScheduleはEvery 10 minutesにして保存。
これでスリープしなくなります。ただバグがあったりするらしいので注意してくださいねー。
振り返り
よかったこと
- 完全無料で作れた(人件費抜き)
- ロゴも作れた
- railsコードの再利用ができた
悪かったこと
- 途中でなんかいもあきらめそうになった
個人でやるとモチベーション管理が一番むずいです...
なにあともあれ使ってくみてださいね(^^♪