20200603のRailsに関する記事は19件です。

Routing Error[No route matches [GET] “/logout”]エラーと格闘した話

前提

-Rails 6.0.3.1
-ruby 2.6.3


railsでアプリを作成中にヘッダーにLogoutのリンクを作成していました。

動作確認で、ボタンを押してみると、
あらまあ....

No route matches [GET] “/logout”

お怒られました....
頼むから、ログアウトさせてくれ...
旅立たせてくれよ...

こうして長いRouting Error[No route matches [GET] “/logout”]エラーとの
戦いが始まるであろうとは、知る由もなかったのである。


やってみたこと

①ルーティングの確認

No route matchesって言ってるし、どうせルーティングミスってるんでしょ!!!
ほんまアホやなワイ。

ちゃんとlogout_path使ってるし、HTTP Verb?: POSTになってるやんな(汗)。

ルーティングはあってはるやん

②viewでメソッドの指定の確認

次いこ次。飲み足りんし、二軒目にきました。

<%= link_to “Log out”, logout_path, method: :post, class: “nav-link text-light”%>

へいらっしゃい!!!!!!!

と思いきや、お主も合ってはるな。
ちゃんと、postしていますな。

③検証ツールで確認

ほいなら、次は個室居酒屋で三軒目や。
HTML上で確認や。

a class=“nav-link text-light” rel=“nofollow” data-method=“post” href=“/logout”>Log out</a>

fuck the po00ce!!!!!!!!!

マジかいな。まだ飲みたらんな!!!!!!!!!!!
data-method=“post
postさん、ちゃんといるんか............

④jQueryがきちんと動いているか確認する

Boys Be Engineer 非エンジニアよ、エンジニアになれ

このイカした記事で、jQueryに問題あるんちゃう?
っていう新たなる誘い。
四軒目に来ました。

Rails6でjQueryの導入方法
Rails 6にjQueryとBootstrapを入れる
以上の記事で、rails6での導入方法をかたっぱしから試すロドリゲス。

撃沈ロドリゲス.................
ほなもう一軒行こうか......

⑤environment.jsの一部の記述を削除

/config/webpack/environment.js
const { environment } = require('@rails/webpacker')
const { VueLoaderPlugin } = require('vue-loader')
const vue = require('./loaders/vue')

environment.plugins.prepend('VueLoaderPlugin', new VueLoaderPlugin())
environment.loaders.prepend('vue', vue)
environment.config.resolve.alias = {'vue$': 'vue/dist/vue.esm.js' }

const webpack = require('webpack')
environment.plugins.prepend('Provide',
    new webpack.ProvidePlugin({
        $: 'jquery/src/jquery',
        jQuery: 'jquery/src/jquery'
    })
)
module.exports = environment

今の設定。

それをこうしてこう!!!!(語彙力なし)

/config/webpack/environment.js
const { environment } = require('@rails/webpacker')
#2-7行目をコメントアウト
// const { VueLoaderPlugin } = require('vue-loader')
// const vue = require('./loaders/vue')

// environment.plugins.prepend('VueLoaderPlugin', new VueLoaderPlugin())
// environment.loaders.prepend('vue', vue)
// environment.config.resolve.alias = {'vue$': 'vue/dist/vue.esm.js' }
#ここまで

const webpack = require('webpack')
environment.plugins.prepend('Provide',
    new webpack.ProvidePlugin({
        $: 'jquery/src/jquery',
        jQuery: 'jquery/src/jquery'
    })
)
module.exports = environment

やっと旅立てる........
vue系のイケイケライブラリが邪魔してたらしい。
環境によっては、コメントアウトしなくても解決するっぽい。

**四軒目でわっしょい(jQueryがきちんと動いているか確認する)の記事しかなかったので、わっっしょいできなかった人は、コメントアウトしてみると行けるかもです。

五軒目にして、やっと旅立てる。
わっしょい!!!!!!

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

【Rails】deviseでのセッションタイムアウト設定

deviseでのセッションタイムアウト設定

目次

  1. セッションタイムアウトを設定するメリット
  2. セッションタイムアウトを設定するデメリット
  3. deviseでのセッションタイムアウト設定

1. セッションタイムアウトを設定するメリット

  1. セッションの盗用などの不正行為の対策になり、安全にアプリケーションを運用することができる
  2. 利用ユーザーのステータスを判定することによって、サーバー側の負担を軽減させることができる

2. セッションタイムアウトを設定するデメリット

  1. 入力フォームなどで、一度中断をし、再開後に入力を行うことができないこと
  2. ログイン状態が切れる回数が多いと、ユーザーが再度ログインする必要があるので、アプリケーションの使い勝手が悪いと判断されてしまうこと

3. deviseでのセッションタイムアウト設定

3-1. Deviseのセッションタイムアウトを設定

以下の記述を入力しましょう。
(コメントアウトされているので、コメントを解除すればOK)

config/initializers/devise.rb
config.timeout_in = 30.minutes

3-2. Userモデルに「timeoutable」を設定

以下の記述を入力しましょう。

app/models/user.rb
class User < ApplicationRecord
  devise :database_authenticatable, :registerable,...省略...:timeoutable
end

※ テストを行う際は1分で設定することがおすすめです。

以上でdeviseでのセッションタイムアウト設定になります。

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

define_methodってどんなmethod?

define_methodってどんなmethod?

gemを読んでいたらdefine_methodなるメソッドが出てきたけど、
よくわからなかったので調べてみた。
直訳するとmethodを定義する。って名前のメソッド。
ますますわからない。。

ということで例をみてみます。

ruby.rb
NUMBERS = %w(zero one two three four five six seven eight nine)

NUMBERS.each_with_index do |word, num|
  define_method word do |i = nil|
    i ? num * i : num
  end
end

p two      #=> 2
p two(2)   #=> 4
p nine     #=> 9
p nine(3)  #=> 27

define_methodはmethodを動的に定義できるメソッドです
上記の例でもtwoやnineと言ったメソッドは直接定義したわけではないけれど
メソッドとして使えることができます。
これはdefine_methodによって動的にtwo,nineメソッドが定義されたからです。

ruby.rb
NUMBERS.each_with_index do |word, num|
  define_method word do |i = nil|
    i ? num * i : num
  end
end

define_methodの引数にwordが渡されています。
これが動的に定義されるメソッド名となります。
wordには["zero","one","two",..."nine"]という配列の要素が入っていきます。
なのでtwo,nineというメソッドが使えました。

そしてdefine_methodのブロック部分が動的に定義されるメソッドの処理内容となります。

ruby.rb
define_method word do |i = nil|
    i ? num * i : num
  end

内容としてはiが存在するときはi * numを返し、
存在しないときはnumを返すということですね。

そしてiは新たに定義されるメソッドの引数に当たっています。
最後に処理結果をもう一度見てみましょう。

p two      #=> 2 #引数がないのでnumを返す
p two(2)   #=> 4 #引数があるので 2 * 2 = 4
p nine     #=> 9 #引数がないのでnumを返す
p nine(3)  #=> 27 #引数があるので 9 * 3 = 27

define_methodの説明はここまでです。
お役に立てたら幸いです。

一人前のエンジニアになるまであと86日

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

Rails】undefined local variable or method エラーについて【定義しているのに出る!!

ちゃんと定義しているのに「undefined local variable or method」エラーが出るエラーに苦しんだので。。。

起きたエラー

無題.png

「invite」というメソッドがありません!というエラーに…。
無題.png
でも「inviteメソッド」は間違いなく書いてあります。

原因

「def invite」の直前部分が「全角スペース」になっているだけでした

全角スペースを半角スペース2個でインデント揃えたら解決しました。

とっても初歩的なミスでした。

同じミスで苦しんでいる人の助けになりますように
一緒に頑張りましょう…!

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

非同期でのお気に入り機能の実装

はじめに

お気に入り機能を作成しました。
いいね機能は作ったことがあるので、いいね機能と同じ感じで作成すれば余裕でしょ!と思っていました。
実際に作ってみて、お気に入りにいれることは簡単にできました。
ですがajaxを用いての非同期にしないとお気に入りボタンを押すたびにredirect_toでページ更新されてしまい、ユーザーライクでは無いと思いました。
下のgifが完成品です。
Alt text

コード&解説

モデルの作成

favoritesモデルを作成します。

class CreateFavorites < ActiveRecord::Migration[5.2]
  def change
    create_table :favorites do |t|
      t.references :user, null: false
      t.references :product, null: false

      t.timestamps
    end
  end
end

そしてfavorite.rbを以下のようにしました。

class Favorite < ApplicationRecord
  belongs_to :user
  belongs_to :product
end

そしてuser.rbに

  has_many :favorites, dependent: :destroy
  has_many :favorites, through: :favorites, source: :product

product.rbに

  has_many :favorites, dependent: :destroy
  has_many :favorites, through: :favorites, source: :user

としました。
これでfavoriteテーブルと言う中間テーブルに、productとuserのidを格納できます。

ルーティング

ルーティングを設定します。

  resources  :products do
    resources :favorites , only: [:index, :create, :destroy]
  end

お気に入り機能を実装するだけでしたら、createとdestroyだけでOKです。
お気に入りを一覧にしたかったので、indexも追加しています。

コントローラー

次にコントローラーです。

class FavoritesController < ApplicationController
  before_action :set_product, only: [:create, :destroy]

  def index
    @favorites = Favorite.where(user_id: current_user.id)
    # favoriteテーブルからuser_idが現在のユーザーのidの物探し出し、@favoritesに代入しています。
    # 後ほどeach文で表示させます。
  end

  def create
   # お気に入りに追加する記述です。@productはprivateの中に記載されています。
    @favorite = Favorite.new(
      user_id: current_user.id, 
      product_id: @product.id
    )
    @favorite.save
  end

  def destroy
   # お気に入りを削除する記述です。
    @favorite = Favorite.find_by(
      user_id: current_user.id, 
      product_id: @product.id
    )
    @favorite.destroy
  end

  private
 # こちらを記入しないとajaxが上手く起動しませんでした。
  def set_product
    @product = Product.find(params[:product_id])
  end
end

HAML

まずはお気に入りボタンを作りたいところをrenderメソッドを書きます。

%ul#favoriteBtn
  = render partial: 'favorites/favorite', locals: { product: @product}

localsで@productと言う変数を呼び出し元ではproductとして扱えるようにしています。
そしたら呼び出し元であるfavorites/_favorite.html.hamlを作成し、お気に入りボタンのみを記述します。

- if Favorite.find_by(user_id: current_user.id, product_id: product.id)
  = link_to(product_favorite_path(@product, product.id), method: :delete, remote: true) do
    %li.optionalBtn.already
      = icon('fa', 'star')
      お気に入り済み!
-else 
  = link_to(product_favorites_path(@product), method: :post, remote: true) do
    %li.optionalBtn.none
      = icon('fa', 'star')
      お気に入りへ! 

if文で条件分岐してあります。favoriteテーブルに現在のユーザーのidと商品のidが両方一致している物があるかをみています。あれば削除ボタン、無ければ追加ボタンを作成します。link_toの中にはそれぞれremote: trueと言う記述をしています。これがあることでajaxが使えるようになります。
ルートは下記のようになっています。:product_idが必要ですので、先ほどコントローラで定義した@productを記述しています。削除ボタンに関しては商品のidも必要ですので、product.idをカンマでつなげています。

                  product_favorites GET    /products/:product_id/favorites(.:format)                                                favorites#index
                                    POST   /products/:product_id/favorites(.:format)                                                favorites#create
                   product_favorite DELETE /products/:product_id/favorites/:id(.:format)                                            favorites#destroy

Ajax

次にviews/favoritesの中にcreate.js.erbとdestroy.js.erbを作成します。
中身は全く一緒ですので同じ記載をします。

$('#favoriteBtn').html("<%= j(render partial: 'favorites/favorite', locals: { product: @product}) %>");

私の場合は#favoriteBtnを非同期通信したいので上記のように記載しています。
ここまできたら非同期でお気に入りボタンが押せるようになっているを思います。

お気に入りを一覧表示する。

コントローラで先ほどのindexアクションで@favoritesの中にはお気に入り情報が入ってるはずです。
入っていたらeach文で一個ずつ表示させます。入っていなかったら、お気に入りに追加した商品はありませんと表示させました。

      - if @favorites.present?
        %ul
          - @favorites.each do |favorite|
            %li
              = link_to product_path(favorite.product.id) do
                .item-image
                  = image_tag (favorite.product.images[0].src.url)
                .item-body
                  .item-name
                    = favorite.product.product_name
                  .item-price
                    = "¥#{favorite.product.price}"
      - else 
        %h1
          お気に入りに追加した商品はありません

私が作成しているアプリではトップ画面にお気に入りされた数も表示しています。
下記のようにcountメソッドを使用して数を取ってきています。

= Favorite.where(product_id: product.id).count

最後に

これでお気に入り登録から一覧表示、お気に入り数までができました。
前回の記事と今回の記事でなかなかajaxについて鍛えられました。
ですが、まだまだひよっこなので勉強していきます。

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

中学2年が1週間で自分のアイディアをいるかいらないか投票できるTogmarks(トグマークス)作った

アイディアにいるかいらないか投票できるTogmarksというサイトを作りました。5月26日に作り始めて6月2日に公開しました。たった1週間しかかけていませんが前作ったQuaよりもいい出来だと思っています(機能の数は少ない)。今回も前と同じようによかった点と悩んだことを振り返ろうと思います。

紹介

トップページ

togmarks.png

素人が個人で1週間で作ったのですごくいいとは言えませんが青色をアクセントカラーにしてシンプルなデザインはそこそこ気に入っています。

投票画面

togmarksshow.png

タイトルと内容は気にしないでください(笑)公開して間もないため投稿がなく開発環境でseedでデータを作るしかなかったんです(泣)

他にもページはありますがどれもtopページと似ていてコメントすることがないので割愛します。

どうして作ったか

自分でアイディアを考えても「これ使われるのかな...人にしられてもいいから他の人の意見が聞きたいな...」と思ったことがよくあります。個人で趣味でやっている人は特にあるとおもいます’。そういうときにこのwebアプリを思いつきました。正直このwebアプリもいると思う人がいるのかわかりませんが投票してくれる人がいるなら自分も使ってみたいです。

今回の良かった点

①サイトマップやデータベース設計をしっかりしてから開発を行った・・・当たり前かもしれませんがQuaのときは一切そういうのをやらなかったので地味にしっかりとやったのは初めてでした。やはりこういうのは重要だなと感じました。
②必要な機能と欲しい機能をわけた・・・最初にそれをまとめておくと次に何をやるべきかがすぐわかるのでスムーズになります。
③cssのコードを少なくできた・・・じつは最も自分的には良かった点です。cssはスマホ用・PC用のデザインと分けるとどうしても長くなりがちですが今回は同じクラスを何回も使うことで最小限似できたと思います。
④技術面で悩んだことが一回もなかった・・・機能とデザインをシンプルにしたからだと思います。

悩んだこと

①お金・・・ロゴやイラスト台です。中2が払える訳ありません。最終的にはなしでいくことにしました。ただファビコンはなしでは寂しいのでいつの日か無料のやつ探して設定しようと思います。
②使われるか・・・誰しもが思うことですがこれ使う人いるの...という不安感です。ただこれを乗り切らないとどんなものもできません。

最後に

このwebアプリを開発中に最も驚いたのは開発スピードです。これが普通なのかもしれませんが基本機能だけだと1週間で作れてしまうんだなと思いました。
最初にしか触れていませんがこのアプリは1週間で作ったと思えばなかなかなのかな?自分的にはそこそこだと思います。
今回2つ目のアプリですが誰も登録しない...ということだけは避けたいです。みなさんお願いします。

https://www.togmarks.com/

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

ログイン状態且つ住所テーブルにデータが登録してある場合としてない場合の条件分岐

def new
    if current_user && Address.find_by(user_id: current_user.id).present?
      @address = Address.find_by(user_id: current_user.id)
      render action: :edit
    else
      @address = Address.new
    end
if current_user && Address.find_by(user_id: current_user.id).present?

2行目 ...presentメソッドはオブジェクトのレシーバーの値が存在すればtrue、存在しなければfalseを返すメソッド。if文などの条件分岐でよく使用するので覚えておきたい。
current_user.idと一致するuser_idが存在すればeditアクションが動く。
ちなみに(renderで同じコントローラーのアクションが動かせるのは本日知りました)

6行目...current_user.idと一致するuser_idが存在しなければnewアクションがそのまま動くので新規登録となる。

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

Rails 5.2/6.0 で MessageEncryptor を使うときは初期化タイミングに気を付けよう

Rails 5.2 から ActiveSupport::MessageEncryptor のデフォルト暗号方式が aes-256-cbc から aes-256-gcm に変更となった。しかし、期化タイミングによっては意図しない暗号方式を使うことになる場合があるため紹介する。

Rails 5.2

以下のバージョンで確認:

  • Ruby 2.6.5
  • Rails 5.2.4.3

デフォルト

まず rails console でデフォルト暗号方式を確認する。

irb> encryptor = ActiveSupport::MessageEncryptor.new 'key'
=> #<ActiveSupport::MessageEncryptor:0x0000561c2eae8940 @secret="key", @sign_secret=nil, @cipher="aes-256-gcm", @aead_mode=true, @verifier=ActiveSupport::MessageEncryptor::NullVerifier, @serializer=Marshal, @options={}, @rotations=[]>
irb> encryptor.instance_variable_get '@cipher'
=> "aes-256-gcm"

確かに aes-256-gcm であることがわかる。

実例

実際のアプリケーションでは、なんらかのモデルに持たせておいて利用することもあるだろう。

app/models/some_model.rb
class SomeModel < ApplicationRecord
  class << self
    attr_reader :encryptor

    def set_key(key)
      @encryptor = ActiveSupport::MessageEncryptor.new key
    end
  end

  set_key 'x' * 32
end

これも同じように確認してみる。

irb> SomeModel.encryptor.instance_variable_get '@cipher'
=> "aes-256-gcm"

問題なさそうに見える。

問題例

ところが、 MessageEncryptor の初期化タイミングが早すぎると、異なる暗号方式になってしまう。例えば after_initialize コールバック内で SomeModel 定数が参照されていると、そのタイミングでオートロードされ、 MessageEncryptor が生成されることとなる。

config/application.rb
class Application < Rails::Application
  config.load_defaults 5.2
  config.after_initialize do
    SomeModel
  end
end
irb> SomeModel.encryptor.instance_variable_get '@cipher'
=> "aes-256-cbc"

aes-256-gcm ではなく aes-256-cbc となってしまった。

原因

ことの問題は Rails.application.config.active_support.use_authenticated_message_encryption の設定反映のタイミングにある。この設定値は過去バージョンとの互換性のために設けられており、 false に設定することでデフォルト暗号方式を aes-256-cbc に戻すことができる。本設定値は Rails 5.2 としてはデフォルト true ではあるが、この設定値が config.after_initialize 実行時点ではまだ反映されていないようなのだ。従ってこのタイミングで初期化してしまうと、 MessageEncryptor 自身のデフォルトである aes-256-cbc となってしまう。

該当コードはこのあたりである。

https://github.com/rails/rails/blob/v5.2.4.3/activesupport/lib/active_support/message_encryptor.rb#L88

解決例

初期化が早すぎるのが問題なので、実際の利用タイミングまで遅らせることが考えられる。

app/models/some_model2.rb
class SomeModel2 < ApplicationRecord
  class << self
    def set_key(key)
      @key = key
    end

    def encryptor
      @encryptor ||= ActiveSupport::MessageEncryptor.new @key
    end
  end

  set_key 'x' * 32
end
config/application.rb
config.after_initialize do
  SomeModel2
end

これでほとんどの場合 aes-256-gcm が利用できる。

irb> SomeModel2.encryptor.instance_variable_get '@cipher'
=> "aes-256-gcm"

ただし、 MessageEncryptor を利用したいタイミング自体が use_authenticated_message_encryption の設定反映前である場合は、これでも解決とはならない。そのときは MessageEncryptor.newcipher: オプションを明示するのが良いだろう。

Rails 6

以下のバージョンで改めて調査したが、同じ状況になるようだ。

  • Ruby 2.7.1p83
  • Rails 6.0.3.1

5.2 と少し事情が違うのは、デフォルトのオートローダーが Zeitwerk となり config/initializers/*.rb で各モデルをオートロードするのが非推奨となった点だ。このため config/initializers/*.rb でうっかりモデルを参照してしまった場合は、警告メッセージにて検出が可能となっている。しかしながら本記事での例のように、 config.after_initialize では警告はないようだ。

Rails では各ファイルは必要に応じてロードされるが、その順番はときに分かりづらいこともある。ロード順によって問題が発生することもあるので気を付けよう。

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

【git/基本編】これだけは押さえてほしいgitの仕組み&コマンド完全攻略版

git basic tutorial.png

今回やること

gitコマンドを使えることは個人開発でもチーム開発でも必須です

特にチーム開発ではgitを使う機会が非常に多くなります

かなり基本的な仕組みとコマンドのみなので実際に使って身につけていただけたらと思います

git(基本編)

gitの仕組み

①ワークツリー

下記コマンドでワークツリーでの変更をステージに記録していきます

$ git add

②ステージ

下記コマンドでステージからローカルリポジトリにコミット(記録を保存)することができます

$ git commit
$ git commit -m ""
# メッセージ付きで記録(変更)を保存
$ git commit -v 
# 変更内容を確認してからcommitが可能

③ローカルリポジトリ

下記コマンドでリモートリポジトリにプッシュ(送る)ことができます

$ git push リモート名 ブランチ名

④リモートリポジトリ

リモートリポジトリはGitHubなどのアプリケーションなどのファイル・ディレクトリの履歴を管理するネット上の場所のことです

リモートリポジトリにファイルなどをアップロードすることでバージョンごとに履歴を管理することができるため、開発において不本意な変更があった際に簡単に戻したいバージョンに戻すことができます

もっと詳しい仕組みを知ってちゃんとgitを使いこなしたい方は下の記事をご覧ください

スクリーンショット 2020-06-03 17.17.44.png

ブランチとは

ブランチとは現在のコミットを指しているただのポインタのことです

それでは以下のgitコマンドでブランチを新規追加していきましょう

$ git branch ブランチ名
$ git branch feature
# 作成したブランチに移動
$ git checkout feature

上の2つのコマンドを同時に行うコマンドが下のコマンドです

$ git checkout -b feature

もっと詳しくブランチについて知ってから他のgitコマンドを身につけたい方は下の記事をご覧ください

スクリーンショット 2020-06-03 17.19.01.png

開発の流れ

1. クローンを作る(コピーを作成する)

リモートリポジトリ(GitHub等)のファイルがワークツリーとローカルリポジトリ(.git directoryが)にコピーされる

$ git clone <repository url>

2. ブランチを作る

$ git checkout -b feature

3. プッシュする

$ git push リモート名 ブランチ名

4. 修正する

プロジェクトに変更を加える

5. 完了後にコミットする

$ git add .

コミットしていきます

$ git commit -m "First commit"

6. プッシュする

$ git push

7. Pull requestを送る

GitHub上でプルリクエストを送ります

以上がgitでの開発の流れですが説明はかなり省略しています

もっと詳しく知って実際の開発に役立てたい方は下の記事をご覧ください

スクリーンショット 2020-06-03 17.19.12.png

新規プロジェクトをGitHubで扱う

①git init

$ git init

Git に必要なファイル(.git)がダウンロードされます

②リモートリポジトリ(github)を新規で登録する

GitHubをブラウザで開き新規リポジトリを作成してください

その後下のコマンドを打ち込みます

$ git remote add origin githubのURL

③プッシュする

$ git push -u origin master

かなり端折って紹介したのでもっとわかりやすい説明は下の記事からご覧ください

スクリーンショット 2020-06-03 17.19.24.png

開発で役立つコマンド

リモートから情報を取得する

リモートリポジトリから情報を取得するには以下の2種類の方法があります

  1. フェッチ(fetch)
  2. プル(pull)

①フェッチ

以下のgitコマンドでリモートリポジトリから情報を取得できます

$ git fetch リモート名

専用に作成されたブランチのワークツリー には以下のgitコマンドを使って反映していきます

$ git merge origin/master

②プル

pullコマンドはこのコマンド1つで以下2つの役割を持ちます

$ git fetch origin master
$ git merge origin/master

実際のプルコマンドは以下です

$ git pull リモート名 ブランチ名

簡単なフェッチとプルの使い方だけだとわかりにくいと思うので下の記事もご覧ください

スクリーンショット 2020-06-03 17.19.34.png

リモート名の変更/削除

リモート名の変更

$ git remote rename 旧リモート名 新リモート名
$ git remote rename sample_app test_app

リモートの削除

$ git remote rm リモート名
$ git remote rm test_app

もっと詳しく知りたい方は下の記事が役立つと思います

スクリーンショット 2020-06-03 17.19.50.png

rebaseコマンドの使い方

*基本的な使い方

$ git rebase -I HEAD~数

修正したいコミットをpickからeditに変更して保存/ファイルを閉じます(コミット削除:pick~文を削除、コミット並び順変更:pick~文を並び替える)

$ git commit --amend

エディタが立ち上がるのでコミットメッセージを変更してください

$ git rebase -continue

*ブランチの変更を別ブランチに取り込みたい場合

$ git rebase master
$ git merge feature
$ git rebase -I HEAD~数

修正したいコミットをpickからsquashに変更して保存/ファイルを閉じます

*コミットを分割したい場合

$ git rebase -I HEAD~数

分割したいコミットをpickからeditに変更して保存/ファイルを閉じます

$ git reset HEAD^

別々にgit addでステージに上げてgit commitでコミットします

$ git add .
$ git commit -m "First commit"
$ git add .
$ git commit -m "Second commit"
$ git rebase —continue

以上がrebaseの使い方となりますがこれだけだとイメージが湧かないと思います

rebaseは開発において非常に重要な箇所なので是非詳しい説明は下の記事でご覧ください

スクリーンショット 2020-06-03 17.20.01.png

ここまででgitの基本を押さえられると思います

まだまだgitコマンドはありますが、まずは今回紹介した基礎を身につけて実際に使ってみてください

開発をする際に必ず役立つと思います

今回の元記事は下の記事になります

スクリーンショット 2020-06-03 17.20.43.png

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

【git/基本編】これだけわかれば100%オッケーなgitの仕組み&コマンド完全攻略版

git basic tutorial.png

今回やること

gitコマンドを使えることは個人開発でもチーム開発でも必須です

特にチーム開発ではgitを使う機会が非常に多くなります

かなり基本的な仕組みとコマンドのみなので実際に使って身につけていただけたらと思います

git(基本編)

gitの仕組み

①ワークツリー

下記コマンドでワークツリーでの変更をステージに記録していきます

$ git add

②ステージ

下記コマンドでステージからローカルリポジトリにコミット(記録を保存)することができます

$ git commit
$ git commit -m ""
# メッセージ付きで記録(変更)を保存
$ git commit -v 
# 変更内容を確認してからcommitが可能

③ローカルリポジトリ

下記コマンドでリモートリポジトリにプッシュ(送る)ことができます

$ git push リモート名 ブランチ名

④リモートリポジトリ

リモートリポジトリはGitHubなどのアプリケーションなどのファイル・ディレクトリの履歴を管理するネット上の場所のことです

リモートリポジトリにファイルなどをアップロードすることでバージョンごとに履歴を管理することができるため、開発において不本意な変更があった際に簡単に戻したいバージョンに戻すことができます

もっと詳しい仕組みを知ってちゃんとgitを使いこなしたい方は下の記事をご覧ください

スクリーンショット 2020-06-03 17.17.44.png

ブランチとは

ブランチとは現在のコミットを指しているただのポインタのことです

それでは以下のgitコマンドでブランチを新規追加していきましょう

$ git branch ブランチ名
$ git branch feature
# 作成したブランチに移動
$ git checkout feature

上の2つのコマンドを同時に行うコマンドが下のコマンドです

$ git checkout -b feature

もっと詳しくブランチについて知ってから他のgitコマンドを身につけたい方は下の記事をご覧ください

スクリーンショット 2020-06-03 17.19.01.png

開発の流れ

1. クローンを作る(コピーを作成する)

リモートリポジトリ(GitHub等)のファイルがワークツリーとローカルリポジトリ(.git directoryが)にコピーされる

$ git clone <repository url>

2. ブランチを作る

$ git checkout -b feature

3. プッシュする

$ git push リモート名 ブランチ名

4. 修正する

プロジェクトに変更を加える

5. 完了後にコミットする

$ git add .

コミットしていきます

$ git commit -m "First commit"

6. プッシュする

$ git push

7. Pull requestを送る

GitHub上でプルリクエストを送ります

以上がgitでの開発の流れですが説明はかなり省略しています

もっと詳しく知って実際の開発に役立てたい方は下の記事をご覧ください

スクリーンショット 2020-06-03 17.19.12.png

新規プロジェクトをGitHubで扱う

①git init

$ git init

Git に必要なファイル(.git)がダウンロードされます

②リモートリポジトリ(github)を新規で登録する

GitHubをブラウザで開き新規リポジトリを作成してください

その後下のコマンドを打ち込みます

$ git remote add origin githubのURL

③プッシュする

$ git push -u origin master

かなり端折って紹介したのでもっとわかりやすい説明は下の記事からご覧ください

スクリーンショット 2020-06-03 17.19.24.png

開発で役立つコマンド

リモートから情報を取得する

リモートリポジトリから情報を取得するには以下の2種類の方法があります

  1. フェッチ(fetch)
  2. プル(pull)

①フェッチ

以下のgitコマンドでリモートリポジトリから情報を取得できます

$ git fetch リモート名

専用に作成されたブランチのワークツリー には以下のgitコマンドを使って反映していきます

$ git merge origin/master

②プル

pullコマンドはこのコマンド1つで以下2つの役割を持ちます

$ git fetch origin master
$ git merge origin/master

実際のプルコマンドは以下です

$ git pull リモート名 ブランチ名

簡単なフェッチとプルの使い方だけだとわかりにくいと思うので下の記事もご覧ください

スクリーンショット 2020-06-03 17.19.34.png

リモート名の変更/削除

リモート名の変更

$ git remote rename 旧リモート名 新リモート名
$ git remote rename sample_app test_app

リモートの削除

$ git remote rm リモート名
$ git remote rm test_app

もっと詳しく知りたい方は下の記事が役立つと思います

スクリーンショット 2020-06-03 17.19.50.png

rebaseコマンドの使い方

*基本的な使い方

$ git rebase -I HEAD~数

修正したいコミットをpickからeditに変更して保存/ファイルを閉じます(コミット削除:pick~文を削除、コミット並び順変更:pick~文を並び替える)

$ git commit --amend

エディタが立ち上がるのでコミットメッセージを変更してください

$ git rebase -continue

*ブランチの変更を別ブランチに取り込みたい場合

$ git rebase master
$ git merge feature
$ git rebase -I HEAD~数

修正したいコミットをpickからsquashに変更して保存/ファイルを閉じます

*コミットを分割したい場合

$ git rebase -I HEAD~数

分割したいコミットをpickからeditに変更して保存/ファイルを閉じます

$ git reset HEAD^

別々にgit addでステージに上げてgit commitでコミットします

$ git add .
$ git commit -m "First commit"
$ git add .
$ git commit -m "Second commit"
$ git rebase —continue

以上がrebaseの使い方となりますがこれだけだとイメージが湧かないと思います

rebaseは開発において非常に重要な箇所なので是非詳しい説明は下の記事でご覧ください

スクリーンショット 2020-06-03 17.20.01.png

ここまででgitの基本を押さえられると思います

まだまだgitコマンドはありますが、まずは今回紹介した基礎を身につけて実際に使ってみてください

開発をする際に必ず役立つと思います

今回の元記事は下の記事になります

スクリーンショット 2020-06-03 17.20.43.png

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

railsでsnsアプリ開発

rails勉強のためにtwitterのようなsnsアプリを作成する。
あくまで個人的なメモみたいなので,めちゃくちゃ汚いです.

環境構築

rails ploject作成(失敗)

作成ディレクトリ内で
$ rails new sns-app
→databaseをpostgresqlにしなければならないため、
rm -rf sns-app
でアプリケーションごと削除

postgresql

参考1

入っていることを確認
$ psql --version
psql (PostgreSQL) 10.10 (Ubuntu 10.10-0ubuntu0.18.04.1)

postgres始動
sudo /etc/init.d/postgresql start

sudo su -
sudo su postgres
でpostgresアカウントに切り替え

postgresアカウントで$psqlでpostgresqlを動かせる状態(DB内)に

/duでroleの一覧

create role "name" login createdb password "passwd";
でcreate DBが出来るroleを作成

ctrl + dまたは/qでDB外へ

psql -U ryosuke postgres
でuserを指定してDB内へ

sudo service postgresql stopでpostgresqlを停止

改めてrails project作成

参考2
rails new sns-app -d postgresql
でDBにpostgresqlを指定して作成

config/database.ymlのdefaultに以下の3行を追加
username: <username> # 設定したPostgreSQL Accountと同一のもの
password: <password> # 設定したPostgreSQL Accountと同一のもの
host: localhost

git接続

git config user.name
git config user.email
で設定確認

作成したディレクトリ上で
git init
git add -A
git commit -m "first commit"
git remote add origin <gitのurl>
git push -u origin master

実際の開発

基本的にrails tutorialを参考に進めていく。

また、rails tutorial通りで動かなかったものをメモしていく。

6章

データをセーブし忘れたので、データがずれてしまったので、
rails db:migrate:resest
でデータベースをリセットする。
rails bd:resetでもいいらしいが、その後migrateファイルを実行する必要がある。

8章

dropdownさせたいが、railstutorial通りにしてもdoropdownできない。
調べてみたところ、_header.html.erbの最後に

_header.html.erb
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
<script>
    $('.dropdown-toggle').dropdown()
</script>

を追加したら、dropdownできるようになった。

11章、12章は飛ばす

アカウントの有効化、パスワードの再設定はメールアドレスが必要になるためとりあえずはやらないで13章へいく。
一旦落ち着いた後やるかもしれない。

13章

大体のpostは実装
写真の投稿はいったん飛ばす

railstutorial 終了

snsアプリの大元となるrails turorial のアプリケーションの開発がおわった。
ここから先は追加機能である
・投稿に対するコメント
・投稿に対するいいね
を実装していく。

いいね(Like)機能

イメージ
・投稿に「Like」マークを追加する。
・いいねしてないときは「Like」、したら「Liking」になる
・自分がいいねしたやつだけを表示する

実装はユーザーのfollowと似たようなものになると思う。

参考1

上記の参考文献1でいいねの実装はできた。
次は、自分がいいねしているポストを表示させるページをつくる。

ルーティングなど、基本的なところはフォロワー表示と同じ。
ユーザーがいいねしているポストは次の参考2のように、関連付けをすることで簡単に取れる。

参考2

user.rb
has_many :like_post, through: :likes, source: :post

最後に、いいねをしたときのステータスの数字が変わるようにajax化する。

ここも、基本的にはフォロワーの時と同じようにしていく。

likes/create.js.erb
$("#post-<%= @post.id %> .like").html("<%= escape_javascript(render "likes/like", post: @post) %>");
$("#iines").html('<%= current_user.likes.count %>');
likes/destroy.js.erb
$("#post-<%= @post.id %> .like").html("<%= escape_javascript(render "likes/like", post: @post) %>");
$("#iines").html('<%= current_user.likes.count %>');

以上のようにすればいい。
初めはcurrent_user@userにしていてはまった。
あくまで変えるのは今ログインしている人のいいね数であって、投稿したひとのいいね数を変えるわけではないということ。

しかし、current_userにしたことで、他の人のページでお気に入りするとその人のいいね数が、ログインしている人のいいね数に変わってしまう。
とりあえずの対処として、以下のように

shared/_stat.html.erb
<% if current_user?(@user) %>
    <a href="<%= iines_user_path(@user) %>">
        <strong id="iines" class="stat">
            <%= @user.likes.count %>
        </strong>
        iines
    </a>
<% end %>

ログインしているひと以外のページでは、その人のいいね数を表示させないことにした。
しかし、これでは、その人がいいねしているものがわからないので、今後違う案を考える。

追記:
色々やってみた結果、以下のように

shared/_stat.html.erb
<a href="<%= iines_user_path(@user) %>">
    <strong <%if current_user?(@user)%>
                id = "iines"
            <%end%>
            class="stat">
        <%= @user.likes.count %>
    </strong>
    iines
</a>

current_userの時のみidを通すことで、ログインしている人のいいね数だけ変わるようにした。

コメント機能

参考1
参考2
参考3

参考3と基本的にやりたいことが同じなのでそこをみて進めていく。
違うところは随時メモしていく。

↓実装イメージ
IMG_20200306_145848.jpg

参考3は新たにコメントページを作るものだった。
今回やりたいのはタイムラインにコメント機能をのせたいので、新たに思考錯誤しながらやっていこうと思う。

とりあえず完成した。

db/migrate/[timestamp]_create_comments.rb
class CreateComments < ActiveRecord::Migration[5.2]
  def change
    create_table :comments do |t|
      t.string :content
      t.integer :user_id
      t.integer :post_id

      t.timestamps
    end
    add_index :comments, :user_id
    add_index :comments, :post_id
    add_index :comments, [:user_id, :post_id]
  end
end
models/comment.rb
class Comment < ApplicationRecord
  belongs_to :user
  belongs_to :post
  validates :user_id, presence: true
  validates :post_id, presence: true
  validates :content, presence: true, length: {maximum: 255}
end
controllers/comments_controller.rb
class CommentsController < ApplicationController
  before_action :logged_in_user
  before_action :correct_user,    only: :destroy

  def create
    @comment = current_user.comments.build(content: params[:comment][:content], post_id:params[:post_id] )
    if @comment.save
      flash[:success] = 'comment create.'
      redirect_to root_url
    else
      redirect_to root_url
      #render 'static_pages/home'
    end

  end

  def destroy
    @comment.destroy
    flash[:success] = "Post deleted"
    redirect_to request.referrer || root_url
  end

  private
    def correct_user
      @comment = current_user.comments.find_by(id: params[:id])
      redirect_to root_url if @comment.nil?
    end
end
config/routes.rb
resources :comments,  only: [:create, :destroy]
views/comments/_comment.html.erb
<% if post.comments.any? %>
    <ol class="comments">
        <% post.comments.each do |comment| %>
            <li id="comment-<%= comment.id %>">
                <%#= link_to gravatar_for(comment.user, size:50),comment.user %>
                <span class="postuser">from <%= link_to "@#{comment.user.name}", comment.user %></span>
                <span class="content"><%= comment.content %></span>
                <span class="timestamp">
                    Commented <%= time_ago_in_words(comment.created_at) %> ago.
                    <% if current_user?(comment.user) %>
                        <%= link_to "delete", comment, method: :delete, data: { confirm: "You sure?" } %>
                    <% end %>
                </span>
            </li>
        <% end %>
    </ol>
<% end %>
<%= render 'comments/comment_form', post: post%>
view/comments/_comment_form.html.erb
<% if !current_user?(post.user) %>
    <%= form_for(post.comments.build) do |f| %>
        <div><%= hidden_field_tag :post_id, post.id %></div>
        <%#= render 'shared/error_messages', object: f.object %>
        <table>
            <tr>
                <td>
                    <div class="comment_text_field">
                        <%= f.text_field :content, placeholder: "Compose new comment..." %>
                    </div>
                </td>
                <td>
                    <%= f.submit "Comment", class: "btn btn-success btn-sm btn-block" %>
                </td>
            </tr>
        </table>
    <% end %>
<% end %>
view/posts/_post.html.erb
<li id="post-<%= post.id %>">
    <%= link_to gravatar_for(post.user, size:50),post.user %>
    <span class="user"><%= link_to post.user.name, post.user %></span>
    <span class="content"><%= post.content %></span>
    <span class="timestamp">
        Posted <%= time_ago_in_words(post.created_at) %> ago.
        <% if current_user?(post.user) %>
            <%= link_to "delete", post, method: :delete, data: { confirm: "You sure?" } %>
        <% end %>
    </span>
    <%= render "likes/like", post: post %>

    <%= render 'comments/comment', post: post %>

</li>

基本的にポストを実装したとき同じ感じだった。

終了!

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

Rails tutorialでMySQLを使う方法

rails tutorialも2週目に入りsqliteでは無く、今後を考えmysqlを使いたいと考えた。

rails new アプリケーション名 --database=mysql

上記を使用することでmysqlが使用できるとのことだがエラーが発生。
下記を実行しろと言われるのでそのまま従う。
gem install mysql2 -v '0.5.3' --source 'https://rubygems.org/'
rails sを使用するとmysqlにエラーがあるよと言われる。bundle installすると同じエラーが発生してしまう。

結論から言うと、下記コマンドを順に実施することで解決した。
sudo apt-get install libmariadb-dev
sudo apt-get install libmysqlclient-dev
sudo yum install mysql-devel'
gem install mysql2 -v '0.5.3' --source 'https://rubygems.org/'

新しいパッケージを入れるためには、その元となる「-dev」なんとかdevというものを事前にインストールしておく必要があるらしい。このgem install するときの元となるデータがなかったためエラーになったみたいだ。

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

Rails Herokuデプロイ手順

プログラミング初学者のため訂正がありましたらご指摘ください。
gitをインストールしている前提です。

自身の環境

  • Ruby 2.5.1
  • Ruby on Rails 5.2.4.1
  • MySQL (gem 'mysql2', '>= 0.4.4', '< 0.6.0')

デプロイの流れ

  1. The Heroku CLIの設定
  2. Herokuにログイン
  3. Herokuにデプロイ

Herokuとは

HerokuとはWebアプリケーションを簡単に全世界に公開できるクラウドプラットフォームです。

参考)HEROKU とは

以下のURLからHerokuのユーザー登録を行います。ユーザー登録は無料です。

https://signup.heroku.com/jp

1. The Heroku CLIの設定

The Heroku CLIをインストールすることで、Herokuのコマンドが使えるようになります。

下記のリンクからOSを指定してダウンロードしてインストールを完了させてください。

https://devcenter.heroku.com/articles/heroku-cli

2. Herokuにログイン

The Heroku CLIをインストールしたので、ターミナル上でHerokuのコマンドが使えるようになりました。

早速ターミナルからHerokuにログインしましょう。

Herokuへアップロードしたいアプリのディレクトリへ移動し、「heroku loginコマンド」を実行してください。

loginコマンド実行後、herokuに登録したメールアドレスとパスワードの入力が必要です。

$ cd app # appの部分を自分の作ったアプリ名にします
$ heroku login # herokuにログインする
Enter your Heroku credentials:
Email:

メールアドレスとパスワードの入力が完了すると以下のように表示されます。

Logged in as 入力したメールアドレス

3. Herokuにデプロイ

HerokuではPostgreSQLデータベースを使います。

なので、PostgreSQLをインストールしていきます。

以下のコマンドをターミナルで実行します。(既にインストールされている方はインストールしなくて大丈夫です。)

$ brew install postgresql

インストールが完了したら、本番 (production) 環境にpg gemをインストールしてRailsがPostgreSQLと通信できるようにします。

以下のコードをGemfileの最下部に追加してください。

Gemfile.
group :production do
  gem 'pg'
end

pg gemは本番用のgemでローカル環境にはインストールしないようにします。その場合、bundle installに--without productionを追加します。このフラグを追加することで、pg gemはローカル環境には反映されないようになります。それでは以下のコマンドを実行します。

$ bundle install --without production

bundle installの本番環境用

次に「heroku create アプリ名」コマンドでheroku上にアプリケーションを作成します。 以下のコマンドを実行します。

$ heroku create

上記のようにアプリ名を入力しないと自動で名前をつけてくれます。
一度登録した名前は使えないので注意してください

上記のコマンドを実行すると、以下のような結果が表示されます。

Creating app... done, ⬢ app(アプリ名)
https://app(アプリ名).herokuapp.com/ | https://git.heroku.com/app(アプリ名).git

https://~~.herokuapp.com/が上記のコマンドで作成されたサブドメインです。 この時点でブラウザに表示可能ですが、今はまだ何もありません。デプロイしてWebページを表示させましょう。

RailsアプリケーションをHerokuにデプロイするには、まずGitを使ってHerokuにリポジトリをプッシュします。

$ git add .
$ git commit -m "initial commit"
$ git push heroku master

上手く行くと、下記のようにremote: Verifying deploy... done.と表示されます。

.
.
.
remote: Verifying deploy... done.
To https://git.heroku.com/app(アプリ名).git
 * [new branch]   master -> master

次に以下コマンドでmigrationを実行します。ローカル環境で行なっていたrails db:migrateのコマンドを本番環境でも行うというイメージです。

$ heroku run rails db:migrate

上記のコマンドを実行したら、以下のコマンドを実行してWebページを表示させましょう。

$ heroku open

以上です。

参考記事

https://qiita.com/kazukimatsumoto/items/a0daa7281a3948701c39
https://qiita.com/NaokiIshimura/items/eee473675d624a17310f

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

【質問用メモ】paramsが全く理解できていない【Rails】

paramsがまったくわからない【Rails】

paramsが全くと言っていいほどわからない。
色々分からない。

読み方→「ぱらむす?」
何の略?→「ぱらめーたー?」

paramsはハッシュらしいけれど、どこのデータに由来しているのかが全く分からない
progateではurlからデータを受け取っていた。

params→urlではなくて
url→paramsということ???

じゃあurlは何処から???
ルーティングの:idって何を指しているのか?

…悩む。きっとデータのやり取りの流れが理解できればすっきりするのだとおもいます。
分かり次第続きを書きたいと思います。

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

[Rails]フォームのすべての値をワンクリックで初期化する(helperメソッド定義+JavaScript)

はじめに

様々な検索条件を付けられる検索フォームを実装している中で、検索条件をワンクリックでリセットできる方法がないかと試行錯誤しました。

結果、下記の方法で実装できたのでまとめます。

環境

  • Ruby2.5.1
  • Rails5.2.4

手順

概要を簡単に説明すると、
1. ヘルパーメソッドにリセットボタンタグを生成するメソッドを定義
2. ビューでそれを呼び出す
3. チェックボックスをjsでクリアする処理を書く
という3本でお送りする感じです

1. ヘルパーメソッドの定義

どのファイルでもいいですが、今回はhelpers/application.rbに定義します。

helpers/application.rb
module ApplicationHelper
  def reset_tag(value = "Reset form", options = {})
    options = options.stringify_keys
    tag :input, { type: "reset", value: value }.update(options)
  end
end

2. ビューファイルで呼び出し

search.html.haml
%div
  = reset_tag 'クリア', id: 'js_clear_btn'
%div
  = f.submit '完了'

本来Railsにreset_tagはありませんが、ヘルパーメソッドで定義したので、この書き方で呼び出せます。

CSSもで調整してこんな感じに↓
スクリーンショット 2020-06-03 13.53.06.png

3. チェックボックスをJavaScriptでクリアする記述

私の場合は、リセットボタンだとチェックボックスをクリア(チェックを外す)ことができなかったので、そこはJavaScript書きました。

コードは環境に大きく依存してしまうので、割愛します。

結果

f923d6ccbb11ae2bb0c6d320371bc226.gif
こんな感じで、text_fieldもnumber_fieldも、selectもcheckboxもすべて初期化するボタンを作成できました!

参考

フォームを初期化するボタンをRailsで使う

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

macにrailsがインストールできない

この記事について

プログラミングの勉強をしています。
勉強の過程で得た知識を、忘れないようまとめておくのと共に、誰かの助けになればと思います。

「rails -v」が上手くいかない!

(base) hoge@MacBook-Pro ~ % rails -v
Rails is not currently installed on this system. To get the latest version, simply type:

    $ sudo gem install rails

You can then rerun your "rails" command.

調べた通りにrailsをインストールしたのに、rails -vを何度実行してもこのエラーが出てしまいます。

対処法

rbenv rehash

このコマンドを実行し、再度rails -vを実行すると

(base) hoge@MacBook-Pro ~ % rails -v
Rails 6.0.3.1

上手くいきました!!

参考

https://qiita.com/amuyikam/items/313bc89c1de320a4257e
https://github.com/railsgirls-jp/coach.info/issues/32

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

【Rails】Geocoding APIを用いて高精度で緯度経度を算出し、Google Mapに表示する方法

目標

ユーザーが登録した住所をマップの中心に表示し、マーカーを立てる。
ezgif.com-video-to-gif (1).gif

開発環境

・Ruby: 2.5.7
・Rails: 5.2.4
・Vagrant: 2.2.7
・VirtualBox: 6.1
・OS: macOS Catalina

前提

下記実装済み。

Slim導入
ログイン機能実装
Google Map表示

gem 'geocoder'だけでは精度が低い(番地指定が出来ない地域がある)為、
Geocoding APIを使用して高精度で住所から緯度経度を特定出来る様に実装していきます。

Geocoding API有効化

1.下記リンクにアクセス

Google Cloud Platform

2. 「APIの概要に移動」をクリック

スクリーンショット 2020-06-03 10.01.36.png

3.「ライブラリ」をクリック

スクリーンショット 2020-06-03 10.01.41.png

4.検索フォームに「geo」と入力し、「Geocoding API」をクリック

スクリーンショット 2020-06-03 10.02.08.png

5.「有効にする」をクリック

スクリーンショット 2020-06-03 10.02.13.png

6.赤枠で囲われている箇所をクリック

スクリーンショット 2020-06-03 10.02.31.png

7.プルダウンメニューが表示されるので、「全てのGoogle Maps API」をクリック

スクリーンショット 2020-06-03 10.04.02.png

8.「認証情報」をクリック

スクリーンショット 2020-06-03 10.12.39.png

9.「APIキーの名前」をクリック

スクリーンショット 2020-06-03 10.12.46.png

10.認証情報の設定をする

①APIの制限
キーを制限を選択し、プルダウンメニューからGeocoding APIを選択する。

Maps JavaScript APIと、Geocoding APIが選択されている事を確認して、保存をクリック

スクリーンショット 2020-06-03 10.13.14.png

11.APIが2個になっているかを確認

APIを追加した事でAPIキーが変更されるという事は無いので、これで完了。

スクリーンショット 2020-06-03 10.13.25.png

実装

1.Gemを導入

Gemfile
gem 'gon'
gem 'geocoder'

gem 'gon'
➡︎ コントローラーで定義したインスタンス変数をビューのJavaScript内で使用出来る様にする。

gem 'geocoder'
➡︎ 住所から緯度経度を算出する。

ターミナル
$ bundle

2.geocorderの設定ファイルを作成し、編集

ターミナル
$ touch config/initializers/geocoder.rb
geocoder.rb
# 追記
Geocoder.configure(
  lookup: :google,
  api_key: ENV['GOOGLE_MAP_API']
)

これでGeocoding APIを使用する事ができ、緯度経度の算出が高精度で行えます。

3.カラムを追加

ターミナル
$ rails g migration AddColumnsToUsers address:string latitude:float longitude:float
add_columns_to_users.rb
class AddColumnsToUsers < ActiveRecord::Migration[5.2]
  def change
    add_column :users, :address, :string
    add_column :users, :latitude, :float
    add_column :users, :longitude, :float
  end
end
ターミナル
$ rails db:migrate

4.モデルを編集

user.rb
  # 追記
  geocoded_by :address
  after_validation :geocode

geocoded_by :address
➡︎ addressカラムを基準に緯度経度を算出する。

after_validation :geocode
➡︎ 住所変更時に緯度経度も変更する。

5.コントローラーを編集

application_controller.rbを編集

ストロングパラメーターに「address」を追加します。

application_controller.rb
def configure_permitted_parameters
  devise_parameter_sanitizer.permit(:sign_up, keys: [:email, :name, :address])
end

users_controller.rbを編集

users_controller.rb
def show
  @user = User.find(params[:id])
  gon.user = @user # 追記
end

6.ビューを編集

application.html.slimを編集

gonを読み込みます。
CSSとJavaScriptより先に読み込んでいる事に注意して下さい。

application.html.slim
doctype html
html
  head
    title
      | Bookers2
    = csrf_meta_tags
    = csp_meta_tag
    = include_gon # 追記
    = stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload'
    = javascript_include_tag 'application', 'data-turbolinks-track': 'reload'

②新規会員登録画面に住所入力フォームを追加

resistrations/new.html.slim
= f.label :address, '住所'
br
= f.text_field :address, class: 'form-control'
br

③マップを編集

users/show.html.erb
#map style='height: 500px; width: 500px;'

- google_api = "https://maps.googleapis.com/maps/api/js?key=#{ ENV['GOOGLE_MAP_API'] }&callback=initMap".html_safe
script{ async src=google_api }

javascript:

  let map;

  function initMap() {
    geocoder = new google.maps.Geocoder()

    map = new google.maps.Map(document.getElementById('map'), {
      // コントローラーで定義した変数から緯度経度を呼び出し、マップの中心に表示
      center: {
        lat: gon.user.latitude,
        lng: gon.user.longitude
      },
      zoom: 12,
    });

    marker = new google.maps.Marker({
      // コントローラーで定義した変数から緯度経度を呼び出し、マーカーを立てる
      position: {
        lat: gon.user.latitude,
        lng: gon.user.longitude
      },
      map: map
    });
  }

注意

turbolinksをオフにしないと地図が切り替わらないので、必ずオフにしましょう。
「turbolinksをオフにする方法」につきましては後日記事にしたいと思います。

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

Rails と Vue の共存

Rails と Vue の共存をしたい。
できれば以前のコードを活かしたい。
いきなりSPAにするにはサンクコストが大きくて、踏ん切りがつかない。

参考

2018年くらいに書かれたものが多い。Railsの遺産を残しながらVueの単一コンポーントの利点を使いたい、しかしSPAには振り切りきれない。

webpack

Sprockets

未検討

検討中

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

AWSへのRailsアプリのデプロイ その2

はじめに

今回は以下の記事の続きです。アプリのデプロイまで行っていきます。
AWSへのRailsアプリのデプロイ その1

データベースのインストール

以下のコマンドでバージョン5.6をインストールします。
バージョンについては、各々の環境ごとに適当なものを選択してください。

sudo yum -y install mysql56-server mysql56-devel mysql56

さっそくmysqlを立ち上げます。

sudo service mysqld start

mysqlのrootユーザーのパスワードを設定します。

sudo /usr/libexec/mysql56/mysqladmin -u root password 'ここにパスワードを入力'

パスワードが設定できたか確認します。

mysql -u root -p

パスワードの入力を促されるため、先ほど設定したパスワードを入力します。

Enter password: 

mysqlへのログインが正常終了すれば「mysql>」が表示されSQL文を実行できるようになります。

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.6.47 MySQL Community Server (GPL)

Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> 

これでmysqlのインストールは完了です。quitでログアウトしておきましょう。

mysql> quit

EC2インスタンスからGitHubにSSH接続する

デプロイを行う際にGitHubからEC2へコードをクローンする必要があります。
以下のコマンドで公開鍵と秘密鍵のペアを作成しましょう。

ssh-keygen -t rsa -b 4096

これで.sshディレクトリの配下に鍵ができるので、catで公開鍵の内容を確認しGitHubに登録します。

cat /home/ec2-user/.ssh/id_rsa.pub

以下のURLからGitHubに公開鍵を登録しましょう。
https://github.com/settings/keys

スクリーンショット 2020-05-31 19.32.15.png
これでGithubにアクセスできるはずなので、EC2上からsshコマンドを実行してみましょう。
「Hi!"ユーザー名"」 と表示されればOKです。

ssh git@github.com

アプリケーションサーバ(unicorn)の設定。

unicornの設定を行うため、まずはローカルでの作業を行います。Gemfileに以下を追記しましょう。
production do の中に記載することで、本番環境でのみunicornを使うことになります。

group :production do
  gem 'unicorn', 'インストールしたいバージョン'
end

gemのインストールも忘れずに。

bundle install

ちょっと長いですが、config/unicorn.rbを以下のように編集します。

app_path = File.expand_path('../../', __FILE__)

worker_processes 1

working_directory app_path

pid "#{app_path}/tmp/pids/unicorn.pid"

listen 3000

stderr_path "#{app_path}/log/unicorn.stderr.log"

stdout_path "#{app_path}/log/unicorn.stdout.log"

timeout 60

preload_app true
GC.respond_to?(:copy_on_write_friendly=) && GC.copy_on_write_friendly = true

check_client_connection false

run_once = true

before_fork do |server, worker|
  defined?(ActiveRecord::Base) &&
    ActiveRecord::Base.connection.disconnect!

  if run_once
    run_once = false # prevent from firing again
  end

  old_pid = "#{server.config[:pid]}.oldbin"
  if File.exist?(old_pid) && server.pid != old_pid
    begin
      sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU
      Process.kill(sig, File.read(old_pid).to_i)
    rescue Errno::ENOENT, Errno::ESRCH => e
      logger.error e
    end
  end
end

after_fork do |_server, _worker|
  defined?(ActiveRecord::Base) && ActiveRecord::Base.establish_connection
end

あとはmasterブランチにpushして完了です。

GitHubからコードをクローンする

EC2インスタンスにディレクトリを作り、権限をec2-userに変更します。

sudo mkdir /var/www/
sudo chown ec2-user /var/www/

コードをクローンするためにはリポジトリのURLが必要なので、以下の赤枠内のボタンからURLを取得します。
スクリーンショット 2020-05-31 23.40.49.png
取得したURLでコードをクローンしましょう。

cd /var/www/
git clone https://github.com/naoto-ysd/freemarket.git

この時点で/var/wwwの配下にアプリがクローンされていると思います。
アプリのディレクトリ内に移動し、各種設定を行いましょう。

$ pwd
/var/www
$ ls -l
合計 4
drwxrwxr-x 15 ec2-user ec2-user 4096  5月 31 14:43 アプリ名

Swap領域を用意する

Swap領域を用意し、メモリ不足に備えておきましょう。
ホームディレクトリで以下のコマンドを入力。

sudo dd if=/dev/zero of=/swapfile1 bs=1M count=512
sudo chmod 600 /swapfile1
sudo mkswap /swapfile1
sudo swapon /swapfile1

gemのインストール

一旦アプリをクローンしたディレクトリに移動します。

cd  /var/www/アプリ名

本番環境でgemを管理するためにbundlerをインストールします。
ローカルで以下のコマンドを実行してbundlerのバージョンを確認しましょう。

bundler -v

これで、ローカル側で使っているバージョンが分かりましたので、EC2上でbundlerのバージョンを指定してインストールします。

gem install bundler -v バージョン

bundle installも忘れず実行。

bundle install

環境変数の設定

パスワードなどのセキュリティに関わる情報は環境変数に設定します。
まずsecret_key_baseを作成しましょう。
EC2上で以下を実行します。

cd /var/www/アプリのディレクトリ

rake secretでcookieの暗号化に文字列を作成します。
このコマンドで生成する文字列は、後から環境変数に設定するのでコピーしておきましょう。

rake secret

/etc/environmentを編集して環境変数を設定しましょう。

sudo vim /etc/environment
DATABASE_PASSWORD='MySQLのrootユーザーのパスワード'
SECRET_KEY_BASE='先程コピーしたsecret_key_base'

環境変数を反映させるため、一度ここでログアウトしてから再度EC2にログインてください。
再度ログインしたら、環境変数が設定されているはずなので、envコマンドで確認します。

env | grep DATABASE_PASSWORD
env | grep SECRET_KEY_BASE

ポートの解放

現時点ではEC2インスタンスがhttpで通信できない状態です。
インバウンドルールを編集し、ポートを解放してあげましょう。
スクリーンショット 2020-06-01 2.10.18.png

先程作成したrunicorn.rbでlisten 3000と記述したので、今回デプロイするアプリではポート番号3000を使うことになります。
インバウンドルールにポート番号3000を追加して、作業は完了です。
スクリーンショット 2020-06-01 2.30.30.png

Railsを起動させる。

Railsを起動させる前にDBの設定を行います。
ローカル環境でdatabase.ymlを編集してproduction: 以下を変更しましょう

production:
  <<: *default
  database: "アプリ名によって異なる。変更不要"
  username: root
  password: <%= ENV['DATABASE_PASSWORD'] %>
  socket: /var/lib/mysql/mysql.sock

ローカルでの変更をコミットしてGithubにプッシュした後、EC2インスタンス上にコードを反映させます。

git pull origin master

EC2インスタンス上にデータベースを作成してマイグレーションしましょう。

rails db:create RAILS_ENV=production
rails db:migrate RAILS_ENV=production

このままの状態だとアセットファイル(画像やjsのこと)がコンパイルされていないので、ビューが崩れてしまいます。
事前にコンパイルを行っておきましょう。

rails assets:precompile RAILS_ENV=production

それではEC2インスタンスでRailsを起動させます。
アプリのディレクトリに移動してから、ユニコーンを起動させるコマンドでRailsを起動させることができます。
-cオプションで設定ファイルのパスを指定し、-E で本番環境で作動させています。

cd /var/www/アプリ名/
bundle exec unicorn_rails -c config/unicorn.rb -E production -D

ここまで出来ればデプロイできたはずなので、実際にブラウザでアプリにアクセスしてみましょう。
http://"Elastic IP":3000
エラーが起きた場合、以下のファイルにエラーログが出力されているので、こちらを確認してみてください。

tail -f /var/www/freemarket/log/unicorn.stderr.log

ウェブサーバのインストール

ウェブサーバとしてNginxをEC2にインストールします。

sudo yum -y install nginx

インストールが終了したら、/etc/nginx/conf.d/rails.confを以下のように編集しましょう。
アプリケーション名やElasticIPは適宜読み替えてください。

upstream app_server {
  server unix:/var/www/アプリケーション名/tmp/sockets/unicorn.sock;
}

server {
  listen 80;
  server_name Elastic IP;

  client_max_body_size 2g;

  root /var/www/アプリケーション名/public;

  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
  }

  try_files $uri/index.html $uri @unicorn;

  location @unicorn {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://app_server;
  }

  error_page 500 502 503 504 /500.html;
}

nginxの権限も変更しておきます。

sudo chmod -R 775 /var/lib/nginx

nginxを再起動させて設定ファイルを読み込ませましょう。

sudo service nginx restart

unicorn関係の修正

現在はunicorn.rbのlistenという項目に3000が指定されていると思います。
それを以下のように修正し、Githubへプッシュしましょう。

listen "#{app_path}/tmp/sockets/unicorn.sock"

EC2への反映も忘れずに。

git pull origin master

unicornを再起動させるため、unicornのプロセスIDを確認します。

ps aux | grep unicorn

ec2-user 14750  0.0 11.6 504768 117792 ?       Sl   Jun01   0:02 unicorn_rails master -c config/unicorn.rb -E production -D                                                                                            

プロセスID14750をkillしましょう。

kiill 14750

これでRailsを再起動させればアプリケーションにアクセスできるはずです。
http://"Elastic IP" (URLにポート番号の指定は不要です。)

RAILS_SERVE_STATIC_FILES=1 unicorn_rails -c config/unicorn.rb -E production -D

Railsの起動でエラーが出たら

以下の方法でエラーの解決方法を調査してみましょう。

・ログの確認
/var/www/アプリ名/log/unicorn.stderr.log
/var/log/nginx/error.log

・以下を再起動してみる
MySQL
Nginx
EC2

いったん完結

アプリのデプロイまで出来たため、前回の記事と合わせていったん完結です。
私の気力次第で自動デプロイについての記事も書きます。

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