20201026のRailsに関する記事は20件です。

[Rails] [メモ] <% %>に=をつける時とつけない時

この記事ではmacOS Catalina10.15.6にインストールしたRuby 2.6.5を使っています。
ヘルパーメソッドをビューファイルで記述する時、ふとした瞬間に<% %>の=をつけるかつけないかで間違ってしまうので、忘備録として書きました。

<% %>の場合

  • ビューファイルで出力させたくない時に使います。
  • 例えば、if文などの条件分岐やeach文の繰り返し処理の時などです。
#if文
<% if @name == 'hoge' %>
<% end %>

#each文
<% @books.each do |book| %>
<% end %>

<%= %>の場合

  • ビューファイルで記述した処理を出力させたい時に使います。
<%= book.title %>

<%=form_with model: @user, url: user_registration_path, class: 'registration-main', local: true do |f| %>
<% end %>

<%= f.label :email %>

<%= render 'shared/error_messages' %>

まとめ

ざっとまとめると<%= %>方が圧倒的に多いですね。
要するに、ifなどの条件分岐やeachのような繰り返し処理は=をつけないで、その他の画面に出力する処理はつけても良いということです。

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

Rails で検索機能を作ろう(ransack)

はじめに

今回はransackというgemを使って検索機能を作っていきます。ransackは少ないコードで複雑な検索機能を簡単に作れるgemでとても便利です。また、ransackではソート機能も簡単に作れるのでそれも含めて作成していきます。

基本的な検索結果の実装

今回検索の対象とするのは、ストレッチ(stretchsテーブル)一覧と、そのカテゴリ(categoriesテーブル)一覧とします。
ストレッチ一覧画面(indexビュー)に検索窓を設けます。

gemをインストール

gem 'ransack';

bundle installでインストール

ビュー

ストレッチのindexビューに検索窓をつける

<div class= serch.id>
      <%= search_form_for @q, class:'form-inline' ,url: stretchs_path do |f| %>
        <%= f.search_field :action_muscles_or_name_cont, class: 'form-control input-lg', placeholder: "ストレッチ名や筋肉名を入力" ,data: {"turbolinks" => false}%>
        <%= f.submit "検索", class: "btn btn-success btn-lg" %>
      <% end %>
</div>

cssで調整

.form-inline .form-control {
    display: inline-block;
    width: 80%;
}

コントローラー

class StretchsController < ApplicationController
  def index
    # 検索機能(検索ワードをparams[:q]で受け取り@stretchsに入れる)
    @q = Stretch.all.ransack(params[:q])
    @stretchs = @q.result(distinct: true).page(params[:page])
  end
end

検索ワードをparams[:q]で受け取り、検索で該当したデータをそれぞれ@stretchsに入れ、
再びindexビューに返す形です。

以上で簡単な検索機能の実装は完了です。

最後に

今回はransackを使って検索機能を作成しました。
間違っていたりするところがあればご教授お願いします。

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

RailsのActive Storageで、アップロード前に画像を圧縮する

概要

Active StorageでAmazon S3等に画像を保存するような場合に、圧縮してから画像をアップロードする。

実装

saveする前に、添付画像(ActionDispatch::Http::UploadedFile)のtempfileを圧縮したものに置き換える。

モデル
class Event < ApplicationRecord
  has_many_attached :images
end
ビュー
<div class="form-group">
  <%= f.label :images %>
  <%= f.file_field :images, multiple: true, class: 'form-control-file' %>
</div>
圧縮&保存
@event.images.each do |image|
  image.tempfile = ImageProcessing::MiniMagick.source(image.tempfile).resize_to_fit(1280, 1280).call
end
@event.save
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ruby on rails でのアプリの作り方(環境構築はできているものとします)

ターミナルにて、「cd 〜」でアプリ作成したいディレクトリを選択する。
rails _ 6.0.0 _ new (作成したいアプリ名) -d mysqlを入力すると「create 〜」がたくさん出た後に「Webpacker successfully installed」が表示されれば成功です。
rails newはrubyのフレームワークであるrailsがWebアプリケーションに必要なファイル一式を作成してくれるコマンドです。

もしエラーが表示された場合は、
「bundle config --delete build.mysql2」
「bundle config --global build.mysql2 --with-opt-dir="$(brew --prefix openssl)"」
「cd ~(作成したアプリ名)」
「bundle install」と順番に入力すれば大丈夫だと思います。

cd (作成したアプリ名)を入力すればそのアプリのディレクトリに移動し、ライブラリの追加などを行えます。

その後、VSCodeなどで(作成したアプリ名)のconfig/database.ymlの14行目くらいに「encoding: utf8mb4」と記述されていると思います。
「utf8mb4」の「mb4」を消し、「encoding: utf8」にします。
ターミナルに移動し、rails db:createを入力すると
「Created database '(作成したアプリ名)_development'」
「Created database '(作成したアプリ名)_test'」の二つが表示されていると思います。
rails sと入力した後、webにて「localhost3000」と入力すると「Yay! You’re on Rails!」の下に、地球に乗った世界各国の人たちがいるイラストが表示されていたら成功です。

初学者なので間違いなどあればご指摘いただけるとありがたいです。

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

Rails Tutorial 第3章学習編

Rails Tutorial 第3章で(。´・ω・)ん?って思ったところ

StaticPagesController.rb
def home
end

def help
end

なんで何も書いてないのにこれで動くんだろうと思っていました。
 ⇒デフォルトの挙動に関する記述が省略されているそうです。
初学者には(。´・ω・)ん?ってなりますよね。

StaticPagesController.rb
def home
#app/views/static_pages/home.html.erbを実行(省略されている記述)
end

def help
#app/views/static_pages/help.html.erbを実行(省略されている記述)
end

次に躓いたのがテストです・・・。
Tech::Campのカリキュラムでは全く扱っていなかったので事前知識もなく(。´・ω・)ん?でした。

テスト駆動開発 TDD(Test Driven Development)
テストしながら開発しようというモノらしいです。
Rails Tutorialで使っているminitestは簡易的なモノで、
一般的にはRspec と Capybara といったツールが使われるようです。

(´-ω-`)チュートリアル終えた後に学ぶ内容が増えたな・・・。

事前に固まっている仕様等は、
『テストを書く』⇒『実装する』⇒『テストする』

デザインなど作りながら変更していく物は、
『実装する』⇒『テストを書く』⇒『テストする』

アプリケーションのコードよりも明らかにテストコードの方が短く簡単に書ける)のであれば、「先に」書く
動作仕様が固まりきっていない場合、アプリケーションのコードを先に書き、期待する動作を「後で」書く
セキュリティが重要な課題またはセキュリティ周りのエラーが発生した場合、テストを「先に」書く
バグを見つけたら、バグの再現するテストを「先に」書き、回帰バグを防ぐ体制を整えて修正に取りかかる
すぐにまた変更しそうなコード(HTML構造の細部など)に対するテストは「後で」書く
リファクタリングするときは「先に」テストを書く。
特に、エラーを起こしそうなコードや止まってしまいそうなコードを集中的にテストする

テストをしない開発はあり得ないという事で・・・テスト書ける様になる事はすごく重要っぽいです。

test/controllers/static_pages_controller_test.rb
require 'test_helper'

class StaticPagesControllerTest < ActionDispatch::IntegrationTest

  test "should get home" do
    get static_pages_home_url #URLにアクセスする
    assert_response :success  #←テスト部分[HTMLページが帰ってくるか確認]
  end

  test "should get help" do
    get static_pages_help_url 
    assert_response :success  
  end
end

そして・・・一番分からなかったのはこれ。

3.6 高度なセットアップ
この追加の節は、テスト用設定について解説します。大きく分けると、成功/失敗の表示設定をする「minitest reporters(3.6.1)」と、ファイルの変更を検出して必要なテストだけを自動実行してくれる「Guard(3.6.2)」の2つです。この節で参考までに示したコードはそれなりに高度なので、今すぐ理解できるようになる必要はありません。

Guardはファイルシステムの変更を監視し、
例えばstatic_pages_test.rbファイルなどを変更すると自動的にテストを実行してくれるツール

あ、なんかめちゃくちゃ便利そう(*'▽')

Guardfile
# Guardのマッチング規則を定義 
guard :minitest, spring: "bin/rails test", all_on_start: false do
  watch(%r{^test/(.*)/?(.*)_test\.rb$})
  watch('test/test_helper.rb') { 'test' }
  watch('config/routes.rb') { interface_tests }
  watch(%r{app/views/layouts/*}) { interface_tests }
  watch(%r{^app/models/(.*?)\.rb$}) do |matches|
    "test/models/#{matches[1]}_test.rb"
  end
  watch(%r{^app/controllers/(.*?)_controller\.rb$}) do |matches|
    resource_tests(matches[1])
  end
  watch(%r{^app/views/([^/]*?)/.*\.html\.erb$}) do |matches|
    ["test/controllers/#{matches[1]}_controller_test.rb"] +
    integration_tests(matches[1])
  end
  watch(%r{^app/helpers/(.*?)_helper\.rb$}) do |matches|
    integration_tests(matches[1])
  end

  watch('app/views/layouts/application.html.erb') do
    'test/integration/site_layout_test.rb'
  end
  watch('app/helpers/sessions_helper.rb') do
    integration_tests << 'test/helpers/sessions_helper_test.rb'
  end
  watch('app/controllers/sessions_controller.rb') do
    ['test/controllers/sessions_controller_test.rb',
     'test/integration/users_login_test.rb']
  end
  watch('app/controllers/account_activations_controller.rb') do
    'test/integration/users_signup_test.rb'
  end
  watch(%r{app/views/users/*}) do
    resource_tests('users') +
    ['test/integration/microposts_interface_test.rb']
  end
end

# 与えられたリソースに対応する統合テストを返す
def integration_tests(resource = :all)
  if resource == :all
    Dir["test/integration/*"]
  else
    Dir["test/integration/#{resource}_*.rb"]
  end
end

# インターフェースが該当するすべてのテストを返す
def interface_tests
  integration_tests << "test/controllers/"
end

# 与えられたリソースに対応するコントローラのテストを返す
def controller_test(resource)
  "test/controllers/#{resource}_controller_test.rb"
end

# 与えられたリソースに対応するすべてのテストを返す
def resource_tests(resource)
  integration_tests(resource) << controller_test(resource)
end

取り合えず、特定のファイルを変更したらテストフォルダ内にあるファイルを実行するという感じですね。
このファイルを設定した後に下記コマンドを実行する事で自動テスト監視が始まるようです。

$ echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf
$ sudo sysctl -p
$ bundle exec guard

$ bin/spring stop    # テストが原因不明で動かなくなったら、このコマンドを実行してみる
$ bundle exec guard

自分でカスタマイズできるとは思えない( ^ω^)・・・)

簡単な内容のおさらい

config/routes.rbは、~にアクセスがあった時、コントローラー#アクションを実行するという記述を書く

config/routes.rb
Rails.application.routes.draw do
  get  'static_pages/home' #この記述はあまり使わない。
 #get 'static_pages/home' => "static_pages#home" こんな風に書くのが一般的な気がする。
  get  'static_pages/help'
  root 'application#hello'
end

app/controller/StaticPagesController.rbには各アクションの内容を記述する。

app/controller/StaticPagesController.rb
def home
#app/views/static_pages/home.html.erbを実行(省略されている記述)
end

def help
#app/views/static_pages/help.html.erbを実行(省略されている記述)
end

ユーザーに表示する画面はビューファイル (格納場所は app/views/コントローラ名/xxx.html.erb)
erbはembedded ruby (htmlファイルにRubyを埋め込める便利な拡張子)
<%> <%>で囲まれた部分がRubyのコード部分。

  • <%=> ... <%> 記述したコードの実行結果をHTML内に表示させる場合にはこっちを使う
  • <%> ... <%> 記述したコードの実行結果を表示させない場合はこっちを使う。

共通HTML部分はapp/views/layouts/application.html.erbで共有する

app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>
    <%= stylesheet_link_tag    'application', media: 'all',
                               'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag    'application',
                               'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <%= yield %>
  </body>
</html>

ページタイトルの受け渡しはprovideメソッド<% provide(:title, "Home") %>を各ビューに記述

app/views/static_pages/home.html.erb
<% provide(:title, "Home") %>
<h1>Sample App</h1>
<p>
  This is the home page for the
  <a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a>
  sample application.
</p>

テストはtestフォルダ以下に格納されている
test/controllers/static_pages_controller_test.rbにテストを記述する事で、
各ページにアクセスした際の応答、タイトル名、ページ要素等をテストできる。

test/controllers/static_pages_controller_test.rb
require 'test_helper'

class StaticPagesControllerTest < ActionDispatch::IntegrationTest

  def setup
    @base_title = "Ruby on Rails Tutorial Sample App"
  end

  test "should get home" do
    get static_pages_home_url
    assert_response :success
    assert_select "title", "Home | #{@base_title}"
  end

  test "should get help" do
    get static_pages_help_url
    assert_response :success
    assert_select "title", "Help | #{@base_title}"
  end

  test "should get about" do
    get static_pages_about_url
    assert_response :success
    assert_select "title", "About | #{@base_title}"
  end
end

元に戻す方法

項目 作成 元に戻す方法
コントローラー rails generate controller StaticPages home help rails destroy controller StaticPages home help
モデル rails generate model User name:string email:string rails destroy model User
データベース rails db:migrate rails db:rollback(一つ前の状態に戻す)
データベース rails db:migrate $ rails db:migrate VERSION=0(初期状態に戻す)

コマンドの短縮形

完全なコマンド 短縮形
rails generate rails g
rails destroy rails d
rails test rails t
rails console rails c
bundle install bundle

おまけ これでも長いという方へ・・・
Linuxのコマンドは.bashrcというファイルを編集する事でカスタマイズできます('ω')ノ

#STEP1 - c9 ~/.bashrc でファイルを開く。
c9 ~/.bashrc

#STEP2 - 文末に下記の様に短縮コマンドを登録する
alias r='rails'
alias g='git'

STEP3 - source ~/.bashrc を実行して登録した短縮コマンドを読み込む
source ~/.bashrc

#STEP4
r cと入力して rails consoleが立ち上がるか確認してみる('ω')ノ

感想

Rails Tutorialの動画(29800円)を見ながら復習がてらQiitaにアウトプットしていますが、
ウェブテキスト版には記述されていない便利な機能などの解説もあったりして満足しています。
今までc9コマンドはファイルを開くのに使っていました。
c9コマンドにopenオプションを付けるとファイルが存在しない場合に新規作成されるのは眉唾でした。
やっぱり人に解説してもらう方が頭にすんなり入ってきますね。
ちょっと高いですが、動画教材もなかなかにおススメです。
Udemy・Coursera・EduXといったオンライン学習サイトで無料~低価格で様々な内容を学習できます。
※Udemyは頻繁にセールを行っていてセール中は90%近く割引になるのでセール中の購入がおススメです。
一度購入したコンテンツは何度でも見れます!内容もかなり濃いものが多いです。

Udemy (https://www.udemy.com/)
Coursera (https://ja.coursera.org/)
EdX (https://www.edx.org/)

c9 open app/views/static_pages/about.html.erb

あとはcloud9上でCtrl + pでファイル検索が出来できるそうです('ω')ノ
私は毎回フォルダを開くことでどこに何があるか覚えたので最初はCtrl+pは使わない事を推奨します。
まぁ、いちいちフォルダを開くのが面倒な方は是非使ってみてください。

今回はテストという新たな内容が入ってきたので、なかなか濃い内容でした。
私は同じ内容を必ず数回読むようにしています。
特に私は物覚えが悪いので何度も繰り返してやっと覚えられる感じです。
見直してみると一回目に読んだ時とは違った気付きがあったりします。
是非、皆さんも一回だけではなく数回読み直してみてください('ω')ノ

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

【Rails】Rake taskでバッチ処理を実装してみた

はじめに

環境

Rails: 5.2.3
Ruby: 2.6.3
MySQL: 5.6.40

内容

  • usersテーブルのquestion_countカラムが更新されていないバグがあり、 バッチを作成し、一括で正しい値に更新できるようにしました。
  • 既存のメソッドを使用しているため分かりにくい箇所があるかもしれませんがご容赦ください。
user.rb
has_many :questions, dependent: false
has_many :only_questions_visible_to_user, -> { where(question_id: nil).visible_to_user }, class_name: 'Question', dependent: false

scope :visible_to_user, -> { where(is_invalid: false).where(deleted: false) }

def update_question_count!
  update!(question_count: count_questions)
end

private

# question_count を更新する時の集計に利用するメソッド
#
# @return [Integer]
def count_questions
  only_questions_visible_to_user.size
end

question.rb
belongs_to :user, optional: true

実装したコード

  • ログを出力して途中経過、更新に失敗したもの認識しやすいようにしてみました。
  • 一度のみの実行で、以降は必要なくなるため、one_shotディレクトリ配下に置いて実行後に削除します。
lib/tasks/one_shot/update_users_question_count.rake
# frozen_string_literal: true

namespace :user do
  desc 'Update users_question_count'
  task update_question_count: :environment do |_task|
    index = 0
    updated_question_counts = 0
    user_count = User.count
    logger = Logger.new($stdout)
    logger.info 'Start'

    User.find_each do |user|
      begin
        if user.question_count != user.only_questions_visible_to_user.size
          user.update_question_count!
          updated_question_counts += 1
        end
      rescue ActiveRecord::RecordInvalid => e
        logger.info "Failed to update user_id: #{user.id}"
        logger.info("#{e.class}: #{e.message}")
        next
      end

      index += 1
      case index
      when 4000, 8000, 12_000, 16_000
        logger.info "Progress: #{index}/#{user_count}"
      end
    end
    logger.info "Updated User Count: #{updated_user_counts}"
    logger.info 'Finished'
  end
end

バッチ実行

bundle exec rake user:update_question_count

  • 約19,000レコードの更新処理で45secほどかかりました。
  • 更新に失敗したカラムが表示されるので別途対応が容易になりました。 スクリーンショット 2020-10-26 午後2.36.25.png
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsで複数画像アップロード機能とその投稿に対して複数画像をスライドできるように実装してみた

1.複数画像アップロード機能を実装

carrierwaveを使用して複数枚の画像をアップロードできるように実装してみた。

carrierwaveとは?

carrierwaveとは、Railsアプリケーションから画像アップロード機能を簡単に実装できるライブラリ。今回は、carrierwave ver2.1.0を使用しました。

どのように使用したか?

まずは、下のGemをインストールする。

自分のアプリ/Gemfile

gem 'carrierwave'
gem 'mini_magick'

アップローダーを生成する。

rails g upload image

これにより次のファイルが生成される。このファイル内でカスタマイズしたいときは処理を加える。

app/upload/image_upload.rb

なので、自分は下のように設定を行いました。

自分のアプリ/app/upload/image_upload.rb

class ImageUploader < CarrierWave::Uploader::Base

    include CarrierWave::MiniMagick

    process resize_to_fill: [1000, 1000]

    version :thumb do
        process resize_to_fit: [223,223]
    end

    version :swiper do
        process resize_to_fit: [400, 400]
    end

    version :thumbnil do
        process resize_to_fit: [100, 100]
    end

    storage :file

    def store_dir
        "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
    end

     def extension_whitelist
        %w(jpg jpeg gif png)
     end

 end

どのように設定を加えていったかというと、、、

include CarrierWave::MiniMagick

アップロード時に画像のリサイズを行いたかったので、minimagickをインストール。image_upload.rb生成時にコメントアウトで記載してあるので#を消して処理コードとして記載。minimagickとは、CプログラムであるimagemagickのRubyのインターフェース。これによって、画像リサイズ用のメソッドを使用することが出来る。

下の処理は、アップロードされるとと、1000×1000pxで切り抜きを行い、次にthumbと呼ばれるバージョンが作成され、223×223pxに拡大縮小される。同じように、swiper、thumbnilと呼ばれるバージョンが作成され、各々のバージョンに拡大縮小される。
※ただし、チーム開発によってはあまりバージョンを増やすのは好ましくないとのこと。

process resize_to_fill: [1000, 1000]


version :thumb do
    process resize_to_fit: [223,223]
end

version :swiper do
    process resize_to_fit: [400, 400]
end

version :thumbnil do
    process resize_to_fit: [100, 100]
end

これは、画像がアップロードした時に保存される場所である。デフォルト記載されている。「public/uploads/指定したモデル名/指定したモデルのカラム名/モデルID/画像と各バージョンで作成した画像」のように置かれている。変更した場合は、オーバライドして記載すれば良い。

def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end

これもデフォルトでコメントアウトで記載されているので処理出来るように記載。許可される拡張機能のホワイトリストを指定することが出来る。jpg、jpeg、gif、png以外の拡張子をアップロードするとレコードが無効になる。

def extension_whitelist
    %w(jpg jpeg gif png)
end

ここまでで設定の説明は終わりにして、次に親となるpostテーブルと子のimageテーブルを作成する。
postとimageでテーブルを分けたのは、複数投稿に対応する為。

posts
content
images
url
post_id
$rails g model Post content:text 

$rails g model Image url:string post:reference

ここでつまずいたのが、自分の場合はimageモデル作成の際にjson型を扱ったことです。 もともと、postテーブル内でimageカラムを作成して複数投稿できる仕様にしようと思ったのですが、新しいimageテーブルを作成して保存するよう変更したため、わざわざjson型にしなくても良いということを後になって気づきました。なので、ここで一つのテーブルで複数画像を扱うならjson型にして、一つのオブジェクトレコードに複数画像を扱えるように設計するのもいいと思います。自分の場合は、別のテーブルを作成してjson型のままにしていますが、特に理由がないのならstring型で作成することをお勧めします。

マイグレーションファイルを作成して、データベースを更新する。

$rails db:migrate

モデルファイルに以下の記述を加える。

自分のアプリ/app/model/image.rb

class Image < ApplicationRecord
    belongs_to :post
    mount_uploader :url, ImageUploader #アップロード機能を使いたいデータにマウントする。
end

自分のアプリ/app/mode/post.rb

class Post < ApplicationRecord
    validates :content, presence: true, length: { maximum: 1000 }
    has_many :images, dependent: :destroy
    accepts_nested_attributes_for :images #postを投稿するとimageも同時に投稿できるようになる
end

ここで注意しなければならないのは、accepts_nested_attributes_forを使うときは、ストロングパラメータにimages_attributesカラムを追記しなければならないこと。以下のようになります。

自分のアプリ/app/controller/post_controller.rb

  def new
    @post = Post.new
    @image = @post.images.build
  end

  def create
    @post = current_user.posts.new(post_params)
    if @post.save
      redirect_to posts_path, success: "投稿しました"
    else
      flash[:danger] = "投稿に失敗しました"
      render :new
    end
  end

  private

  def post_params
    params.require(:post).permit(:content, images_attributes: [:url])
  end

これで複数画像をパラメーターとして渡せるように設定できました。
続いて、viewで画像をどのように複数投稿できるようにするか考えていきます。
ここで、自分は色々ハマまりました。fields_forメソッドでは、第2引数にmultiple: trueを記述することで複数投稿できるとのことですが、うまくいかず、、、。なので別の方法として、javascriptで複数投稿できるように実装しました。この記事がとてもよく書かれていたので参考にさせていただきました。→Qiita この記事の通りに設定すれば、javascriptが起動して、アップロードするたびにプログラムが動いてくれるはずです。

2. swiperで1つの投稿に対して複数画像をスライドできるように実装

swiperとは?

ざっくりというと、スライド機能の実装が簡単にできるフレームワーク。

どのように使用したか?

 まずは、アプリケーション内でswiperを使えるように設定します。いくつか方法があるのですが、私はyarnを利用して導入しました。こちらの記事のyarnでの導入方法や内容がとても分かりやすかったので参考にさせていただきました。
Qiita

swiperをyarnで導入します。

$yarn add swiper

$yarn install

導入できたか確認するには、packege.json を確認してください。もしyarnを導入していないのであれば、下記のコマンドでyarnを導入してください。(macをお使いの場合)

$brew installl yarn

導入したら、application.js、application.scssに下記のように記載します。

自分のアプリ/app/assets/stylesheets/application.scss

@import "swiper/swiper-bundle";

自分のアプリ/app/assets/javascript/application.js

 //= require swiper/swiper-bundle.js
 //= swiper.js

swiper.jsファイルを作成し、下記のように記述してください。swiperでは、swiperで加えたい種類のスライド方法を自分で記述し作成する必要があります。swiperのデモから自分のお好みのスライド方法を選び、ソースコードから!-- Initialize Swiper --より下のスクリプト内のjsのコードをコピペしてください。スクリプトタグは記載する必要はありません。私の場合は、ページネーション/動的弾丸でのスライドにしたので下記のようになります。このjsファイル名はswiper.jsでなくても構いません。ファイル名を変更したい場合は、applicaion.js内で記載したファイル名も変更してください。デモ

自分のアプリ/app/assets/javascript/swiper.js

var swiper = new Swiper(".swiper-container", {
pagination: {
    el: ".swiper-pagination",
    dynamicBullets: true,
    },
});

これで準備は整ったので、viewで実際に実装してみます。
ページネーション/動的弾丸での実装例なので他のスライド方法を選んだ方は、ソースコードを確認してください。

自分のアプリ/app/views/posts/index.html.slim

 .swiper-container.top-carousel
    .swiper-wrapper(style="transform: translate3d(0px, 0px, 0px)")
        - @post.images.each do |img|
            .swiper-slide(style="width: 400px;")
                = link_to post do
                = image_tag img.swiper.url, class: "card-img-top"
     .swiper-pagination

~省略~

= javascript_include_tag "application"  

ここで大事なのは、= javascript_include_tag "application"を一番最後に記述することです。これを書き忘れるとswiperが起動してくれません。application.html.slimに書くという方法もありますが、自分はswiperを必要とするページの部分だけに記述してます。また、このimg.url.swiper.urlは、carrierwaveで作成したswiperバージョンの画像を呼び出しています。

これで、自分の場合はswiperを実装することができました。

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

Railsで問い合わせフォームを実装する

RailsでGmailを利用した問い合わせフォームを実装しました。

ルーティングの設定

まず、ルーティングを設定します。
問い合わせフォームのページで問合せ内容を入力→送信したら送信完了ページに遷移するという想定です。

config/routes.rb
Rails.application.routes.draw do
  resource :contacts, only: [:new, :create] do
    get "/thanks" => "contacts#thanks"
  end
end

モデルの作成

問合せフォームで入力する内容は、お名前、メールアドレス、問合せ内容の3点としました。

$ rails g model contact name:string email:string content:text
$ rails db:migrate

コントローラの作成

$ rails g controller contacts
app/controller/contacts_controller.rb
class ContactsController < ApplicationController
  def new
    @contact = Contact.new
  end

  def create
    @contact = Contact.new(contact_params)
    if @contact.save
      ContactMailer.contact_mail(@contact).deliver
      redirect_to thanks_contacts_path
    else
      render :new
    end
  end

  def thanks
  end

  private
  def contact_params
    params.require(:contact).permit(:name, :email, :content)
  end
end

ビュー(お問い合わせフォーム)の作成

私が作成したサイトのテイストに合わせて一部ひらがなにしている箇所がございますが気にしないでください。

app/view/contacts/new.html.erb
<h3>おといあわせ</h3>
<%= form_with(model: @contact, local: true) do |f| %>
  <%= f.label :name, "おなまえ" %>
  <%= f.text_field :name %>
  <%= f.label :email, "メールアドレス" %>
  <%= f.email_field :email, autocomplete: "email" %>
  <%= f.label :content, "ないよう" %>
  <%= f.text_field :content %>
  <%= f.submit "おくる" %>
<% end %>

ビュー(送信完了画面)の作成

app/view/contacts/thanks.html.erb
<h3>おといあわせ、ありがとうございました。</h3>

メーラーの作成

$ rails g mailer ContactMailer

メール送信処理を記載

app/model/contact_mailer.rb
class ContactMailer < ApplicationMailer
  def contact_mail(contact)
    @contact = contact
    mail to:"自分のメールアドレス", subject: "お問い合わせ"
  end
end

メール文の作成

app/view/contact_mailer/contact_mail.html.erb
<p>ユーザーネーム:<%= @contact.name %></p>
<p>メールアドレス:<%= @contact.email %></p>
<p>お問い合わせ内容:<%= @contact.content %></p>

Gmailサーバーの設定

config/environments/development.rb
Rails.application.configure do
  config.action_mailer.perform_deliveries = true
  config.action_mailer.raise_delivery_errors = true
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = {
    address: 'smtp.gmail.com',
    domain: 'gmail.com',
    port: 587,
    user_name: '自分のメールアドレス',
    password: ENV["GMAIL_KEY"],
    authentication: 'plain',
    enable_starttls_auto: true
  }
end

パスワードはGitHubに上がってしまわないように、.envファイルに記載することにします。

Gmailキーの設定

アプリケーションディレクトリ直下の.envファイル(ない場合は作成)に以下を記載します。

GMAIL_KEY=パスワード

ここに入力するパスワードはGoogleアカウントにアクセスし生成したアプリパスワードを入力します。

セキュリティ→Googleへのログインの欄
2段階認証を設定していない方は、まず設定をした上で、アプリパスワードを生成します。
ここで生成したパスワードを入力します。

こちらで実装は完了です。

これで問合せフォームからメールを送信すると
スクリーンショット 2020-10-25 23.32.31.png

無事、送受信ができました。

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

Docker × Rails × RSpecで開発環境で’Could not find ’****’ in any of the sources’が出た時の対処方法

【Rails】Docker × Rails × RSpecの開発環境で’Could not find ’****’ in any of the sources’が出た時の対処方法

Gemfile
group :development, :test do
  ~ 以下追加 ~
  gem 'rspec-rails'
  gem 'factory_bot_rails'
end

Gemfileを更新したのでdockerコマンドでbundle install実行

$ docker-compose run web bundle exec rails g rspec:install

エラーメッセージ

Could not find diff-lcs-1.4.4 in any of the sources
Run `bundle install` to install missing gems.

色んな記事を参照させてもらって実行してみるもなかなかうまくいかず・・・

解決方法

いろいろググっている内にキャッシュで bundle install が実行されないていない場合がある?という記事を見させていただき、早速実行しました

$ docker-compose build --no-cache

実行結果

$ docker-compose run web bundle exec rails g rspec:install
Creating app_run ... done
Running via Spring preloader in process 64
      create  .rspec
      create  spec
      create  spec/spec_helper.rb
      create  spec/rails_helper.rb

見事クリエイトに成功

原因

docker-compose build しても cache が有効になっていて設定変更が反映されてうまく動作しないことがあるので、開発中にGemfileを更新した時は

$ docker-compose build --no-cache

で実行する方がいいとのことです

まとめ

spring stop関連の記事が多かったため解決するのに時間がかかってしまった点が反省点。でも初学者だからこそこの積み重ねが大事とも感じました

参考

以下の記事参考にさせていただきました!ありがとうございました!

Dockerでコンテナ内にbundle installされない問題の解決法
docker をキャッシュを使わないでビルドする

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

[解決] RailsでWebpacker::Manifest::MissingEntryError

はじめに

RailsのWebpacker::Manifest::MissingEntryErrorは、初学者あるあるらしい。
でもすぐ解決できた。

発生した場面

Rails6,MySQLをDockerで環境構築した.

"yay, you are on rails!"

早速書き始めて、root ディレクトリを変えたり、viewを書いたりして、ブラウザで確認。

Webpacker::Manifest::MissingEntryError

解決方法

qiita.rb
bundle exec rails webpacker:install

他の方法
https://github.com/rails/webpacker/issues/1730
https://blog.yuhiisk.com/archive/2018/04/24/rails-error-collection.html#Webpacker

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

thinreportsで中国語(韓国語)のPDFを表示したい

カスタムフォントが選択できない

Screen Shot 2020-10-26 at 11.12.08.png

現状フォントは固定で、持ち込みのフォントは指定できない様子。
このまま中国語(韓国語でも)を入れようとすると、PDFの状態で文字化けを起こす。

解決方法

韓国語や中国語のテキストをPDFで表示できない

Railsであれば、ここにあるようにinitializerをつくってやる。

config/initializers/thinreports.rb
Thinreports.configure do |config|
  config.fallback_fonts <<
    Rails.root.join("app/thinreports/NotoSansCJKsc-Regular.ttf").to_s
end

ここで重要なのはttfフォントで、NOTOフォントを使う必要がある。
(□表示は英語圏ではTOFUと呼ばれ、もう豆腐表示はうんざり - no more tofu - NOTO らしい 、ついでにtofulearn.com

最初は「CJK」なんだからフォントファイル一個でChineseJapaneseKorean全部表示できるんでしょ?って思ってたけど、どうやら違う。適当にダウンロードしてきたNotoCJKファイルは日本語バージョンだったため引き続き中国語の表示ができなかった(□になる部分がPDFでは空白表示だった)。

よくよく調べるとCJKでも各地域ごとのフォントバージョンがあるらしい。

  • Simplified Chinese (SC)
  • Traditional Chinese (TC)
  • Japanese (JP)
  • Korean (KR)

最初に使ってたファイルはよくよく見るとNotoSansCJKjp-Regular.ttfだった。なので、NotoSansCJKsc-Regular.ttfを適当に探してみて、当ててみたらバッチリだった。

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

Rails でmarkdownを実装

はじめに

今回はメモアプリを開発しているのですがメモの投稿をmarkdownで実装したいと思い今回はその方法について学習していきます。

今回欲しかった機能
・markdown
・リアルタイムプレビュー

gemの導入

gem 'redcarpet', '~> 2.3.0'
gem 'coderay'
bundle install

マークダウン記法の実装

app/heplers/markdown_helper.rb
上記のファイルのところにmarkdown_helper.rbのファイルを新しく作成する。

markdown_helper.rb
module MarkdownHelper
  def markdown(explanation) #()内はカラム名を入れる
    options = {
    filter_html: true,
    hard_wrap: true,
    space_after_headers: true,
    with_toc_data: true
    }

    extensions = {
    autolink: true,
    no_intra_emphasis: true,
    fenced_code_blocks: true,
    tables: true
    }

    renderer = Redcarpet::Render::HTML.new(options)
    markdown = Redcarpet::Markdown.new(renderer, extensions)
    markdown.render(explanation).html_safe #()内にはカラム名
  end
end

optionsとextentionsの中身(filter_htmlとか)は参考サイトを参照してほしい。もっと丁寧に書いてあって参考になるはず。

リアルタイムプレビューの実装

まず、vue.jsとmarked.jsを読み込むように記述をする。

application.html.erb
<-- Vue.js読み込みの記述-->
<script src='https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.10/vue.js'></script>
<--marked.js読み込みの記述-->
<script src='https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.5/marked.js'></script>

viewの修正

new

_form.html.erb
<%= form_with model:note, local: true do |f| %>
  <div class='form-group'>
    <%= f.label :タイトル %>
    <%= f.text_field :title, class: 'form-control', id: 'note_title' %>
  </div>
  <div class='form-group'>
    <%= f.label :カテゴリー %>
    <%= f.collection_select :category_id, Category.all, :id, :name %>
  </div>
  <div class='form-group'>
    <div id='editor'>
      <%= f.label :内容 %>
      <%= f.text_area :explanation, rows: 5, class: 'form-control', id: 'note_explanation', "v-model" => "input", name: "note[explanation]" %>
    <div v-html='input | marked'></div>
  </div>
  <%= f.submit '登録', class: 'btn btn-success' %>
  </div>
  <% end %>

  <!-- リアルタイムプレビュー -->
  <script type="text/javascript">
    window.onload = function() {
      new Vue({
      el: '#editor',
      data: {
        input: '<%== j @note.explanation %>',
      },
      filters: {
      marked: marked,
      },
      });
    };
  </script>

上記のようになるのですが、部分的に解説をします。

<!-- リアルタイムプレビュー -->
  <script type="text/javascript">
    window.onload = function() {
      new Vue({
      el: '#editor',
      data: {
        input: '<%== j @note.explanation %>',   # 自分で設定したインスタンス変数とカラム名
      },
      filters: {
      marked: marked,
      },
      });
    };
  </script>

input: '<%== j @note.explanation %>'はeditの時にnote.explanationをフォームに入れるためです。

次に苦労したのが、form_withのf.text_areaにv-model inputを持たせてやる方法でした。v-というのが、Vue.js独特の記述らしく、Rubyタグの中で使うには

"v-model" => "input"

としてやる必要がありました。-で区切っているため、””なしで記述しても反応がありませんでした。

次にname属性です。

name: "note[explanation]" アプリ名[カラム名]

上記のように指定します。

最後に、text_areaに記述された部分が表示されるように記述をしてやる必要があります。

v-htmlもvue.jsの表現です。

ここでは、rubyタグではなく、HTMLタグ内の表記なので、このままで問題ありません。

show

私の場合、showアクションにマークダウン記法の記事を表示させたいと思っているので、それを修正する。

<div class='stretch-text'>
  <h2>タイトル:<%= @note.title %></h2>
  <h2>カテゴリ:<%= @note.category.name %></h2>
  <h2>説明:<%= markdown(@note.explanation) %></h2>   #ここを修正
  <%= link_to "編集する", edit_note_path(@note),data: {"turbolinks" => false} %>
  <%= link_to "削除", note_path(@note), method: :delete %>
</div>

変更点はmarkdown(“#{@note.explanation})としたところです。

こうすることで、マークダウン記法を読み取れるようになりました。

これで完成!

ここまで来れば実装できると思います。

最後に

説明不足のところや理解不足のところが多々ありますが分かり次第更新していこうと思います。
また、間違っていることろがあればご教授のほどよろしくお願いします。

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

ストロングパラメータはtrueなのになぜかテーブルに保存できない。

うまくいかなかったこと

paramsに値は入っているのに、テーブルに保存ができない。エラーも出ない。

ターミナル
     6: def create
     7:   judge = Judge.new(judge_params)
     8:   judge.save
 =>  9:   binding.pry
    10: 
    11:   redirect_to  root_path 
    12: end

[1] pry(#<JudgesController>)> judge
=> #<Judge:0x00007fd58efb37c0
 id: nil,
 judge_correct_id: 2,
 comment: "めお",
 created_at: nil,
 updated_at: nil>
[2] pry(#<JudgesController>)> judge.save
=> false

結論

アソシエーションを組んで外部キーが存在するはずなのに、それをmigrationファイルに記入していなかったから。

検証方法(save!メソッド)

saveメソッドはtrueかfalseしか返しませんが、save!メソッドはfalseの場合、例外が発生するそうなので、ターミナルにエラーの原因となっていることが表示されました。
ターミナル上でインスタンス変数.saveとしてfalseと返されたところをインスタンス変数.save!としたところ、

Validation failed: User must exist, Post must exist・・・hogehoge

という記述がありました。
確かにアソシエーションを組んでいるのにUserとPostに関係するidを作成していなかったなと思い、追加したところうまく行きました。

以上

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

rails-erdを使って分割したyamlの設定ファイルごとにERDを自動生成する

はじめに

前回の「rails-erd はどうやってエンティティや関連づけ情報を取得しているのか」に引き続き、rails-erd 関連の記事になります。

rails-erd を使うと ERD をコマンド一つで自動生成できます。ただ、一つの ERD に全てのモデルを表示させようとすると、 かなり見辛い です。そこで今回は、グループ分けしたモデルごとに yaml の設定ファイルを用意し、コマンドで一つで、全てのグループの ERD を一括生成する実装について紹介したいと思います。

ちなみに、エンブレースが開発している MCS の全モデルを1つの ERD に含めて生成するとこんな感じになります?
(※ 解像度を低くしてます。)

Screen Shot 2020-10-26 at 12.56.09.png

全体像

まずは、出来上がるファイル構成を紹介します。

erd
 ├── config
 │    └── xxx.yml     # 設定ファイルたち
 ├── xxx.png          # 生成されたERDたち
lib
 └── task/erd.rake    # タスク
  • erd/config/ 配下に xxx.yml という設定ファイルを設置
  • lib/task/erd.rake にタスクを作成
  • erd.rake で作成したタスクを実行すると、erd/ 配下に ERD が自動生成される?

といった感じのものを作っていきます。

rails-erd の導入

rails-erd の導入方法については、他に紹介している記事がたくさんあるので、こちらの記事では省略します。

設定ファイルの設置

ファイルごとに全てのオプションを書くのは冗長なので、共通オプションを記載する共通ファイルを一つ用意し、個別ファイルには共通ファイルとの差分のみ記載するような作りにします。

共通ファイル

まずは、共通ファイルを準備し、オプションを記載します。

common.yml
attributes:
  - content
  - foreign_key
disconnected: true
filename: erd/dummy
filetype: png
indirect: false
inheritance: true
markup: true
notation: crowsfoot
orientation: vertical
polymorphism: false
sort: false
warn: false
title: dummy
exclude: null
only: null
only_recursion_depth: null
prepend_primary: false
cluster: false
splines: spline

※ ちなみに、どのようなオプションがあるかは、以下のコマンドで確かめられます。

$ erd -h

個別ファイル

次に、個別ファイルを作成します。
こちらは、titleonly だけの指定になるので、かなり簡潔です?

xxx.yml
title: sample title
only:
  - XXX
  - YYY
  - ZZZ

※ 個別ファイルのファイル名と生成される ERD のファイル名が異なっているとわかりづらいので、オプションの filename は、タスクの中で自動的に個別ファイルのファイル名で上書きされるようにします。

タスクの作成

Kernel.#system を使えば、system("bundle", "exec", "erd") のような形で、rails-erd が用意したタスクを実行できますが、より簡潔にするため RailsERD::CLI を使って実装していきたいと思います。
※ RailsERD::CLI は、名前の通り ERD の生成を CLI から実行するためのクラスです。

erd.rake
# RailsERD::CLI を利用できるようにするため、rails_erd/cli を読み込む
require "rails_erd/cli"

namespace :erd do
  desc "ERDの一括生成"
  task bulk_generate: :environment do
    common_file = Pathname.new("erd/config/common.yml")
    common_options = YAML.load_file(common_file)

    partial_files = Pathname.new("erd/config").glob("*").reject {|file| file == common_file }
    partial_files.each do |partial_file|
      partial_options = YAML.load_file(partial_file)
      partial_file_name = File.basename(partial_file, ".*")

      # 共通オプションと個別オプションの結合
      # 個別ファイルのファイル名で filename を上書き
      # キーを文字列からシンボルに変更する
      options = common_options
                  .merge(partial_options)
                  .merge({ filename: "erd/#{partial_file_name}" })
                  .symbolize_keys

      # ERD生成の開始
      RailsERD::CLI.new(Dir.pwd, options).start
    end
  end
end

これで、以下のコマンドで ERD が一括生成されるようになるはずです!

$ bundle exec rake erd:bulk_generate

モデルのグループ分けのコツ

上記で ERD の一括生成の方法の説明は終わりなのですが、モデルのグループ分けも一筋縄ではいかなかったので、筆者がグループ分けしてみて得た知見を共有したいと思います。

機能ごとにグループ分けする

  • 例)ログイン機能、通知設定機能、etc.
  • メリット
    • 機能ごとに分けることでビジネスロジックが理解しやすくなる
    • テーブル数を程よく少なくできる

1つのERDに含むテーブルはせいぜい10個程度にする

一つの ERD に10個以上のテーブルが入る場合は、機能を分割できないか検討してみると良いです。

  • メリット
    • どのテーブル、関連付けが重要かすぐにわかる
    • 見辛さを緩和できる

ファイル名は、機能の中心となるテーブル名に寄せる

  • 例)通知設定のメインのテーブルが notification_settings であれば、ファイル名を notification_setting.yml にする
  • メリット
    • ファイル名とテーブル名が結びつき、何の機能か推測しやすい
    • 中心となるテーブルがわかる
    • ファイル名に統一感を出すことができる
  • 補足
    • 機能の中心となるテーブルが中間テーブルで、機能の名称として相応しくない場合や、すでに機能に名前がついている場合などは、テーブル名とは別の名前をつけるのが吉

最後に

rails-erd を使用して複数の ERD を一括生成する方法、そしてモデルのグループ分けのコツについて紹介しました。新規メンバーとしてプロジェクトに加わった際には、ERD があるとビジネスロジックの理解がスムーズになるため、大変ありがたいです。こちらの記事が ERD を用意する上での参考になれば幸いです。

参考

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

deviseでsign up しようとすると自動でroot_pathにリダイレクトしてしまう

結論

ログイン時は新規登録とログインのリンクを表示しないように設定する。
明らかにわかることもボーッと同じことを考えていると抜け出せなくなるのでリフレッシュするか人に話すことが大切。

現象

deviseでsign up しようとすると自動でroot_pathにリダイレクトしてしまっていました。
なぜかデータベースに保存されていたものを削除したら新規登録ページに行けました。

rails sを立ち上げているターミナルを観察すると、
Redirected to http://localhost:3000/
という文字がありました。

実際新規登録をクリックしたときに一瞬URIが表示されているのが見えていました。

二重でログインできないようになっていると考えられる。当たり前。

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

"Docker-compose" で "Rails6" の安定的な開発環境構築マニュアル

本記事の目的

Docker・Rails初心者である私がDocker-composeを使用しRails6の環境構築を行った際
御見識ある方に情報を提供頂き、無事に環境構築する事ができました。
しかしながら、構築内容で実行している内容が初心者の私には非常に理解しづらく、
Rails5での環境構築時と違い処理事項を間違えると環境構築できませんでした。
環境構築にあたり、ポイントが複数あると思います。

本記事では自身が相談し、回答頂いた事項を元に

  • 環境構築時のコードを分解解説し自身の学習と知識定着を行う
  • 自身の忘備録と今後の環境構築時のマニュアルとして使う
  • 他の方に少しでも参考資料として役立ててもらえればとの意図

上記を目的にまとめました。

初心者ゆえに間違いがあるかもしれませんが、お気づきの点がありましたら、
ご指摘頂けますと幸いです。
少しでも参考になりましたらLGTM頂けると感激です。

この記事で作成する環境

Docker-compose

  • Web
    • Ruby version:2.7〜
    • Rails version:6.0.3.4〜
  • db
    • PostgreSQL version: 12.4〜

とりあえず使いたい方

早々に使ってみて構築したい方は下記GitHubリポジトリに公開しております。
READMEに手順記載しておりますが、下記のコマンドを順に実行して下さい。

  1. 下記サイトのREADMEよりgit clone <Project name> の実行
  2. cd <Project name> でプロジェクトディレクトリ移動
  3. ./qs setup コマンド実行

*下記サイトのREADMEを参照して実行をお願いします。
Rails6-QS

コマンド完了まで20分ぐらいかかります。
辛抱強くお待ち願います。(笑)
終わるとブラウザでlocalhost:3000を叩けばお馴染みのRails初期画面が現れます。
DockerのDashboardにもプロジェクト名の中にweb,dbのコンテナがあるはずです。

この記事で作成するもの

  • Dockerfile
  • Docker-compose.yml
  • シェルスクリプト(sample.bash)
    *公開リポジトリはqs(クイックスタートの略)と名前をしております。
  • .gitignore
  • Gemfile
  • database.yml

①Dockerfileの作成

まずはDockerfileから作成を行なっていきます。
Dockerfileの作成にあたっては

上記のサイトの説明がわかりやすく整備されています。

Dockerfile で定義されたイメージを使って作成されるコンテナは、可能ならばエフェメラル(短命;ephemeral)にすべきです。私たちの「エフェメラル」とは、停止・破棄可能であり、明らかに最小のセットアップで構築して使えることを意味します。

上記サイト引用の通りDockerfileは最小のセットアップで構築する事を目指しております。
以降で今回作成するDockerfileを項目毎に説明していきます。

ファイルの構成

Rubyバージョンの指定 Version:2.7

FROM ruby:2.7

rails consoleで日本語を使う為に必要

ENV LANG C.UTF-8

警告非表示・リッスンポート設定

  1. DEBCONFの警告をなくすための設定
    [Ubuntu manual] http://manpages.ubuntu.com/manpages/bionic/man7/debconf.7.html
  2. apt-keyコマンドによって出る警告防止の為
  3. Dockerのマウント領域に生成されるファイルが、
    キャッシュディレクトリの書き込み権限が無くてエラーを吐くケースがあリます。
    XDG_CACHE_HOMEに書き込み権限のあるディレクトリを指定してますが、
    どうもRailsのみの使用では発生しなさそうです。
    問題なければ外してもいいと思います。
  4. コンテナが接続用にリッスンするポート
ENV DEBCONF_NOWARNINGS yes
ENV APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE yes
ENV XDG_CACHE_HOME /tmp
EXPOSE 3000

コンテナパッケージインストール

  1. apt-get とapt-get install-y でキャッシュ利用されず最新バージョンのパッケージを使用できる。
  2. ビルドツールのインストール
  3. PostgreSQL対応に必要です。
  4. vimのインストール*
  5. lessコマンド(linux)を追加する為に指定しています。*
  6. オープンソースのツールパッケージgraphvizを使う為*

*印部分は使わない場合は削除してもいいと思います。

RUN apt-get update -qq && apt-get install -y \
    build-essential \
    libpq-dev \
    vim \
    less \
    graphviz

yarnのインストール

Rails6よりWebpackが標準となったので、yanrインストールがないとエラーが発生します。

  1. https対処の為 apt-transport-https でパッケージをインストールしています。
  2. その後のコマンドはyarnのインストールです。
RUN apt-get install apt-transport-https
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN apt-get update && apt-get install -y yarn

ワークディレクトリの作成

# setting work directory
RUN mkdir /app
WORKDIR /app

環境変数設定

  • スクリプトやコンテナに入ったときに使う為
ENV HOME /app

Gemfile作成

COPY Gemfile /app/Gemfile

上記全てを記載すると下記の内容になると思います。
(*部分的にコメント追記しております。)

# use ruby version 2.7
FROM ruby:2.7

# using japanese on rails console
ENV LANG C.UTF-8

# remove warn
ENV DEBCONF_NOWARNINGS yes
ENV APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE yes
ENV XDG_CACHE_HOME /tmp
EXPOSE 3000

# install package to docker container
RUN apt-get update -qq && apt-get install -y \
    build-essential \
    libpq-dev \
    vim \
    less \
    graphviz

# install yarn
RUN apt-get install apt-transport-https
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN apt-get update && apt-get install -y yarn

# setting work directory
RUN mkdir /app
WORKDIR /app

# setting environment value
ENV HOME /app

# executing bundle install
COPY Gemfile /app/Gemfile

②Docker-compose.yml ファイルの作成

docker-composeのversion指定

現状は3です。

version: '3'

service作成

  • image
    データベース・webなどを指定します。
    今回使われそうな db redis chrome web: &app spring solagraphを指定しました。
    必要に応じて削除等して修正頂ければと思います。
  • port
    ポートの設定(一般的に設定されるポート内容で作成しております。)
  • volume
    マウント設定。db等Dockerコンテナ削除後に抹消しては困るデータの格納先の指定です。
  • build
    Dockerfile等があるパスを示しますが、基本は.でカレントディレクトリとなります。

補足的事項

  • shm_size
    selenium-chromeを使用した場合メモリ不足なる事あるので少し増やしています。
  • .:
    docker-composeの機能でボリュームの読み込みを高速化するために使用しています。
  • <<: *app
    webサービスの設定をspringに継承しています。
  • tty: true
    コンテナを起動し続ける設定
  • ポート設定について
    左側がホスト側のポートで、右側がコンテナ側のポートとなります。

これも上記全て記載してまとめると下記の通りとなります。

version: '3'
services:
  db:
    image: postgres
    ports:
      - "5432:5432"
    volumes:
      - data:/var/lib/postgresql/data:cached
    environment:
      POSTGRES_PASSWORD: postgres
  redis:
    image: redis
    ports:
      - "6379:6379"
    command: redis-server --appendonly yes
    volumes:
       - redis-data:/data:cached
  chrome:
    image: selenium/standalone-chrome
    ports:
      - "4444:4444"
  web: &app
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/app:cached
      - bundle:/usr/local/bundle:cached
      - /app/.git
    environment:
      HOME: /app
      RAILS_ENV: development
    ports:
      - "3000:3000"
    tty: true
    links:
      - db
  spring:
    <<: *app
    command: bundle exec spring server
    ports: []
  solargraph:
    <<: *app
    command: bundle exec solargraph socket --host=0.0.0.0 --port=7658
    ports:
      - "8091:7658"
    links: []

volumes:
  bundle:
    driver: local
  data:
    driver: local
  redis-data:
    driver: local

③スクリプト作成

シェルスクリプトで実行内容をまとめておきます。こうする事によりDockerfileを「停止・破棄可能であり、明らかに最小のセットアップで構築して使えること」が実現できます。シェルスクリプトとは、Unixコマンドを実行するために使用されるものです。

シェルスクリプトの基本抜粋

シャルスクリプトの解説記事ではありませんが、自身が対象シェルスクリプトを理解する為に基本事項を抜粋し記載します。
記事作成とシェル動作の理解にあたり下記サイトを参考にさせて頂きました。
[初心者向けシェルスクリプトの基本コマンドの紹介]
https://qiita.com/zayarwinttun/items/0dae4cb66d8f4bd2a337
[シェルスクリプトリファレンス]
https://shellscript.sunone.me/

  • 宣言
    #!/bin/bash
    シェルスクリプトの宣言を行うために必要。
    #!/bin/shの書き方もありますが、bashの独自機能を使う場合はshではNGとなります。
    参考にしたサイト:https://sechiro.hatenablog.com/entry/20120806/1344267619
    特にこだわりがなければ、#!/bin/bash とするといいと思われます。

  • コメントアウト
    先頭に#をつけるだけです。

  • 出力
    echoで出力

  • if条件

    • ifの基本の書き方は if [ 条件 ] then コマンド fi です。
    • 条件が真の場合 then の次のコマンドを実行します。
    • 違う条件の場合 elif [ 条件2 ] を確認します。
    • 真の条件がない場合 else の次のコマンドを実行して終了します。
    • else がない場合は、そのまま終了します。
  • 引数の取り方
    変数をアクセスする時変数名の前に$を入れます。あるいは$入れて変数を{}で囲みます。

  • -e
    特殊テキストをエスケープ

  • $*
    全部の引数をまとめて1つとして処理。同じような処理に$@があります。
    ダブルコーテーションで囲なければ$@と同じであるが、囲むと引数毎に出力するか、
    まとめて一つの引数で出力するかの違いがあります。

  • $1
    1番目の引数

  • $0
    スクリプト名

  • 関数
    シェルスクリプトでは、関数を書いて引用することができます
    Function () {
    echo
    }

  • 終了処理
    スクリプトを途中で終了するにはexitコマンドに数字を与えます。

  • Swith
    switchの基本の書き方は case 変数 in 条件・値) コマンド ;; esac です。
    条件・値が変数と合う場合次のコマンドを実行します。

シェルスクリプト構成の概要

  1. 最初にdocker-composeのコマンドをフルパスでdcに指定します。
  2. dockerがインストールしていない場合はインストールをするようにメッセージが出ます。
  3. それぞれの変数に値を格納します(rm, app, db, app_name)
  4. echoで$1のコマンド値を実行
  5. $1は関数で与えられた値(関数によってはswitch構文で展開)される与えられたコマンドを処理する形になります。
  6. $0でスクリプト名を記載しhelpとして使用できるようにしています。

上記内容で、各種コマンドや設定事項を入れ込んだスクリプトファイルを作成すると下記の通りとなります。

qs.bash
dc=$(which docker-compose) # docker-compose command with full path

if [[ -x "$dc" ]]; then
  :
else
  echo "Please install Docker before run this command."
  exit 2
fi

rm="--rm" # To destroy a container

app="web" # describe $application service name from docker-compose.yml

db="db" # describe database service name from docker-compose.yml

app_name=$(pwd | awk -F "/" '{ print $NF }') # get project dir name

# define container name
app_container="${app_name}_${app}_1"
db_container="${app_name}_${db}_1"

echoing() {
  echo "========================================================"
  echo "$1"
  echo "========================================================"
}

rm_pids() {
  if [ -f "tmp/pids/server.pid" ]; then
    rm -f tmp/pids/server.pid
  fi
}

create_project() {
  echoing "Exec Bundle Install for executing rails new command"
  compose_build $app
  bundle_cmd install

  echoing "Exec rails new with postgresql and webpack"
  bundle_exec rails new . -f -d=postgresql $*

  echoing "Update config/database.yml"
  mv database.yml config/database.yml

  echoing "Exec db create"
  bundle_exec rails db:create

  echoing "docker-compose up"
  compose_up $app

  echo "You can access to localhost:3000"
}

init_services() {
  echoing "Building containers"
  $dc down -v
  $dc build --no-cache $app

  bundle_cmd install

  if [ "--webpack" == "$1" ]; then
    run_yarn install
  fi

  rails_cmd db:migrate:reset
  rails_cmd db:seed

  rm_pids

  $dc up $app
}

compose_up() {
  echoing "Create and start containers $*"
  rm_pids
  $dc up -d "$1"
}

compose_down() {
  echoing "Stop and remove containers $*"
  $dc down $*
}

compose_build() {
  echoing "Build containers $*"
  $dc build $*
}

compose_start() {
  echoing "Start services $*"
  rm_pids
  $dc start $*
}

compose_stop() {
  echoing "Stop services $*"
  $dc stop $*
}

compose_restart() {
  echoing "Restart services $*"
  $dc restart $*
}

compose_ps() {
  echoing "Showing running containers"
  $dc ps
}

logs() {
  echoing "Logs $*"
  $dc logs -f $1
}

invoke_bash() {
  $dc run $rm -u root $1 bash
}

invoke_run() {
  renv=""
  if [ -n "$RAILS_ENV" ]; then
    renv="-e RAILS_ENV=$RAILS_ENV "
  fi

  if [ -n "$TRUNCATE_LOGS" ]; then
    renv="$renv -e TRUNCATE_LOGS=$TRUNCATE_LOGS "
  fi

  dbenv=""
  if [ -n "$DISABLE_DATABASE_ENVIRONMENT_CHECK" ]; then
    dbenv="-e DISABLE_DATABASE_ENVIRONMENT_CHECK=$DISABLE_DATABASE_ENVIRONMENT_CHECK "
  fi

  $dc run $rm ${renv}${dbenv}$*
}

run_app() {
  invoke_run $app $*
}

run_db() {
  invoke_run $db $*
}

run_spring() {
  $dc exec spring $*
}

run_solargraph() {
  invoke_run solargraph $*
}

rails_server() {
  rm_pids
  # $dc run $rm ${renv}--service-ports $app rails s -p 3000 -b 0.0.0.0
  $dc run $rm --service-ports $app bundle exec foreman start -f Procfile.dev
}

rails_db() {
  case "$1" in
  set)
    rails_cmd db:migrate
    ;;
  up)
    rails_cmd db:migrate:up VERSION="$2"
    ;;
  down)
    rails_cmd db:migrate:down VERSION="$2"
    ;;
  reset)
    rails_cmd db:reset
    ;;
  *)
    rails_cmd db:migrate:status
    ;;
  esac
}

spring_db() {
  case "$1" in
  set)
    spring_cmd rake db:migrate
    ;;
  up)
    spring_cmd rake db:migrate:up VERSION="$2"
    ;;
  down)
    spring_cmd rake db:migrate:down VERSION="$2"
    ;;
  reset)
    spring_cmd rake db:reset
    ;;
  *)
    spring_cmd rake db:migrate:status
    ;;
  esac
}

spring_dive() {
  $dc exec spring bash
}

rails_cmd() {
  bundle_exec rails $*
}

rake_cmd() {
  bundle_exec rake $*
}

rspec_cmd() {
  $dc start chrome
  bundle_exec rspec $*
}

test_cmd() {
  bundle_exec test $*
}

bundle_cmd() {
  run_app bundle $*
}

bundle_exec() {
  run_app bundle exec $*
}

rubocop_cmd() {
  bundle_exec rubocop $*
}

rails_console() {
  bundle_exec rails c $*
}

spring_cmd() {
  run_spring spring $*
}

solargraph_cmd() {
  run_solargraph solargraph $*
}

rake_reset_db() {
  echoing "Running reset db"
  compose_stop $app
  DISABLE_DATABASE_ENVIRONMENT_CHECK=1 rake_cmd "db:reset"
  rake_cmd "db:fdw:setup"
  RAILS_ENV=test rake_cmd "db:fdw:setup"
  compose_up $app
}

db_console() {
  # from config/database.yml
  database="development"
  username="postgres"
  port="5432"

  run_db psql -h $db_container -p $port -U $username $database
}

db_dump() {
  # from config/database.yml
  database="development"
  username="postgres"
  port="5432"

  tm=$(date +\%Y\%m\%d-\%H\%M)
  dump_file=tmp/dbdump-${dbname}-${tm}.dump

  echoing "Dump database $dbname data to $dump_file"

  run_db pg_dump -h $db_container -p $port -U $username --disable-triggers $database >$dump_file
  echo "done"
}

run_yarn() {
  run_app bin/yarn $*
}

run_npm() {
  run_app npm $*
}

run_webpack() {
  run_app webpack $*
}

cmd=$1
shift
case "$cmd" in
setup)
  create_project $* && exit 0
  ;;
init)
  init_services $* && exit 0
  ;;
ps)
  compose_ps && exit 0
  ;;
up)
  compose_up $* && compose_ps && exit 0
  ;;
build)
  compose_build $* && exit 0
  ;;
start)
  compose_start $* && exit 0
  ;;
stop)
  compose_stop $* && exit 0
  ;;
restart)
  compose_restart $* && exit 0
  ;;
down)
  compose_down $* && exit 0
  ;;
logs)
  logs $*
  ;;
bash)
  invoke_bash $*
  ;;
run)
  invoke_run $*
  ;;
server)
  rails_server $*
  ;;
rails)
  rails_cmd $*
  ;;
db)
  rails_db $*
  ;;
cons)
  rails_console $*
  ;;
rake)
  rake_cmd $*
  ;;
rspec)
  rspec_cmd $*
  ;;
test)
  test_cmd $*
  ;;
bundle)
  bundle_cmd $*
  ;;
rubocop)
  rubocop_cmd $*
  ;;
reset-db)
  rake_reset_db
  ;;
psql)
  db_console $*
  ;;
db-dump)
  db_dump $*
  ;;
yarn)
  run_yarn $*
  ;;
npm)
  run_npm $*
  ;;
webpack)
  run_webpack $*
  ;;
spring)
  spring_cmd $*
  ;;
sdb)
  spring_db $*
  ;;
sdive)
  spring_dive $*
  ;;
solargraph)
  solargraph_cmd $*
  ;;
*)
  read -d '' help <<-EOF
Usage: $0 command

Service:
  setup    Create new rails application
  init     Initialize backend services then run
  ps       Show status of services
  up       Create service containers and start backend services
  down     Stop backend services and remove service containers
  start    Start services
  stop     Stop services
  logs     [options] default: none. View output from containers
  bash     [service] invoke bash
  run      [service] [command] run command in given container

App:
  server   Run rails server
  rails    [args] Run rails command in application container
  rake     [args] Run rake command in application container
  db       [args] Run rails db command you can use set(migrate), up, down, reset, other is status
           ex: ./qs db set #running rails db:migrate
               ./qs db up 2019010101 #running rails db:migrate:up VERSION=2019010101
  rspec    [args] Run rspec command in application container
  test     [args] Run Minitest command in application container
  bundle   [args] Run bundle command in application container
  cons     Run rails console
  rubocop  [args] Run rubocop
  yarn      Run yarn command in application container
  npm       Run npm  command in application container
  webpack   Run webpack  command in application container

Spring
  spring    Exec spring command in Spring container
  sdive     Into spring container
  sdb       [args] Run rails db command you can use set(migrate), up, down, reset, other is status
             ex: ./qs db set #running rails db:migrate
                 ./qs db up 2019010101 #running rails db:migrate:up VERSION=2019010101

Solargraph
  solargraph Run solargraph command in Spring container

DB:
  reset-db  reset database in DB container
  psql      launch psql console in DB container
  pg-dump   dump database data as sql file in DB container
EOF
  echo "$help"
  exit 2
  ;;
esac

その他作成ファイル

その他の設定ファイルですが、一般的な構築で作成しておりますので説明は割愛致します。
補足的な事項として、DBとしてPostgreSQLを選んでおります。
理由としてMySQLではRails6.0よりバリデータのエラーが発生する事があり設定を追加する必要がある為です。
この点に関してはMySQLを使用する場合は設定を行えばいいのですが、
PostgreSQLでは設定不要の為、こちらをDBとして採用しています。
詳細は下記サイトを参照ください。
Rails 6.0で"Uniqueness validator will no longer enforce case sensitive comparison in Rails 6.1."という警告が出たときの対処法

database.yml
default: &default
  adapter: postgresql
  encoding: utf8
  min_messages: WARNING
  host: db
  port: 5432
  username: postgres
  password: postgres
  pool: 5
  timeout: 5000
  stats_execution_limit: 10

development:
  <<: *default
  database: development

test:
  <<: *default
  database: test

production:
  <<: *default
  database: production

Gemfile

source 'https://rubygems.org'

gem 'rails', '~> 6.0'

.gitignore

.bash_history
.bundle
.solargraph
.atom
.vscode
.viminfo

あとがき

ローカルでのRails6の開発環境構築はhomebrewでrbenvなどを使いながら
それほど大きな工数がかからなかった印象ですが、安定的なコンテナでの開発環境の構築は、
Docker公式サイトでもRails5での記載で、Rails6での構築は難しい印象でした。

また公式サイトのQuickStartでは実行コマンドがDockerfileに記載されており、
出来る限り最小のセットアップで記載する場合、シェルスクリプトへ分けた方が
開発環境としてメンテナンス性も含めいいと考えられます。
*本番環境はDockerfileが変わる可能性も含め

この記事を読了頂きありがとうございました。何らか開発の助けになれば幸いです。

最後に、この記事をまとめるにあたり多くの協力とご助言を賜りました。
ありがとうございました。

参照サイト・資料元

Quickstart Compose and Rails
Dockerfileのベストプラクティス
Bashスクリプト実行サンプル
新しいLinuxの教科書 SB Creative

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

【初心者】Railsチュートリアル

はじめに

3年目の初心者PG
SIerに就職したけど、Excelと格闘の毎日に嫌気がさし、スキルアップのためにRailsチュートリアルをとりあえずやってみる。
主に、自分が詰まった箇所などを忘備録として残していく。

第1章 ゼロからデプロイまで

1.ExecJS::RuntimeUnavailable
 チュートリアル通り進めていき、いざrailsサーバを起動しようとしたところ上記のエラーが発生

% rails server
JavaScript runtime. See https://github.com/rails/execjs for a list of available runtimes. (ExecJS::RuntimeUnavailable)

 [解決策]
 ・gemファイルに下記文言を追加後、bundle update 
 gem 'mini_racer'

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

Heroku CLI 操作(コマンド)

あくまでもコマンド一覧です。デプロイする時の順番ではないのでご注意
railsアプリケーションをHerokuにデプロイする為、gemファイルに記述
ruby:Gemfile
 group :production do
   gem 'rails_12factor'
  end

rails_12factorは、開発環境ではなく本番環境で使用するGem,productionは本番環境で使用できる様にする為
コマンド一覧


herokuにログイン

heroku login --interactive

Heroku上に公開するためのアプリケーションを作成

heroku create アプリ名

アプリケーションが反映されているか

git config --list | grep heroku

heroku上でmy sqlの作成(ClearDBアドオン)

heroku addons:add cleardb

Ruby on Railsを使う場合は、 MySQLに対応するGemに変更

heroku_cleardb=heroku config:get CLEARDB_DATABASE_URL

自身のmysqlのバージョンに変更(URL)

heroku config:set DATABASE_URL=[自身のmysql]${heroku_cleardb:5}

credentials.yml.encをmaster.keyによって復号し、中身を確認したい時

EDITOR="vi" bin/rails credentials:edit

 
Heroku上で環境変数の設定

heroku config:set RAILS_MASTER_KEY=cat config/master.key

Herokuの環境変数一覧を表示

heroku config

herokuにアプリ反映

git push heroku master

heroku上でマイグレーションの反映

heroku run rails db:migrate
 
heroku runはheroku上で操作したい時に使用する

Herokuにデプロイされたアプリケーションの情報を参照したい時

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

コピぺで使える簡易的なスロットマシーン実装

コピぺで使える簡易的なスロットマシーン実装

51dfdc85977ada043ac57c858b1ee611.png

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>スロットマシーン 1</title>
<style>
input {
    width:40px;
    font-size:30px;
    text-align:center;
}
button {
    width:50px;
}
.x1 {
    padding:10px 0;
}
.x1 div {
    float:left;
    width:60px;
    text-align:center;
}
</style>
<script>
window.onload = function() {
    var a = document.getElementById('a');
    var b1 = document.getElementById('b1');
    var b2 = document.getElementById('b2');
    var b3 = document.getElementById('b3');
    var c1 = document.getElementById('c1');
    var c2 = document.getElementById('c2');
    var c3 = document.getElementById('c3');
    var t1 = null;
    var t2 = null;
    var t3 = null;

    function start() {
        if (t1) {
            clearInterval(t1);
        }
        if (t2) {
            clearInterval(t2);
        }
        if (t3) {
            clearInterval(t3);
        }
        c1.value = Math.floor(Math.random() * 10);
        c2.value = Math.floor(Math.random() * 10);
        c3.value = Math.floor(Math.random() * 10);
        t1 = setInterval(function () {
            c1.value = (+c1.value + 1) % 10;
        }, 200);
        t2 = setInterval(function () {
            c2.value = (+c2.value + 1) % 10;
        }, 200);
        t3 = setInterval(function () {
            c3.value = (+c3.value + 1) % 10;
        }, 200);
    }

    function stop1() {
        if (t1) {
            clearInterval(t1);
            t1 = null;
        }
        check();
    }

    function stop2() {
        if (t2) {
            clearInterval(t2);
            t2 = null;
        }
        check();
    }

    function stop3() {
        if (t3) {
            clearInterval(t3);
            t3 = null;
        }
        check();
    }

    function check() {
        if (!t1 && !t2 && !t3) {
            if (c1.value == c2.value && c1.value == c3.value) {
                alert('あたり!');
            } else {
                alert('はずれ!');
            }
        }
    }

    a.addEventListener('click', start);
    b1.addEventListener('click', stop1);
    b2.addEventListener('click', stop2);
    b3.addEventListener('click', stop3);

    start();
}
</script>
</head>
<body>
    <button type="button" id="a">start</button>
    <div class="x1">
        <div>
            <input type="text" id="c1">
            <button type="button" id="b1">stop</button>
        </div>
        <div>
            <input type="text" id="c2">
            <button type="button" id="b2">stop</button>
        </div>
        <div>
            <input type="text" id="c3">
            <button type="button" id="b3">stop</button>
        </div>
    </div>
</body>
</html>

現場からは以上です!

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

[Rails] form_with の2種類の書き方

この記事ではmacOS Catalina10.15.6にインストールしたRuby 2.6.5を使っています。

form_withとは

  • 情報を送信するためのヘルパーメソッドです。
  • 入力に必要なHTMLを表示してくれます。
  • form_withには2つの書き方があります。
  • 1つ目は、入力された情報をデータベースに保存する場合、2つ目は入力された情報をデータベースに保存しない場合です。

データベースに保存する時

  • model:に続けてモデルクラスのインスタンスを記述します。
  • f.text_fieldでテキストボックスを作成します。
<%= form_with model: @book, local: true do |f| %>  
    <%= f.text_field :keyword, placeholder: "keyword", class: "search-input"%>
    <%= f.submit "search", class: "search-btn" %>
<% end %>

データベースに保存しない時

  • url:に続けて情報送信先のパスを記述します。
<%= form_with url: search_path, local: true do |f| %>
   <%= f.text_field :keyword, placeholder: "keyword", class: "search-input"%>
   <%= f.submit "search", class: "search-btn" %>
<% end %>

ルーティングでネストしている場合

  • 例えばpostコントローラーにcommentコントローラーのルーティングがネストしているとしましょう。
  • その場合、コードはこんな感じになります。
  • モデルクラスのインスタンスを親クラスと子クラスの順で2つ記述すれば良いのですね。
<%= form_with model: [@post, @comment] do |f| %>
  <%= f.text_field :comment%>
  <%= f.submit %>
<% end %>

参考

https://pikawaka.com/rails/form_with
https://qiita.com/hmmrjn/items/24f3b8eade206ace17e2

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