20201212のRailsに関する記事は25件です。

ActiveRecordで生SQLを実行して結果を配列にキャストする

※ Railsのバージョンは5.2を想定

  1. 何はともあれ生SQLを実行するコードを書く

    result = ActiveRecord::Base.connection.select_all('SELECT x_id as id FROM users')
    
  2. 取得結果から配列にしたいSELECT結果を指定して抜き出し、新たな配列を生成する

    ids = result.map { |h| h['id'] }
    pp ids
    # [1, 2, 3, 4, 5, 6, 7]
    
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

groupdateを使った際にGroupdate::Errorが出た話

 はじめに

今回railsで簡単なグラフを作成する際にchartkickなどと一緒に使うgemのgroupdateを使った際に
出たエラー解決を備忘録として残します。
初学者のため間違えばあればご指摘頂けると幸いです。

 Groupdate::Errorが出た

chartkickとgroupdateを無事導入しいざ実装と思った時にGroupdate::Errorの文字が、、、
bundleの確認やサーバーの再起動を試したが特に変化なし。

 エラーが出た理由

エラー文を詳しく確認してみると
Groupdate::Error - Be sure to install time zone support - https://github.com/ankane/groupdate#for-mysql:
これはタイムゾーンサポートをこのURLからインストールしろと言われてました。

解決策

URL先でタイムゾーンサポートについての記述があり、そこで指定された以下のコマンドをターミナルで実行

$ mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql

最後に

無事エラーは解消されグラフ機能を実装する事ができました!
エラー文は苦手意識があるのですが、しっかり読解しようとすれば案外解決方法を提示してくれてる場合が多いので今後はしっかりエラーと向き合っていきます!!

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

yamlファイルとは

はじめに

現在Railsを勉強中です。
アプリケーションを作成する上で、モデルやカラム、その他メッセージ等を日本語で出力したり扱いたい場面が必ずあると思います。自分の場合、すぐに忘れてしまうためその都度ググって、書き方合ってたかを確認しています。
ぶっちゃけYAMLファイルの仕様等を詳細に把握していなくても、問題なく作業が進むので今までないがしろにしてきましたが、今回は基本的な部分を調べて、アウトプットしようと思います。

YAMLファイルの特徴

分かりやすさ

構造化されたデータを扱うためのフォーマットであり、目的はXML等と似ているが、「読みやすい」「書きやすい」「わかりやすい」という利点がある。

構造

インデントによって、階層の構造を表現している

YAMLファイルで扱うデータ型

  • スカラー(文字列・数値・真偽値 etc)
  • シーケンス(配列)
  • マッピング(ハッシュ)

YAMLファイルの書き方

スカラー

YAMLはデータ型を自動的に判別してくれる
数字を文字列で扱いたい場合は '(シングルクォート)もしくは"(ダブルクォート)で囲むと強制的に文字列として認識してくれる

#数値
int1: 2
int2: 123,456

#浮動小数点
float1: 0.1

#NULL
nil1: nil
nil2: ~

#Boolean
bool1: true
bool2: false
bool3: yes
bool4: no
bool5: on
bool6: of

#日付
birthday: 1990-01-01
#タイムスタンプ
stamp: 2020-12-01 10:00:00 + 0900

#文字列
 str1:hoge
 str2:'true'
 str3:"333"

配列

行頭に-をいれることで、配列として扱うことが出来る。このときに-と値の間には半角スペースをいれること

- Ruby
- Java
- PHP

出力用メソッド

以降の出力例でも同様のものを使用

require 'yaml'

p YAML.load_file('test.yml')

出力結果

yaml_test.rb
["Ruby", "Java", "PHP"]

半角スペースでインデントを入れると、配列をネストさせることが出来る

- parent1
-
  - children1.1
  - children1.2
  - children1.3
  -
    - grandchild1.3.1
    - grandchild1.3.2
    - grandchild1.3.3
- parent2

出力結果

["parent1", ["children1.1", "children1.2", "children1.3", ["grandchild1.3.1", "grandchild1.3.2", "grandchild1.3.3"]], "parent2"]

ハッシュ

:で「キー:値」のように区切って記述する
おそらくこれが、railsで扱う中で一番多いパターンだと思います。

name: 名前
age: 年齢
gender: 性別
address: 住所

出力結果

{"name"=>"名前", "age"=>"年齢", "gender"=>"性別", "address"=>"住所"}

ハッシュに関しても半角スペースでインデントすることで、ネストさせることが可能

music:
  rock: ロック
  pop: ポップス
  jaz: ジャズ

出力結果

{"music"=>{"rock"=>"ロック", "pop"=>"ポップス", "jaz"=>"ジャズ"}}

アンカーとエイリアス

YAMLではアンカーとエイリアスを仕様することで、対象の構造に対して参照することが出来る
&nameでアンカーをつけ、*nameで参照することができる。

Railsの database.ymlなどではデフォルトで使われている

default: &default
  adapter: postgresql
  encoding: unicode

development:
  <<: *default

ちなみにここで登場している <<を用いることでハッシュをマージ出来る。

{"default"=>{"adapter"=>"postgresql", "encoding"=>"unicode"}, "development"=>{"adapter"=>"postgresql", "encoding"=>"unicode"}}
参考文献

プログラマーのための YAML 入門 (初級編)

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

yamlファイルの書き方やと特徴

はじめに

現在Railsを勉強中です。
アプリケーションを作成する上で、モデルやカラム、その他メッセージ等を日本語で出力したり扱いたい場面が必ずあると思います。自分の場合、すぐに忘れてしまうためその都度ググって、書き方合ってたかを確認しています。
ぶっちゃけYAMLファイルの仕様等を詳細に把握していなくても、問題なく作業が進むので今までないがしろにしてきましたが、今回は基本的な部分を調べて、アウトプットしようと思います。

YAMLファイルの特徴

分かりやすさ

構造化されたデータを扱うためのフォーマットであり、目的はXML等と似ているが、「読みやすい」「書きやすい」「わかりやすい」という利点がある。

構造

インデントによって、階層の構造を表現している

YAMLファイルで扱うデータ型

  • スカラー(文字列・数値・真偽値 etc)
  • シーケンス(配列)
  • マッピング(ハッシュ)

YAMLファイルの書き方

スカラー

YAMLはデータ型を自動的に判別してくれる
数字を文字列で扱いたい場合は '(シングルクォート)もしくは"(ダブルクォート)で囲むと強制的に文字列として認識してくれる

#数値
int1: 2
int2: 123,456

#浮動小数点
float1: 0.1

#NULL
nil1: nil
nil2: ~

#Boolean
bool1: true
bool2: false
bool3: yes
bool4: no
bool5: on
bool6: of

#日付
birthday: 1990-01-01
#タイムスタンプ
stamp: 2020-12-01 10:00:00 + 0900

#文字列
 str1:hoge
 str2:'true'
 str3:"333"

配列

行頭に-をいれることで、配列として扱うことが出来る。このときに-と値の間には半角スペースをいれること

- Ruby
- Java
- PHP

出力用メソッド

以降の出力例でも同様のものを使用

require 'yaml'

p YAML.load_file('test.yml')

出力結果

yaml_test.rb
["Ruby", "Java", "PHP"]

半角スペースでインデントを入れると、配列をネストさせることが出来る

- parent1
-
  - children1.1
  - children1.2
  - children1.3
  -
    - grandchild1.3.1
    - grandchild1.3.2
    - grandchild1.3.3
- parent2

出力結果

["parent1", ["children1.1", "children1.2", "children1.3", ["grandchild1.3.1", "grandchild1.3.2", "grandchild1.3.3"]], "parent2"]

ハッシュ

:で「キー:値」のように区切って記述する
おそらくこれが、railsで扱う中で一番多いパターンだと思います。

name: 名前
age: 年齢
gender: 性別
address: 住所

出力結果

{"name"=>"名前", "age"=>"年齢", "gender"=>"性別", "address"=>"住所"}

ハッシュに関しても半角スペースでインデントすることで、ネストさせることが可能

music:
  rock: ロック
  pop: ポップス
  jaz: ジャズ

出力結果

{"music"=>{"rock"=>"ロック", "pop"=>"ポップス", "jaz"=>"ジャズ"}}

アンカーとエイリアス

YAMLではアンカーとエイリアスを仕様することで、対象の構造に対して参照することが出来る
&nameでアンカーをつけ、*nameで参照することができる。

Railsの database.ymlなどではデフォルトで使われている

default: &default
  adapter: postgresql
  encoding: unicode

development:
  <<: *default

ちなみにここで登場している <<を用いることでハッシュをマージ出来る。

{"default"=>{"adapter"=>"postgresql", "encoding"=>"unicode"}, "development"=>{"adapter"=>"postgresql", "encoding"=>"unicode"}}
参考文献

プログラマーのための YAML 入門 (初級編)

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

ストロングパラメーターに外部キーを渡す方法

概要

ポートフォリオに投稿機能を実装中、ストロングパラメーターを用いて値を渡そうとしたのですが
何度やっても投稿が保存されませんでした。

  def create
    @post = Post.new(post_params)
    binding.pry
    if @post.save
      flash[:success] = "投稿しました"
      redirect_to posts_path
    else
      render action: :new
    end
  end

binding.pryを差し込んでデバッグしたみたのですが結果は

permitted: true

じゃあなんで投稿できない。。

調べたところ単純な記述ミスでした。

軽くハマってしまったので自分の備忘録も兼ねての投稿です。

開発環境

  • Rails 6.0.3.4
  • ruby 2.6.3

実装方法

元々のコード

def post_params
  params.require(:post).permit(:user_id, :title, :content, :price, :img)
end

正しいコード

def post_params
  params.require(:post).permit(:title, :content, :price, :img).merge(user_id: current_user.id)
end


外部キーのuser_idを渡す時にmergeメソッドを使ったら投稿できるようになりました!!

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

【Active Job】shoryuken + Amazon SQSを動かしてみた

sqs_settings.png
Railsの非同期処理をActive Job + shoryuken + SQSで実装したのでメモを残します。

※RailsアプリケーションはDocker環境で構築済みの前提です。環境構築はこちら
※Active Jobとバックエンドの比較はこちら

環境

  • Ruby 2.7.2
  • Rails 6.0.3.4
  • MySQL 8.0.20
  • shoryuken 5.0.5
  • Docker version 19.03.13

1. SQSの設定

まずAWSコンソールにログインし、画面上でSQSの設定をしていきます。
Amazon Simple Queue Service (SQS) は、完全マネージド型のメッセージキューイングサービスです。
画面や設定等は2020/11時点のものです。

キューを作成します。

sqs_top.png

ここでSQSの詳細な設定は割愛しますが、要件に応じて様々な設定はできそうです。
キューの名前だけ指定し、その他はデフォルト値で設定します。

sqs_settings.png

これでSQS側の設定は完了です。
あとはローカル環境からアクセスするためのアクセスキーをIAMで発行しました。

2. shoryukenの設定

まずGemを入れていきます。

Gemfile
gem 'aws-sdk-sqs'
gem 'shoryuken'

bundle installを実行し、shoryukenの設定ファイルも追加します。
AWSへの接続情報として、発行したアクセスキー等を環境変数に設定して利用します。
キーの管理はcredentialsでも良いかなと思いました。(プロダクトの方針次第)

config/shoryuken.yml
aws:
  access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %>
  secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
  region: <%= ENV["AWS_REGION"] %>
concurrency: 1
logfile: ./log/shoryuken.log
:queues:
  - development_default

3. Active Jobの設定

Active Jobで非同期処理を実装していきます。

config/application.rb
require "active_job/railtie"

module App
  class Application < Rails::Application
    ...
    config.active_job.queue_adapter = :shoryuken
    ...
  end
end

4. ジョブの作成と動作確認

ようやくジョブを作成します。

rails g job shoryuken_sample
app/jobs/shoryuken_sample_job.rb
class ShoryukenSampleJob < ApplicationJob
  queue_as :default

  def perform
    puts '--------------------------------'
    puts '-----------  昇龍拳  ------------'
    puts '--------------------------------'
  end
end

続いて動作確認を行います。

$ bundle exec shoryuken -C config/shoryuken.yml

(↑僕の環境では特にコマンド実行後、特に何も表示されませんでしたが、キュイーイングしたら動きました。)
別タブのターミナルでRailsコンソールからShoryukenSampleJobをキューイングしてみます。

$ rails c
Loading development environment (Rails 6.0.3.4)
> ShoryukenSampleJob.set(wait: 5.second).perform_later

Enqueued ShoryukenSampleJob (Job ID: ad754d56-8f50-4864-8b24-69479ef5c7f7) to Shoryuken(development_default) at 2020-11-25 11:32:39 UTC
=> #<ShoryukenSampleJob:0x000055821986c0b8
 @arguments=[],
 @exception_executions={},
 @executions=0,
 @job_id="ad754d56-8f50-4864-8b24-69479ef5c7f7",
 @priority=nil,
 @queue_name="development_default",
 @scheduled_at=1606303959.7208154>

キューイングすると先ほど起動したshoryuken側でジョブが実行されたことが確認できました。

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

投稿アプリに基本的な検索機能を実装

概要

検索機能を実装する方法をまとめました。

例として、写真投稿アプリに基本的な検索機能を実装する方法を紹介します。

初学者なので、間違いがあればご指摘いただきたいです。

参照

以下のページを参照しました。ありがとうございました。
Railsで検索機能を実装する方法を現役エンジニアが解説【初心者向け】

完成イメージ

今回は、投稿写真のキャプションで検索する機能を実装します。
貼り付けた画像_2020_12_12_19_32.png
Image from Gyazo

環境

  • macOS Catalina 10.15.7
  • ruby 2.6.5
  • Rails 6.0.3.4

実装の流れ

  • ルーティングを追加
  • コントローラーにsearchメソッドを作成
  • 検索フォームを作成
  • 検索結果表示画面を作成

今回のコード

1. ルーティングを追加

routes.rb
  resources :photos do
    resources :comments, only: :create
    collection do
      get 'search'
    end
  end
  1. photosコントローラーにsearchアクションを追加します。
  2. collectionとすることで:idを含まないルーティングになります。
    ちなみに、memberとすると:idを含むルーティングになります。
    参照:https://qiita.com/k152744/items/141345e34fc0095217fe

2. コントローラーにsearchメソッドを作成

photos_controller.rb
  def search
    if params[:keyword].present?
      @photos = Photo.where('caption LIKE ?', "%#{params[:keyword]}%")
      @keyword = params[:keyword]
    else
      @photos = Photo.all
    end
  end
  1. 検索ボタンをクリックするとsearchアクションが呼び出され、入力した検索ワードをparams[:keyword]で取得できます。:keywordでなくとも好きなキー名をつけることができますが、今回は:keywordとしました。
  2. 今回は写真のキャプションで検索するため、Photo.where('caption LIKE ?', "%#{params[:keyword]}%")としました。これで、入力した検索ワードがキャプション内に含まれる写真をすべて取得できます。whereメソッドの使い方については、以下をご参照ください。https://techacademy.jp/magazine/22330
  3. 何も入力せずに検索ボタンをクリックした場合は、Photo.allですべての写真を取得することとしました。
  4. 入力した検索ワードを取得して検索結果表示画面で使用するため、@keyword = params[:keyword]としました。

3. 検索フォームを作成

index.html.erb
  # クラス名などは省略してあります
  <%= form_with url: search_photos_path, local: true, method: :get do |form| %>
    <%= form.text_field :keyword %>
    <%= form.submit "検索" %>
  <% end %>
  1. form.text_field :keywordとすることで、検索ボタンをクリックした後、:keywordキーに、入力した検索ワードが値として設定されます。コントローラーのsearchメソッドでparams[:keyword]と設定すると、その値を取得することができます。

4. 検索結果表示画面を作成

search.html.erb
  ## クラス名などは省略してあります
  <h2>検索結果 "<%= @keyword %>"</h2>
  <ul>
    <% @photos.each do |photo| %>
      <li>
        <%= link_to photo_path(photo.id) do %>
          <%= image_tag photo.image.variant(gravity: :center, resize:"640x640^", crop:"640x640+0+0"), if photo.image.attached? %>
        <% end %>
      </li>
    <% end %>
  </ul>
  1. 上記のとおり、コントローラーのsearchメソッドで、検索ワードが含まれる写真を@photosに格納しました。@photos.each do |photo|で、それらひとつひとつの写真を取り出し、画面に表示させます。
  2. <%= @keyword %>で、入力した検索ワードも表示させました。

おわりに

以上が、今回行った基本的な検索機能実装の方法です。
ハッシュタグ検索など、より高度な検索も今後挑戦してみたいですね。

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

railsのmigrateファイルと仲良くなる

はじめに

現在、某プログラミングスクールに通い、Railsを学び初めて4ヶ月ほどの初学者です
個人開発、チーム開発でいつも同じところでRubyのRailから外れてしまうので、道標を残します
初めての投稿なので誤字脱字あったらすいません

開発環境、他

IDE : Cloud9
Ruby : 2.6.3
Ruby on Rails : 5.2.4.4
rails new〜 でなんらかのアプリケーション作成済
テーブル作成済
sample_appという名前で作った簡易写真投稿アプリケーションでmigrateあたりをまとめていこうと思います

カラムの追加・削除・変更

listsというテーブルを使います
スクリーンショット 2020-12-12 15.56.38.png

カラムの追加

ここに"hoge"というカラムをstring型で追加するとします

ターミナル
 rails g migration AddhogeToLists hoge:string

db/migrate/日時addhoge_to_lists.rb というファイルが作成されます
スクリーンショット 2020-12-12 15.40.44.png
add
column :テーブル名, :カラム名, :データ型
こんな感じに書いてあげて、

ターミナル
 rails db:migrate

schemaファイルをみてみると
スクリーンショット 2020-12-12 15.46.20.png

しっかりいてます
追加できました(上2行は気にしないでください)

カラムの削除

次は先ほど追加したものを削除します

ターミナル
 rails g migration RemovehogeToLists hoge:string

スクリーンショット 2020-12-12 15.55.55.png

ターミナル
 rails db:migrate

schema確認!
スクリーンショット 2020-12-12 15.56.38.png
消えてますね( ˊ̱˂˃ˋ̱ )

カラムの変更

スクリーンショット 2020-12-12 15.56.38.png
上から2行目のbodyカラムのデータ型をstringからtextに変更しようと思います

ターミナル
 rails g migration change_data_body_to_lists

カラム追加・削除と同じように
db/migrate/日時_addhoge_to_lists.rb というファイルが作成されるので、
スクリーンショット 2020-12-12 16.13.50.png

ターミナル
 rails db:migrate

schema確認!!
スクリーンショット 2020-12-12 16.17.00.png
しっかりと変わっていますね

まとめます

カラム追加→rails g migration Addカラム名To複数形テーブル名 (なくてもok)カラム名:データ型
rails db:migrate
カラム削除→rails g migration Removeカラム名To複数形テーブル名 (なくてもok)カラム名:データ型
rails db:migrate
カラム変更→rails g migration change_data_カラム名to複数形テーブル名
rails db:migrate

migrateファイルを削除する

原則migrateファイルは削除しません
テーブル内容の変更削除をする場合、上記のようにmigrateファイルを作って反映の繰り返しです
(migrateだけファイルの量膨大になる)
でも個人開発の時やgitにpush前で自分が作ったmigrateファイルの時を戻したいと思うこともあるはず…
今回は上記で作った3つのmigrateファイルがいらないので無かったことにしたいと思います

今のmigrateファイルってどんな感じ?

ターミナル
 rails db:migrate:status

スクリーンショット 2020-12-12 16.29.11.png
下3行目からが今さっき追加したファイルですね
Statusがupになっているのでバッチリ反映されています

rollbackの出番

ファイルがupの状態だと、schemaに反映されているのでファイルを削除するとエラーは起こりませんがデータベース問題でややこしくなります
下から2行目を消してみました
スクリーンショット 2020-12-12 16.42.04.png
確かにmigrateフォルダからは消え去っているのですが、migrate statusには残っています
チーム開発の場合、このままだとデータベースの相違問題が起こるし、何より気持ち悪いのでファイルを直で消すのはやめましょう
schema
スクリーンショット 2020-12-12 16.42.57.png
hogeカラムも復活してないのでやめましょう

Statusをdownにすると消しても問題ありません
(down状態だとファイルの内容はどこにも反映されていない状態)

では戻してみましょう

ターミナル
 rails db:rollback

これで一つ前のmigrateファイルが巻き戻り、downに戻ります

でも今回は複数のファイルを巻き戻したいので複数行指定します

ターミナル
 rails db:rollback STEPn

nには巻き戻したい行数を入れます。
今回は3ですね
*巻き戻したぶん、全部downになりますが、最後にrails db:migrateをすると全部反映してくれるので問題ありません
やってみみました
スクリーンショット 2020-12-12 16.49.54.png
…エラーかよ(´༎ຶོρ༎ຶོ`)
「migrationにchange_columnがあるから巻き戻せません
巻き戻すには
1、#changeメソッドのところを#upか#downにしてね
2、#reversibleメソッドを使ってね」
ということなので、changeをupに変えていざ実行
スクリーンショット 2020-12-12 16.57.52.png
rollbackしてみる
スクリーンショット 2020-12-12 17.00.56.png
できました
ステータス確認!
スクリーンショット 2020-12-12 17.02.27.png
schema確認!
スクリーンショット 2020-12-12 17.05.50.png
全てもとに戻りました
ファイルを消して、再びステータス確認!!
スクリーンショット 2020-12-12 17.07.08.png

いい感じですね( ˊ̱˂˃ˋ̱ )

ぐちゃぐちゃになったmigrateファイルはリセットしましょう

ターミナル
 rails db:migrate:reset

その後に

ターミナル
 rails db:migrate

データベースがまっさらになるので最初から投稿し直しになります
(もしseedファイルにデータを入れている場合、rails db:seedをやってあげてください)

まとめます

migrateファイルを巻き戻す場合はrails db:rollbackを使う
複数行ならrails db:rollback STEP=n
def changeの場合だと巻き戻らないのでupやdownに変えてあげる
巻き戻したmigrateファイルをいじって、rails db:migrate
migrateファイルがぐちゃぐちゃになったり、データ投稿した内容を一旦リセットしたくなったら(投稿物が”テスト”ばかりとか)rails db:migrate:resetをやってみる

終わりに

migrate周辺でいつも迷子になるのでまとめました
カラム名を打ち間違えてそのままmigrateとかやってしまうので、そういうところ改善したいですね
記念すべき1記事目を最後までご覧いただきましてありがとうございました
間違えてるところ、おかしなところがあれば教えてください

参考

https://qiita.com/azusanakano/items/a2847e4e582b9a627e3a
https://qiita.com/yana_dev/items/c96594bbea3329ef0fec

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

Railsチュートリアル(第6版)攻略 〜アカウント作成編〜

本記事の目的

本記事の目的はRailsチュートリアルの学習をしている未経験エンジニアの学習・理解を支援することです。本記事では、Railsチュートリアルに沿って開発していくアプリの動作をテーマに区切って概説します。Railsチュートリアルを初めて走行する方にとっては、完成したアプリの動作全体をあらかじめ理解しておくことで、現在自分がチュートリアルのどの部分を学習しているのか、学習進捗の現在地を把握するマップとしてご活用いただけると思います。また、Railsチュートリアルを1周走破した方にとっては、自身が開発したアプリの動作全体像を振り返ることで、復習と理解の一助としてご活用いただければ幸いです。

アカウント作成の流れ

概要

ユーザー操作の観点で見ると、アカウント新規作成は下記3stepで進みます。

  1. ユーザーがサインアップへのリンクを踏み、新規ユーザー登録のための入力フォームが表示される。
  2. ユーザーがフォームに必要情報を入力して送信ボタンを押すと、入力フォームに記入したMailアドレスへ向けてアカウント有効化メールが送信される。
  3. ユーザーがアカウント有効化メールに記載されたリンクを踏むと、アカウントが有効化され、ユーザーの新規作成が完了する。

詳細

概要で説明した3stepでそれぞれでのアプリ動作の詳細を以下に説明します。

  1. ユーザーが/signupパスへのリンクをクリックすると、クライアント(Webブラウザ)からサーバーへ/signupパスへのGETリクエストが送信され、Usersコントローラ内のnewアクションが実行される。newアクションでは、Userモデルのインスタンスが新規作成され、newアクションに対応したview(new.html.erb)をRailsが自動で表示する。このとき、新規作成したuserインスタンスはviewへ渡される。なお、new.html.erbは新規ユーザー登録の入力フォームである。
  2. Railsは、new.html.erbへ渡されたuserインスタンスが空であるかどうか自動で判定を行う。空であった場合にRailsはユーザーの新規作成であると判断し、ユーザーが入力フォームの送信ボタンをクリックすると、/signupパスへのPOSTリクエストがサーバー側へ送信され、Usersコントローラ内のcreateアクションが実行される。このcreateアクション実行の直前にはアカウント有効化トークンが発行され、かつ、トークンがダイジェスト化され、ダイジェスト化したアカウント有効化トークン(アカウント有効化ダイジェスト)がDBに保存される。createアクションでは、フォームの入力情報を受け取り、受け取った情報から許可されたキーに対応した値のみを新規作成されたuserインスタンスに格納し、DBへの保存を試みる。そして、新規作成したユーザーのDB保存に成功すると、そのユーザーに向けてアカウント有効化メールを送信する。このアカウント有効化メールには、アカウント有効化のためのURLが添付されている。
  3. 新規ユーザーがアカウント有効化のURLをクリックすると、AccountActivationコントローラのeditアクションが実行される。また,当該URLにはアカウント有効化トークンとユーザーのemailアドレスが仕込まれており、サーバー側はGETリクエストを受けるとURLに仕込まれたemailアドレスを手がかりにしてDBから該当ユーザーの検索を行う。そして、検索にヒットしたユーザーが存在し、かつ、そのユーザーが未だアカウント有効化されておらず、加えて、受け取ったアカウント有効化トークンをダイジェスト化した値がDBに保存されていたアカウント有効化ダイジェストと一致した場合に、アカウントを有効化してセッションを立ててログインする。最後にuserのホーム画面へリダイレクトを行い、StaticPagesコントローラ内のhomeアクションを実行して、アクションに対応したview(home.html.erb)を表示する。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

deviseのcontroller#createをいじったけどエラーでた時のメモ

app/contoller/customers/registrations_controller.rb
class Customers::RegistrationsController < Devise::RegistrationsController
  before_action :configure_sign_up_params, only: [:create]

...
  def create
    super
    @customer.company_id = params[:company_id]
    binding.pry
    if @customer.save
      CustomerStatus.create(paid: false, room_plus: false, dozen_sessions: false, numbers_of_contractnt: 0, customer_id: @customer.id)
    end
  end
...
  protected

  def configure_sign_up_params
    devise_parameter_sanitizer.permit(:sign_up, keys: [:company_id])
  end

カスタマーをずっと保存できなかった。
スクリーンショット 2020-12-12 15.14.49.png

原因はモデルのcustomer.rbのここでした
スクリーンショット 2020-12-12 15.16.21.png

deviseはbelongs_to をしたら新規登録でうまくいかなくなるみたいなので、気をつけましょうというメモです。

 解決法

7行目の部分です

スクリーンショット 2020-12-12 15.17.46.png

以上!

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

N + 1問題 - Railsで解説!

はじめに

Ruby on RailsなどDB(データベース)を使用するサーバーサイド言語で必ず上がる「N + 1問題」。

主に1対多のアソシエーション関係がある時に起こる問題です。
Railsでは一覧表示機能を含む1対多の関係が不可欠な機能が実装されるので、N + 1問題は理解しておくべきかと思います。

対象者

rails tutorialを学習済みの方
SQL初学者の方

使用環境

・ruby 2.6.4
・Rails 5.2.3
・MySQL 5.4

N+1問題とは

一言で表すと、

「テーブル参照のSQLが大量に発行されてしまうこと」

実際に見ていきましょう。
今回は掲示板投稿機能を実装するためのrailsのファイルを使用します。

まず、N + 1問題を引き起こす投稿機能モデルのコントローラーとビューのファイルの中身です。

app/controllers/boards_controller.rb(コントローラー)

class BoardsController < ApplicationController

  def index
    @boards = Board.all
  end
end

app/views/boards/index.html.erb(ビュー)

  <div class="row">
    <div class="col-12">
      <div class="row">
        <% if @boards.present? %>
        <%= render @boards %>
        <% else %>
        <p><%= t('.no_board') %></p>
        <% end %>
      </div>
    </div>
  </div>

/render @boards/
これによってrailsはファイルの同じディレクトリにある_board.html.erbファイルをパーシャルとして読み込んでくれる仕様になっています。
(よしなにやってくれるrailsの特徴ですね)

同時にコントローラーで取得した@boardsを繰り返し処理で1つずつboardとしてパーシャルに渡します。
(長いですが、一言で言うと掲示板の投稿が1つずつ作成されているコードです)

app/views/boards/_board.html.erb(ビュー)

<div class="col-sm-12 col-lg-4 mb-3">
  <div id="board-id-<%= board.id %>">
    <div class="card">
      <%= image_tag 'board_placeholder.png', class: 'card-img-top', width: 300, height: 200 %>
      <div class="card-body">
        <h4 class="card-title">
          <%= link_to  board.title, "#" %>
        </h4>
        <div class='mr10 float-right'>
          <%= link_to '#', id: 'button-edit-#{board.id}' do %>
          <%= icon 'fa', 'pen' %>
          <% end %>
          <%= link_to '#', id: 'button-delete-#{board.id}', method: :delete, data: {confirm: ''} do %>
          <%= icon 'fas', 'trash' %>
          <% end %>
        </div>
        <ul class="list-inline">
          <li class="list-inline-item"><i class="far fa-user"></i>
            <%= board.user.decorate.full_name %>
          </li>
          <li class="list-inline-item"><i class="far fa-calendar"></i>
            <%= l board.created_at, format: :short %>
          </li>
        </ul>
        <p class="card-text">
          <%= board.body %>
        </p>
      </div>
    </div>
  </div>
</div>

この掲示板一覧を表示するタイミングで発行されるSQL文が以下になります。

 Rendering boards/index.html.erb within layouts/application
  Board Load (1.6ms)  SELECT "boards".* FROM "boards"
   app/views/boards/index.html.erb:16
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
   app/views/boards/_board.html.erb:19
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 3], ["LIMIT", 1]]
   app/views/boards/_board.html.erb:19
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
   app/views/boards/_board.html.erb:19
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
   app/views/boards/_board.html.erb:19
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
   app/views/boards/_board.html.erb:19
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
   app/views/boards/_board.html.erb:19
  User Load (0.1ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
   app/views/boards/_board.html.erb:19
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
   app/views/boards/_board.html.erb:19
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 3], ["LIMIT", 1]]
   app/views/boards/_board.html.erb:19
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 3], ["LIMIT", 1]]
   app/views/boards/_board.html.erb:19
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
   app/views/boards/_board.html.erb:19
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 3], ["LIMIT", 1]]
   app/views/boards/_board.html.erb:19
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 3], ["LIMIT", 1]]
   app/views/boards/_board.html.erb:19
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
   app/views/boards/_board.html.erb:19
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
   app/views/boards/_board.html.erb:19
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
   app/views/boards/_board.html.erb:19
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
   app/views/boards/_board.html.erb:19
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 3], ["LIMIT", 1]]
   app/views/boards/_board.html.erb:19
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
   app/views/boards/_board.html.erb:19
  CACHE User Load (0.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]

めちゃくちゃ長い、、、
これrails tutorialではマイクロポストで投稿一覧を表示しますが、同じように長いSQL文が発行されます。

なぜこのようなことが起きるのか?
諸悪の根源はたった一文です

@boards = Board.all

ん?この部分はrails tutorialで習った通りじゃないですか?

何が問題かというと、@boardsに格納されている投稿(board)が呼び出される度に、そのboardがどのuserのものであるかを検索してい状態です。

つまり、投稿画面に遷移する時に、掲示板の全ての投稿を取得するために

Boardテーブル全体を参照するSQL文が1回発行される

Board Load (1.6ms)  SELECT "boards".* FROM "boards"

そして、のUsersテーブルを参照するSQLの文章が

掲示板の投稿の数(N回)だけ発行されている状態

  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]

この投稿数の数(N) + 最初の全体参照(1)が"N + 1問題"です。

解決方法

しかし、このN + 1問題は問題の文を以下のように書き換えるだけで簡単に解決できてしまいます。

@boards = Board.all.includes(:user)

includesメソッドによりBoardテーブル参照時に、(boardの外部参照のためのuser_idカラムを元に)Userテーブルも同時に参照するようにしています。
よってテーブル参照回数も2回となります!!
(たとえ掲示板の投稿が増えたとしても)

  Board Load (3.0ms)  SELECT "boards".* FROM "boards" ORDER BY "boards"."created_at" DESC
   app/views/boards/index.html.erb:16
  User Load (0.9ms)  SELECT "users".* FROM "users" WHERE "users"."id" IN (?, ?, ?)  [["id", 2], ["id", 1], ["id", 3]]
   app/views/boards/index.html.erb:16

SQL文の発行も2回で済みます。
1対多のアソシエーション関係を持つモデルを扱う場合は是非覚えておきましょう!

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

Active Adminの検索条件にenum値が反映されない時の対処方法

Active Adminの検索条件にenum値が反映されない現象が発生する。

現象詳細

enum値は以下の通り。

enum status: { not_started: 0, in_progress: 1, done: 9 }

Active Admin内のfilter設定は以下の通り。(enum値の日本語化対応も込み)

filter :status, as: :select, collection:Inquiry.statuses_i18n.invert

この時に検索条件にenum値の選択項目が表示されるものの、絞り込みが動作しない現象が発生する。
スクリーンショット 2020-12-12 14.15.24.png

原因

activeadminの検索にはransack gemを使用してが、ransackがうまくenumに対応できていないことが原因。
以下のように変更すると正しく動作する。

filter :status, as: :select, collection:Inquiry.statuses_i18n.invert.map{ |k, v| [k, Inquiry.statuses[v]]}

原因詳細

filter :status, as: :select, collection:Inquiry.statuses_i18n.invert

上記フィルターを指定した際に、サーバへ送付されるパラメータは以下のようになる。

{"q"=>{"status_eq"=>"in_progress"}, "commit"=>"絞り込む", "order"=>"id_desc"}

これを受けて、本来は、in_prgressに対応した1で検索をしてほしいが、実際のSQLを見ると以下のように'status'=0となっている。

SELECT COUNT(*) FROM (SELECT 1 AS one FROM `inquiries` WHERE `inquiries`.`status` = 0 LIMIT 30 OFFSET 0) subquery_for_count

つまりransack側でin_progress → 1という変換を期待してたがenumの値をとってくれず、
数値にカラムに文字列を指定したので、0が指定された。

解決方法

filterに指定したcollection:以降の部分は、コンソールで叩くと以下のようになる。

>Inquiry.statuses_i18n.invert

{"未着手"=>"not_started", "進行中"=>"in_progress", "完了"=>"done"}

collectionではkeyが表示内容、valueがサーバへ送信される値なので、ハッシュを以下のような形にできれば、ransackで正しく検索できる様になる。

{"未着手"=>0, "進行中"=>1, "完了"=>9}

そのため、collectionに読み込ませる値を以下のようにすると、ransackでも読み取れる値にできる(arrayでもcollectionは問題なく読み込んでくれる模様)

Inquiry.statuses_i18n.invert.map{ |key, value| [key, Inquiry.statuses[value]]}
> [["未着手", 0], ["進行中", 1], ["完了", 9]]

参照:RansackはRailsのenumに対応していないっぽい
https://www.tom08.net/entry/2016/12/05/121746

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

【Ruby on Rails】Railsコマンドまとめ 

はじめに

Rails 初心者用。
よく使うコマンドをまとめてみた。

コマンド一覧

rails new

railsで新しいアプリケーションを作成する際に使用するコマンド

rails new [アプリケーション名] -オプション

rails generate controller

ページを表示する為に必要なファイルを生成する。
コントローラーとかビュー。それに伴ってルーティングも作成される。
()内は指定しなくても大丈夫。後からファイルに指定すれば。
※「generate」の部分は「g」と省略可能。 → rails g controller

rails g controller [コントローラー名] ([アクション名])

rails generate migration

マイグレーションファイルを生成する。
マイグレーションファイルとは、データベースのテーブルの情報を変更する際に使用するファイル。
※「generate」の部分は「g」と省略可能。 → rails g migration

rails g controller [マイグレーションファイル名] 

rails generate model

モデルファイルを生成する。
モデルファイルは、コントローラから受け取ったデータをデータベースに渡したり、反対にデータベースからの情報をコントローラに渡したりする役割がある。
※「generate」の部分は「g」と省略可能。 → rails g model

rails g model [モデル名]

rails server

rails サーバーを起動する。
※「server」の部分は「s」と省略可能。 → rails s

rails s

rails console

コンソールを起動することができる。
オプションで「--sandbox」をつけると、データベースに変更を与えないようにすることができる。
※「console」の部分は「c」と省略可能。 → rails c

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

Active Adminで設定した心当たりのない検索条件が表示される。

Active Adminで設定した心当たりのない検索条件が表示される現象が発生した。
101763720-84ed4080-3b22-11eb-8c53-983a21187eaf.png

BOOKMARK
FACILITIES
BOOKMARK FACILITIESなんてパラメータ知らない。。。

選択項目に変な値が出るし。。。

結論

Active Admin内でfilterの設定を行なっていないことが原因。
filterで検索条件を指定しておかないと全てのパラメータの検索条件が表示される。

検索条件を明示したいなら、filterの設定を行う必要ある。

app/admin/users.rb

  # 絞り込み条件の項目設定
  filter :email
  filter :nickname
  filter :birth_year
  filter :sex, as: :select, collection:User.sexes_i18n.invert.map{|key,value| [key,User.sexes[value]]}

スクリーンショット 2020-12-12 13.52.35.png
設定した検索条件のみ表示されることが確認できた。
これで解決!

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

【Rails Colorpicker】カラーピッカーの選択色を特定要素の色と連動させる

【Rails Colorpicker】カラーピッカーの選択色を特定要素の色と連動させる

この記事でできるようになること

以下のGIFのように、カラーピッカーで選択した色がリアルタイムで、何か特定の要素の持つ色と連動させることができるようになる!
GIFではちょっとわかりにくいですが、今回はFontawesomeで用意したピンの色と、カラーピッカーでの選択色とをリアルタイムで連携させてます。

カラーピッカーとの連携.gif

考え方

以下のことをやっていくとなんかいけそうだとまず考える。
①カラーピッカーで選択している色を取得する
②その選択色をもってして、ピンのcolorを変更する

んー簡単そう。
とりあえず、やってみよ

あ、ちなみにカラーピッカーはHTML5の標準搭載の機能でした
めっちゃすごない???!!
これだけでカラーピッカー実装できるんですよ?。。。

index.html
<input type="color">

実装コーディング

index.html.erb
<%# ↓これがアイコン %>
<i class="fas fa-location-arrow" id="arrow-icon"></i>

<%# ↓これがカラーピッカー %>
<input type="color" class="arrow-icon-color-selector" id="arrow-icon-colorーselector" value="#e66465">
index.js
  // まずカラーピッカーの要素をcolorpickerという変数に入れる
  const colorpicker = document.querySelector('.arrow-icon-color-selector');

  // 次に、ピンの要素をarrowiconという変数に入れる
  const arrowicon = document.getElementById('arrow-icon');

  colorpicker.addEventListener('input', function(e) {  // カラーピッカーの入力値(inputの値)が変更されたら{}内の処理を実行する
    arrowicon.style.color = e.target.value; // アイコンのCSSのcolorプロパティの値を右辺の値にする。右辺の値とはすなわち、カラーピッカーでの選択値である。
 });

コーディングもめっちゃシンプルでした。。。。
応用すれば、画面の背景を変えたりできるので是非に!

例えばこんな感じにしたかったら

カラーピッカーと背景の連動.gif

index.js
  const colorpicker = document.querySelector('.arrow-icon-color-selector');
  const arrowicon = document.getElementById('arrow-icon');

  colorpicker.addEventListener('input', function(e) {
    document.body.style.backgroundColor = e.target.value;
  });

以上です!!
お疲れ様でした!!

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

VagrantでRuby2.7.2 (Ruby on Rails5.1.7)のローカル環境の構築

記事の目的

  • 自分のメモ用
  • dotinstallにおけるローカル環境構築講座に躓いた方に参考にしてもらう

初投稿になりますので、至らぬ所多々あると思いますがご了承下さい

PC環境

  • macOS Catalina 10.15.7
  • MacBook Pro (13-inch, 2020, Two Thunderbolt 3 ports)
  • プロセッサ 1.4 GHz クアッドコアIntel Core i5
  • メモリ 8GB

バージョン

  • CentOs version: 7
  • Ruby version: 2.7.2 (x86_64-linux)
  • Rails version: 5.1.7

記事の内容

  1. Virtual Box, Vagrantのインストール
  2. Vagrant で Cent OS7 (Linux) をインストール
  3. CentOSの起動と停止方法
  4. Cyberduckをインストール
  5. rbenv をインストール
  6. ruby-buildプラグイン を追加
  7. Ruby をインストール
  8. Bundler のインストール
  9. Ruby on Rails のインストール
  10. Ruby on Rails の接続

構築手順

私は下記記事を参照に基本的には環境構築を実施した。

https://www.sejuku.net/blog/39936#_Ruby_on_Rails

ただしCent OS内のフォルダーを見える化(操作しやすく)するため、上記記事に描かれていない、Cyberduckのインストールも合わせて実施した。

こちらの手順はドットインストールを参照いただきたいが、エラーがでた場合な下記記事を参考にして欲しい。

https://qiita.com/Lassieena/items/603fe89df26b59ca06f7

エラー

環境構築を実施していく中で、2点詰まったエラーがあったのでメモしておく

1. gem 'listen'が見つかりません

Could not load the 'listen' gem. Add `gem 'listen'` to the development group of your Gemfile (LoadError)

解決法

cybetduckからGemfileを見つけて開き、下記をコード内に追加

group :development do
gem 'listen'
end

Gemfileは下記のようになるはず

source "https://rubygems.org"
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
gem "rails", "~> 5.1.0" 
group :development do
  gem 'listen'
end 

2. gem 'sqlite3'が見つかりません

Add `gem 'sqlite3'` to your Gemfile

解決法

先ほどと同様にcybetduckからGemfileを見つけて開き、下記をコード内に追加

gem 'sqlite3', '~> 1.3.6'

Gemfileは下記のようになるはず

source "https://rubygems.org"
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
gem "rails", "~> 5.1.0"
gem 'sqlite3', '~> 1.3.6'
group :development do
  gem 'listen'
end

3. Ruby on Rails の接続時エラー

最終接続時につながらずエラーが出る場合は下記記事を参照
私はNo.2までの処理を実行し、接続できた

https://qiita.com/Ago0727/items/325df5e39e3406fa16d2

最後に

私自身、初学者であり、コマンドラインの使い方も分からずにインストール、アンインストールを繰り返してかなり苦労した。

参考サイトをご覧いただき、少しでも困っている方々の助けになればと思い投稿しました。

初投稿でもありますので、温かい目で見てください笑

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

[Rails]twilioでSMSを送信する

tiwilioでサインアップする

https://jp.twilio.com/try-twilio
まずは会員登録をしましょう。
テストであれば無料で使えます。

必要な情報を入手

TRIAL NUMBERアカウントSIDAUTHTOKENを入手しましょう!
(consoleのトップ画面に表示されています。)

gemをインストール

gem 'twilio-ruby'

コード作成

モデルを作成

message.rb
class Message
  def initialize(tel:)
    @tel = tel
  end

  def hello(user:)
    @message = "#{user.name}さんこんにちは"
    send
  end

  private

  def send
    @tel = "+81" + @tel.slice(1..11)
    account_sid = ENV['TWILLIO_ACCOUNT_SID']
    auth_token = ENV['TWILLIO_AUTH_TOKEN']
    @client = Twilio::REST::Client.new account_sid, auth_token
    @client.messages.create(
        from: ENV['TWILLIO_PHONE_NUMBER'], # TRIAL NUMBERを入力
        to: @tel,
        body: @message
    )
  end
end

コントローラーを設定

users_controller.rb
def send_sms
    user = User.first
    message = Message.new(tel: ENV['YOUR_PHONE_NUMBER']) # twilioに登録した電話番号
    message.hello(user: user)
end

完成です!

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

Ruby on Railsのbundle installで躓いたときの解決法

はじめに

Ruby on Railsチュートリアルにて初めてのアプリケーションを作成していたところ、bundle installが上手くいかずエラーが出ました:sob:

ある方法を試したところ、無事この画面に辿り着けました!
riding_rails.png
今回、私が試した方法をご紹介します。

何があった

Ruby on Railsチュートリアル第1章で、hello_appディレクトリにbundleをインストールしようとしたところ

$ bundle install
The dependency tzinfo-data (>= 0) will be unused by any of the platforms Bundler is installing for. 

と出てしまい、インストールされなかった模様。

どうする?

色々探してみた結果、今回はこちらのサイトを参考に、
Gemfile.lockのファイルを削除する
という方法を取ってみることにしました。

ざっくりまとめると、バージョンのちょっとした違いによってかかってしまうlockを一旦解除する、ということなのかなと解釈しました。

どうやった?

Gemfile.lockはファイルナビゲーターのhello_appディレクトリ内にありましたので、右クリック→ Deleteで削除。

これだけです。

ちなみにGemfile.lockに関しては削除しても再度bundleをインストールするとまた作成されるとのことです。無惨様かよ。

こうなった

そして改めて

$ bundle install

すると・・・

$ bundle install
Fetching gem metadata from https://rubygems.org/............

おぉっ!さっきとは文章が変わった!!

そしてPreview → Preview Running Appricationで
画面を表示させてみると・・・

riding_rails.png

はい、出ました!:pray:パチパチ

まとめ

bundle install 時のエラーは、Gemfile.lockファイルを削除することで解消できる場合がある。

です。
間違ってたらごめんなさいw

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

if文について

最初に

カレンダー企画2020の12日目
プログラミングの勉強を始めて3ヵ月程経ったので学んだことのメモをアウトプットとして記事に残します。
これからプログラミングの世界に入る人の手助けになれたら嬉しい限りです。
間違っていたり、言葉が違っていたり、誤解されるような言葉があったら教えてください^^
言葉を長々と読みづらかったら申し訳ありません。少しずつなれてがんばります。

if文についてまとめてみる

if文??

if文とは、「もしAならBを実行、AでないならCを実行」といったように、条件や状況に応じて実行内容を変える条件分岐で使用するもの

書き方と言葉で表すと、、、

if 条件
 処理
end

これは
条件に当てはまる(true)なら処理の内容が実行されます。
条件に当てはまらない(false)なら処理の内容は行われない。

ここで条件を記述する上でさまざまな条件をつける為に「比較演算子」「論理演算子」があるのでまとめていきます。

比較演算子

<   #右辺の方が大きい
<=  #右辺の方が大きい、または等しい( "≦" これと同じだと私は認識しています。)
>   #左辺の方が大きい
>=  #左辺の方が大きい、または等しい( "≧" これと同じだと私は認識しています。)

右辺と左辺を比較してそれに伴って処理を変える時に使う。

論理演算子

!   #否定
&&  #両方の条件が正しいならtrue( "and" という意味ですね。)
||  #片方の条件が正しいならtrue( "or" という意味ですね。)
==  #右辺と左辺が等しい(数学でいう "=" という意味ですね。)
!=  #右辺と左辺が等しくない(数学でいう "≠" という意味ですね。)

私は比較演算子や論理演算子を自分の認識(カッコ内)で置き換えて少し覚えやすくしました!

elsif / else

これはifを記述する時によく出てくるもので意味としては、
if文の条件に合わなかった時(false)で行う処理を設定できる。

if 条件
 処理A
else
 処理B
end

「条件がtrueならば処理Aを行う。falseならば処理Bを行う。」

if 条件1
 処理A
elsif 条件2
 処理B
elsif 条件3
 処理C
.
.
.
elsif 条件n
 処理x
else
 処理z
end

elseでは1つの条件に対して条件分岐を行いましたが、
elsifでは条件を無限に書くことができます。(感覚的にif文をたくさんつなげて1つにまとめた!みたな)

最後に

if文についてまとめてみました。他にも条件分岐という観点ではたくさん書き方があるようです。
個人的にif文が苦手で使いこなせるまで時間がかかったのでまとめて整理しました。

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

【rails】ActiveSupportの期間指定メソッドを使ってコードがスッキリした話

お久しぶりです。スージーです。
今日はrailsでスパゲッティコードを便利メソッドでキレイにしたよという話です。

環境

  • ruby 2.6.6
  • rails 5.2.3

参考

【知らずに損した】ActiveSupportの期間指定メソッドall_day, all_week, all_month, all_year
Active Support コア拡張機能

今週の日曜日〜土曜日の期間でデータを取得したい時

使うメソッドとしてはbeginning_of_weekend_of_weekを使って今週の日曜日と今週の土曜日を取得してみましょう。

# 今週日曜日(日曜始まり)を取得するメソッド
rb(main):001:0> Date.today.beginning_of_week
=> Mon, 07 Dec 2020
# これだと月曜始まりで取得してしまうので-1します
rb(main):002:0> Date.today.beginning_of_week - 1
=> Sun, 06 Dec 2020
# 日曜日が取れました!

同じように土曜日を取得しましょう

# 今週土曜日を取得するメソッド
rb(main):003:0> Date.today.end_of_week - 1
=> Sat, 12 Dec 2020
# 土曜日が取れました!

次に日曜日〜土曜日までのデータを取得してみる

今回はStudyモデルというTBLにid, time, total, user_id, created_atカラムを持つ学習時間を記録するTBLを例に考えます

カラム タイプ
id digint
time float
total float
user_id integer
created_at datetime

このテーブルに以下のデータが入っていると想定します

irb(main):002:0> Study.all
  Study Load (0.6ms)  SELECT  `studies`.* FROM `studies` LIMIT 11
=> #<ActiveRecord::Relation [#<Study id: 2, time: 0.5, total: 0.5, user_id: nil, created_at: "2020-12-05 11:09:38", updated_at: "2020-12-05 11:09:38">, #<Study id: 3, time: 1.5, total: 2.0, user_id: nil, created_at: "2020-12-07 11:09:42", updated_at: "2020-12-07 11:09:42">, #<Study id: 4, time: 2.0, total: 4.0, user_id: nil, created_at: "2020-12-07 11:09:49", updated_at: "2020-12-07 11:09:49">, #<Study id: 5, time: 0.5, total: 4.5, user_id: nil, created_at: "2020-12-07 11:26:38", updated_at: "2020-12-07 11:26:38">, #<Study id: 6, time: 1.0, total: 5.5, user_id: nil, created_at: "2020-12-07 11:27:31", updated_at: "2020-12-07 11:27:31">, #<Study id: 7, time: 0.5, total: 6.0, user_id: nil, created_at: "2020-12-07 23:16:04", updated_at: "2020-12-07 23:16:04">, #<Study id: 8, time: 1.5, total: 7.5, user_id: nil, created_at: "2020-12-07 23:18:49", updated_at: "2020-12-07 23:18:49">]>

id2~8までの7件のレコードが存在しています(id1が歯抜けしているのは無視して下さいw)

このデータがある状態で先程のメソッドを使って期間を今週に絞ってデータを取得してみたいと思います。

irb(main):003:0> Study.where(created_at: Date.today.beginning_of_week - 1..Date.today.end_of_week - 1).sum(:time)
   (4.1ms)  SELECT SUM(`studies`.`time`) FROM `studies` WHERE `studies`.`created_at` BETWEEN '2020-12-06' AND '2020-12-12'
=> 7.0

whereでcreated_atが今週日曜日(12/6)〜今週土曜日(12/12)までの7日間のデータを取得して、sumメソッドでtimeカラムの合計を計算します

スパゲッティコードを書く

まず私が最初に書いたスパゲッティコードで書きますw

# studies_controller.rb
~省略~
def index
@today = Date.today
@this_week_total_time = Study.where(created_at: @today.beginning_of_week - 1..@today.end_of_week - 1).sum(:time)
end
~省略~

controllerにこんな書いてたらどんどんfatになっていく予感しかしないですし、汚いコードですね

リファクタリング1

モデルメソッドを使ってcontrollerの見通しをよくします

# studies_controller.rb
~省略~
def index
@this_week_total_time = Study.this_week_total
end
~省略~

# models / study.rb
~省略~
def this_week_total
@today = Date.today
self.where(created_at: @today.beginning_of_week - 1..@today.end_of_week - 1).sum(:time)
end
~省略~

ロジック部分をモデルに移行したので、コントローラーがスッキリしました!

本題railsの便利メソッドを使う

コントローラーはキレイになりましたが、モデルメソッドが冗長です
そこでrailsが用意してくれているall_weekメソッドを使ってリファクタリングしましょう

# models / study.rb
~省略~
def this_week_total
@today = Date.today
+@range = @today.all_week(:sunday) ← 追加
self.where(created_at: @range).sum(:time)
end
~省略~

all_weekは引数を取ることで任意の曜日始まりにできます.今回は日曜始まりにしたいので(:sunday)を渡します
最初のコードに比べると大分キレイなコードになりました!
以前のコードだとbeginning_of_week - 1なので、「週の始まりの日付を取得しているけど、-1しているから~えーっと、結局何曜日なの!?」って何ヶ月後の自分が見たら思うでしょうw
リファクタリングした@range = @today.all_week(:sunday)であれば「日曜始まりで期間が今週なんだな」と直感的に分かるようになりました

念の為、確認してみましょう

irb(main):006:0> @today = Date.today
=> Wed, 09 Dec 2020
irb(main):007:0> @range = @today.all_week(:sunday)
=> Sun, 06 Dec 2020..Sat, 12 Dec 2020
irb(main):008:0> Study.where(created_at: @range).sum(:time)
   (0.5ms)  SELECT SUM(`studies`.`time`) FROM `studies` WHERE `studies`.`created_at` BETWEEN '2020-12-06' AND '2020-12-12'
=> 7.0

ちゃんと指定した期間のデータを取得する事ができました!
公式リファレンスに詳しく書いているので、こちらも合わせて読んでみて下さい!!

終わり

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

Homebrew の初期化ができない場合

本記事の内容

Homebrewの初期化をする際のエラーを共有し、初学者の方に役立てればと思い作成しました。

エラーコード

initdb: error: directory "/usr/local/var/postgres" exists but is not empty
If you want to create a new database system, either remove or empty
the directory "/usr/local/var/postgres" or run initdb
with an argument other than "/usr/local/var/postgres".

Data page checksums are disabled.

エラーコードの意味

ディレクトリ "/usr/local/var/postgres" は存在しますが、空ではありません。
新しいデータベースシステムを作成したい場合は
ディレクトリ"/usr/local/var/postgres "を指定するか、initdbを実行します。
に"/usr/local/var/postgres "以外の引数を指定してください。

解決方法

rm -rf /usr/local/var/postgresを実行した後に再度、initdb /usr/local/var/postgres -E utf8を実行すると、、、

Success. You can now start the database server using:
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PostgreSQL の初期化ができない場合

本記事の内容

PostgreSQLの初期化をする際のエラーを共有し、初学者の方に役立てればと思い作成しました。

エラーコード

initdb: error: directory "/usr/local/var/postgres" exists but is not empty
If you want to create a new database system, either remove or empty
the directory "/usr/local/var/postgres" or run initdb
with an argument other than "/usr/local/var/postgres".

Data page checksums are disabled.

エラーコードの意味

ディレクトリ "/usr/local/var/postgres" は存在しますが、空ではありません。
新しいデータベースシステムを作成したい場合は
ディレクトリ"/usr/local/var/postgres "を指定するか、initdbを実行します。
に"/usr/local/var/postgres "以外の引数を指定してください。

解決方法

  • rm -rf /usr/local/var/postgresを実行.
  • initdb /usr/local/var/postgres -E utf8を実行。
Success. You can now start the database server using:
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RailsのHTTPステータス

分類

  1. 情報レスポンス (100 ~ 199)
  2. 成功レスポンス (200 ~ 299)
  3. リダイレクト (300 ~ 399)
  4. クライアントエラー (400 ~ 499)
  5. サーバエラー (500 ~ 599)

↓下記サイトで適宜確認する
MDN web docs - HTTP レスポンスステータスコード

書き方

# シンボルを使う

render json: @user, status: 201
or
render json: @user, status: :created

render status: 500
or
render status: :internal_server_error
ステータスコードのみ返す
# リクエストが正常に処理された
head :ok

# リクエエストが不正
head :bad_request

def destroy
  @user.destroy
  head 204
end

コンソールで確認

pp Rack::Utils::SYMBOL_TO_STATUS_CODE

{:continue=>100,
 :switching_protocols=>101,
 :processing=>102,
 :early_hints=>103,
 :ok=>200,
 :created=>201,
 :accepted=>202,
 :non_authoritative_information=>203,
 :no_content=>204,
 :reset_content=>205,
 :partial_content=>206,
 :multi_status=>207,
 :already_reported=>208,
 :im_used=>226,
 :multiple_choices=>300,
 :moved_permanently=>301,
 :found=>302,
 :see_other=>303,
 :not_modified=>304,
 :use_proxy=>305,
 :"(unused)"=>306,
 :temporary_redirect=>307,
 :permanent_redirect=>308,
 :bad_request=>400,
 :unauthorized=>401,
 :payment_required=>402,
 :forbidden=>403,
 :not_found=>404,
 :method_not_allowed=>405,
 :not_acceptable=>406,
 :proxy_authentication_required=>407,
 :request_timeout=>408,
 :conflict=>409,
 :gone=>410,
 :length_required=>411,
 :precondition_failed=>412,
 :payload_too_large=>413,
 :uri_too_long=>414,
 :unsupported_media_type=>415,
 :range_not_satisfiable=>416,
 :expectation_failed=>417,
 :misdirected_request=>421,
 :unprocessable_entity=>422,
 :locked=>423,
 :failed_dependency=>424,
 :too_early=>425,
 :upgrade_required=>426,
 :precondition_required=>428,
 :too_many_requests=>429,
 :request_header_fields_too_large=>431,
 :unavailable_for_legal_reasons=>451,
 :internal_server_error=>500,
 :not_implemented=>501,
 :bad_gateway=>502,
 :service_unavailable=>503,
 :gateway_timeout=>504,
 :http_version_not_supported=>505,
 :variant_also_negotiates=>506,
 :insufficient_storage=>507,
 :loop_detected=>508,
 :bandwidth_limit_exceeded=>509,
 :not_extended=>510,
 :network_authentication_required=>511}

参考URL

Railsガイド - レイアウトとレンダリング
MDN web docs - HTTP レスポンスステータスコード

RailsのHTTPステータスのシンボル表現
Rails Controllerのrenderメソッドレシピ集

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

【React】Railsでsaveされた時に、Reactでサクセスメッセージを表示

個人のブログで、ReactとRailsでDBとやりとりする記事を作りました

フロントReact、バックRailsでデータベースに保存する

某プログラミングスクール(◯MM)で課題で出されたものをReactで作ってみて、そこにサクセスメッセージを出そう、と言うのが今回の目的です。

メモ書き程度で書いていきます。

完成後の動作

フォーム内容の保存に成功するとサクセスメッセージが呼び出されます。
流れとしては、

  • stateを作る
  • createが呼ばれsaveされたらstateを変更する
  • stateをコンポーネントに渡してメッセージを表示させる

こんな感じです。

stateを作る

  state = {
    books: [],
    successCreate: false
  }

successCreateと言うstateを作りました。
ここは初期値はfalseとして、createが呼ばれたらtrueとします。

createが呼ばれsaveされたらstateを変更する

  createBook = (title, body) => {
    axios
      .post('http://localhost:3001/books', { title: title, body: body})
      .then((response) => {
        const newData = update(this.state.books, { $push: [response.data]})
        this.setState({books: newData, successCreate: true})
      })
  }

Rails側でbooksコントローラーのcreateを呼び出し、保存されたデータはbooksに追加し、successCreateはtureに変更します。
ちなみにbooksにはBookモデルのデータが全て入っています。

stateをコンポーネントに渡してメッセージを表示させる

このsuccessCreateの値をコンポーネントに渡します。

<BookCreateForm
  createBook={this.createBook}
  successCreate={this.state.successCreate}
/>

受け取った先で、stateがtrueの時にメッセージを表示するよう記述します。

{this.props.successCreate && (
  <p style={{color: '#16de69', fontSize: 6}}>Book was successfully created.</p>
)}

これでBookがcreateされ、stateが変更した時にメッセージが出るようになりました。

react側とrails側でバリデーションをかけてより安全性を高めれば、思いがけないメッセージの表示はなくなるかと。

忘備録的なものなのでとりあえず動いた時点で記事にしております、あしからずです。

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

font-awesomeのアイコンを塗りつぶす

font-awesomeのアイコンを塗りつぶそう

いいね機能を作る際に、ハートマークを赤く塗りつぶす方法をメモしときます。

font-awesomeのアイコンを塗る潰すにはsolidのアイコンを選ばないといけないらしいです。

スクリーンショット 2020-12-12 0.51.26.png

こちらの画像の右上でsolidのアイコンを選択できてますね。

<i class="fas fa-heart"></i>

ちなみの上記のようなコードになっています。
classのfasのsがsolidのsなんだろうなと思います(多分)

細かいところで躓いてしまうことが多いので、一個一個わからないことを潰していきたいです。

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