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

link_toメソッドのクリックできる部分を拡大させたい

はじめに

link_toメソッドを使って、ページ遷移をしているが、クリックできる部分が文字のところだけだったことに不満を感じたので、調べて実装しました。

CSSでブロック要素に変えて、padding

link_toメソッドにクラス名をつけます。
つける時はclass: "クラス名"
そのクラス名に対して、CSSでdisplay: block;のスタイルをつけます。
さらに、paddingで範囲を広げると、クリックできる部分が拡大します。

ちなみに、marginしてもクリックできる部分は広がりません。

erb
<ul>
  <li class="menu-list">
    <%= link_to 'マイページ', hoge_path, class: "menu-name" %>
  </li>
  <li class="menu-list">
    <%= link_to 'カレンダー', hoge_path, class: "menu-name" %>
  </li>
</ul>
css
.menu-list {
  margin: 30px auto;
  border: black 3px solid;
  padding: 0px;
}
.menu-name {
  display: block; 
  padding: 30px;
}

display: block;とpaddingが大事な部分です。

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

carrierwaveでpdfファイル投稿機能をつける

はじめに

前回書いた記事でも触れたのですが、carrierwaveを用いてRailsアプリにpdf投稿機能をつけたのでその際に行った手順を備忘録として残しておきます。

carrierwaveの導入

gemfileに、下の1行を加えてbundle installします。

gemfile
gem 'carrierwave'

dbにfileカラムを追加

今回、送信されたデータをdbに保存するために、元々作っていたpostsテーブルにfileカラムを追加しました。マイグレーションファイルを作ってカラム追加しただけなのでコマンドは割愛します。

carrierwaveクラスの作成

carrierwaveを使うには、専用のクラスを作る必要があります。使い方の概要は以下の記事を参考にしました。
https://pikawaka.com/rails/carrierwave

以下、上記ページとほぼ同じではありますが自分が行った手順をまとめます。

bin/rails g コマンドでcarrierwaveクラスを生成

terminal
bundle exec rails g uploader アップローダー名

以下の場所 app/uploaders/アップローダー名_uploader.rb に作られた設定ファイルで次のように記述します。

app/uploaders/アップローダー名_uploader.rb
class アップローダークラス < CarrierWave::Uploader::Base
  #保存場所の設定
  storage :file

  #保存するフォルダの設定
  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end
end

今回はpublic配下のuploadsフォルダ内に投稿されたpdfファイルを保存します。デプロイの際は外部のストレージサービスへの指定にしたりもできるようです。

アップローダークラスとモデルの紐付け

クラスと関連づけたいモデルで、以下の記述をします。

モデル名.rb
class モデル名 < ActiveRecord::Base
  mount_uploader :関連付けたいカラム名, アップローダークラス
end

フォームにfile_fieldを追加&dbに保存

パラメーターでfile_fieldの情報をfileカラムに保存するようにしました。(保存場所はご自分の任意の保存したいカラムで構いません)コントローラーでいつも通り記述するだけなので割愛します。

viewで表示する

viewで次の記述をします。

app/views/任意のview
<object data="<%= @post.file.url %>" type="application/pdf" width="200" height="300"></object>

@postはこのviewをレンダリングするアクションで定義したpostモデルのインスタンス変数で、fileというカラムを持っています。そこに、carrierwaveで生成したアップローダークラスが持つurlメソッドを用いて、ファイルまでのurlを指定しています。(自分で設定したモデル、カラム名に適宜置き換えてください。) width, height で表示するサムネイルのサイズを指定できます。

以上で表示できました!

終わりに

サムネイル生成の方法はobjectを使うもの以外もあるようなので気になる方は調べてみるとよいかもしれません。僕はサムネイルがなかなか実装できずcarrierwaveのエラーだと思っていたらform_withの指定ミスだったので、もし詰まっている方はそちらも確認してみるとよいかもです。

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

RubyOnRails、Authentication plugin 'caching_sha2_password' cannot be loadedエラーの解決法

RubyOnRails、Authentication plugin 'caching_sha2_password' cannot be loadedエラーの解決法

Ruby on rails 開発時に、databaseをmysql 8.0に設定してしたく、database.ymlをmysql設定の上で、rails db:migrate を実行したところ、エラー「Authentication plugin ‘caching_sha2_password’ cannot be loaded」となった時の解決法を共有します。
*laravelにも同様のエラーが発生するとの。

環境の整理

  • 開発環境:Windows10 Home 64ビットオペレーティングシステム、x64ベースプロセッサ
  • Rails version 5系
  • Mysql
    • version 8.0
    • user: root
    • password: root(=今回の例)
  • RubyOnRailsのdatabase.yml設定状況 スクリーンショット 2021-01-16 213315.png

原因

mysql 8.0以降に、認証方式がcaching_sha2_passwordを使うようになったこと。
しかし、Railsはこれに対応していなかったこと。

方法

対象のユーザーの認証方式を「caching_sha2_password」から「mysql_native_password」に変更する。
今回をuserがrootの認証方式を変更する。

  1. mysql -u root -p でmysqlにアクセスする
  2. root (今回のpassword)を入力、Enterする。
  3. SELECT user, host, plugin FROM mysql.user; でユーザー一覧を表示させ、確認する。

    • root の認証方式が「caching_sha2_password」だ 111.png
  4. ALTER USER root IDENTIFIED WITH mysql_native_password BY 'root'; を実行する。

    • 構文:ALTER USER ユーザー名 IDENTIFIED WITH mysql_native_password BY 'password';
  5. SELECT user, host, plugin FROM mysql.user; でrootの認証方式が変更されていることを確認する。
    222.png

  6. exit でmysqlから抜ける

  7. rails db:migrate で本題のrailsのmigrateコマンドを実行する。

  8. エラーなく完了された。
    333.png

*補足:
my.ini(macだとmy.cnf)にて、
default_authentication_plugin=caching_sha2_password

default_authentication_plugin=mysql_native_password
に変更すると、エラーが消えるとの話もあったが、
変更したあとでmysqlを再起動しても変更されなかった。
ちなみに、my.iniの場所は「C:\ProgramData\MySQL\MySQL Server 8.0」である。

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

formオブジェクトでタグ付け機能を実装

実装の流れ


tagモデルと中間テーブルを作成

投稿とタグは多対多の関係になるため、中間テーブルを作成します。

投稿のモデルを作成します。

$ rails g model item name:string user:references

タグモデルを作成します。

$ rails g model tag word:string

中間テーブルを作成します。

$ rails g model item_tag_relation item:references tag:references 

マイグレーションファイルを確認します。

db/migrate/create_items.rb
class CreateItems < ActiveRecord::Migration[6.0]
  def change
    create_table :items do |t|
      t.string :name
      t.references :user, foreign_key: true
      t.timestamps
    end
  end
end
db/migrate/create_tags.rb
class CreateTags < ActiveRecord::Migration[6.0]
  def change
    create_table :tags do |t|
      t.string :word
      t.timestamps
    end
  end
end
db/migrate/create_item_tag_relations.rb
class CreateItemTagRelations < ActiveRecord::Migration[6.0]
  def change
    create_table :item_tag_relations do |t|
      t.references :item, foreign_key: true
      t.references :tag, foreign_key: true
      t.timestamps
    end
  end
end

unique: trueで同じタグ名を登録しないようにできますが、うまく実装できなかったので別の方法で一意性を持たせました。

$ rails db:migrate

モデルの関連付けとバリデーション

app/models/item.rb
class Item < ApplicationRecord
  has_many :item_tag_relations
  has_many :tags, through: :item_tag_relations, dependent: :destroy

  belongs_to :user
end

「has_many :tags, through: :item_tag_relations」の記述にによって、item_tag_relationsモデルを通してアイテムに紐づくタグを取得します。

app/models/tag.rb
class Tag < ApplicationRecord
  has_many :item_tag_relations, dependent: :destroy
  has_many :items, through: :item_tag_relations

  validates :word, uniqueness: true
end

「validates :word, uniqueness: true」の記述によって、タグの名前が重複して登録されるの防ぎます。(何故かうまく働きませんでした...)

app/models/item_tag_relation.rb
class ItemTagRelation < ApplicationRecord
  belongs_to :item
  belongs_to :tag
end

ルーティングを設定

config/routes.rb
Rails.application.routes.draw do
 root to: 'items#index'
 resources :items
end

formオブジェクトの作成

Formオブジェクトは、1つのフォーム送信で複数のモデルを更新するときに使用するツールです。自分で定義したクラスをモデルのように扱うことができます。

modelsディレクトリ配下に「app/models/item_tag.rb」ファイルを作成します。

app/models/item_tag.rb
class ItemTag
  include ActiveModel::Model
  attr_accessor :name, :user_id, :item_id, :tag_ids
end

 ActiveModel::Modelをincludeすることで、そのクラスのインスタンスはActiveRecordを継承したクラスのインスタンスと同様に form_with や render などのヘルパーメソッドの引数として扱えたり、バリデーションの機能が使えるようになります。

 attr_accessorで使用したいカラム名をセットします。

 続いて、フォームからパラメーターとして送られてきた情報をテーブルに保存する処理を追加します。

app/models/item_tag.rb
class ItemTag
  include ActiveModel::Model
  attr_accessor :name, :user_id, :item_id, :tag_ids

  def save
    @item = Item.create(name: name, user_id: user_id)
    tag_list = tag_ids.split(/[[:blank:]]+/).select(&:present?)
    tag_list.each do |tag_name|
      @tag = Tag.where(word: tag_name).first_or_initialize
      @tag.save
      unless ItemTagRelation.where(item_id: @item.id,tag_id: @tag.id).exists?
        ItemTagRelation.create(item_id: @item.id, tag_id: @tag.id)
      end
    end
  end
end

 アイテムの情報を保存し「@item」という変数に代入しています。


 tag_list = tag_ids.split(/[[:blank:]]+/).select(&:present?)は入力フォームのf.text_fieldから送られたタグをtag_idsとしてparamsで送信します。

 そして、split(/[[:blank:]]+/)によってtag_ids内の文字列を空白で区切り、バラバラの単語にして配列に入れていきます。
 
 最後に、select(&:present?)は、配列化した値をそれぞれpresent?メソッドで判定して、真であれば取り出します。


@tag = Tag.where(word: tag_name).first_or_initializeで新規タグか既存タグかの判別をします。

判別をして既存タグなら既存のidを使用。新規ならidを生成します。


 unless ItemTagRelation.where(item_id: @item.id,tag_id: @tag.id).exists?は今回重複したタグを保存できないようにしたかったのですが、バリデーションやマイグレーションファイルに一意性を持たせても保存されてしまったので、苦肉の策でモデルにて対処しました。

 ItemTagRelation.where(item_id: @item.id,tag_id: @tag.id).exists?で、中間テーブルであるitem_tag_relationモデルの投稿に対して、同じ名前のタグが存在していないかを.exists?で判定しています。
 
 タグが重複した場合はtureになるのでunlessで条件式をかけています。


controllerの処理

$ rails g controller items
app/controllers/items_controller.rb
  def new
    @item = ItemTag.new
  end

  def create
    @item = ItemTag.new(itemtags_params)
    if @item.valid?
      @item.save
      redirect_to items_path(@item)
    else
      render :new
    end
  end

 private

  def itemtags_params
    params.require(:item_tag).permit(:name, :text, :image, :tag_ids).merge(user_id: current_user.id)
  end

formオブジェクトに対してnewメソッドを使用しています。


viewの作成

関連する所のみ記述します。

app/views/items/new.html.erb
<%= form_with model: @item, url: items_path, local: true do |f| %>
  <%= f.text_field :tag_ids %>
<%= f.submit "投稿する" %>

tag_idsはitemモデルで「 has_many :tags, through: :item_tag_relations」の関連付けをすることよってアイテムオブジェクトに使用できるようになります。

ひとまずこれで、タグ付け機能を実装できます。

参考にさせていただいた記事

【Ruby on Rails】タグ検索機能を実装してみた
https://qiita.com/E6YOteYPzmFGfOD/items/177f18e706df05f9b42e

初心者が手探りで Rails のタグ付機能を gem なしで実装してみる
https://qiita.com/ryutaro9595/items/042a1ec713c8c1f2c1d6

rails 投稿記事にタグをつける機能を実装する。
https://shirohige3.hatenablog.com/entry/2020/11/08/013327

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

【CircleCI2.0】JavaScript に対応するように設定

はじめに

CircleCI で JavaScript を扱えるように設定しました。
今まで問題なく動作していた CircleCI のテストでしたが、あることをしてから通らなくなったので対処方法を記していきます。

今までの設定ファイルはこちらです。

目次

  • 環境

  • 問題

  • 原因

    • RSpecでjs: trueを使用
    • 今回 ローカル環境CircleCI環境 をあわせるために行った変更
  • 解決策

    • spec/support/capybara.rb
      • 変更前
      • 変更後
    • spec/rails_helper.rb
    • Dockerfile
    • .circleci/config.yml
    • .circleci/config.yml 全体
    • config/database.yml.ci
  • まとめ

  • おわりに

  • 参考文献

環境

  • Ruby: 2.6.6
  • Bundler: 2.0.2
  • MySQL: 8.0
  • CircleCI: 2.0

問題

SocketError: 
Failed to open TCP connection to chrome:4444 
(getaddrinfo: No address associated with hostname)
# chrome:4444へのTCP接続のオープンに失敗
SocketError: getaddrinfo: No address associated with hostname
# ホスト名に関連付けられたアドレスはありません

原因

RSpecでjs: trueを使用

RSpecで JavaScriptのテストを実装 したところローカル環境で通っていたテストがCircleCIの自動テストでは通りませんでした。
結論として、ローカル環境とCircleCIの環境の差異が原因かと思います。
ローカルではchromeコンテナを立ち上げて System Spec を通していましたが、 CircleCI の設定ファイル でも設定が必要なのでエラーが起きていました。

今回ローカル環境とCircleCI環境をあわせるために行った変更

  • chromeコンテナ から Dockerfileで chrome を追加するようにしたこと
  • Chrome使用時のURLを指定していたので削除したこと
  • CircleCI の設定ファイルChrome の追加background で使用するようにしたこと

解決策

spec/support/capybara.rb

大幅に変更したように見えますが、url を指定していないというのがポイントです。

変更前
require 'capybara/rspec'
require 'selenium-webdriver'

module CapybaraSupport
  Capybara.javascript_driver = :selenium_chrome_headless
  Capybara.default_driver    = :selenium_chrome_headless
  Capybara.register_driver :selenium_chrome_headless do |app|
    url = 'http://chrome:4444/wd/hub'
    caps = ::Selenium::WebDriver::Remote::Capabilities.chrome(
      'goog:chromeOptions' => {
        'args' => [
          'no-sandbox',
          'headless',
          'disable-gpu',
          'window-size=1680,1050'
        ]
      }
    )
    Capybara::Selenium::Driver.new(app, browser: :chrome, url: url, desired_capabilities: caps)
  end
変更後
require 'capybara/rspec'
require 'selenium-webdriver'

Capybara.register_driver :selenium_chrome_headless do |app|
  options = ::Selenium::WebDriver::Chrome::Options.new

  options.add_argument('--headless')
  options.add_argument('--no-sandbox')
  options.add_argument('--disable-dev-shm-usage')
  options.add_argument('--window-size=1400,1400')

  driver = Capybara::Selenium::Driver.new(app, browser: :chrome, options: options)
end

Capybara.javascript_driver = :selenium_chrome_headless

spec/rails_helper.rb

RSpec.configure do |config|
  config.before(:each, type: :system) do
    driven_by :rack_test
  end

  config.before(:each, type: :system, js: true) do
    driven_by :selenium_chrome_headless
  end
end

Dockerfile

ローカル環境のテストで Chrome を使用したいので DockerfileChromeの追加 をしています。
この記述を RUN mkdir /myapp の前に書きました。

RUN apt-get update && apt-get install -y unzip && \
    CHROME_DRIVER_VERSION=`curl -sS chromedriver.storage.googleapis.com/LATEST_RELEASE` && \
    wget -N http://chromedriver.storage.googleapis.com/$CHROME_DRIVER_VERSION/chromedriver_linux64.zip -P ~/ && \
    unzip ~/chromedriver_linux64.zip -d ~/ && \
    rm ~/chromedriver_linux64.zip && \
    chown root:root ~/chromedriver && \
    chmod 755 ~/chromedriver && \
    mv ~/chromedriver /usr/bin/chromedriver && \
    sh -c 'wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -' && \
    sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list' && \
    apt-get update && apt-get install -y google-chrome-stable

# ルート直下にmyappという名前で作業ディレクトリを作成(コンテナ内のアプリケーションディレクトリ)
RUN mkdir /myapp
WORKDIR /myapp

.circleci/config.yml

CircleCIの設定ファイル。Chromeを追加 することで ローカル環境との差異 をなくすようにしました。

    steps:
      - run:
          name: Chrome Driver Install
          command: |
            curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
            echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
            sudo apt-get update && sudo apt-get install -y unzip
            wget -N http://chromedriver.storage.googleapis.com/87.0.4280.88/chromedriver_linux64.zip -P ~/
            unzip ~/chromedriver_linux64.zip -d ~/
            rm ~/chromedriver_linux64.zip
            sudo chown root:root ~/chromedriver
            sudo chmod 755 ~/chromedriver
            sudo mv ~/chromedriver /usr/bin/chromedriver
            sh -c 'wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -'
            sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list'
            sudo apt-get update && sudo apt-get install -y google-chrome-stable
          background: true

.circleci/config.yml 全体

RSpecを動かすところで no_output_timeout: 15m と記述しています。
こちらはなくともテストには直接関係ないので削除しても大丈夫です。

なにも設定しなければ標準で10分の制限時間があり、それを過ぎるとタイムアウトエラーになってしまうので念の為付けております。テストの数とかにもよると思いますが、実際にはほんの数分で終わるので不要です。

version: 2

jobs:
  build:
    docker:
      - image: circleci/ruby:2.6.6-node-browsers
        environment:
          - BUNDLER_VERSION: 2.0.2
          - RAILS_ENV: 'test'
      - image: circleci/mysql:8.0
        command: [--default-authentication-plugin=mysql_native_password]
        environment:
          - MYSQL_USER: root
          - MYSQL_DB: ci_test
          - MYSQL_ROOT_HOST: "127.0.0.1"

    working_directory: ~/myapp

    steps:
      - run:
          name: Chrome Driver Install
          command: |
            curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
            echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
            sudo apt-get update && sudo apt-get install -y unzip
            wget -N http://chromedriver.storage.googleapis.com/87.0.4280.88/chromedriver_linux64.zip -P ~/
            unzip ~/chromedriver_linux64.zip -d ~/
            rm ~/chromedriver_linux64.zip
            sudo chown root:root ~/chromedriver
            sudo chmod 755 ~/chromedriver
            sudo mv ~/chromedriver /usr/bin/chromedriver
            sh -c 'wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -'
            sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list'
            sudo apt-get update && sudo apt-get install -y google-chrome-stable
          background: true

      - checkout

      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "Gemfile.lock" }}
            - v1-dependencies-

      - run:
          name: install dependencies
          command: |
            gem install bundler -v 2.0.2
            bundle install --jobs=4 --retry=3 --path vendor/bundle

      - save_cache:
          key: v1-dependencies-{{ checksum "Gemfile.lock" }}
          paths:
            - ./vendor/bundle

      - run: mv config/database.yml.ci config/database.yml
      - run: yarn install
      - run: bundle exec rake db:create
      - run: bundle exec rake db:schema:load

      - run:
          name: run tests
          command: |
            mkdir /tmp/test-results
            TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | \
              circleci tests split --split-by=timings)"
            bundle exec rspec \
              --format RspecJunitFormatter \
              --out /tmp/test-results/rspec.xml \
              --format progress \
              $TEST_FILES
          no_output_timeout: 15m

      - store_test_results:
          path: /tmp/test-results
      - store_artifacts:
          path: /tmp/test-results
          destination: test-results

config/database.yml.ci

test:
  adapter: mysql2
  encoding: utf8
  pool: 5
  username: 'root'
  port: 3306
  host: '127.0.0.1'
  database: ci_test

まとめ

  • DockerfileCircleCIの設定ファイルChromeを追加
  • ローカルで通用してもCircleCI上で失敗することがある。
  • ありがたいことに記事(情報)がたくさんあるので、その中で自分がどの問題に直面しているのかを理解することが大事。

おわりに

前回の記事に変更前の CircleCIの設定ファイル があります。(厳密に言えば少しリファクタなどしています)
JavaScript適用前 ですが、 CircleCI についてまとめていますのでよろしければご覧ください。

参考文献

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

deviseメール認証時、認証メールに画像を挿入する --備忘録--

前提

deviceのログイン機能
【Rails】deviseを導入してみる

メールの認証機能
【devise】メール認証のサインアップ・イン・アウト機能
devise でメール認証を実装したい【Rails】

上記2つの機能を実装済みです。

mailerをオーバーライドし、メソッドを作成

「app/controllers/users」に「mailer.rb」を作成します。
deviceのmailerを継承します。

mailer.rb
class Users::Mailer < Devise::Mailer
end

「config/initializers/devise.rb」の設定をします

devise.rb
config.mailer = 'Users::Mailer'

挿入したい画像を「/app/assets/images/mailer/」に入れる。
先ほど作成した「mailer.rb」にHTML形式のメールにで挿入する為のメソッドを追記する。

mailer.rb
class Users::Mailer < Devise::Mailer
  before_action :add_image

  private

  def add_image
    images = ['***.png', '***.jpg']

    images.each do |img|
      attachments.inline[img] = File.read("#{Rails.root}/app/assets/images/mailer/" + img)
    end
  end
end

HTMLの編集

[/app/views/users/mailer/confirmation_instructions.html.erb」のファイルを修正する

confirmation_instructions.html.erb
<p>Welcome <%= @email %>!</p>

<p>会員登録ありがとうございます。</p>
<%= image_tag attachments['***.png'].url, alt: "***" %>
<%= image_tag attachments['***.jpg'].url, alt: "***" %>
<p><%= link_to 'アカウント有効化', confirmation_url(@resource, confirmation_token: @token) %></p>

こちらで会員登録した際に画像が挿入されています。

以上。ここまで読んでいただきありがとうございます。

参考

Rails Devise でパスワードリセットなどのメールテンプレート(Mailer ビュー)をカスタマイズ

Deviseの認証メールをカスタマイズする方法

HTMLメールで画像を載せる [rails][初心者]

本番環境
【Rails】メール送信設定 〜gmail利用〜

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

dotenv-rails必要なのか?

現在awsで作成しているアプリケーションをデプロイ中に
dotenv-rails必要あるのかと思ったので投稿

dotenv-railsとは

Railsで使える環境変数を管理できるgem(dotenv-rails)や.envの導入方法

簡単にいうと自分で変数セットしていろんなところで使えちゃいます。ということなのだが

rails5.2からはcredentials.yml.encという物がデフォルトで追加されています。皆さんのconfigフォルダの中にも存在すると思います。これも環境変数指定できいろんなところで使えちゃいます。

どっちも同じならどっち使ってもいいじゃん!て思いますよね〜

ただただ変数をセットするdotenv-railsとは違いcredentials.yml.encは暗号化して環境変数を保持するんです!そしてconfig/master.keyを使って複合して使うという違いがあります。

環境変数は見られたくないんだけど〜っていうところに使う物なので暗号化は大切ですね!

もしdotenv-railsを使い大事な値を.envで管理していると何かの拍子にフォルダを見られた際にふむふむここねといって.env内見られたら終わりです。

credentials.yml.encであれば見られても暗号化されているので「わけワカメ」となるわけですね。

おまけ

credentials.yml.encはgitに上げてもmaster.keyがないかぎり他の人はどうしようもないのでデプロイの際にcloneで持ってきてmaster.keyをローカルから引っ張ってこれば使えちゃうんですよね。

セキュリティー面を考えたらこっちの方が良いのは明らかですねー

ただcredentials.yml.encを使用する時には

Rails.application.credentials.セットした環境変数
#dotenv-railsだと
ENV['セットした環境変数']

長い!! でもVScodeだと何回か打ってると予測してくれるから問題なし

そして環境変数を設定するときも(dockerだと)

docker-compose run -e EDITOR="vim" web rails credentials:edit

でvim開いて編集という面倒くささはあります。

ちなみにFile encrypted and saved.とでてしまう人は多分vimが入っていないのでinstallしてください

僕の場合だと

Dockerfile
#追加 apt-get install vim

いやーまだまだ知らないことがたくさんあって面白いな〜

何か間違っていたらご教授お願いします。

では〜⭐️

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

ActiveRecordでwhere in句を書こうとして詰まったこと

SQLで書くとわかるが、Railsでどのように書くか悩んだので、書いておく

知りたかったこと

SELECT * FROM Tables WHERE (name, task) not in ((yamada, "running"),(yamada, "swimming"));

いろいろ悩んだが上手くまとめられなかったので、サブクエリで解決しました〜!
配列で渡すと複数個渡せますし、このようにサブクエリにすると欲しい条件が作れるのかなと思います!

期待値通りのクエリが発行
Table.where.not(id: (Table.select(:id).where(name: yamada).where(task: ["running", "swimming"])))

当初の方針

最初の方針ではwhere句を複数繰り返すことで条件を絞れると思ってましたが、以下のように書いたら"yamada"さんの全てのtaskを弾いてしまいます。実際に発行されるSQLも下に記載しておきます。
ベン図を頭の中に描きながら書いていきました。

期待値と違うクエリが発行
Table.where.not(name: yamada).where.not(task: ["running", "swimming"])
期待値と違うクエリ
SELECT `tables`.* FROM `tables` WHERE `tables`.`deleted_at` IS NULL AND (`tables`.`name` != "yamada") AND (`tables`.`task` NOT IN ("running", "swimming"))

参考文献

Rails ガイド

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

[React + TypeScript ] HTMLSelectElementのつもりなのに、Property 'options' does not exist on type 'HTMLElement'.

課題

今日もTypeScriptから怒られた。

something.tsx
const months = document.getElementById('datetime_2i')
months ? (months.options[1].selected = true) : null
エラー
> Property 'options' does not exist on type 'HTMLElement'.

HTMLSelectElementのつもりなんだけどな。

結論

つもりなら書けと言うことらしい。
地味に時間取られる。

something.tsx
const months = document.getElementById('datetime_2i') as HTMLSelectElement
months ? (months.options[1].selected = true) : null

TypeScript素人故怒られまくる。
エラー解決するたびに只管メモします。

参考情報

Property 'selectedOptions','selectedIndex','options' does not exist on type 'HTMLElement'
https://sharepoint.stackexchange.com/questions/283252/property-selectedoptions-selectedindex-options-does-not-exist-on-type-htm

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

form_with関連でつまずいたことのまとめ

はじめに

Railsチュートリアル(version5.1対応)を1周して、ポートフォリオ作りをする際に、form_withでいくつか詰まったので備忘録として記事を書きます。間違っているところがあればコメントいただけるとありがたいです。

以下発生したエラーごとにまとめていきます。

flashが表示されない

以下のような記事を投稿するフォームを作成

_post_form.html.erb
<%= form_with model: @post, url: yield(:form_url), method: yield(:method),
  local: true, multipart: true do |form| %>

・・・フォームいろいろ

<% end %>

初め、local: true の設定を行わずに書いていたのですが、投稿成功のflashの表示ができなくなって困っていました。どうやら、form_withはデフォルトではAjaxを用いて通信を行うようで、それによりflashが表示できないようです。(詳しい原理理解はしていません)

ファイルの送信が行えない

これは以下のようにpdfファイルを送信するフォームを作る際に起こりました。

_post_form.html.erb
<%= form_with model: @post, url: yield(:form_url), method: yield(:method),
  local: true, multipart: true do |form| %>

・・・他のフォーム・・・

<%= form.label :file, "pdfファイル", class: "control-label" %>
<%= form.file_field :file, class: "form-control-file" %>

<% end %>

pdfファイルの送信には、carrierwave を導入しました。carrierwaveのセッティングについては別記事にまとめます。今回は、それが終わった後の話です。
フォームが送れないのでググったところ、form_withの引数に、multipart: trueを指定していませんでした。これを指定すると、ファイルの形式も送信できるようになるようです。Rails4以降ではfile_fieldの記述があれば暗黙にmultipart: trueが指定される、と書いていたのですが、なぜか僕はされていませんでした・・・。

scopeオプションについて

以下の記事を参照しました。
https://qiita.com/akilax/items/f36b13f377f7e442bc73

データをパラメーターとして送る際に strong parameters として送るために指定する値、と理解しました。(正しいのか・・・?)

終わりに

まだ理解が浅いので、今後新しい発見があり次第追記していくつもりです。form_with 奥が深いな・・・。

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

テーブルが存在するのに、Table doesn't existと言われた話

はじめに

先日、PCの電源を閉じた後、再度dockerを起動し、docker-compose run wen rails sと入力すると、以下のようなエラーが出てしまいました。

Mysql2::Error: Table 'share_read_development.books' doesn't exist

現在でも、主原因は解明できておりません。
本記事では、僕が解決に向けて試したことを記載していきます。

エラーが起きた主原因は不明でしたが、エラーの解決は済んでおり開発自体は進んでおります。
もし同じようなエラーに苦しんでいる方は、参考にしてみてください。

また原因がわかる方がいらっしゃいましたら、コメントで教えていただけると幸いです。

開発環境

Ruby 2.72
Rails 6.0.2.3
MySQL 5.7
Docker/docker-compose

発生したエラー

冒頭でも簡単に記載しましたが、以下のようなエラーが出ました。
booksテーブルがないと言われています。

rails aborted!
ActiveRecord::StatementInvalid: Mysql2::Error: Table 'share_read_development.books' doesn't exist
/usr/local/bundle/gems/mysql2-0.5.3/lib/mysql2/client.rb:131:in `_query'
/usr/local/bundle/gems/mysql2-0.5.3/lib/mysql2/client.rb:131:in `block in query'
/usr/local/bundle/gems/mysql2-0.5.3/lib/mysql2/client.rb:130:in `handle_interrupt'
/usr/local/bundle/gems/mysql2-0.5.3/lib/mysql2/client.rb:130:in `query'
/usr/local/bundle/gems/activerecord-6.0.3.4/lib/active_record/connection_adapters/abstract_mysql_adapter.rb:201:in `block (2 levels) in execute'
/usr/local/bundle/gems/activesupport-6.0.3.4/lib/active_support/dependencies/interlock.rb:48:in `block in permit_concurrent_loads'
/usr/local/bundle/gems/activesupport-6.0.3.4/lib/active_support/concurrency/share_lock.rb:187:in `yield_shares'

# 中略

Caused by:
Mysql2::Error: Table 'share_read_development.books' doesn't exist
/usr/local/bundle/gems/mysql2-0.5.3/lib/mysql2/client.rb:131:in `_query'
/usr/local/bundle/gems/mysql2-0.5.3/lib/mysql2/client.rb:131:in `block in query'
/usr/local/bundle/gems/mysql2-0.5.3/lib/mysql2/client.rb:130:in `handle_interrupt'
/usr/local/bundle/gems/mysql2-0.5.3/lib/mysql2/client.rb:130:in `query'

# 中略

/usr/local/bundle/gems/activesupport-6.0.3.4/lib/active_support/dependencies.rb:291:in `load_dependency'
/usr/local/bundle/gems/activesupport-6.0.3.4/lib/active_support/dependencies.rb:324:in `require'
bin/rails:4:in `<main>'
Tasks: TOP => db:schema:dump
(See full trace by running task with --trace)

試したこと

マイグレーションの実行状況の確認
まず、マイグレーションの実行状況を確認しました。

$ docker-compose run web rails db:migrate:status

 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20201207135139  Create users
   up     20201213135207  Create reviews
   up     20201218052640  Create books
   up     20201218075413  Add bookgenreid to books
   up     20201220063200  Add book to reviews
   up     20201222080803  Create relationships
   up     20201222131717  Create favorites
   up     20201222233733  Create comments
   up     20201224140712  Create bookcases
   up     20201225105949  Create notifications
   up     20201226102230  Add status to review
   up     20201230042031  Add caption to books

全てのマイグレーションファイルが実行されていることがわかりました。

データベースの確認
次にmysqlに接続し、デーベースのテーブルを確認しました。

$ docker-compose run web rails db
> show tables;

そうすると、以下のように表示されました。
booksテーブルは存在している?

+----------------------------------+
| Tables_in_share_read_development |
+----------------------------------+
| ar_internal_metadata             |
| bookcases                        |
| books                            |
| comments                         |
| favorites                        |
| notifications                    |
| relationships                    |
| reviews                          |
| schema_migrations                |
| users                            |
+----------------------------------+

しかし、以下のコマンドでは、booksテーブルがないと言われてしまいます。

> select * from books;

他のテーブルのデータは取得できます。

> select * from bookcases;
+----+------+---------------+---------+----------------------------+----------------------------+
| id | read | book_id       | user_id | created_at                 | updated_at                 |
+----+------+---------------+---------+----------------------------+----------------------------+
|  1 |    0 | 9784296108008 |       1 | 2020-12-28 01:18:40.540283 | 2020-12-28 01:18:40.540283 |
|  3 |    0 | 9784478820094 |       3 | 2020-12-28 12:39:00.697316 | 2020-12-28 12:39:00.697316 |
| 37 |    0 | 9784478820094 |       1 | 2020-12-29 08:16:25.944979 | 2020-12-29 08:16:25.944979 |
| 39 |    0 | 9784804614151 |       1 | 2020-12-29 08:26:56.615557 | 2020-12-29 08:26:56.615557 |
| 41 |    0 | 9784907095536 |       1 | 2020-12-29 08:27:01.301378 | 2020-12-29 08:27:01.301378 |
| 42 |    0 | 9784908925658 |       1 | 2020-12-29 08:39:11.191829 | 2020-12-29 08:39:11.191829 |
| 45 |    0 | 9784284204705 |       1 | 2020-12-30 04:10:08.090943 | 2020-12-30 04:10:08.090943 |
+----+------+---------------+---------+----------------------------+----------------------------+

公式ドキュメントを調べても、自身で試したことしか記載していませんでした。

エラー Table 'xxx' doesn't exist または Can't find file: 'xxx' (errno: 2) が発生する場合、xxx という名前のカレントデータベースにテーブルがないことを示しています。
SHOW TABLES を使用して、カレントデータベースにあるテーブルを確認できます。

【URL】
http://download.nust.na/pub6/mysql/doc/refman/4.1/ja/cannot-find-table.html

データベースの作り直し
あまり気が進みませんでしたが、データベースを作り直すことにしました。

$ docker-compose run web rails db:reset
$ docker-compose run web rails db:create
$ docker-compose run web rails db:migrate

これでエラーが解消することができました!
個人開発なので、データベースを削除するという方法で済みましたが、実際の現場ではこの方法は推奨されないと思います。
もし、今回のエラーの原因等がわかる方がいらっしゃいましたらコメントにて教えていただけると幸いです。

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

記事を投稿する

備忘録的に使用しています。
間違い等々あればご指摘ください!

1.コントローラーで定義
 newとcreateの定義
 newは新規作成するだけ、定義なし 
 createは「どんな内容」を投稿するか
  テーブル名.create(引数) 

2.投稿フォームのviewの作成
 new.html.erb : 投稿するときに出る画面
  ・フォームタグで作成
  form_tag ('/テーブル名' method: :post) do

 create.html.erb :投稿後に切り替わった画面

  

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

heroku と vercel にお手軽デプロイ

heroku の cli を入れる

ゴニョゴニョ調べてください?

rails api のデプロイ heroku

できてる rails app に行く

cd hogehoge-api

heroku app を作る

heroku create -a hogehoge-api

heroku の Deploy タブ押して github との接続とかして、 Deploy Branch ボタンを押す。
終わり??

next.js のデプロイ vercel

vercel のマイページ行く
New Project を押す
github とつなぐ
Deploy を押す
終わり??

かんたんすぎる!!!!!!!!!!!!!!!

あとはそれぞれのダッシュボードでドメインの設定とかをポチポチするだけです

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

部分テンプレートを使用する(保守性の高いコードを書く)

前書き

ある程度ポートフォリオが完成してきたところでコードの手直しを行なっていくことにしました。
実際の業務では保守性の高いコードが求められているからです。具体的には同じコードは一つにまとめておくことによって手直しするときに複数直さなくても済むように改善していきます。
書き方を忘れないように備忘録として残しておきます。

部分テンプレートの使用

ヘッダーは他のページでも繰り返し使用するので部分テンプレートとしてまとめていきます。
部分テンプレートとは、ビューファイルで繰り返し使用するコードを切り出し、再利用する仕組みのことをいいます。
部分テンプレートとして切り出すときに作成するファイルは命名規則として、アンダースコアを先頭に記述します。
今回の場合、_header.html.erbとなります。
app/views/shared/
header.html.erbディレクトリに作成していきます。

renderメソッド

renderメソッドは、部分テンプレートを呼び出す際に利用するメソッドのことです。
<%= render "ディレクトリの指定" %>と記述します。
例えばindex.html.erbやshow.html.erbでもヘッダーのコードを使いたい時にrenderメソッドで使い回すことができます。

index.html.erb
<%= render "shared/header" %>

<div id="home-index" class="contents row">
  <h2 class="page-title">Find your favorite!</h2>
  <p class="page-p">歌いたかったあの曲との出会い提供するMY KARAOKE。
  </p>
  <p class="page-p">このページではみんなが歌いたい曲の情報が満載です。
     みんなの曲を見てレパートリーを増やしましょう。
  </p>
省略
_header.html.erb
<header class='top-page-header wrapper'>
  <%= link_to 'MY KARAOKE', root_path, class: "title" %>

  <nav>
    <ul class="main-nav">
      <% if user_signed_in?%>
        <li><%= link_to current_user.nickname, new_user_session_path, class: "user-nickname" %></li>
        <li><%= link_to 'ログアウト', destroy_user_session_path, method: :delete, class: "logout" %></li>
      <% else %>
        <li><%= link_to'ログイン', new_user_session_path, class: "login" %></li>
        <li><%= link_to '新規登録', new_user_registration_path, class: "sign-up" %></li>
        <li><%= link_to 'ゲストログイン', users_guest_sign_in_path, method: :post %></li>
      <% end %>
    </ul>
  </nav>
</header>

一行目の<%= render "shared/header" %>よって_header.html.erbのコードを使用することができます。
部分テンプレートを作成したことによってindex以外のページでも同じように使い回すことができます。

show.html.erb
<%= render "shared/header" %>

<div class="main">
  <div class="song-show">
    <table class="detail-table">
      <tbody>
        <tr>
          <th class="show-detail-value">投稿者</th>
          <td class="show-detail-song">
            <%= link_to user_path(@song.user_id) do %>
              <%= @song.user.nickname %>
            <% end %>
          </td> 
        </tr>
省略

今回はわかりやすいようにヘッダーの例を出しましたがもちろんそれ以外も部分テンプレートが使える場面があります。
例えばnewとeditは新規投稿する際にフォームなどはほぼ同じ記述になるので(少なくとも僕の場合は)使えたりします保守性の観点からまとめてあげるほうが後々楽になるのでやっておくほうがいいと思います。

後書き

とりあえず簡単な部分テンプレートいついてまとめました。 localsオプションを使った部分テンプレートの記事を次回書いてみようかと思っています。

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

VScodeのスニペット機能を活用しよう ~ もう<%=%>はいちいち打ちたくない ~

概要

railsの開発をしていると、結構書くことになる「<%= %>」や「<% %>」。
いちいち打つのは結構めんどくさい。
なので、VScodeのスニペット機能を使って簡単にこれらのめんどくさいコードを打つ時間の短縮をしてみよう!
もちろん、他の言語でもOK!

導入の仕方

VScodeの左下の歯車マークをクリック

スクリーンショット 2021-01-16 13.39.34.png

Command paletteを開く

スクリーンショット 2021-01-16 13.36.46.png

snippetsと打って、省略したいコードの言語の拡張子を選択

スクリーンショット 2021-01-16 13.37.32.png

スクリーンショット 2021-01-16 13.38.04.png

スニペットを記述しよう

スクリーンショット 2021-01-16 13.38.35.png

自由にスニペットは作れるのですが、
と書き方は、以下のように
はじめの””の中には、当該スニペットの端的な内容
prefixの後には、スニペットを出力するためのトリガー
bodyの後には、実際出力したいコードの内容
descriptionの後には、スニペットの説明
を記述します!

ruby
{
    // Place your snippets for erb here. Each snippet is defined under a snippet name and has a prefix, body and 
    // description. The prefix is what is used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
    // $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. Placeholders with the 
    // same ids are connected.
    // Example:
    "write <%=%> more easier": {
        "prefix": "pa",
        "body": [
            "<%= $0 %>"
        ],
        "description": "Log output to console"
    }
}

また、$0をかけば、カーソルの位置を指定できます。
上の例のようにかけば、<%= %>における=と%の間にカーソルが合います。
同様に、$1や$2をかけば、改行を挿入できます。

また、以下のように記述すれば複数のスニペットを作成できます。

ruby
{
    // Place your snippets for erb here. Each snippet is defined under a snippet name and has a prefix, body and 
    // description. The prefix is what is used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
    // $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. Placeholders with the 
    // same ids are connected.
    // Example:
    "write <%=%> more easier": {
        "prefix": "pa",
        "body": [
            "<%= $0 %>"
        ],
        "description": "Log output to console"
    },
    "write <%%>": {
        "prefix": "ni",
        "body": [
            "<%%>",
        ],
        "description": "Log output to console"
    }
}

終わり

Author: Kazuhito Nakayama
Twitter
Qiita

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

Docker ComposeでRails環境を構築

初学者の方向けに発信されているきよとのプログラミング大学のチャンネルで、Docker Composeを使ったRails環境構築の動画を見つけ、これが非常に分かりやすかったので、備忘録として記事にまとめたいと思います。

DockerでRails環境をつくりたいという方はこの動画を見ればOKだと思います。
https://youtu.be/ltDdZAJli8c

Docker Composeとは

複数のアプリケーションをまとめて操作できるツール。例えばRailsでアプリケーションを開発する際、最低限Webサーバーとデータベースサーバーが必要になるが、通常それぞれのサーバーを構築し、接続するなどの操作が必要となる。docker-composeではコマンド一発でそれらを立ち上げて接続することができるため、非常に楽に開発環境を構築することができる。

全体の流れ

  • Docker関連のファイルを用意
  • 初期設定
  • 起動
  • よく使うコマンド

Docker関連のファイルを用意

① Dockerfile

ここにrailsのイメージを作成する記述を行う。

Dockerfile
# ベースイメージを指定
FROM ruby:2.7

# nodejsとyarnをインストールするため、JavaScript関連のライブラリをインストール
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
  && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
  # nodejsとyarnをインストール
  && apt-get update -qq \
  && apt-get install -y nodejs yarn
# 作業ディレクトリを指定
WORKDIR /app
COPY ./src /app
# Ruby関連のライブラリ(gem)のインストール
RUN bundle config --local set path 'vendor/bundle' \
  && bundle install

※ APIモードで開発をする場合、nodejsとyarnは不要

② Gemfile

次にGemfileを用意します。

Gemfile
source 'https://rubygems.org'

gem 'rails', '~> 6.1.0'

上記のように、railsのライブラリが入った状態でrails newを実行すると、railsのファイルの雛形を一斉に作ることができる。その際、Gemfileが新しく作成され、それと置き換わる形となる。

③ docker-compose.yml

最後にdocker-compose.ymlを用意します。

docker-compose.yml
ersion: '3'
services:
  db:
    image: mysql:8.0
    # mysql8.0から認証形式が変更になっていて、それを5系の認証形式に戻す設定。これをしないとエラーになる
    command: --default-authentication-plugin=mysql_native_password
    volumes:
      - ./src/db/mysql-data:/var/lib/mysql
    # 環境変数の設定
    # MySQLはパスワードを設定しないとエラーになる
    environment:
      MYSQL_ROOT_PASSWORD: password
  web:
    build: .
    # 標準入出力を有効にする設定
    # これをしないとデバックができない
    tty: true
    stdin_open: true
    command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - ./src:/app
      # gemを入れた際に、buildし直さなくても良くする設定
      - bundle:/usr/local/bundle
    ports:
      - "3000:3000"
    # railsからMySQLへ接続する際、接続情報としてdbサービスのIPアドレスを指定する必要がある。その接続先のIPアドレスをdbで接続できるようにする設定
    depends_on:
      - db
volumes:
  bundle:
    driver: local

開発をしていると、A server is already running. Check /app/tmp/pids/server.pid.のエラーでハマることがある。これは、サーバーが実行中か否かをserver.pidの有無で判断しており、何らかの理由でサーバーが実行していないがserver.pidファイルが残った状態となったときに起こる。これを防ぐため、起動時にはserver.pidの削除を行う。

command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"

初期設定

ファイルが用意できたらrails newコマンドを実行する。

$ docker-compose run web rails new . --force --database=mysql

Gemfileが変更されたため、イメージの再ビルド

$ docker-compose build

config/database.ymlを参照し、データベースへの接続先情報を修正する。

database.yml
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  # docker-compose.ymlで設定したパスワードを入力
  password: password
  # docker-compose.ymlのdepends_onで設定した値を入力
  host: db
  # 以下略

起動

$ docker-compose up -d

ブラウザでlocalhost:3000へアクセスし、下画面が表示されれば成功!
image.png

よく使うコマンド

  • イメージのビルド
$ docker-compose build
  • コンテナの作成と起動
$ docker-compose up -d
  • コンテナを停止、削除
$ docker-compose down
  • コンテナの一覧を表示
$ docker-compose ps
  • ログを表示
docker-compose logs
  • コンテナを作成してコマンドを実行
$ docker-compose run <サービス> <コマンド>
  • 起動中のコンテナにコマンド実行
$ docker-compose exec <サービス> <コマンド>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RailsにjQueryを導入する方法

jQueryの導入

gemファイルの確認

Gemfileの中に、

gem 'jquery-rails'

がない場合は、自分でそのファイルの一番下に記入して、ターミナルで

bundle install

を実行します。

application.jsの中身変更

//= require jquery
//= require rails-ujs
//= require activestorage
//= require_tree .

上記のように変更します。
順番が重要みたいです。

作動するか確認

適当にビューファイルを選択し、その中に

<h1>テスト</h1>
<script type="text/javascript">
  $("h1").css("color", "red");
</script>

のように記述すると、jQueryが効いてh1タグの文字が赤くなると思います。

※私の場合、最初jQueryが作動しなかったので、一旦サーバーを再起動したら、正常に動きました。

別のファイルにjQueryを記述する

コードが増えてくると、このままだとビューファイルの中が煩雑になってくるので、test.jsのようなファイルを別に作成します。
作成する場所は「app/assets/javascripts」の配下です。

jQueryの様式に則って、

$(function() {
 $("h1").css("color", "green");
});

のようにコードを書きます。

先ほどのビューファイルに書いたは、削除します。

これで、再度ブラウザで確認し、h1タグの文字が赤くなっていればjQueryは無事に起動しています。

参考記事

https://web-camp.io/magazine/archives/17690
こちらの記事がとても分かりやすかったです。

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

Railsアプリにransackを導入したけどあたふたした話。

ポートフォリオ用のアプリにransackを使って検索機能を実装しようとした際にちょっと詰まったので
備忘録を残しておきます。

やりたいこと

検索文字列を含んだ投稿を検索する機能を実装したい。

ひとまずransackをインストール

Gemfile
gem 'ransack'
$ bundle install

コントローラーについて

posts_controller.rb
class PostsController < ApplicationController
  before_action :set_q, only: [:index, :search]

  def search
    @results = @q.result
  end

  private
    def set_q
      @q = Post.ransack(params[:q])
    end
end

ルーティングについて

routes
resources :posts do
  collection do
    get :search
  end
end

ビューについて

posts/index.html.erb
<%= search_form_for @q, url: search_posts_path do |f|%>
  <%= f.text_field :body_cont, placeholder: "検索"%>
  <%= f.submit "検索"%>
<% end%>
posts/search.html.erb
お好みにカスタマイズ

結論

色々な記事などに<%= f.search_field :body_cont %>
と記されていたのですが、これだとうまく行かなかったです。
ヤケクソで<%= f.text_field :body_cont %>にすると
すんなり行きましたー!

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

エラーメッセージの日本語化

はじめに

オリアプ制作の中で、エラーメッセージの日本語化を行ったので、忘れないよう載せておこうと思います。
ユーザーがきちんとフォーム入力を出来ていない際に、エラーメッセージが英語ではどこに不備があるかが分かりづらいのでは?と感じたため、日本語化を実装しようと思いました。

事前状況:ユーザー登録等にはdeviseを導入している / 単体エラーコードは記述済み
今回の流れとして、localeファイル内に日本語変換用yamlファイルを作成する事で英語を翻訳していく。
(localeファイル:多言語化用の言語ファイル)

1.gemの導入

1.エラーメッセージを日本語化するために『rails-i18n』というgemをGemfileに記述しbundle installする。
これは以下のリンク先に記述してある語句を日本語にしてくれるもの。

https://github.com/svenfuchs/rails-i18n/blob/master/rails/locale/ja.yml

Gemfile
gem 'rails-i18n'

2.config/application.rb に config.i18n.default_locale = :ja を記述し、言語の設定を行う

config/appllication.rb
module IdeaApp
  class Application < Rails::Application
    # 中略
    config.i18n.default_locale = :ja
    # 中略
  end
end

2.devise関連の日本語化

ユーザー登録等にはdeviseを導入しているため、それに関連するものの日本語化を行う。
1.config/locales に devise.ja.yml を作成する。
 →config / locales / devise.ja.yml

2.devise.ja.yml内に以下のリンク先に記述してあるコードをペーストする。
ペーストすることで、記述してある語句を日本語にする。
https://github.com/tigrish/devise-i18n/blob/master/rails/locales/ja.yml

3.指定した単語の日本語化

ここまでの実装で、rails-i18ndevise.ja.ymlに記述してある語句に関しては日本語化出来ているが、そのほかの語句は以下の画像のように日本語化出来ていない。

そのため、こちらで語句(NicknameやTitle、Category)などを指定し、日本語に変換する必要がある。

1.config/locales に ja.yml を作成する
 →config / locales / ja.yml

2. ja.yml に以下のように変換したい語句の変換前・変換後を記述する

config/locales/ja.yml
ja:
  activerecord:
    attributes:
      user: #Userモデル
        nickname: ニックネーム
        phone_number: 電話番号
        first_name: 名前
        last_name: 名字
        first_name_kana: 名前カナ
        last_name_kana: 名字カナ
      idea: #Ideaモデル
        title: アイデア名
        idea: アイデアの内容
        price: 価格
        category_id: カテゴリー
    errors:
     messages:
       other_than:  --」以外を選択してください

4.日本語に変換後

これでエラーメッセージを日本語化することが出来た。

5.補足:エラーコード修正

すでに単体テストコードを記述している場合は、期待するエラーメッセージも日本語に変換されるため、書き換えが必要になる。
例としてNicknameのエラーコードを記載する。

spec/models/user_spec.rb  書き換え前
# 中略
context '新規登録がうまくいかないとき' do
  it 'nicknameが空だと登録できない' do
    @user.nickname = ''
    @user.valid?
    expect(@user.errors.full_messages).to include("Nickname can't be blank")
  end
end
# 中略
spec/models/user_spec.rb  書き換え後
# 中略
context '新規登録がうまくいかないとき' do
  it 'nicknameが空だと登録できない' do
    @user.nickname = ''
    @user.valid?
    expect(@user.errors.full_messages).to include("ニックネームを入力してください")
  end
end
# 中略

最後に

英語が苦手な人にもエラーメッセージが読めるように実装することが出来ました。
今後も誰にでも使いやすいアプリを制作できるように意識していきたいです。

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

【3行で説明】プログラミングスクールの技術記事を検索結果に表示させない方法

※単純に初歩的すぎる記事を見る必要がなくなった時に使う方法です。他意はありません。
1.Chromeでこの拡張機能(uBlacklist)を入れる。
2.表示してほしくないサイトに行く、または調べる
3.拡張機能のボタン(ブラウザ右上のパズルのようなマーク)から選択して、ブロックを押す。

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

[Rails]"kaminari"の使い方について

はじめに

"kaminari"の実装をやったので忘れないように記していきます。:zap:

「kaminari」

ページネーションを実装するためのrubyのgemの一つです。

何かの一覧ページを表示した時に、たくさんある場合見やすいようにページを数字で分割してくれ、最初や最後のページに飛べるボタンが実装できたりします。

実装

インストール

まずはgemをインストールします。
日本語表記にするので一緒に「i18n」もインストールします。

「i18n」は以前学習していましたのでいちお貼っておきます。

[Rails]日本語表記にする方法

Gemfile
gem 'kaminari'
gem 'rails-i18n'

インストール!


bundle install

コントローラ

controller.rb
def index
    @advises = Advise.page(params[:page])
  end

ビューファイル

view.html.erb
 <div class="advise-lists">
   <% @advises.each do |advise| %>
     <ul class="advise-text">
       <li><%= link_to advise.title, advise_path(advise), class: "advise2_link" %></li>
     </ul>
   <% end %>     <!--↑ 一覧表示の部分-->            
 </div>         <!--↓ ページネーション実装部分-->      

 <%= paginate @advises %>


「kaminari」の設定ファイルを作成


rails g kaminari:config

「kaminari_config」ファイルが作成されます。
お好みで変更していきます。

こちらでは「default_per_page」を1ページあたり3行とわざと小さく設定しています。

config/initializers/kaminari_config.rb
# frozen_string_literal: true

Kaminari.configure do |config|
 config.default_per_page = 3
  # config.max_per_page = nil
  # config.window = 4
  # config.outer_window = 0
  # config.left = 0
  # config.right = 0
  # config.page_method_name = :page
  # config.param_name = :page
  # config.max_pages = nil
  # config.params_on_first_page = false
end

たくさん項目がありますが
こちらでは
フリーランスLIFE!:【Rails】でページネーションをgemで実装!

TECH SCORE BLOG:Railsライブラリ紹介: ページングを行う「kaminari」

以下のように説明されています。

default_per_page
デフォルトのページあたりの表示件数(デフォルトは 25)。

max_per_page
ページあたりの表示件数の最大(デフォルトは nil、つまり無制限)。

window
表示中のページの左右何ページ分のリンクを表示するかを指定します(デフォルトは 4)。上記画像はデフォルトの 4 で、11 ページを表示しているところです。11 の左右それぞれ 4 ページ分のリンクが生成されています。

outer_window
先頭ページ、及び最終ページから何ページ分のリンクを表示するかを指定します(デフォルトは 0)。left、right が指定された場合は、そちらの値が優先されます。

left
先頭ページから何ページ分のリンクを表示するかを指定します(デフォルトは 0)。上記画像は 3 を指定した場合です。

right
最終ページから何ページ分のリンクを表示するかを指定します(デフォルトは 0)。上記画像は 2 を指定した場合です。

page_method_name
モデルに追加されるページ番号を指定するスコープの名前(デフォルトは page)。

param_name
ページ番号を渡すために使用するリクエストパラメータの名前(デフォルトは page)。

引用: Railsライブラリ紹介: ページングを行う「kaminari」

ロケールの設定

ロケールファイルのロードパスを設定します。
デフォルトロケールを「日本語( ja )」にセットします。

config/application.rb
config.i18n.load_path +=
      Dir[Rails.root.join("config", "locales", "**", "*.{ry,yml}").to_s]
    config.i18n.default_locale = :ja

viewディレクトリを作り、その下にファイルを作ります。

locales/views/pagenate.ja.yml
ja:
  views:
    pagination:
      first: "先頭"
      last: "最後"
      previous: "前へ"
      next: "次へ"
      truncate: "..."

そうすると英語表記から日本語表記に代わって表示され、ページネーションが実装されます。

スクリーンショット 2021-01-15 23.30.18.png

さらにカスタマイズをしたい場合は


rails g kaminari:views default

を入力すると
viewにこれらが作成されます。

スクリーンショット 2021-01-15 23.35.38.png

これらのファイルを編集すれば、ページネートのビューを変更することができます。
(_gap.html.erbはページが省略される"..."の部分、
_page.html.erbはページ番号の部分、
_paginator.html.erbは全体の構成定義)

まとめ

装着するの自体はそんなに難しくはないですが、カスタマイズの仕方をもう少し触って勉強していきたいと思います。
装飾とカスタマイズの部分をまた近々やっていきたいと思います。
    
       :runner::dash:  :runner: :runner::runner::dash:

参考

kikawaka:【Rails】kaminariの使い方をマスターしよう!

設定項目を確認するには・・

RAILS GUIDES:Configuring Rails Applications

装飾の参考

ぽてちる:【Rails】kaminariを使ってページネーションを実装する方法

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