20200926のRubyに関する記事は24件です。

二つのテーブルを繋ぐ存在、中間テーブル

中間テーブルとは

 二つのアソシエーションしたいテーブル同士が「多対多」の関係のときに、テーブルの間を受け持つ、便利なやつ。

具体例

 LINEを思い浮かべると、一人のユーザーはいくつものグループに所属している。また、一つのグループには、何人ものユーザーが招待されている。このとき、ユーザーとグループは「多対多」の関係と言える。

問題点

 「多対多」のテーブルをそのままアソシエーションすることが困難である。

解決策

 先の例で言えば、ユーザーとグループの間に組み合わせを記録するテーブルをかませる。それが、中間テーブル。ユーザーとグループの組み合わせを記録するというのがポイントで、カラムにはユーザーidとグループidが必要となる。

記述

 アソシエーションをするため、「has_manyメソッド」「belongs_toメソッド」を使う。
 そのモデル(テーブル)ファイルの目線になって、繋がりを持ちたいモデル(テーブル)にはが複数か単数か考える。
ex) user(モデル) has_many groups
ここは、もはや英語の話。

group.rb
has_many :user_groups
has_many :users, through: :user_groups
user.rb
has_many :user_groups
has_many :groups, through: :user_groups
user_group.rb
belongs_to :user
belongs_to :group

注意

 直接的に繋がっていないモデルには、「throughオプション」を使う。

ポイント

  • 中間テーブルは必ず「belongs_toメソッド」で、後に続くモデル名は単数形。
  • アソシエーションしたいテーブル同士は間接的に多対多の関係になる。
  • 中間テーブルではないテーブルは必ず「has_manyメソッド」で、後に続くモデル名は複数形。
  • 「throughオプション」を使って、経由しているモデル名を複数形で記述。

最後に

 人生で初めてQiitaに投稿します。自分のアウトプットを目的としていますが、お気づきの点があれば、ご指摘ください。

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

Ruby on RailsにてRails new〜デプロイまでの忘備録2

Ruby on RailsにてRails new〜デプロイまでの忘備録2です!

、Rails newコマンドでアプリケーション作成からデプロイまでの一連をつらつらと書いていきます。

前回
https://qiita.com/gonshiba-n/items/abd1b11e35f99eb5975f

Railsアプリケーションの日本語化と日本時間適応

config/application.rb
require_relative 'boot'

require 'rails/all'

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module xxxxxx
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 5.2
#ここから
    config.time_zone = 'Asia/Tokyo' #日本時間設定
    config.i18n.default_locale = :ja #日本語設定
    config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}').to_s] #起動時にja.ymlを読み込みさせる
#ここまでを追加
#-省略-
  end
end

これで日本語化の設定は出来たので、読み込むためのファイルを入手しましょう!
ターミナルは今、Railsの作業ディレクトリにいますか?
いるのであれば、下記コマンドを入力してGitHubから日本語化ファイルを入手しましょう。

ターミナル.
curl -s https://raw.githubusercontent.com/svenfuchs/rails-i18n/master/rails/locale/ja.yml -o config/locales/ja.yml

次に日本時間です。
新しくconfigディレクトリの中にinitializersディレクトリ内にtime_formats.rbを作成しましょう。

ターミナル.
touch config/initializers/time_formats.rb

これで作成できます!
time_formats.rbを開いて下記のコードを書いてあげれば準備完了です。

config/initializers/time_formats.rb
Time::DATE_FORMATS[:datetime_jp] = '%Y年 %m月 %d日 %H時 %M分'

実際には、下記のように使用することで
2020年9月25日12時00分みたいに表示されるようになります。

<%= xxxxx.created_at.to_s(:datetime_jp) %>
<%= xxxxx.updated_at.to_s(:datetime_jp) %>

Rspec導入については過去にまとめてあるのでそちらをどうぞ!
https://qiita.com/gonshiba-n/items/36c91e000fdc9b18aa28
ただ、開発環境とテスト環境にRspecを書いた方がテストファイルを作成するジェネレータを使用できるため、下記のグループ内に入れ込む方が良いと思われます!

ついでにRubocopも入れちゃいます。
Rubocopはリンターと呼ばれるもので、コードがルールから外れてる場合やタイポなどチェックできる優れものです!

Gemfile.
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]
#ここに、Rspecをはじめとするテストgemを記す
  gem 'rspec-rails'
  gem 'capybara', '>= 2.15'
  gem 'selenium-webdriver'
  gem 'webdrivers'
  gem 'factory_bot_rails'
  gem 'rubocop-airbnb'#←リンター
end

他にも自分が使いたいgemを書いたら

ターミナル.
bundle

上記を実行!

Rubocopについては、こちらの記事を参考にしてください!
https://qiita.com/shunsuke_sasauchi/items/70ccc4b02be72640f699

rootの設定

railsアプリにアクセスした時に一番最初に表示されるページを設定します。
今は雛形のみで何も中身がないので作成します。
rails g controllerでView,controllerと諸々を作っちゃいましょう。

ターミナル.
rails g controller StaticPages top about login

僕の例ですみません!
これで一通り、railsが自動であれやこれやを作成してくれました。

次はルーディングの設定をします。
congig/routes.rbを開きます!

config/routes.rb
Rails.application.routes.draw do
  resources :static_pages#←こっちはrailsが作ってくれたコードを消してresource任せにしています

  root 'static_pages#top'#←これを追加
end

これでroot設定完了!
試しにサーバーを起動して
http://localhost:3000
にアクセスして見ると設定したページが表示されていると思います。

config/environments/production.rbの設定

本番環境では画像の動的表示がoffになっているのでonに変更!

config/environments/production.rb
  config.assets.compile = true #デフォルトではfalse
end

これでOK!

いよいよherokuにデプロイ!

herokuには登録しておいてください!
クレジットカードが必要だったと思いますが、検索するとめちゃくちゃ分かりやすい記事があると思うのでそちらを参考にしてください!
PostgreSQLを使用しているのでDB周りの設定はしていません。
他のDBを使用する場合は別途設定が必要になるのでお気をつけください。

まずherokuをCLIで使えるようにしたらログインしましょう!

ターミナル.
heroku login

herokuにアプリケーションを作成していきます。
アプリ名はそのままURLに組み込まれる為、URLで使用できない文字は使えません!
そして、すでに使われてしまっているアプリ名も使用できません!

ターミナル.
heroku create 好きなアプリ名(URLに使われるため _ とかは使えない)

いよいよherokuのリモートリポジトリにpushしてデプロイしていきます。

ターミナル.
git push heroku master

DBのマイグレーションファイルがある場合は下記のコマンドでマイグレートしてあげてください

ターミナル.
heroku run rails db:migrate

ここまでくれば、後は実際にURLにアクセスして確かめてみましょう!

最後に

ここまで読んで頂きありがとうございました。
前回はアプリケーション完成間際にデプロイした為、凄く苦労しました。
アプリケーションの開発前の設定後にデプロイしてしまった方が絶対に楽だし、
開発環境と本番環境の両方で動作確認をしながら開発できる安心感は絶大だと思います。
ここまでざっくり、手順だけ書いてきましたが、出来ない!とかエラーが出た!とか間違ってる!とかいう場合は是非、ご教授くださると助かります。

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

【Rails】devise関連のルーティングまとめ

deviseも便利な機能が故、それぞれ独自のメソッドが自動で生成してくれるルーティングについて、こんがらがってしまいます。
そんな同じお悩みの方はぜひ。

devise_for

routes.rb
  devise_for :users
$ rails routes

Prefix                   Verb   URI Pattern                    Controller#Action

new_user_session         GET    /users/sign_in(.:format)       devise/sessions#new
user_session             POST   /users/sign_in(.:format)       devise/sessions#create
destroy_user_session     DELETE /users/sign_out(.:format)      devise/sessions#destroy
user_password            POST   /users/password(.:format)      devise/passwords#create
new_user_password        GET    /users/password/new(.:format)  devise/passwords#new
edit_user_password       GET    /users/password/edit(.:format) devise/passwords#edit
                         PATCH  /users/password(.:format)      devise/passwords#update
                         PUT    /users/password(.:format)      devise/passwords#update
cancel_user_registration GET    /users/cancel(.:format)        devise/registrations#cancel
       user_registration POST   /users(.:format)               devise/registrations#create
   new_user_registration GET    /users/sign_up(.:format)       devise/registrations#new
  edit_user_registration GET    /users/edit(.:format)          devise/registrations#edit
                         PATCH  /users(.:format)               devise/registrations#update
                         PUT    /users(.:format)               devise/registrations#update
                         DELETE /users(.:format)               devise/registrations#destroy

resources :usersとの比較

アクション名 リクエスト resources devise_for
new GET /users/new /users/sign_up(.:format)
edit GET /users/:id/edit /users/edit(.:format)
show GET /users/:id なし
index GET /users なし
create POST /users /users(.:format)
update PATCH / PUT /users /users(.:format)
destroy DELETE /users /users(.:format)

devise_scope

routes.rb
  devise_scope :user do
    get 'signin' => 'devise_token_auth/sessions#new'
    post 'signin' => 'devise_token_auth/sessions#create'
    post 'signup' => 'users#create'
    put 'update' => 'users#update'
  end
$ rails routes

Prefix Verb   URI Pattern                  Controller#Action

signin GET    /signin(.:format)            devise_token_auth/sessions#new
       POST   /signin(.:format)            devise_token_auth/sessions#create
signup POST   /signup(.:format)            users#create
update PUT    /update(.:format)            users#update

mount_devise_token_auth_for

routes.rb
  mount_devise_token_auth_for 'User', controllers: {
    registrations: 'users'
  }
$ rails routes

Prefix Verb   URI Pattern                  Controller#Action

signin GET    /signin(.:format)            devise_token_auth/sessions#new
       POST   /signin(.:format)            devise_token_auth/sessions#create
signup POST   /signup(.:format)            users#create
update PUT    /update(.:format)            users#update
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

(Ruby on Rails6) テーブルへのデータの作成

まえがき

テーブルでのデータ設定で、便利かなと思ったので、1つ・複数 のテーブルへのデータ設定を記録します。
いずれも、最後に save を行いますので。忘れずに!
データを取り出す時に、エラーになってしまいますよ!!

テーブルへのデータの作成

1つのデータ設定

コマンド
rails console

変数1 = モデル名.new(カラム名: "内容")
test1 = Test.new(description: "smple_text")

変数1.save
test1.save

複数のデータ設定

先のコマンドに , を入力します。

コマンド
rails console

変数1 = モデル名.new(カラム名: "内容",カラム名: "内容")
test1 = Test.new(description: "smple_text",title: "smple_title" )

変数1.save
test1.save

あとがき

ここまで読んでいただき、ありがとうございました。
以上が、テーブルへのデータの作成でした。
是非、お役立てください。

Myリンク

また、Twitter・Portfolio のリンクがありますので、気になった方は
ぜひ繋がってください。プログラミング学習を共有できるフレンドが出来るととても嬉しいです。

Twitter
Portfolio
Github

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

(Ruby on Rails6) モデルとテーブルを作成する方法

まえがき

今回は、Ruby on Rails6 でデーターベースのテーブルを作成する方法を忘却録として残します。

モデルとテーブルを作成する方法

bin/ ・・・Linux の開発環境で使用します。
(私はMAC{Unix}での開発環境で不要な文字ですが、知識として持っておくといいと思います。)
また、テーブル名前は "Form" の様に 頭文字を大文字にすると良いです。

モデルと1種類のカラムの作成

コマンド
$ bin/rails g model Smple_form title:string
$ bin/rails g model デーブル名 カラム名:データ型
or
$ bin/rails generate model Smple_form title:string
$ bin/rails generate model デーブル名 カラム名:データ型

モデルと複数のカラムの作成

コマンド
$ bin/rails g model Smple_form description:text title:string
$ bin/rails g model デーブル名 カラム名:データ型 カラム名:データ型
or
$ bin/rails g generate Smple_form description:text title:string
$ bin/rails g generate デーブル名 カラム名:データ型 カラム名:データ型

テーブルの作成 マイグレーション

コマンド
$ rails db:migrate

たまにマイグレーションを忘れて、エラーを出してしまいます。
ご注意ください。

マイグレーションファイルの作成

↓は、複数カラムを作成したものになります。

20200926124610_create_任意s.rb
class CreateGoals < ActiveRecord::Migration[6.0]
  def change
    create_table :goals do |t|
      t.text :description
      t.string :title

      t.timestamps
    end
  end
end

あとがき

ここまで読んでいただき、ありがとうございました。
以上が、モデルとデーターベースの作成でした。複数のカラム設定を記録できてよかったです。
是非、お役立てください。

Myリンク

また、Twitter・Portfolio のリンクがありますので、気になった方は
ぜひ繋がってください。プログラミング学習を共有できるフレンドが出来るととても嬉しいです。

Twitter
Portfolio
Github

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

docker-composeを用いたRailsのAPIサーバー環境構築

筆者について

ProgateのRuby, Railsコースを一通りやった。
その後Dockerで環境作ってRailsでAPIサーバー作った。

本記事について

Progateではviewを含んだrailsの書き方を学んだが、APIサーバーとしてのみRailsを使いたかった。
また、dockerで開発したかったため公式のクイックスタートを参考にRailsの開発環境を作った。
その過程で得られたノウハウをまとめる。

APIサーバーの開発で使うGemについては別記事で書く。

前提

Docker, docker-composeの使い方がわかること

環境

Ruby 2.7
MySQL 5.7
VSCode
Mac 10.14.5
Sequel Pro データベース見る用

Rails new するまで

まずはプロジェクトフォルダを作成。ここではrails-sampleとした。
そして、この直下に Dockerfileを作成

FROM ruby:2.7

RUN apt-get update -qq && apt-get install -y
RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install

# Add a script to be executed every time the container starts.
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]

次にrailsをインストールするためのGemfileを用意

source 'https://rubygems.org'
gem 'rails', '~>5'

空のGemfile.lockを作る

touch Gemfile.lock

Dockerfileに記載されているentrypoint.shを作る

entrypoint.sh
#!/bin/bash
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /myapp/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"

なぜこれらのファイルを作るのかはDocker 公式クイックスタートの方を見ていただければ。

docker-compose.ymlを作る

docker-compose.yml
version: '3'
services:
  server:
    build: .
    tty: true
    volumes:
      - .:/myapp
    working_dir: /myapp
    ports:
      - "3000:3000"
    depends_on:
      - mysql
    command: bash
    # command: > 
    #   bash -c "rm -f tmp/pids/server.pid &&
    #       bundle exec rails s -p 3000 -b '0.0.0.0'"
  mysql:
    image: mysql:5.7
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: mysql
    volumes:
      - "./mysql/db-data/:/var/lib/mysql" # データ永続化
      - "./mysql/my.cnf:/etc/mysql/conf.d/my.cnf" # 日本語をデータとして使うために必要

MySQLのデータの永続化と日本語対応のために

rails-sample > mysql > db-data フォルダを作成。
mysqlフォルダ以下にmy.cnfを作成

my.cnf
[mysqld]
character-set-server=utf8

ここまででこのような構成になる。
スクリーンショット 2020-09-26 20.12.16.png

それができたらrails newする。

docker-compose run server rails new . -MC --force --api --database=mysql --skip-active-storage

railsコマンドやコマンドのヘルプでオプションを調べ、不要そうなものを省いている。
重要なオプションは以下

--force // rails new 時にファイルを上書き
--api // api開発に不要なviewとかを生成しない
--database=myql // デフォルトではsqliteだがmysqlを指定する

これでいろいろ作られる。

スクリーンショット 2020-09-26 20.23.52.png

で、ここでGemfileGemfile.lockが上書きされて新しくなっている。
これをイメージのほうに反映させるために、

docker-compose build

する必要がある。

事前に必要なgemがわかっている場合にはここでGemfileに書いておく。

これでrails new完了

mysqlに繋がるように設定ファイルを書く。

config > database.yml

database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: mysql

development:
  <<: *default
  host: mysql
  database: myapp_development

...
test:
  <<: *default
  host: mysql
  database: myapp_test

productionは不要なのでまるっとコメントアウトした
host名はdocker-compose.ymlのサービス名
passwordもdocker-compose.ymlで指定したもの

できたらdocker-compose up -dでコンテナを起動し、VSCodeのAttach Shellで中に入る

rails db:create

でDBを作る

root@dc075120af8a:/myapp# rails db:create
...
Created database 'myapp_development'
Created database 'myapp_test'

これでデータベースが作れた。
Sequel Proで接続すればデータベースができていることが確認できる

あとはProgateで学んだ通りモデル作ってマイグレーションすればテーブルができる。

参考

Docker 公式クイックスタート 英語
日本語の方は内容が古いので注意。

Railsガイド RailsによるAPI専用アプリケーション

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

Rakeタスクを定義してみよう。

Rakeタスクってなに

タスクってなに、、、「やること」っていう意味かな。はじめて聞いた時はそう考えましたが、調べてみるとRuby on Railsにはタスクというものが存在するらしい。

Rakeタスクとは

このタスクという機能は、いちいちアプリケーションを立ち上げるなくてもターミナルから任意の処理を実行することができるものらしい。自分が携わっているアプリケーションでは、開発段階でサンプルのデータが必要だったので、それをこのタスクというものを使って作成した。

タスクを作成してみる

rails g task sample

これでsample.rakeというタスクに関するファイルを作成する。
lib/tasksにsample.taskという名前のファイルを作成。

namespace :greet do
end

作成したファイルには、デフォルトで上のようなコードが書かれている。
この中を自分がタスクとして行いたい処理をコマンド一つで実行されるように書いていく。

# タスク名前を書く。
namespace :sample do
  # タスクの説明を書く。 desc => description(説明)
  desc ""
  # db => タスクの名前を書く。
  task db: :environment do
    # 実行したい処理を記述する場所
  end
end

上から、、、、
●名前を書く → namespace
●タスクの説明 →desc
●タスクの名前 → task db: 上の例だと db がそう。

namespace :sample do
  desc "ゴリラと表示するタスク"
  task gorira: :environment do
    puts "ゴリラ"
  end
end

作成したタスクがきちんと動作するか確認をしてみる。

rails sample:gorira

ゴリラ

これでrake タスクの完成。

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

配列内の任意の文字を探す判定するメソッドの作り方

【概要】

1.結論

2.includeメソッドとは何か

3.どのようにプログラムしたか

1.結論

include?メソッドを使う!


2.include?メソッドとは何か

include?は配列の中に指定した要素が、あるかを判定するメソッドです!


3.どのようにプログラムしたか

def array_hello(strs)
  if strs.include?(hello)
    puts "True"
  else
    puts "False"
  end
end

"strs"の引数から"hello"という文字を探したいので、
strs.include?(hello)という書き方にしています!
引数.include?(探したい配列内の文字)で適用できます!

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

(ECサイト)注文情報入力時におけるバリデーション

前提条件

ECサイトでECサイトで注文情報入力 ==> 注文確認画面の間に注文情報入力でバリデーションをかけたい

1.よく使うバリデーション

app/models/book.rb
validates :title, presence: true

などの普段よく使うバリデーションは
booksテーブルにtitleというカラムがあり
データベースに保存される時、つまり @book.save(book_params)の時にtitleカラムが空白だとバリデーションがかかる。
しかし、ECサイトで注文情報入力 ==> 注文確認画面
 ==> 注文確定(ここで.saveが行われる)というフローで実装する際、注文情報入力 ==> 注文確認画面の間に.saveが発生しない為、モデルにかけるバリデーションをrenderで呼び出すことができない為if文で条件分岐を書いてflash[:notice]を使う必要がある。

2.if文の実装

app/controllers/order_controllers.rb
when 3
        if    params[:order][:new_add][:postal_code] == "" && params[:order][:new_add][:address] == "" && params[:order][:new_add][:name] == ""
              flash[:notice] = "新しいお届け先が全て入力されていません"
              redirect_to new_order_path
        elsif params[:order][:new_add][:postal_code] == ""
              flash[:notice] = "郵便番号が入力されていません"
              redirect_to new_order_path

        elsif params[:order][:new_add][:address] == ""
              flash[:notice] = "住所が入力されていません"
              redirect_to new_order_path
        elsif params[:order][:new_add][:name] == ""
              flash[:notice] = "宛名が入力されていません"
              redirect_to new_order_path
        else
            @order.postal_code = params[:order][:new_add][:postal_code]
            @order.address = params[:order][:new_add][:address]
            @order.name = params[:order][:new_add][:name]
        end
 end

3.コードの説明

まず、case文を使い、ラジオボタンを3個order/new.html.erbに書きwhenで3パターン分岐させている。
そして、3個目のラジオボタンを選ぶと注文情報入力時に新しいお届け先を入力できるように実装している。
[:new_add] は注文情報入力時に新しいお届け先を入力する際のパラメータ。

app/controllers/order_controllers.rb
params[:フォームで送られてくる値] == ""
flash[:notice] = ”ホニャホニャ"

と書くことで空欄の時にフラッシュメッセージを出せる。

4.今回の実装を終えて

当初 == nil にしており値が返ってきていなかったがターミナルを見ると""になっていたので条件文を変えるとうまくいった。
&&で条件文を繋ぐ時に最後に一個だけイコールを入れるのではなく毎回イコールが必要である。

5.参考サイト

https://qiita.com/GreenFingers_tk/items/ed5219e1e0cdd5e5d1b1#new

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

Railsにフォントを導入するまで

はじめに

ネット上には素晴らしいフリーフォントがたくさんあります。
デザインの表現の幅を広げるために是非、活用していきたいところ。
そこで、フリーフォントをRailsに導入していきます。

フォントファイルの導入

ここでは導入したいフォントファイルをsmog.otfとします。
publicフォルダにfontsフォルダを作り、そこにフォントファイルを配置。

- public
    - fonts
        - smog.otf

使用するcssファイル(ここではsample.css)に以下のコードを追加します。
font-familyの名前は自由に設定できます、今回は'Smog'としましょう。
またformatはファイルのフォーマットに合わせます。

フォーマット 拡張子
format('woff') .woff
format('truetype') .ttf
format('opentype') .otf または .ttf
format('embedded-opentype') .eot
format('svg') .svg または .svgz
sample.css
@font-face {
  font-family: "Smog";
  src: asset-url('/fonts/smog.otf') format('opentype');
  font-weight: normal;
  font-style: normal;
}

あとはいつも通りcssでフォントを指定すれば使えます。
以下は例です。

sample.css
.foo h1 {
  font-family: 'Smog';
}
index.html.erb
<div class="foo">
  <h1>hello!</h1>
</div>

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

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

【Rails】【bootstrap】レスポンシブに文字の大きさを変更したい

前提

gem bootstrapを使用

やりたいこと

Railsを使ってレスポンシブな画面を作る。
その際に文字の大きさをいい感じに大きくしたり小さくしたりしたい。

結論

app/assets/stylesheets/application.scss
body, html { font-size: 30px; }
@media screen and (min-width: 576px) and (max-width: 768px) { body, html { font-size: 30px; } }
@media screen and (min-width: 769px) and (max-width: 992px) { body, html { font-size: 30px; } }
@media screen and (min-width: 993px) and (max-width: 1200px) { body, html { font-size: 16px; } }
@media screen and (min-width: 1201px) { body, html { font-size: 20px; } }

上記のサイズを変更すればOK
色々見ているとpxで設定しない方がよいというのもあるので、他の方法も検討中
今回はRailsというよりはscssの書き方になる

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

sidekiqのリトライ上限を設定して死んだキューをslackで通知する方法

はじめに

非同期でjobを処理してくれるsidekiqを導入する中で、利便性を生かしつつも自分のアプリ専用にカスタマイズしたい、そんな時に役に立った設定をまとめています。

sidekiqとは

sidekiqとは、非同期処理を可能にしてくれるライブラリです。複数のジョブを同時に実行させる時などに、各ジョブのqueueの名称を分けることで、処理の優先順位を指定することができます。似たようなライブラリにresqueやdelayed_jobなどがあるかと思います。
簡単に導入できるのですが、つまづいてしまったキューをデフォルトで25回だか26回だかリトライするとか、その後はDEADとなって実行していたキューのログが見られないなどといった面倒な点もあります。
そこでこの記事では、例外を投げた時などにいつまでもリトライせず上限を設定してDEADとし、その際にslackにキューの内容とエラーメッセージを投げるという設定をする方法についてお話しします。

環境

Ruby 2.6.6
Rails 6.0.2
sidekiqにはredisが必要になります。

# On OSX
brew update
brew install redis
brew services start redis

失敗したキューをダッシュボードで確認する

gemにsidekiq-failuresを追加することでダッシュボードで確認することができ、失敗したキュー全てをリトライさせることもできます。

gem 'sidekiq-failures'

image.png

failuresの一覧でもエラーの詳細が確認できます。
image.png

他にも投げられたキューを知る&分析するなどでたくさんgemがあるようですので参考までに載せておきます

リトライの上限を設定する

sidekiqは確かデフォルトで25,6回程度リトライをしてからキューを殺すといった仕様になっていたかと思います。
そこで、たくさんのジョブを一気に処理させる時など、そこまでリトライしなくていいからダメになった何度かチャレンジしてダメになったら教えて・・・という人のために、リトライの上限をjobファイルに記載します。

app/jobs/your_job.rb
class YourJob < ActiveJob::Base
  ...
  queue_as :default
  sidekiq_options retry: 5
  ...
end

これで5回トライしてダメだったキューはDEADキューとなります。

キューの死亡をslackで通知

Railsアプリにおいてslack通知をとても簡単にしてくれるgemがslack-incoming-webhooksです。

gem 'slack-incoming-webhooks'

通知させるチャネルのURL取得はこのページを確認してください。

initializerでキューが死亡した場合の処理を設定(チャネルのURLは.envに保存します)

app/config/initializers/sidekiq.rb
Sidekiq.configure_server do |config|
  config.death_handlers << ->(job, ex) do
    slack = Slack::Incoming::Webhooks.new(ENV['SLACK_WEBHOOK_URL'])
    attachments = [{
      title: "Sidekiq failure",
      text: "ONE DEAD JOB IS FOUND:\n (#{job['args']}) \n msg(#{job['error_message']})",
      color: "#fb2489"
    }]
    slack.post "", attachments: attachments
  end
end

これで自然とDEADになってしまったキューはslack通知されるようになります。
image.png

注意点

  • sidekiqのダッシュボード上でキューを殺しても通知は来ない
    config.death_handlersに通知の設定をする場合、ダッシュボード上でマニュアルにキューを死亡させた場合には通知が来ません。なのでリトライ上限の5回を超えた場合にのみ通知が来るようになります。

  • rescure_from Exceptionで通知設定するとリトライしてくれない
    例外処理なので一度ジョブを処理してエラーとなると死亡と看做され、slack通知はしてくれますがリトライはしてくれません。なんらかの事情で処理されずそれでもリトライして欲しい場合には、上記の通りconfig.death_handlersでslack通知の設定をおすすめします。

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

sidekiqのリトライ上限を設定して死んだjobをslackで通知する方法

はじめに

非同期でjobを処理してくれるsidekiqを導入する中で、利便性を生かしつつも自分のアプリ専用にカスタマイズしたい、そんな時に役に立った設定をまとめています。

sidekiqとは

sidekiqとは、非同期処理を可能にしてくれるライブラリです。複数のジョブを同時に実行させる時などに、各ジョブのqueueの名称を分けることで、処理の優先順位を指定することができます。似たようなライブラリにresqueやdelayed_jobなどがあるかと思います。
簡単に導入できるのですが、つまづいてしまったキューをデフォルトで25回だか26回だかリトライするとか、その後はDEADとなって実行していたキューのログが見られないなどといった面倒な点もあります。
そこでこの記事では、例外を投げた時などにいつまでもリトライせず上限を設定してDEADとし、その際にslackにキューの内容とエラーメッセージを投げるという設定をする方法についてお話しします。

環境

Ruby 2.6.6
Rails 6.0.2
sidekiqにはredisが必要になります。

# On OSX
brew update
brew install redis
brew services start redis

失敗したキューをダッシュボードで確認する

gemにsidekiq-failuresを追加することでダッシュボードで確認することができ、失敗したキュー全てをリトライさせることもできます。

gem 'sidekiq-failures'

image.png

failuresの一覧でもエラーの詳細が確認できます。
image.png

他にも投げられたキューを知る&分析するなどでたくさんgemがあるようですので参考までに載せておきます

リトライの上限を設定する

sidekiqは確かデフォルトで25,6回程度リトライをしてからキューを殺すといった仕様になっていたかと思います。
そこで、たくさんのジョブを一気に処理させる時など、そこまでリトライしなくていいからダメになった何度かチャレンジしてダメになったら教えて・・・という人のために、リトライの上限をjobファイルに記載します。

app/jobs/your_job.rb
class YourJob < ActiveJob::Base
  ...
  queue_as :default
  sidekiq_options retry: 5
  ...
end

これで5回トライしてダメだったキューはDEADキューとなります。

キューの死亡をslackで通知

Railsアプリにおいてslack通知をとても簡単にしてくれるgemがslack-incoming-webhooksです。

gem 'slack-incoming-webhooks'

通知させるチャネルのURL取得はこのページを確認してください。

initializerでキューが死亡した場合の処理を設定(チャネルのURLは.envに保存します)

app/config/initializers/sidekiq.rb
Sidekiq.configure_server do |config|
  config.death_handlers << ->(job, ex) do
    slack = Slack::Incoming::Webhooks.new(ENV['SLACK_WEBHOOK_URL'])
    attachments = [{
      title: "Sidekiq failure",
      text: "ONE DEAD JOB IS FOUND:\n (#{job['args']}) \n msg(#{job['error_message']})",
      color: "#fb2489"
    }]
    slack.post "", attachments: attachments
  end
end

これで自然とDEADになってしまったキューはslack通知されるようになります。
image.png

注意点

  • sidekiqのダッシュボード上でキューを殺しても通知は来ない
    config.death_handlersに通知の設定をする場合、ダッシュボード上でマニュアルにキューを死亡させた場合には通知が来ません。なのでリトライ上限の5回を超えた場合にのみ通知が来るようになります。

  • rescure_from Exceptionで通知設定するとリトライしてくれない
    例外処理なので一度ジョブを処理してエラーとなると死亡と看做され、slack通知はしてくれますがリトライはしてくれません。なんらかの事情で処理されずそれでもリトライして欲しい場合には、上記の通りconfig.death_handlersでslack通知の設定をおすすめします。

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

特殊変数$1, $2, $3 ... で巨大な整数を使おうとすると、警告が表示される

Rubyには、$1, $2, $3 ...という特殊変数があり、$nには最後に成功したパターンマッチで n 番目の括弧にマッチした値が代入されます。

"abc" =~ /(.)(.)(.)/
p $1 #=> "a"
p $2 #=> "b"
p $3 #=> "c"

2020/09/26現在のるりまには

番号 n はいくらでも大きな正整数を利用できます。

とありますが、実際には超巨大な値を使おうとすると、warningが表示されます (遊んでいるときに気が付いた)

$ ruby -e '$9999999999999999'
-e:1: warning: `$9999999999999999' is too big for a number variable, always nil

こうなると$nのnとしてどれだけの値が使えるのか気になってくるので、簡単な二分探索を使った以下のコードで調べてみたところ、自分の環境では最大値は1073741823のようでした。

require 'stringio'

ok = 0
ng = 10**10

while (ok-ng).abs > 1
  io = StringIO.new
  $stderr = io

  mi = (ok+ng)/2
  eval("$#{mi}")
  if io.size == 0
    ok = mi
  else
    ng = mi
  end

  $stderr = STDERR
end

p ok #=> 1073741823

別の方法で確認してみても、$1073741823が最大で、それよりも大きい値になると警告がでるようです。ただ1073741823という値はいかにも環境依存っぽいので、環境によってはもっと大きい値まで使えるかもしれませんし、もっと小さい値で警告が出てくるかもしれません。

$ ruby -e '$1073741823' 
#=> 何も起きない

$ ruby -e '$1073741824'
#=> 警告が出力される
#=> -e:1: warning: `$1073741824' is too big for a number variable, always nil

当然の疑問として、キャプチャ数が1073741823個を超える正規表現でマッチが成功した場合どうなるのかということですが、これは無問題。Rubyではキャプチャ数の上限が32767と決まっており、それを超えるような正規表現はコンパイルに失敗します。

$ ruby -e 'Regexp.compile("(.)"*32767)' 
#=> 何も起きない

$ ruby -e 'Regexp.compile("(.)"*32768)'
#=> RegexpErrorが発生する。メッセージは次の通り
#=> `initialize': too many capture groups are specified:

自分は以下のような二分探索を用いた簡単なスクリプトで32767という値を見つけましたが、Rubyの正規表現エンジンである鬼雲のソースコードを見ると、ONIG_MAX_CAPTURE_GROUP_NUMというキャプチャ数の上限を示す変数があって、これが32767になっているようです。 であれば、特殊変数$1, $2, $3 ...の側の最大値を32767にしてもよいような気はしますが(´・ω・`)

ok = 0
ng = 10**8

while (ok-ng).abs > 1
  mi = (ok+ng)/2
  begin
    Regexp.compile("(.)"*mi)
    ok = mi
  rescue RegexpError => e
    ng = mi
  end
end

p ok #=> 32767

環境情報

$ ruby -v
ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-linux]
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

FizzBuzz問題の備忘録

昨日のドリルで登場したFizzBuzz問題。

模範回答としては、

def fizz_buzz
  num = 1
  while num <= 100 do
    if num % 15 == 0
      puts "FizzBuzz"
    elsif num % 3 == 0
      puts "Fizz"
    elsif num % 5 == 0
      puts "Buzz"
    else
      puts num
    end

    num = num + 1
  end
end

fizz_buzz

というのが正解だったけど、
rubocopを使ったところ、

def fizz_buzz
  num = 1
  while num <= 100
    if (num % 15).zero?
      puts 'FizzBuzz'
    elsif (num % 3).zero?
      puts 'Fizz'
    elsif (num % 5).zero?
      puts 'Buzz'
    else
      puts num
    end
    num += 1
  end
end

fizz_buzz

と言う形で、
数式を()で括り「その数値が0か否か」を判断する、
zero?メソッドを使った別の記述が(偶然だけど)できた。

rubocop的にはやはり、
可能な限りスッキリと整頓した記述がいいんだろうな。

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

【Ruby】getsメソッドの注意点

標準入力からの文字列との比較処理を行ったところ、なぜかうまく行かなかったので
その原因と解決策を備忘録として記載します。

問題点

getsメソッドは標準入力からの文字列を受け取るためのメソッドです。
このメソッドを利用して取得した入力文字列と別の文字列を比較しようとすると
思い通りの結果が得られませんでした。

input = gets # hogeを入力
bool = (input == 'hoge')
print bool 
false

同じ値の文字列同士を比較してるはずなのになぜかfalseが返ってきました。

原因

調べたところ、どうやらgetsメソッドは標準で末尾に改行コード(\n)を追加するみたいです。

input = puts # hogeを入力
p input
"hoge\n"

改行コードが含まれている状態で比較しようとしていたので、比較しても弾かれてたみたいです。

解決策

末尾の改行コードを削除すればよさそうなので調べてみたところ、
そのためのメソッドとしてchompメソッドというのがあり、
こちらを利用したら、期待した結果が得られました!

input = gets.chomp # hogeを入力
bool = (input == 'hoge')
print bool 
true

補足

chompは何かの略称かなと思って調べてみたところ、teratailでの回答が参考になりました。
chompってなんの略?

推測をかなり含んでいますが
もともと、chopというのがあり末尾1文字を消す事ができました。
テキストファイルの末尾は改行で終わるのが(Unixの)マナーだったのでこれで問題なかったのですが
末尾に改行がついてないことや1文字でない環境もあったりと問題になり
「末尾の改行を削除する」関数が追加されchopのmultiline用だからchompになりました。

chopを末尾1文字から改行コード削除用にしたのが、chompメソッドみたいです。

参考

https://stackoverflow.com/questions/21504202/why-is-stringchomp-named-like-this

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

バリデーションメッセージを Decorator で加工する

のっぴきならない事情があり、フォームの入力パターンに応じて、バリデーションメッセージを生成後に加工したかったのでメモ。
例えば、下記のようなフォームがあったとする。

new.slim
= form_for post_form, url: confirm_post_path do |f|
  - if post_form.errors.present?
    ul
      - post_form.errors.full_messages.each do |msg| 
        li = msg

しかし、フォーム内の特定の選択肢を選んだ場合に、バリデーションメッセージを変えるという要件が加わったとする。
この場合、errors.full_messages は Array なので、Decorator で中身を1件ずつチェックして力技で置換した。

new.slim
= form_for post_form, url: confirm_post_path do |f|
  - post_form_decorator = ::PostFormDecorator.new(f.object)
  - if post_form.errors.present?
    ul
      - post_form_decorator.post_error_display(post_form.errors.full_messages).each do |msg|
        li = msg
post_form_decorator.rb
class PostFormDecorator
  delegate_missing_to :@post_form

  def initialize(post_form)
    @post_form = post_form
  end

  def post_error_display(error_full_messages)
    error_full_messages.each do |msg|
      if @post_form.category == 'music'
        msg.gsub!(/#{@post_form.model.class.human_attribute_name(:author)}/, '歌手')
      end
    end
  end
end

破壊的メソッドで中身を入れ替えているので、「!」を付けなければgsubで置換されないので注意。

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

(Ruby on Rails6) 投稿された内容を"消去" する

まえがき

ここでは、RubyonRails6を使用して、投稿内容を 編集(内容の消去) を行う忘却録を記録します。
以前の投稿で 編集機能の実装 を行いました。編集機能の実装はそちらで記録しているので確認されたい方は、そちらでご確認ください。

投稿された内容を"消去" する

この投稿を実装するためには、アクションデータの消去(クリック)・投稿一覧への転送 を行います。

routes の設定

routes に deleteアクション を作成します。
form/:id/delete で、消去したいidのURLを特定させています。
また、データベースを変更する場合はroutes上で "get" ではなく "post" で設定します。

config/routes



post "form/:id/delete" => "form#delete"

View へのリンク設定

app/views/任意.html.erb
・
・
・
<%= link_to("削除", "/form/#{@post.id}/delete", {method: "post"}) %>

link_to を用いて、先ほど作成した deleteアクション へリンクしています。

注意: get と post の違い

{method: "post"}) をつけることで、routesのpostと紐づけることができます。
ややこしい!!

app/views/任意.html.erb
postでは↓エラー
<%= link_to("削除", "/form/#{@forms.id}/delete") %>

↓が正しい
<%= link_to("削除", "/form/#{@forms.id}/delete", {method: "post"}) %>

データを取り出して削除する

app/controllers/任意.rb
  def delete
    @forms = Form.find_by(id: params[:id])
    @forms.destroy

    redirect_to("/")
  end

↑の詳細

app/controllers/任意.rb
  def delete
    # find_byメソッドで、データを取得する
    @forms = Form.find_by(id: params[:id])
  end
app/controllers/任意.rb
  def delete
    # @テーブル名.destroy で削除する
    @forms.destroy
  end
app/controllers/任意.rb
  def delete
    # redirect_toメソッド でリダイレクトを設定する
    redirect_to("/")
  end

以上が、完了しエラーが怒らなければ、削除機能が出来上がっているはずです。
いかがでしたか?

あとがき

ここまで読んでいただき、ありがとうございました。
データベースの設定から表示・修正の機能を実装していて、投稿に削除機能をつけると本格的なサイトみたいですね。
でも、投稿機能が無事に削除された時は嬉しいけど切ない気持ちになります(Why?)

データーベースの作成・編集・デリート と基本機能を今までで実装しました。
セキュリティーや詳細機能を今後は学びたいと思います。

参考リンク

Ruby on Rails6 実践ガイド

Myリンク

また、Twitter・Portfolio のリンクがありますので、気になった方は
ぜひ繋がってください。プログラミング学習を共有できるフレンドが出来るととても嬉しいです。

Twitter
Portfolio
Github

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

CodeWarでの勉強(ruby)②

この記事について

最近始めたCodewarを通じて学べたことを少しずつアウトプット

問題

An isogram is a word that has no repeating letters, consecutive or non-consecutive. Implement a function that determines whether a string that contains only letters is an isogram. Assume the empty string is an isogram. Ignore letter case.

引数で渡された文字列がアイソグラムであるかどうかチェックをするメソッドを作りなさい。
ただし、大文字・小文字は無視する。
※アイソグラムとは、同じアルファベットが使用されていない文字のこと。

is_isogram("Dermatoglyphics" ) == true
is_isogram("aba" ) == false
is_isogram("moOse" ) == false # -- ignore letter case

僕が考えた回答

def is_isogram(string)
  string = string.downcase.chars
  if string == string.uniq
    return true
  else 
    return false
  end
end

①引数で渡された文字列をまずはdowncaseで全て小文字にして、charsで各文字を配列にいれる。
②配列に入れられた各文字と、uniqメソッドで重複した文字を排除した配列が同じであればtrueを返す
③配列が異なればfalseを返す。

理想の答え

def is_isogram(string)
  string.downcase.chars.uniq == string.downcase.chars
end

わざわざ条件分岐をしなくても==でtrueとfalseを返してくれるんやな。。。。

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

CodeWarでの勉強②

この記事について

最近始めたCodewarを通じて学べたことを少しずつアウトプット

問題

An isogram is a word that has no repeating letters, consecutive or non-consecutive. Implement a function that determines whether a string that contains only letters is an isogram. Assume the empty string is an isogram. Ignore letter case.

引数で渡された文字列がアイソグラムであるかどうかチェックをするメソッドを作りなさい。
ただし、大文字・小文字は無視する。
※アイソグラムとは、同じアルファベットが使用されていない文字のこと。

is_isogram("Dermatoglyphics" ) == true
is_isogram("aba" ) == false
is_isogram("moOse" ) == false # -- ignore letter case

僕が考えた回答

def is_isogram(string)
  string = string.downcase.chars
  if string == string.uniq
    return true
  else 
    return false
  end
end

①引数で渡された文字列をまずはdowncaseで全て小文字にして、charsで各文字を配列にいれる。
②配列に入れられた各文字と、uniqメソッドで重複した文字を排除した配列が同じであればtrueを返す
③配列が異なればfalseを返す。

理想の答え

def is_isogram(string)
  string.downcase.chars.uniq == string.downcase.chars
end

わざわざ条件分岐をしなくても==でtrueとfalseを返してくれるんやな。。。。

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

macOS で Ruby 3.0.0-preview1 をインストール(Homebrew の ruby-build を使わない方法も)

はじめに

Ruby 3.0.0 Preview 1 がリリースされました。
https://www.ruby-lang.org/en/news/2020/09/25/ruby-3-0-0-preview1-released/

型システム(という呼び方でいいのかしらん?)とか,並行プログラミングをサポートする Ractor だとか,超目玉機能が試せます。

macOS だと Homebrew で rbenv と ruby-build の二つのパッケージを入れて Ruby をインストールしている人が多いと思います。
本記事の読者はそういう方を念頭に置いています。

インストール その(1)

今回,3.0.0 Preview 1 がリリースされて速攻1で ruby-build が更新されたので,

brew update
brew upgrade ruby-build
rbenv install 3.0.0-preview1

とすれば OK。

インストール その(2)

ところが,Homebrew の ruby-build は,対応する Ruby がリリースされてすぐに更新されるとは限りません。
今回はたいへんありがたいタイミングでしたが,3.0.0-dev の場合はリリースされてもなっかなか入らず,結局 3.0.0-preview1 と同時に入ったのでした。

こういう場合,Homebrew の ruby-build パッケージを使わない方法があると Slack の ruby-jp で教えていただきました。

試してみたので,その方法を書きます。

まず,現状では Homebrew で rbenv と ruby-build が入っているので,ruby-build のほうをアンインストールします。
しかし,単純に

brew uninstall ruby-build

とやると,

Error: Refusing to uninstall /usr/local/Cellar/ruby-build/20200926
because it is required by rbenv, which is currently installed.
You can override this and force removal with:
  brew uninstall --ignore-dependencies ruby-build

とエラーが出て実行できませんでした。
(なお,消そうとしたヤツが「20200926」と最新になっているのは,brew upgrade したあとでこれを行ったからです)

そこで,上記のメッセージに書かれているとおり,

brew uninstall --ignore-dependencies ruby-build

とやってアンインストールしました。

次に,ruby-build を GitHub のリポジトリーからクローンします。
ruby-build は(単体でも使えるそうですが)rbenv と組み合わせる場合は,rbenv のプラグインとして働くよう,プラグイン置き場に置く必要があります。

典型的には,それはホームディレクトリーの .rbenv/plugins という場所です(Homebrew で ruby-build を入れた場合はこの場所にはありません)。
つまり,~/.rbenv/plugins ですね。

しかし,典型的でないケースもありうるので,確実に場所を把握したいところ。

rbenv root

plugins ディレクトリーの親ディレクトリーが表示されるので,以下の手順ではこれを利用します。

まず,plugins ディレクトリーは存在するとは限らないので,

mkdir -p "$(rbenv root)"/plugins

とやってディレクトリーを作ります。既に存在していたとしても問題は生じません。

そして,

git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build

とやると,しかるべき場所に最新の ruby-build がクローンされます。

この状態で

rbenv install 3.0.0-preview1

とすると,3.0.0 Preview1 がインストールされます!
説明が長かったけど,やるべきことは単純ですね。四箇所コピペするだけでした。

将来,新しい Ruby がリリースされたら

git -C "$(rbenv root)"/plugins/ruby-build pull

で ruby-build を最新版にすればそれがインストールできます。

このへんのことは ruby-build の README にちゃんと書いてあります。

コピペ用まとめ

Homebrew で rbenv と ruby-build がインストールされている環境で,Homebrew 版の ruby-build をアンインストールしてから Ruby 3.0.0-preview1 をインストールするまでの全手順を,コピペしやすいよう,ここにまとめました。

Homebrew 版の ruby-build をアンインストール:

brew uninstall --ignore-dependencies ruby-build

GitHub から ruby-build をクローン:

mkdir -p "$(rbenv root)"/plugins
git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build

Ruby 3.0.0-preview をインストール:

rbenv install 3.0.0-preview1

クローンした ruby-build を更新:

git -C "$(rbenv root)"/plugins/ruby-build pull

さいごに

Ruby の新しい時代が始まる。さあ,扉を開こう!

え? 「うちは Windows」だって?


  1. タイムラグ 1 日くらい? 

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

Rails6.0ルーティングまとめ

はじめに

Rails6.0のルーティングのパス名 resouces resourceなどを忘備録を兼ねてまとめます。

明示的なルーティング指定

routes.rb
# ルートへアクセスするルーティング
root 'users#show'
root to 'users#show'
root '/', to: 'users#show'
routes.rb
# '/users/:id'でusersコントローラのshowアクションにルーティング
get '/users/:id', to: 'users#show'
routes.rb
# 'hoge'でusersコントローラのshowにルーティング
# as:オプションを使うとルーティングに名前を指定可能
get '/users/:id', to: 'users#show', as: 'hoge'

<%= form_with %><%= link_to %>などでurlを指定する際に、直接/posts/:idなどのurlのように指定可能ですが、変更の際に修正箇所が多くなり得策ではありません。
as:で名前を付けることで、修正しやすくなり、コードも読みやすくなります。

resourcesとresouceの違い

resources(複数)...7つのアクションがid付きで生成されます。
resource(単数) ...indexアクションを除いた6つのアクションがidなしで生成されます。
「写真」「ユーザー」「商品」のようにアプリケーションに複数存在する場合はresources(複数)
「自身のプロフィール」のように一つしか存在せず、idやindexが必要ない場合はresource(単数)

resources(複数)

routes.rb
resources :photos

のような記述で、以下の7つのルーティングが生成されます。この場合、いずれもPhotosコントローラに対応します。

動詞 パス コントローラ#アクション 目的
GET /photos photos#index すべての写真の一覧を表示
GET /photos/new photos#new 写真を1つ作成するためのHTMLフォームを返す
POST /photos photos#create 写真を1つ作成する
GET /photos/:id photos#show 特定の写真を表示する
GET /photos/:id/edit photos#edit 写真編集用のHTMLフォームを1つ返す
PATCH/PUT /photos/:id photos#update 特定の写真を更新する
DELETE /photos/:id photos#destroy 特定の写真を削除する

resource(単数)

routes.rb
resource :geocoder

以上の記述で以下の6つのルーティングが生成されます。この場合、いずれもgeocoderに対応します。

動詞 パス コントローラ#アクション 目的
GET /geocoder/new geocoders#new geocoder作成用のHTMLフォームを返す
POST /geocoder geocoders#create geocoderを作成する
GET /geocoder geocoders#show 1つしかないgeocoderリソースを表示する
GET /geocoder/edit geocoders#edit geocoder編集用のHTMLフォームを返す
PATCH/PUT /geocoder geocoders#update 1つしかないgeocoderリソースを更新する
DELETE /geocoder geocoders#destroy geocoderリソースを削除する

注意点

Railsのルーティングはルーティングファイルの上から順に実行します。そのため、同じ条件のルーティングが複数存在する場合、上のルーティングのみ有効になります。なお、無関係なURLの場合は順番は関係ありません。

参考

Railsのルーティング - Railsガイド v6.0
https://railsguides.jp/routing.html

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

Ruby on RailsにてRails new〜デプロイまでの忘備録1

Ruby on RailsにてRails new〜デプロイまでの忘備録です!

何回かに分けて、Rails newコマンドでアプリケーション作成からデプロイまでの一連をつらつらと書いていきます。
1回目は、Railsアプリケーション雛形作成からリモートリポジトリへpushまで書いていきます。

足りない点や間違っている点があったら、教えていただけると嬉しいです。

※Ruby,Rails,GitはPCにインストール済みを想定します。
GitHubもリポジトリの作成等の説明は省きます。

環境

開発環境
言語:Ruby 2.5.1
FW:Ruby on Rails 5.2.4
DB:PostgreSQL
test:RSpec
バージョン管理:Git,GitHub

環境:MacBookAir
※VirtualBox,Docker等の仮想環境はRailsの基礎を重視するために導入しませんでした。
デプロイ先:heroku
AWSも環境と同じ理由で導入しませんでした。

Railsアプリ作成

Rails newコマンドを使ってアプリケーションのディレクトリを作成しましょう!

ターミナル.
rails new <App_name> -option

実際に私はDBにPostgreSQLを使用したかったので下記のようなコマンドを入力して、最初にアプリケーションに組み込みました。(後でも変更可能です)

ターミナル.
rails new App_name -d postgresql

そうするとRailsアプリケーションに必要なディレクトリがスルスル作られます。

作成後、今いるディレクトリから先ほど作成したディレクトリにcdコマンドで移動します。

ターミナル.
 cd App_name

さて、DBを作成しておきましょう!

ターミナル.
 rails db:create

これでDBが作成されます。

ターミナル.
 rails s

Railsのサーバーを立ち上げ
http://localhost:3000
にブラウザからアクセス!

正しくサーバーが立ち上がったのが確認できましたか?
ちなみに終了はcontrol + c で終了できます。

Git管理を始める

Gitを使い始めましょう!

ターミナル.
git init

これでGit管理する準備は整いました。
Git関連ディレクトリは、隠しディレクトリとして設定されているので、command + shift + . で可視化しておいてもいいかも知れません

作ったアプリケーションをステージングする
私は大体、ステージングの前にステータス(git status)や差分(git diff)の確認を行っていますが割愛します。(変更されたファイルの状態を確認すること)

ターミナル.
git add .

add .(ドット)で全ての変更されたファイルをステージングします。
この場合はRails newで作成された全ファイルですね!

ターミナル.
git commit -m "first commit"

上のコマンドで、変更を記録します!
commitの後ろの -m はオプションであり、コメントを残すためのオプションです!
commitする際は必ずコメントを残すことが決められているので、コメントはどういう変更したのかが理解できるように追加しましょう

次はリモートリポジトリへpush!

GitHubにリモートリポジトリを作成したら

ターミナル.
git push

と打つと怒られます。
要はリモートリポジトリの接続先が分からないので教えてあげます。
(怒られついでに下記のコマンドを入力するように求められます)

ターミナル.
git remote add <name> <url>

実際のコマンドっぽく書くと↓

ターミナル.
git remote origin https://github.com/×××

これでOK
あとは下記のコマンドでpushされる。

ターミナル.
git push -u origin master

初回だけは上記のコマンドを使用するが2回目以降はgit pushだけでOK!
ブランチを切ったりする場合も同じです。

今回はここまでとします。
あくまで、自分用の忘備録として書いていますが、
ご覧いただきありがとうございました!

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

Safari で disable_with オプションを付けても変わらない場合

Railsでフォームを作る際、送信ボタンに disable_with オプションを付けることで、二重送信を防ぐことができる。

= f.button '送信する', data: { disable_with: '送信中…' }

しかし、Safariに限って、なぜかボタンの文言が変化しなかった。GitHub上でも、多々報告されている。
disable_with doesn't work with link in Safari #306

解決策

結論から書くと、JSで送信処理をあえて遅らせることで、とりいそぎは回避できた。
Issue内ではバニラJSで書かれた例が出てくるので、jQueryを使っていなけば、そちらを参考にした方が早いかもしれない。

= f.button '送信する', data: { disable_with: '送信中…' }, class: 'disable_with_safari'
$('.disable-with-safari').click(function (event) {
  if ($(this).data('disableWith')) {
    $(this).prop('disabled', true);
    $(this).text($(this).data('disableWith'));
    var form = $(this).closest('form');
    if (form.length) {
      event.preventDefault();
      setTimeout(() => form.submit(), 300);
    }
  }
});

備考

冒頭のIssueでも議論されていたが、Safariの独特な仕様で、一度submitが走った後はDOMの更新が行われなくなるようだ。(あくまでもIssue上でのコメントなので、正確な仕様は一次情報を参照してください)
そのため、disable_withをつけても、ボタンの文言は変わらなかった。

ちなみに、今回の問題について検索すると以下の解決策が出てきていたが、わたしの場合は効果がなかった。

  • cursor: pointer; をつける
  • 空のclickイベントを設定する
  • 空のtouchstartイベントを設定する
  • バインドを$(document)に変更する
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む