20191221のRailsに関する記事は21件です。

[Rails]特定のインスタンスに対して前後のレコードを取得したりランダムで取得したりするあれを試してみた

はじめに

こんにちはどうも、pirikaraです。
髪の毛を切りました。

今回はこんなやつを実装しました。
スクリーンショット 2019-12-21 12.36.00.png

特定の投稿(今回はitemの出品)に関して、DBから前後のレコードを取得して表示させたりリンクを飛ばす感じのあれです。
あとDBからランダムにレコードを取得して表示させたりリンク飛ばしたりする感じのあれです。

まずは特定の投稿に関してDBから前後レコードを取得する奴から実装していきます。
Rails標準のAPIでは見つからなかったので、今回はmodelに対してメソッドを書き込んでいきます。

いざ、実装

今回はItemクラスのインスタンスに関して、その前後レコードを取得するメソッドをmodels/item.rbに記述していきます。
前のレコードを取得するメソッドを『previous』
後のレコードを取得するメソッドを『next』
としてmodelに定義していきます。

item.rb
class Item < ApplicationRecord
  #......省略


  def previous
    Item.where("id < ?", self.id).order("id DESC").first
  end

  def next
    Item.where("id > ?", self.id).order("id ASC").first
  end
end

現在のインスタンス(self)のidより大きいか小さいかで前後レコードを判定・取得します。
作成したメソッドをview側で呼び出します。

items/show.haml
#......省略

- if @item.previous.present?
  =link_to item_path(@item.previous.id) do
    = @item.previous.name
- else
- else
  .none
- if @item.next.present?
  =link_to item_path(@item.next.id) do
    = @item.next.name
- else
  .none
#......省略

controller側で@item = Item.find(params[:id])などとし、Itemのshow画面に遷移。
@itemに対して『previous』 『next』メソッドを使用することで、@itemの前後レコードを取得できます。

また、前後レコードがない場合(最新のレコード、もしくは最古のレコードの場合)にリンクを表示しないよう『present?』メソッドによって真偽判定、条件分けしています。

Image from Gyazo

左右感がちょっと気持ち悪いですが、実装できました。(あとで直します。)

変化球

前後レコードではなく、DB内のデータをランダムで取得するあれを実装を試みてみます。
ネットサーフィンしながらいくつか方法を見つけたので試してみます。

1. RAND()関数

MySQLのネイティブ関数RAND()を使用してみます。

items_controller.rb
def show
  #......省略

  @random1 = Item.order("RAND()").limit(1)
  @random2 = Item.order("RAND()").limit(1)

 #......省略
end

左右のリンクがあるので、それぞれ@random1@random2として変数をインスタンス変数を定義してみました。
viewはこちら

items/show.haml
- if @random1.present?
  =link_to item_path(@random1.ids) do
    - @random1.each do |random1|
      = random1.name
- else
  .none
- if @random2.present?
  =link_to item_path(@random2.ids) do
    - @random2.each do |random2|
      = random2.name
- else
  .none

RAND()関数で取得したデータにlimitつけてましたが、配列で取得されるみたいなので『ids』としないとid取れませんでした。
また、nameについてもeach文で取り出してあげないと表示されませんでした悲しい。

そして結果がこちら。
Image from Gyazo
スクリーンショット 2019-12-21 14.32.36.png
......ねこもうさぎも被りました。

このあと何回もページ遷移してみました。
確かにランダムで表示されるようにはなったようですが、左右の値が毎回同じでした。
実際にDBテーブル内に存在する値からランダムに取得してくれるのはありがたいですが、
randam1とrandam2で別々に値を取得してくれるなんてそんな都合よく世界はできていなかったようです。

別の方法を試します。

2. Model.all.sample

モデルから全てのレコードを取得した上で1件抽出する感じ。
ゴリ押ししてみます。

items_controller.rb
def show
  #......省略

  @random1 = Item.all.sample
  @random2 = Item.all.sample

 #......省略
end
items/show.haml
- if @random1.present?
  =link_to item_path(@random1.id) do
    = @random1.name
- else
  .none
- if @random2.present?
  =link_to item_path(@random2.id) do
    = @random2.name
- else
  .none

今回は配列でなくデータ単体を取ってこれたので、idsとかeach文なんてまどろっこしいことをせずに済みました。やったね。
気になる結果は......
Image from Gyazo
で!!!け!!!た!!!
random1とrandom2で別々の値が取ってこれてます。さすがゴリ押し。
これにて実装完了......と思ったその時。見つけてしまいました。

ActiveRecord でランダムなレコードが欲しい(1件、複数件)

『全件取ってランダムに1件取り出すのはダサい』

.........ダサい???

確かに全部とってランダムに1件はメモリやらなんやらに理解の浅い僕でも効率が悪いのは理解できます。
こういう時にindexが便利なのか......?

とにかくダサいのは嫌なので別の方法を試します。(終わりが見えない)

3. Model.offset(rand(Model.count)).limit(1)

記事の方法をパクり...参考にさせていただきました。ありがとうございます。
レコード未満のランダム生成された整数をoffsetでレコード取得の開始位置とし、1個だけデータを取ってくる感じです。

items_controller.rb
def show
  #......省略

  @random1 = Item.offset( rand(Item.count) ).limit(1)
  @random2 = Item.offset( rand(Item.count) ).limit(1)

 #......省略
end
items/show.haml
- if @random1.present?
  =link_to item_path(@random1.ids) do
    - @random1.each do |random1|
      = random1.name
- else
  .none
- if @random2.present?
  =link_to item_path(@random2.ids) do
    - @random2.each do |random2|
      = random2.name
- else
  .none

......each文でないと取り出せませんでした......idsも復活しました......
しかしoffsetで開始を指定している分、Model.all.sampleの時よりはスマートなデータ取得ができている気がします。
さて結果は......
Image from Gyazo
......ランダムなってるやん。
さすがスマート。

『自分のデータは除いて......』の実装はしていないのでGIFでは可愛いうさぎが延々と出現してしまっていますが、
きちんとランダムにリンクが生成されています。

これで終わりにしようと思いましたが、僕は根に持つタイプなのでダサくない方法をもう一つ考えてみます。

4. Model.where('id >= ?', rand(Model.first.id..Model.last.id)).limit(1)

offset、 limitを使った書き方の書き換えとしてwhereに置き換える方法が紹介されていたので、試してみます。
randの引数でランダム数値生成の範囲指定を行いますが、今回は先頭レコードと最終レコードのidを範囲として指定しています。

Rails: データベースのパフォーマンスを損なう3つの書き方(翻訳)

items_controller.rb
def show
  #......省略

  @random1 = Item.where('id >= ?', rand(Item.first.id..Item.last.id)).limit(1)
  @random2 = Item.where('id >= ?', rand(Item.first.id..Item.last.id)).limit(1)

 #......省略
end
items/show.haml
- if @random1.present?
  =link_to item_path(@random1.ids) do
    - @random1.each do |random1|
      = random1.name
- else
  .none
- if @random2.present?
  =link_to item_path(@random2.ids) do
    - @random2.each do |random2|
      = random2.name
- else
  .none

こちらもeach文、idsを用いて配列からデータを取り出して出力しています。
結果は......
Image from Gyazo

ランダムになってました。満足。

比較

rails consoleからSQL文とSQL発行の所要時間が確認できるので、
上記4つのものを確認・比較してみます。

1個目
スクリーンショット 2019-12-21 16.06.59.png
2個目
スクリーンショット 2019-12-21 16.06.08.png
3個目
スクリーンショット 2019-12-21 16.07.41.png
4個目
スクリーンショット 2019-12-21 16.08.35.png

......DBにデータが7つしかないので速さは大差ないですね。そりゃそうか。
SQL文は4個目では3回発行されています。あまりよろしくないですね......
スマートな実装としては3個目推奨でしょうか。

という訳でseeds.rbを読み込んでデータを1000件作ってみました。

seeds.rb
1000.times do |index|
  Item.create!(name: "アイテム#{index}",
              seller_id: 1, 
              description: "内容#{index}", 
              category_id: index,
              condition_id: index, 
              prefecture_id: index, 
              sendingmethod_id: index, 
              postageburden_id: index, 
              shippingday_id: index, price: index, 
              profit: index)
end

スクリーンショット 2019-12-21 22.39.10.png
もう一度検索スピードを検証してみます。

1個目
スクリーンショット 2019-12-21 22.41.53.png
2個目
スクリーンショット 2019-12-21 22.43.45.png
3個目
スクリーンショット 2019-12-21 22.45.02.png
4個目
スクリーンショット 2019-12-21 22.46.11.png

SQL発行の所要時間に大きく差が出ました。
1個目、2個目は3個目、4個目に比べて10倍以上の時間がかかってしまっています。
クエリ文が3回発行されてしまっていることを考えると、
今回試した手法の中ではoffsetを用いた3番目の方法がベストプラクティスとなります。

おわりに

今回はSQLについて理解を深めることができました。
Indexを用いた検索でも検証を行ってみたいですね。
大規模なWebアプリケーションになればなるほど『どんな手法で検索をするか』で処理スピードに大きな差が生まれてしまうことを実感できました。

また気が向いたらなんか書きます。

おわり。

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

Railsチュートリアル 第13章 ユーザーのマイクロポスト - 「マイクロポストが投稿日時の降順(=新しい順)に表示されるようにする」という実装を、Micropostモデルに追加する

マイクロポストの順序付けに対するテスト

まず、「最も新しいマイクロポストが、RDBから最初に取り出されるようにする」を確認するためのテストを書いていきます。

まず準備段階として、「fixture上に存在する、most_recentという識別子を持ったマイクロポストが最初に表示されるようにする」というテストを実装します。

test "order should be most recent first" do
  assert_equal microposts(:most_recent), Micropost.first
end

必要なfixtureが定義されていないため、現時点でテストは成功しない

上記テストを実装した時点でテストを実行してみます。

# rails test test/models/micropost_test.rb
Running via Spring preloader in process 1532
Started with run options --seed 54438

ERROR["test_order_should_be_most_recent_first", MicropostTest, 0.8859796000033384]
 test_order_should_be_most_recent_first#MicropostTest (0.89s)
StandardError:         StandardError: No fixture named 'most_recent' found for fixture set 'microposts'
            test/models/micropost_test.rb:29:in `block in <class:MicropostTest>'

  5/5: [===================================] 100% Time: 00:00:00, Time: 00:00:00

Finished in 0.89262s
5 tests, 4 assertions, 0 failures, 1 errors, 0 skips
StandardError: No fixture named 'most_recent' found for fixture set 'microposts'

most_recentという名前のfixtureが存在しない」というエラーメッセージですね。

必要なfixtureを定義する

まずは、必要なfixtureを定義する必要があります。対象のファイルはtest/fixtures/microposts.ymlです。

test/fixtures/microposts.yml
orange:
  content: "I just ate an orange!"
  created_at: <%= 10.minutes.ago %>

tau_manifesto:
  content: "Check out the @tauday site by @mhartl: http://tauday.com"
  created_at: <%= 3.years.ago %>

cat_video:
  content: "Sad cats are sad: http://youtu.be/PKffm2uI4dk"
  created_at: <%= 2.hours.ago %>

most_recent:
  content: "Writing a short test"
  created_at: <%= Time.zone.now %>

most_recentという識別子を持ったマイクロポストが、最も新しいcreated_atの値を持つ」という内容になっていますね。

fixture内では、マジックカラムの値を手動で更新することができる

「埋め込みRubyを使ってcreated_atに直接値を設定している」というのは、test/fixtures/microposts.ymlにおける重要なポイントです。

通常、created_atupdated_atといったマジックカラムには、直接値を設定することはできません。これらの属性に対する値は、通常はRailsによって自動設定されるものです。しかしながら、fixtureファイル中においては、これらの属性に対する値を直接設定することが可能なのです。

必要なfixtureを定義したところで、再びテストを実行してみる

# rails test test/models/micropost_test.rb
Running via Spring preloader in process 1559
Started with run options --seed 16916

 FAIL["test_order_should_be_most_recent_first", MicropostTest, 0.3459459000005154]
 test_order_should_be_most_recent_first#MicropostTest (0.35s)
        --- expected
        +++ actual
        @@ -1 +1 @@
        -#<Micropost id: 941832919, content: "Writing a short test", user_id: nil, created_at: "2019-12-21 09:08:30", updated_at: "2019-12-21 09:08:30">
        +#<Micropost id: 12348100, content: "Sad cats are sad: http://youtu.be/PKffm2uI4dk", user_id: nil, created_at: "2019-12-21 07:08:30", updated_at: "2019-12-21 09:08:30">
        test/models/micropost_test.rb:29:in `block in <class:MicropostTest>'

  5/5: [===================================] 100% Time: 00:00:00, Time: 00:00:00

Finished in 0.94467s
5 tests, 5 assertions, 1 failures, 0 errors, 0 skips

テスト失敗時のメッセージに変化がありました。「最も新しいマイクロポストが、最初に取り出されていない」という趣旨のメッセージが出力されています。

「最も新しいマイクロポストが、RDBから最初に取り出されるようにする」という実装

Railsのdefault_scopeメソッドをMicropostモデルで呼び出せば、マイクロポストを常に特定の順番で取り出せるようになります。「新しい順に取り出す」という場合は、「created_atの降順に取り出す」ようにします。

4.0以降のRailsでは、以下のように記述すれば、「created_atの降順に取り出す」という取り出し順序を実現できます。

default_scope -> { order(created_at: :desc) }

「ラムダ式(もしくは無名関数)」なる文法要素

Rubyにおいて、->(もしくはlambda)というのは、「与えられたブロックから手続きオブジェクト(Procのインスタンス)を生成して返す」という関数です(Rubyリファレンスマニュアルより)。

>> -> { puts "foo" }
=> #<Proc:0x00007f086c61bba8@(irb):1 (lambda)>
>> -> { puts "foo" }.call
foo
=> nil

重要なのは以下の点でしょうか。

  • -> { puts "foo" }という呼び出しは、Procオブジェクトを返す
  • Procオブジェクトのcallメソッドを呼ぶと、ブロック内の処理が評価される

Procとかラムダ式とかクロージャーとか、このあたりの背景については全く理解できていないので、改めて学習する必要があると考えています。

default_scopeの引数として、ラムダ式が使われている

「引数としてラムダ式が使われている」というのは、default_scopeの大きな特徴です。

-> { hogehoge(fuga) }

default_scopeにおけるラムダ式の使い方としては、「order(created_at: :desc)というメソッドそのものを引数として取る」というところでしょうか。

Micropostモデルにdefault_scopeを追加した時点でのテストの結果

上記実装をMicropostモデルに追加したところで、test/models/micropost_test.rbに対するテストを再び実行します。

# rails test test/models/micropost_test.rb
Running via Spring preloader in process 1584
Started with run options --seed 38140

  5/5: [===================================] 100% Time: 00:00:00, Time: 00:00:00

Finished in 0.78921s
5 tests, 5 assertions, 0 failures, 0 errors, 0 skips

今度はテストが成功しました。

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

Fast JSON API をつかって得た、JSON:APIの知見

もう話題になってから、2年くらいの月日がたってしまったと考えると、時の速さを感じます。
そんな時の速さと同じくらい、早くserializeできるというFast JSON APIをつかって、今年の前半期でサービスを作ったので、得た知見を残しておこうと想います。

ざっくりとした内容は、6月の表参道.rb で少し話させてもらいました!

fast_jsonapi使ったぞ

今回紹介するのは、fast_jsonapiをつかったRubyのコードの書き方というよりは、
fast_jsonapiに使われている、JSON:APIというフォーマットについて書こうと思います。

動機、経緯

新サービスのjsonを返す、APIをRailsで作ることになったので、serializerを選定してました。
以前のサービスは、jbuilderをつかっていたのですが、jsonの管理にとてもとても苦しい思いをしたので辞めました。
Railsのserializerを選定するとなった時、当時も現在も AMS(active_model_serializers)fast_jsonapiの2択になるのかなと思います。
エンジニアとしては、新しい技術をいれたくなるのはやまやまなのですが、以下の点を検討したあと、道入を決めました。

  • 知見の確保先
  • JSON:APIにフロント側が対応できるか
  • JSON:API対応させるか、どこまで対応させるか
  • 最悪の場合、AMSに乗り換えられるか

入れてみた雑感として、fast_jsonapi ですこし大変になってきそうなのが、JSON:API への対応だと思います。
自由に形を変えられる、jbuilderを考えると、天と地くらいあります。
結構特殊な、形をしているため、クライアントサイドとのすり合わせも必用です。

fast_jsonapiをいれる上で、Rails上で工夫した点等はいくつかあるのですが、其のへんのベストプラクティスがまとまる前に開発が終わってしまました。(TT)

ということで、今回はJSON:APIについて、現在僕が調べているところをざっくばらんに紹介していこうと思います。

JSON:APIとは

jsonの構造の規約を定めたものです。
以下に公式のページがあります。
jsonapi.org

JSON:APIがどのような立ち位置なのかといと、こちら
で紹介されているのですが、GraphQLとREST の中間的な立ち位置になっています。
JSON:APIをリサーチした雑感でいうと、悪く書いている記事はほとんどありませんでした。

JSON:APIのフォーマット

JSON:APIのフォーマットについて。jsonapi.org とっぷにサンプルの構造がバンとはってありますが、すべてこのような感じのjsonで返します。
よくあるweb APIをつくるとなると、以下のようなフォーマットがおおくなるのではとおもいます。

{
  "data": [{
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "JSON:API paints my bikeshed!",
      "body": "The shortest article. Ever.",
      "created": "2015-05-22T14:56:29.000Z",
      "updated": "2015-05-22T14:56:28.000Z"
    },
    "relationships": {
      "author": {
        "data": {"id": "42", "type": "people"}
      }
    }
  }],
  "included": [
    {
      "type": "people",
      "id": "42",
      "attributes": {
        "name": "John",
        "age": 80,
        "gender": "male"
      }
    }
  ]
}

特徴的なのが、type, relationships included といったところでしょうか。

type はリソースの名前が入ります。僕はModelの名前をいれていました。
relationshipsはリレーションが組んである、idとtypeが入ります。もし、関連データでidしかいらないとなった場合と、included からデータをもってくるときにつかいます、
included は、リレーションが組んである、データの詳細を返しているという感じですね。

この構造をみたときに、思うのが、

パース面倒そうじゃない???

です。

そうです。ここがちょっと苦労したところです。
公式 ではクライアント向けのライブラリーが何個も紹介されています。
この辺をつかえば、良い感じにうまくいきそうな気はしてました。
しかし、ここは僕の知見外になってしまうのですが、iOS側(Swift) のライブラリはうまくいかなかったパースが何個かあったみたいです。
なので、クライアント側のひとと相談が大切です。

また、POSTなどするときも、JSON:APIで定められている規約を使いたいです。
其の際の、Rails側でのパースはNetflix製の
restful-jsonapi
を使わせてもらいました。

こちらは特に苦労はなかったと思います。

JSON:APIへの対応

JSON:APIをつかう上で、若干失敗したなと思ったのが、パラメータの既約を初期に設定しなかったことです。
ここは、僕の調査不足もあったのですが、前述したとおり、JSON:API はGraphQLとRESTの中間の立ち位置になります。
JSON:APIはGraphQLもどきのようなことができることも推奨しています。 公式 Recommendations

GET /comments?filter[post]=1,2&filter[author]=12 HTTP/1.1

このように パラメータでfilterしたり、includeできたりすることを推奨しています。
このような部分はなるだけ実装したいものです。クライアント側に伝えられず、途中から実装という形にしていきました。

また、この機能はfast_jsonapiに実装されているわけではなく、自分で良い感じに実装しないといけません。
そこも、なかなか大変だとおもいました。

まとめ

今回は、fast_jsonapiというより、JSON:APIについて、所感をまとめました。
サービスが途中で終了してしまったため、運用上の知見をまとめあげるまではいけませんでした。
日本では、この辺の知見は落ちてないため、基本海外から引っ張ってくる形になるとおもいます。
海外だと、fast_jsonapiに関しても、JSON:APIに関しても悪い事は書かれていないように感じます。

JSON:APIの形式自体は、AMSも対応しているということもあり、RailsでREST APIをつくる上で、検討すべき点に入ってきます。
知見がすくないのも否めないので、実際に導入して、運用しているところの意見があれば、聞きたいです!

個人的には、このJSON:APIの規約どおりに、コードをまとめることができれば、運用は良い方向になるのではと思っています。

参考資料

Netflix medium
https://medium.com/netflix-techblog/fast-json-api-serialization-with-ruby-on-rails-7c06578ad17f

Netflix github
https://github.com/Netflix/restful-jsonapi

Error Serializer について
https://blog.codeship.com/the-json-api-spec/

AMS VS fast_jsonapi
https://medium.com/soundstripe-engineering/greener-pastures-migrating-a-production-api-from-activemodel-serializers-to-fast-json-api-9627be51c64

AMS VS fast_jsonapi
https://driggl.com/blog/a/from-activemodel-serializers-to-fast-jsonapi

JSON:API について喋っている動画
https://nordicapis.com/the-benefits-of-using-json-api/

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

[Ruby on Rails]slickの矢印の画像を変更する方法[JQuery]

実現したいこと

slickの画像(スライド)を次に送るための両側の矢印の画像を好きなものにする。

色々参考にしたがうまくいかなかったので、自分がうまくいったやり方を残しておきます。

前提

Ruby on Railsで開発を行っています。slickは導入できているものとします。
Rails 5.2.4
ruby 2.5.1
jquery-rails 4.3.5

手順

画像の用意

矢印にしたい画像をapp/asset/imagesフォルダに入れます。

矢印のデフォルト画像の変更

おそらく\2190と\2192の部分が、矢印のデフォルトの画像を指定している部分だと思います。なので、この部分を任意の矢印の画像に取り替えます。

slick-theme.scss
変更前
$slick-prev-character: "\2190" !default;
$slick-next-character: "\2192" !default;

変更後
$slick-prev-character: image-url("left.png") !default;
$slick-next-character: image-url("right.png") !default;

矢印の表示と位置調整

位置の調整は以下の記事を参考にさせていただきました。
https://qiita.com/milneo/items/3560cb01cba92c2ccb6f
これで、矢印が表示されたと思います。slider.scssはslickに対してcssを記述しているファイルです。名前などは人それぞれ違うと思うので気をつけてください。

slider.scss
.slick-prev{
  left: 50px;
  height: 80px;
  width: 80px;
  z-index: 10;
}

.slick-next{
  right: 50px;
  height: 80px;
  width: 80px;
  z-index: 10;
}

最後に

なんとか、矢印の画像の変更はできました。
ただ、まだコードの意味や自分が行ったことの意味を理解していないので、もっと勉強しなけらばなと思いました。

参考

https://qiita.com/milneo/items/3560cb01cba92c2ccb6f

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

【Rails】Migration

Migrationとは

Railsでのデータベースへの変更を加える際に使用する機能
下記の順で実行する

  1. DBスキーマを変更するコードを記述したRubyのファイル マイグレーションファイルを作成
  2. マイグレーションファイルを適用する

ひとつのマイグレーションがバーションとして扱われる
開発用, 本番用, テスト用と個別に管理される

マイグレーションの適用

開発環境以外はRAIS_ENVで指定

# 開発環境
rails db:migrate
# 本番環境
rails db:migrate RAILS_ENV=production
# テスト環境
rails db:migrate RAILS_ENV=test

# 指定バージョンまでマイグレーションを適用
rails db:migrate VERSION=20191221~

マイグレーションの取り消し

# 1つ前のマイグレーションを取り消す
rails db:rollback
# 指定したステップ数だけ取り消す
rails db:rollback STEP=3
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

herokuにruby on railsアプリをmysqlを使用してデプロイする。deploy

前提条件

nodeとyarnは必ず最新にしておいてください。
それは書きません。

プロジェクトの作成

noracorn-railsというプロジェクトで作成します

ghq get https://github.com/noracorn/noracorn-rails.git
rails new noracorn-rails
cd noracorn-rails

scaffoldで、適当にサイトを作成

rails generate scaffold person name:string age:integer
rake db:migrate

トップページをいったんscaffoldで作成したものにする

noracorn-rails/config/routes.rb
Rails.application.routes.draw do
  resources :people
  root 'people#index'
end

立ち上がることを確認しましょう

以下のコマンドを打ってから、http://localhost:3000/にアクセス
Personのscaffoldにアクセスできることを確認する

bundle install
rails server

herokuでアプリを作成する

heroku login
heroku create noracornrails

herokuにmysqlを追加

(herokuにクレジットカードを登録してないと追加できません。)

heroku addons:add cleardb:ignite -a noracornrails

database設定

noracorn-rails/database.yml
production:
  <<: *default
  url: <%= ENV['DATABASE_URL'] %>
  username: <%= ENV['DATABASE_USERNAME'] %>
  password: <%= ENV['DATABASE_PASSWORD'] %>

以下のコマンドを打つと、データベース接続情報が表示されます。

heroku config

こんな感じで表示されます

mysql://user_xxx:password_xxx@host_xxx/dename_xxx?reconnect=true

表示された接続情報をherokuの環境変数に入れていく

heroku config:set DATABASE_URL="mysql2://user_xxx:password_xxx@host_xxx/dename_xxx?reconnect=true"
heroku config:set DATABASE_USERNAME="user_xxx"
heroku config:set DATABASE_PASSWORD="password_xxx"

config.assets.initialize_on_precompile = falseを、application.rbに入れる

noracorn-rails/config/application.rb
module NoracornRails
  class Application < Rails::Application
    config.load_defaults 6.0
    config.assets.initialize_on_precompile = false
  end
end

production.rbのconfig.assets.compileをtrueにする

noracorn-rails/config/environments/production.rb
config.assets.compile = true

Gem Fileを編集する。

ローカル環境とテストでは、sqlite3を使用してherokuではmysqlを使用するようにした。
上のほうで定義されているsqlite3は、コメントアウトしておいてください。

#gem 'sqlite3', '~> 1.4'

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]
  gem 'sqlite3', '~> 1.4'
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 'sqlite3', '~> 1.4'
  gem 'spring-watcher-listen', '~> 2.0.0'
end

group :production do
  gem 'mysql2'
end

bundle installする

bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl/lib --with-cppflags=-I/usr/local/opt/openssl/include"

bundle install

すべてコミットして、herokuにpush

git add .
git commit
git push origin master
heroku git:remote --app noracornrails
git push heroku master

herokuのmysqlをマイグレーション

heroku run rails db:migrate

アプリが動いているか確認する

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

【Rails】新規アプリケーションの作成準備

まえがき

備忘のためのメモでもあるので、少し簡単に記載させていただいております。少しずつ肉付けできればとは考えておりますが、わかりにくいところなどありましたら申し訳ございません。ご質問やご指摘などメッセージいただきましたら私の方でもお調べしますので、共に前進できればと考えております。何卒よろしくお願い申し上げます。
また、TECH::EXPERTにて学習させていただいているため内容は参照させていただいております。

開発環境

MacOS:10.14.6
Ruby:2.5.1
Rails:5.2.4
MySQL:0.5.2

index

1.ターミナルで新規アプリケーションのディレクトリを作成
2.gemのバージョン指定を追記/変更
3.データベース作成 + ブラウザで確認

1.ターミナルで新規アプリケーションのディレクトリを作成

# 新規アプリケーションを作成したいディレクトリに移動
$ cd ~/ディレクトリ名

# 新規アプリをバージョンを5.2.3で、-dオプションでMySQLの使用を明示して作成
$ rails _5.2.4_ new アプリ名 -d mysql

# アプリ名ディレクトリに移動
$ cd アプリ名

# 現在のディレクトリのパスを表示(確認までに)
$ pwd

※以下のエラーが出る場合

Installing mysql2 0.5.2 with native extensions

Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

    current directory: /Users/user_name/Programs/web/foobar-repo/vendor/bundle/ruby/2.5.1/gems/mysql2-0.5.2/ext/mysql2
/Users/user_name/.rbenv/versions/2.5.1/bin/ruby -r (以下略)

バージョンに関するエラー
ターミナルで以下のコマンドを実行

$ gem install mysql2 -v '0.5.2' --source 'https://rubygems.org/' -- --with-cppflags=-I/usr/local/opt/openssl/include --with-ldflags=-L/usr/local/opt/openssl/lib
$ cd ~/ディレクトリ名/アプリ名
$ bundle install

2.gemのバージョン指定を追記/変更

テキストエディタでアプリ名のディレクトリを開き、Gemfileから必要に応じてgemのバージョンを変更します。
私の場合は「mysql2」と「sass-rails」のバージョンに変更が必要でしたので以下で変更しました。
また一番下に新たにgemを3つ追記しております。

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

~中略~

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 5.2.4'
# Use mysql as the database for Active Record
gem 'mysql2', '0.5.2'
# Use Puma as the app server
gem 'puma', '~> 3.11'
# Use SCSS for stylesheets
gem 'sass-rails', '5.0.7'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'
# See https://github.com/rails/execjs#readme for more supported runtimes
# gem 'mini_racer', platforms: :ruby

~中略~

gem 'pry-rails'
gem 'compass-rails', '3.1.0'
gem 'sprockets', '3.7.2'

ターミナルで以下を実行し
Gemのバージョン指定を管理している「Gemfile.lock」というファイルを更新

# Gemfileを元にgemをインストールし、Gemfile.lockを更新する
$ bundle update

3.データベース作成

ターミナルで以下を実行

# データベースの作成
$ rails db:create

※ここまで終わったら以下のコマンドでサーバーを起動し
ブラウザ(http://localhost:3000)で確認

# サーバーを起動
$ rails s
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

マイグレーションファイルの作成、変更、削除まで

今回は、物件のファイルを作ることを想定します。

流れ

マイグレファイル作成→カラムすべて間違い→もう一度入れ直したい

1.マイグレファイルを作成する

$ rails g migration CreateHomes

2.作成したマイグレファイルをエディターで編集する

create_homes.rb
class CreateHomes < ActiveRecord::Migration[5.2]
  def change
    create_table :homes do |t|
      t.string :"物件名"
      t.string :"賃料"
      t.string :"住所"
      t.text :"備考"
    end
  end
end

3.マイグレーションをターミナル上で入力

$ rails db:migrate

4.マイグレファイルを削除するため、削除用のファイルを作る

rails g migration RemoveColumnsFromeHomes

5.作ったファイルを編集する

remove_columns_from_homes.rb
class RemoveColumnsFromHomes < ActiveRecord::Migration[5.2]
  def change
    remove_column :Homes, :"物件名", :string
    remove_column :Homes, :"賃料", :text
    remove_column :Homes, :"住所", :text
    remove_column :Homes, :"備考", :text
  end
end

6.マイグレーションをターミナル上で入力

$ rails db:migrate

※こうすることで、再び作り直すことができます。
rollbackでも削除は、可能ですが複数開発のときに何を編集したのか分からなくなるのでやめましょう。

7. カラムを追加するためのマイグレファイル作成

$ rails g migration AddColumnsToHomes

8.マイグレファイルを編集

add_columns_to_homes.rb
class AddColumnsToHomes < ActiveRecord::Migration[5.2]
  def change
    add_column :homes, :property, :string
    add_column :homes, :rent, :text
    add_column :homes, :address, :text
    add_column :homes, :age, :text
    add_column :homes, :remarks, :text

  end
end


何かを分からないことがありましたら、コメントを頂ければ1日以内に返信するように致します。

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

rails server が失敗する

初めての記事で、超低レベルな内容になりますがよろしくお願いします。
rails new 任意の名前
を実行した後に
rails server 
を実行すると思うんですが、ここで
cd 任意の名前
を実行しないとダメなんですね。
それはそう、って感じなんですけどね。しっかりと自分が作成したディレクトリに移動してからサーバーを立ち上げましょう。

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

Railsで中間テーブルダブルポリモーフィックやってみた。

Ruby on Rails Advent Calendar 2019の18日目が未投稿だったので代わりにでも。

はじめに

Railsを用いたサービス開発中に、中間テーブルとポリモーフィック関連を組み合わせる機会があり、ググってもあまり情報がないのでここに書く。

前提

  • とあるプラットフォームが複数のサブスクリプションサービスを持っている(サービスA, サービスB, etc.)
    • ユーザーは一つのアカウントで複数のサービスを契約できる。また同一サービスに対して複数契約もできる。
  • それぞれのサービスに対して、申し込み情報契約情報を別テーブルで保持する。これらはユーザーテーブルと関連づけられる。
  • ビジネスフロー例
    1. サービスAへの申し込み発生 → 申し込みレコードを発行
    2. 申し込みの妥当性確認などビジネスサイドの手続き。
    3. 2の処理完了 → 申し込み情報レコードを元に契約情報レコードを発行
  • 各申し込み/契約に対して、支払い情報請求先情報が別テーブルで関連づいている。
    • これらの情報はサービスをまたいで共有することができる。例えば、とあるユーザーがサービスAへの申し込みで登録した支払い/請求先情報を、サービスBへの申し込みにも利用することができる(→中間テーブルを採用)。

ER図を眺めてみる

サービスAのことだけ考えた場合、ER図は下記のようになる。
(各テーブルのフィールド、また本題と関係ないリレーションは省略)

スクリーンショット 2019-12-21 11.04.06.png

サービスA向けの申し込み情報テーブルをServiceAOrder, 契約情報をServiceAContractとして、中間テーブルを介してそれぞれが支払い情報Payment、請求先情報BillRecipientを持つ。

この時点で中間テーブルが4つ作られているが、サービスが増えるごとに4つずつ新しく中間テーブルを増やすのは非常にだるい、、

ここで気がつく。
中間テーブルにポリモーフィック関連って使えるのかな?
もしかして両サイドポリモーフィックもいける、、?

もしかして中間テーブルダブルポリモーフィックできちゃう、、?

実装

というわけでやってみた。ソースコードはこちら

検証環境はRuby 2.6.3, Rails 6.0.2

方針としてはSubscriptionモデルを中間テーブルとして、holdertargetという2つのポリモーフィックなbelongs_toを作る。やろうとすれば割り当てるモデルに制限はないが、意味合い的に次のような割り当てをする。

  • holder: SeviceAOrder, ServiceAContract, 他のサービスを追加していく
  • target: Payment, BillRecipient

またシンプルに中間テーブルを利用する場合だと次のような指定をすれば良いが、ポリモーフィック関連を利用する場合はhas_manyにオプションでsource, source_typeをつけてテーブルを明示的に指定する必要がある(Railsガイドのこのあたり)。

has_many :subscriptions
has_many :payments, through: :subscriptions

モデルのリレーション一覧↓

# app/models/subscription.rb
class Subscription < ApplicationRecord
  belongs_to :holder, polymorphic: true
  belongs_to :target, polymorphic: true
end

# app/models/service_a_order.rb
class ServeceAOrder < ApplicationRecord
  has_many :subscriptions, as: :holder
  has_many :payments, through: :subscriptions, source: :target, source_type: 'Payment'
  has_many :bill_recipients, through: :subscriptions, source: :target, source_type: 'BillRecipient'
end

# app/models/service_a_contract.rb
class ServeceAContract < ApplicationRecord
  has_many :subscriptions, as: :holder
  has_many :payments, through: :subscriptions, source: :target, source_type: 'Payment'
  has_many :bill_recipients, through: :subscriptions, source: :target, source_type: 'BillRecipient'
end

# app/models/bill_recipient.rb
class BillRecipient < ApplicationRecord
  has_many :subscriptions, as: :target
  has_many :service_a_orders, through: :subscriptions, source: :holder, source_type: 'ServiceAOrder'
  has_many :service_a_contracts, through: :payment_bill_recipient_holders, source: :holder, source_type: 'ServiceAContract'
end

# app/models/payment.rb
class Payment < ApplicationRecord
  has_many :subscriptions, as: :target
  has_many :service_a_orders, through: :subscriptions, source: :holder, source_type: 'ServiceAOrder'
  has_many :service_a_contracts, through: :subscriptions, source: :holder, source_type: 'ServiceAContract'
end

簡単なテスト↓

# spec/models/service_a_order_spec.rb
require 'rails_helper'

RSpec.describe ServiceAOrder, type: :model do
  describe '中間テーブル機能チェック' do
    it 'service_a_orderレコードに対して、ポリモーフィックなpaymentとbill_paymentレコードがきちんと紐づく' do
      user = User.new(name: 'Dan', email: 'test@example.com')
      user.save!
      service_a_order = ServiceAOrder.new(plan_type: 1, user: user)
      service_a_order.save

      payment = Payment.new(payment_type: 1)    
      service_a_order.subscriptions.create(target: payment)
      # service_a_order.payments << payment # こっちの書き方でもOK
      bill_recipient = BillRecipient.new(address: 'Chiyoda')
      service_a_order.subscriptions.create(target: bill_recipient)
      # service_a_order.bill_recipients << bill_recipient # こっちの書き方でもOK

      expect(service_a_order.payments.count).to eq 1
      expect(service_a_order.payments.first).to eq(payment)
      expect(service_a_order.bill_recipients.count).to eq 1
      expect(service_a_order.bill_recipients.first).to eq(bill_recipient)
    end
  end
end

ちなみにソースコードの方ではServiceBOrderServiceBContractを追加しているが、いけてそう。

参考

Railsのポリモーフィック関連とはなんなのか
Combining has_many :through with polymorphic associations in ActiveRecord

まとめ

そのうち地雷を踏みそうだけど後悔はしていない。

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

番外編 1. Rubyチュートリアル

Ruby in Twenty Minutes

https://www.ruby-lang.org/en/documentation/quickstart/

irbを使ってみよう

rails consoleを使ってみよう

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

Railsをherokuでデプロイする方法

herokuでのデプロイは、AWSに比べてめちゃめちゃ簡単だったので、まとめました!

(githubへのpush、会員登録、クレジットカード登録など完了後)

herokuにログインする

デプロイしたいアプリに移動したら

$ heroku login

何かキーを押してくださいと言われるので、適当にエンターキーを押す。

herokuのページに推移する。

loginを押してターミナルに戻る

ログイン完了

作ったアプリをherokuとリンクさせる

デプロイしたいアプリに移動したら

$ heroku create アプリ名

アプリ名がURLに入るのでしっかり考えましょう
すでにそのアプリ名がherokuで使われている場合はできません

データベースを作成する

※データベースが必要な場合のみ

ターミナル

$ heroku addons:create cleardb:ignite

これでデータベース作成は完了しました。

mysql2の環境変数を指定

初期設定だとmysql2の設定ができていないのでそこを設定していきます。
現在のmysqlの設定を確認します。

$ heroku config

以下のような長い文字列が出てくるので、それに応じて環境変数を入力していきます。

CLEARDB_DATABASE_URL: mysql://<ユーザー名>:<パスワード>@<ホスト名>/<データベース名>?reconnect=true

heroku configで表示された文字列をもとに、以下のように入力していきます。

$ heroku config:add DB_USERNAME='<ユーザー名>'
$ heroku config:add DB_PASSWORD='<パスワード>'
$ heroku config:add DB_HOSTNAME='<ホスト名>'
$ heroku config:add DB_NAME='<データベース名>'
$ heroku config:add DB_PORT='3306'
$ heroku config:add DATABASE_URL='mysql2://<ユーザー名>:<パスワード>@<ホスト名>/<データベース名>?reconnect=true'

エラー対策の微調整

config/environments/production.rb
 #初期はfalseなので変更
 config.assets.compile = true 

 #config.assets.js_compressor = :uglifierを変更
 config.assets.js_compressor = Uglifier.new(harmony: true)

デプロイ

$ git push heroku master

データベースのmigrate

$ heroku rake db:migrate

アプリの立ち上げ

$ heroku open

これでブラウザに、作ったアプリが表示されます!

補足

万が一、エラーが出てしまった場合は

$ heroku logs -t 

で確認できるので、修正し、ローカルからgithubへのプッシュ。
そして再度

$ git push heroku master

をすれば大丈夫です。

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

Railsでerbをhamlに変換する方法

Hamlって便利ですよねー!
ただrailsの初期設定ではerbファイルとして、生成されてしまいます。

どうせならHamlに統一してコーディングしましょう。

gemのインストール

Gemfile

gem 'haml-rails'

を入れて

ターミナル

$ bundle install
$ rails haml:erb2haml

これで一括変換されます。

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

Railsでアプリを作る簡単な流れ

一からアプリを立ち上げるとなると、意外と、何からしていいか分からない人もいると思うので、まとめました。

(アプリのダウンロードなど、環境構築などは完了していること)

アプリを作成する

保存したい場所に移動して

私はデータベース名は、mysqlでやってます。
指定しなければ、SQLiteというものが入ります。

ターミナル

$ rails new アプリ名 -d mysql(データベース名)

gemのインストール

ターミナル

$ bundle install

コントローラーを作成する

投稿サイトを作る場合のコントローラーを作成します。
※コントローラー名は複数形にしましょう

ターミナル

$ rails g controller posts(コントローラー名)
posts.controller.rb
class PostsController < ApplicationController
  def index(アクション名)
    #空でいいので作成する
  end  
end

データベースを作成する

データベースが必要であれば作成します。
通常であれば2つのファイルが生成されます。

ターミナル

$ rails db:create

モデルを作成する

データベースが必要な場合はモデルを作成します。
※モデル名は単数形にしましょう

ターミナル

$ rails g model post(モデル名)

モデルを作成すると、マイグレーションファイルも同時生成されます。
必要なカラムがあれば追加します。

20190000_xx_xx.rb
class CreatePosts < ActiveRecord::Migration[5.2]
  def change
    create_table :posts do |t|
      #t.(型名) :(カラム名), (オプション)
      t.text :content, null: false
      t.timestamps
    end
  end
end

カラムの追加が完了したら

ターミナル

$ rails db:migrate

これでデータベースの準備は完了です。

トップページのルーティングを作成する

routes.rb
 #root to: "コントロ-ラー名#アクション名"
 root to: "posts#index"

トップページのviewを作成する

app/views/posts(コントローラー名)の中に

index(アクション名).html.erbを作成
index.html.erb
 HELLO WORLD

railsを起動する

ターミナル

$ rails s

localhost:3000で起動します

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

【Railsチュートリアル】 NoMethodError in StaticPages#homeが出た時の対処法

エラー発生

Railsチュートリアル第5章の5.1.1ナビゲーションをやってRailsサーバーを再起動すると下記のようなエラーが発生。

NoMethodError in StaticPages#home
undefined method full_title

image.png

原因

ググってみると下記のサイトを発見。

「Rails Tutorialでrails sエラーで困っています・・・」
https://teratail.com/questions/12510

その回答として
「full_title を app/helper/下のファイルで定義すれば erb ファイル中で参照できると思います。」

試しにapp/helpers/application_helper.rbを見ると中身が空だった。

対処法

Railsチュートリアル第4章「リスト4.2: full_titleヘルパーを定義する」の中身を書いたらエラーが解決し、無事表示された。このエラーが表示されたら、app/helpers/下を見てみよう。

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

railsでapplication.scssと同じディレクトリのscssファイルが読み込まれないときの対処法

背景と対象

usersコントローラを作成したときに生成された、app/assets/users.scssに記述したscssが反映されない。つまりはアセットパイプラインの仕組みが適用されていない状況になってしまっている状況。全部app/assets/application.scssに書けばcssの適用は出来ますがめっちゃ見ずらいのでやめた方がいいです。このような状況でつまっている方の役に立てればと思い書きました。ちなみにアセットパイプラインについては以下のページがおすすめです!
https://diveintocode.jp/blogs/Technology/AssetPipeline

解決方法

とっても簡単です!

app/assets/application.scssのコメントアウトの最下部に*= require_selfとrequire_tree を以下のように追加してください。それぞれのコードの意味はコード内に書いてあります。ちなみにこれらの順番はどっちでもよく、require_selfを先に書けばapplication.scssが先に読み込まれます。後に書けばapplication.scss以外のscssファイルが先に読み込まれます。

app/assets/application.scss
/*
 * This is a manifest file that'll be compiled into application.css, which will include all the files
 * listed below.
 *
 * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
 * vendor/assets/stylesheets directory can be referenced here using a relative path.
 *
 * You're free to add application-wide styles to this file and they'll appear at the bottom of the
 * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
 * files in this directory. Styles in this file should be added after the last require_* statement.
 * It is generally better to create a new file per style scope.
 *
 *= require_self まずはこのファイルを読み込むという記述 追加!
 *= require_tree  app/assets以下のcssファイルを読み込んでいる 追加!
 */
}

これでアセットパイプラインの仕組みを利用して分かりやすく、すっきりしたコードが書けます!

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

【Rails+PostgreSQL+Heroku】環境構築まとめ

やりたいこと

rails new で作ったアプリをheorkuでデプロイしたい。
herokuではsqliteではなくpostgresqlを使わないとダメなので、初めからその設定をしておく。
psql 12.1
Rails 5.0.7.2

railsの設定

rails new e-stat-rails --database=postgresql
rails db:create
rails db:migrate
rails server
localhost:3000で起動できているか確認。

エラー対処

【再起動して解決】connections on Unix domain socket “/tmp/.s.PGSQL.5432”?への対処

【rails】Specified 'postgresql' for database adapter, but the gem is not loaded と怒られた件

herokuへ

Herokuへデプロイした時に「The page you were looking for doesn't exist. 」エラーが出る
こうならないようにcontrollerとroutesを設定してrootでhelloworldと表示するようにする。

application_controller.rb
class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception

  def hello
    render html:"hello, world!"
  end
end
routes.rb
Rails.application.routes.draw do
  root 'application#hello'
end

git add .
git commit -m "hogehoge"
git push origin master
heroku create
git push heroku
open heroku

できた!!

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

ずら〜っと、Railsでデータベースを確認する方法一覧

データベースクライアントの起動
$ rails dbconsole

こうなる
sqlite>

テーブル一覧の見方
sqlite> .tables

指定したテーブルのカラムの確認方法(スキーマの確認)
.schema テーブル名

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

WindowsにRails環境を導入してみる

WindowsにRailsを導入しようとしたらめちゃくちゃ手こずったので、記録しておこうと思って書きました

初めに

ここからRubyをダウンロードする、Devkitがついてるやつがいいらしい
インストールが完了したらコマンドプロンプトを開いてgem install railsを実行
問題なくインストールできたようなので次のステップへ

rails new hogeを実行するとガーっとファイルが作られていって安心していたら変なのが出る

Could not find gem 'sqlite3 (~> 1.4) x64-mingw32' in any of the gem sources listed in your Gemfile.
Run `bundle install` to install missing gems.

意訳:ふえぇ、SQLite3 v1.4が見つからないよぉ
Railsを始めてsqlite3まわりのエラーで躓いている人たちへを見るとSQLite3でエラーが頻発して阿鼻叫喚としてるとか書いてある、怖い

Gemfileを編集する

# Use sqlite3 as the database for Active Record
 gem 'sqlite3', '~> 1.4'

2行目のSQLite3のバージョンを下げてみる

# Use sqlite3 as the database for Active Record
 gem 'sqlite3', '~> 1.3.6'

ディレクトリ移動してbundle install

hoge>bundle install

Bundle complete! 14 Gemfile dependencies, 70 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.

勝ったなガハハ、サーバ立ててlocalhost:3000にアクセスしてやろう。

hoge>rails server

C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/activesupport-6.0.2.1/lib/active_support/dependencies.rb:325:in `require': cannot load such file -- sqlite3/sqlite3_native (LoadError)

勝ってなかった。
SQLite3くんが悪さをしているように見えるので消してやりましょう

hoge>gem uninstall sqlite3
Successfully uninstalled sqlite3-1.3.13-x64-mingw32

gem install sqlite3 --platform rubyでSQLite3を再インストール

hoge>gem install sqlite3 --platform ruby
Temporarily enhancing PATH for MSYS/MINGW...
Installing required msys2 packages: mingw-w64-x86_64-sqlite3
Building native extensions. This could take a while...
Successfully installed sqlite3-1.4.2
Parsing documentation for sqlite3-1.4.2
Installing ri documentation for sqlite3-1.4.2
Done installing documentation for sqlite3 after 1 seconds
1 gem installed

通った。
なおサーバは立たない、なんでや。

Railsのバージョンを下げる

rails 環境構築~ヘルスケアwebサービスを自分で作る医者の日記~【Windows】RubyとRuby on Raisの環境構築でSQLite3まわりで苦労したのコメント欄にRailsのバージョンを下げたらいけたと書いてあったので早速gem i -v 5.2.3 railsを実行
終わったぽいのでrails new hogeでプロジェクトを作るとすんなり通った。
これはいけたのでは?
恐る恐るrails server実行

キャプチャ.PNG

対戦ありがとうございました。

原因

詳しいことは不明ですが、Rails6.0.2.1とSQLite3 v1.4の相性がよくなかったのかなと思います

最終的な環境

Ruby 2.6.5p114
Gem 3.0.3
Rails 5.2.3
SQLite3 1.4.2

最後に

Qiitaで記事を書くのは初めてなので、変なところがありましたらご指摘いただけると幸いです。

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

【gemなし】Railsでラベル機能を作る

速攻でラベルのモッグを作りたい時のためにメモ

rails new

$ rails _5.2.3_ new sample-relation -d postgresql --skip-bundl && cd sample-relation && bundle install --path vendor/bundle && rails db:create

scaffoldで無駄なファイルが生成されないよう設定

/config/application.rb
module SampleRelation
  class Application < Rails::Application
    # ここから下を追加
    config.generators do |g|
      g.javascripts false
      g.helper false
      g.test_framework false
    end
  end
end

postテーブル(投稿機能機能)をscaffoldで生成

$ rails g scaffold post title:string details:string

labelテーブル(ラベル機能)をscaffoldで生成

$ rails g scaffold label title:string

post_labelテーブル(postとlabelの中間)をmodelを生成

$ rails g model post_label post:references label:references

アソシエーション

投稿

post.rb
class Post < ApplicationRecord
  has_many :post_labels, dependent: :destroy, foreign_key: 'post_id'
  has_many :labels, through: :post_labels, source: :label
end

中間

post_label.rb
class PostLabel < ApplicationRecord
  belongs_to :post, optional: true
  belongs_to :label, optional: true
end

ラベル

label.rb
class Label < ApplicationRecord
  has_many :post_labels, dependent: :destroy, foreign_key: 'label_id'
  has_many :posts, through: :post_labels, source: :post
end

コントローラー

posts_controller.rb
  private
    def post_params
      params.require(:post).permit(:title, :details, label_ids: [] )
    end

ビュー

新規投稿画面

new.html.erb
<%= form_with(model: post, local: true) do |form| %>
  <% if post.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(post.errors.count, "error") %> prohibited this post from being saved:</h2>

      <ul>
      <% post.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= form.post :title %>
    <%= form.text_field :title %>
  </div>

  <div class="field">
    <%= form.post :details %>
    <%= form.text_field :details %>
  </div>

  <div class="field">
  <% Label.all.each do |label| %>
      <% if action_name == 'new' || action_name == 'create' %>
        <%= form.check_box :label_ids, { multiple: true, checked: label[:checked], disabled: label[:disabled], include_hidden: false}, label[:id], "" %>
        <label><%= label.title %></label>
      <% elsif action_name == 'edit' || action_name == 'update' %>
        <%= form.check_box :label_ids, { multiple: true, checked: @task.label_ids.include?(label.id), disabled: label[:disabled], include_hidden: false}, label[:id], "" %>
        <label><%= label.title %></label>
      <% end %>
    <% end %>
  </div>

  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>

投稿一覧

index.html.erb
<p id="notice"><%= notice %></p>

<h1>Posts</h1>

<table>
  <thead>
    <tr>
      <th>Title</th>
      <th colspan="3"></th>
    </tr>
  </thead>

  <tbody>
    <% @posts.each do |post| %>
      <tr>
      <% post.post_labels.each do |post_label| %>
        <%= post_label.label.title %><br>
      <% end %>
        <td><%= post.title %></td>
        <td><%= link_to 'Show', post %></td>
        <td><%= link_to 'Edit', edit_post_path(post) %></td>
        <td><%= link_to 'Destroy', post, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
    <% end %>
  </tbody>
</table>

<br>

<%= link_to 'New post', new_post_path %>

めんどくさがりな方のためにラベルのシードデータの設定

seeds.rb
  20.times do |i|
    Label.create!(title: "sample#{i + 1}")
  end

migrate(テーブルをDBに反映)してseedデータを作ってrails s(サーバー起動)

$ rails db:migrate && rails db:seed && rails s

以上です!

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

Rails6 マイグレーションファイルの記載ミスでマイグレートしてしまったらrollbackを使おう

目的

  • マイグレーションファイルの記載を間違え、マイグレートしてしまった時の対処法をまとめる

筆者がやらかしたこと

  1. マイグレーションファイルの記載をミスる。
  2. その状態でマイグレートしてしまう。
  3. データベースを確認したところ期待した方になっていない。
  4. 現在のマイグレーションファイルを削除する。
  5. 再度、マイグレーションファイルを作成し正式な記載にをした。
  6. マイグレートを実行した。
  7. データベースが期待したものになっていた。

間違えてマイグレートをしてしまった時はrollebaskをしよう

  • マイグレート後にDBに異変を感じたらすぐに下記のコマンドを実行してマイグレート前の状態に戻す。

     $ rails db:rolleback
    
  • そのあとでマイグレーションファイルの記載を確認、修正を行い再度、マイグレートを行う。

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