20201014のRailsに関する記事は26件です。

【Rails】画像をアップロードせずに編集するとデフォルトの画像で上書きされてしまう問題の解決方法【ActiveStorage】

現在、個人開発中のアプリがかなり完成に近づきつつある中、新たに新しいバグを見つけてしまいました、、(リリース前に気付いてよかった)

前置き長いんで、さっさと解決策知りたい方はこの辺飛ばしちゃってください!!

プロフィール画像などの画像のアップロード機能をActiveStorageを使い実装したのですが、以下のようなバグが見つかりました。
例えば、あるユーザーがユーザー編集ページで画像の設定をしたとします。そして、次にパスワードを変更したくなったとします。当然、ユーザーは新しいパスワードのみ入力し、その値が編集ページのフォームからポストされます。
このとき、フォームのファイル選択エリア(file_field)には前回アップロードした画像は設定されていないので、この状態でupdateアクションが実行されてしまうと前回アップロードした画像が消えてしまい、アプリで設定しているデフォルトの画像で上書きされてしまうのです。

つまり、このままでは編集をするたびに毎回画像をアップロードしないと画像の変更を維持できないという最悪のUXをユーザーに提供してしまいます。これはなんとかしなければいけませんね、、というわけで解決策を書きます!

解決策(超簡単)

コントローラーに以下を追記します。

users_controller.rb
def update
    @user = User.find(params[:id])
    @user.avatar.attach(params[:avatar]) if @user.avatar.blank?
    if @user.update(user_params)
      flash[:success] = 'プロフィールを更新しました'
      redirect_to @user
    else
      render 'edit'
    end
  end

if @user.avatar.blank?を追記するだけです!
実は、ググってもググってもActiveStorageですでに設定された画像のキャッシュを作成するやり方がわからなかったので、自分で考えて色々と仮説検証した結果この一文を編み出し、解決することができました。(CarrierWaveなら出てきた)
テストもパスすることを確認しました。(この一文を消すとちゃんとテストに失敗することも確認済)

しかし、これだと

既に設定されている画像を普通に変更する場合、@user.avatar.bkank?がfalseになって@user.avatar.attach(params[:avatar])が実行されずに画像の変更ができないんじゃないか?

と思いませんか?僕は思います。。wでも、実際画像は更新されるし、テストもパスするのでとりあえずこれで良しとしようと思います。

どなたかこのあたりの原理が分かる方、もしよければコメントいただけますと幸いです。

テストコード

補足として実際にパスしたテストコードをここに掲載します(関連する部分のみ抜粋)。

upload_image_spec.rb
require 'rails_helper'

RSpec.describe '画像のアップロード', type: :system do
  let(:user) { FactoryBot.create(:user) }

  before do
    valid_login(user)
  end

  # 画像をアップロードして保存する
  def upload_user_avatar(user)
    visit edit_user_path(user)
    attach_file 'user_avatar', "#{Rails.root}/spec/fixtures/images/test.jpg"
    click_on '保存する'
  end

  it 'userがアップロードした画像がマイページに表示されること' do
    upload_user_avatar(user)
    expect(page).to have_selector("img[src$='test.jpg']")
  end

  it "userが画像の更新に成功すること" do
    visit edit_user_path(user)
    attach_file 'user_avatar', "#{Rails.root}/spec/fixtures/images/updated_test.jpg"
    click_on '保存する'
    expect(page).to have_selector("img[src$='updated_test.jpg']")
  end

  it "画像をアップロードせずに編集したとき、デフォルトの画像データで上書きされないこと" do
    upload_user_avatar(user)
    visit edit_user_path(user)
    click_on '保存する'
    expect(page).to have_selector("img[src$='test.jpg']")
  end
end

最後まで読んでいただきありがとうございます!

日々学んだことをアウトプットしてます!ご指摘などあれば是非ともコメントいただけますと嬉しいです!!

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

DB設計で悩んだ、本日の学び

はじめに

 本日の学習したDB設計について、簡単にまとめる。

必要なテーブル・カラムの洗い出し

・エンティティはデータが登録させるタイミングを考える。
・プルダウンはActiveHashを用いることができる。
・ActiveHashを用いたカラムはinteger型また、カラム名に_idをつけるとわかりやすい。
・郵便番号や電話番号はstring型で扱うのがよい。
・日付はdata型を用いる。
・数値も文字も入る可能性があるカラムはstring型。
・テーブル名で判断できるカラム名はつけない。
ex)usersテーブルで、カラム名をuser_nameとしない。nameでよい。
 

ActiveHash

・ER図には繋がりを記載する。
・gem 'active_hash'を導入する。

アソシエーション

・1対1の関係にある場合、親にhas_oneを子にbelongs_toの記述をする。
・親子の判断は、もう一方が存在しえないと、存在しない方が「子」。
・外部キーをどこに置くのか、よく考える。

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

【AWS S3】AWS Access Key Id you provided does not exist in our records エラー【Rails AWS EC2】

エラー内容

本番環境(EC2)で画像投稿(carrierwave)をしようとすると、下記のようなエラーが起きる。
スクリーンショット 2020-10-14 1.02.13.png

表示されている(読み込まれている)AWSAccessKeyIdは以前使用していた古いキー。
エラー文から古いアクセスキーが読み込まれているため整合性が取れず起きたエラーと判断した。

エラーに対するTRY

  • .bash_profileの更新
  • .envファイルの確認
  • .awsディレクトリ以下の確認(config,credentials)
  • aws configure の確認
  • AWS IAMによりポリシー等の確認

.bash_profileでexportしていたアクセスキーIDが確かに古いものであった。
それを新しいアクセスキーに更新し、.envファイルやIAM、aws configure listを確認し、最新のアクセスキーIDに更新されたことを確認したが、画像を投稿すると同じエラーが生じる。Dockerを利用しているため、古いイメージなどを消去するも、変化なし。

ローカル
$ aws configure list
AWS Access Key ID [None]: AKIA...(新しいアクセスキー)
AWS Secret Access Key [None]: KEY...(新しいアクセスキー)
Default region name: ーーー
Default output format: json

解決方法

途方に暮れていたところ、

「EC2で不具合が起きた時はまずEC2インスタンスを再起動させよ」という先人の言葉をふと思い出した。

「あぁ、これが正解だ」と思った。恐らく、EC2インスタンスを再起動させないと上手く読み込まれない。EC2インスタンスからexitでログアウトし、再ログイン(ssh)ではダメだった。

EC2インスタンスを再起動させると予想通り解決し、正常に画像を投稿できた。

学び

AWS CLIにより、ターミナルから古いキーを新しいキーに変更した場合は必ずEC2インスタンスを再起動させる!

AWSアクセスキーID等は最新なのに私と同じようなエラーが起きるという方はまずは使用しているEC2インスタンスを再起動させてみてください。

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

form_withのフォーム部品の属性

初めて記事を書きます。
スクール学習中にform_withについて学習した事をここに記録します。

  • 使用環境
    • Rails 6.0.0
    • Ruby 2.6.5

form_withとは

form_withメソッドとは、、、

フォームを実装するためのヘルパーメソッドです。

ヘルパーメソッドとは、、、

railsにおいて主にビューでHTMLタグを出現させたり、テキストを加工するためのメソッドの総称。
HTMLでも同様の機能を果たす事ができますが、ヘルパーメソッドを使う利点があります。
1.パスの指定やRubyの埋め込みなどの記述がシンプルになるため
2.セキュリティ上の問題を解消するため
ヘルパーメソッドで書けるのであれば優先的にそうしましょう。

form_withのフォーム部品

<h1>新規投稿ページ</h1>
<%= form_with url: "/posts", method: :post, local: true do |form| %>
  <%= form.text_field :content %>
  <%= form.submit '投稿する' %>
<% end %>

該当部分、、、
<%= form.text_field :content %>
<%= form.submit '投稿する' %>

form_withのフォーム部品の属性

上記該当部分に属性を追加する事ができる。
属性として指定できるのは
.1 name属性
.2 value属性
.3 id属性

     <%= f.text_area :tag_name, name:'item', value:@item.tags[0].tag_name, id:"tag-name" %>

.1 name属性
nameで定義されている文字列がHTTPリクエストで送信するパラメーターのkeyとなります。そしてフォーム欄に記入した文字列がvalueとして格納されて送信されます。パラメーターの中身が複数になってしまった時などにはここを指定する事で1つのパラメーターに揃える事ができます。

.2 value属性
初期値を指定できます。元々その値を入力しておく事ができます。

.3 id属性
JavaScliptで指定する。

そして、上記で紹介した属性を記述しなくても、実際にHTMLファイル内ではじめに紹介した属性指定なしのコードを記入するだけで、実は裏では自動でinput要素に置き換えられ、細かな設定をしてくれています。
それを確認するにはコードを打ってから、ブラウザの検証ツールを開いて確認してみてください。
ですので、あくまで指定しないといけない状況の場合指定すればいいと思います。
また、form_withの中身を見るには、createもしくはupdateアクション直下でbindin.pryを記入して中身を確認してください。

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

[rails]navbarやヘッダーをTOPページのみ非表示にする

概要

railsでオリジナルアプリ製作中に躓いた出来事。
下記の赤い枠で囲まれた部分を、部分テンプレートとして呼び出していました。
スクリーンショット 2020-10-14 21.51.51.png
※↑ユーザー登録画面、作成中なので見づらいです。。

トップページは以下のような構成で、ヘッダーを呼び出したくないので、どうしようかと考えてました。
スクリーンショット 2020-10-14 21.47.49.png
※↑オリジナルアプリのTopページ

部分テンプレートの呼び出し方

トップページ以外には全てヘッダーを表示させたいのでapplication.html.erbで部分テンプレートをレンダーしています。

application.html.erb
<!DOCTYPE html>
<html>
  <head>~省略~</head>
  <body>
    <%= render "shared/header" %> <%# ここでヘッダーを呼び出している。
    <%= yield %>
    <%= render "shared/footer" %>
  </body>
</html>

current_page?で場合分けしてみた

こちらの記事を参考に現在のページがtopページ(root_path)でない場合は、部分テンプレートを呼び出さないようにしてみた。

application.html.erb
<body>
  <% unless current_page?(root_path) %> <%# unlessで現在のページがrootなら呼び出さない
    <%= render "shared/header" %>
  <% end %>
  <%= yield %>
  <%= render "shared/footer" %>
</body>

まとめ

部分テンプレートを呼び出すページを指定する時に、コントローラーに記載したり
JavaScriptで呼び出すページを発火させたり、様々な手段がありそうですが
自分の場合は1ページのみ非表示なのでこのやり方が良いかなと思いました。

もしこの記載方法が推奨されてない理由などありましたら、ご指摘いただければと思います。

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

【0からDockerに挑戦】④Dockerを使ってnginx・puma・rails6.0・mysqlの開発環境を構築する

背景

未経験から自社開発系企業の就職を目指します。
良質なポートフォリオ作成のためDockerを勉強することにしました。

知識レベルとしては、Ruby on railsを使って簡単なアプリケーション開発、gitを使ったバージョン管理、herokuを使ってデプロイできるレベルです。またDockerを学ぶ上で必要とされるlinuxやネットワーク関連の勉強はほぼしていないです。
自分の忘備録かつ、同じくらいのレベルでこれからDockerに挑戦してみようと思っている方に向けて少しでも役に立てればと思います。


最終目標

・Dockerを使って0からRuby on Rails環境(nginx・puma)が構築できるようになること。
以前①〜③でrails6.0とmysqlを使ってDockerの環境を構築したのですが、今後のAWSEC2でデプロイする予定なので、webサーバーとアプリケーション・サーバーを別々にしたほうが良いと考えました。以前までのファイル構成や知識をベースとしています。

【前回までの記事】
【0からDockerに挑戦】①Dockerの概要と用語
【0からDockerに挑戦】②DockerとDocker-composeを使ってRuby on Rails・MYSQLの開発環境をつくる (part1)
【0からDockerに挑戦】③DockerとDocker-composeを使ってRuby on Rails・MYSQLの開発環境をつくる (part2)

前回までで基本的なDockerの知識を抑えていたので、スムーズにいくかなと思ったら、大量のエラーに出会い死にかけました。(結局1日半費やしました笑)

Dockerを使ってnginx・puma・rails6.0・mysqlの開発環境を構築する

今回の環境と条件

・Docker・Docker-composeを使って環境構築をする。
・railsのバージョンは6
・rubyのバージョンは2.6
・データベースはmysql
・webサーバーにnginxを使用。
・アプリケーション・サーバーはpumaを使用。

手順

今回は下記手順で実施したいと思います。
 ①ローカルPC上に必要なディレクトリ・ファイルをつくる
 ②ファイルに必要な記述を書く
 ③docker-composeをビルド・実行させる && rails newをする
 ④必要なファイルの編集・エラーの修正
 ⑤データベース作成・サーバー起動

途中で遭遇したエラーについても説明します。また今回、自分が作りたい環境と同じ構成だったこともあり下記記事を参照しました。とてもわかりやすかったです。ファイルの中身は違いますが、構成とかは真似させて頂いています。

【参照記事】
@eightyさんの記事です。
[Docker + Rails + Puma + Nginx + MySQL]

①ローカルPC上に必要なディレクトリ・ファイルをつくる

今回はデスクトップ上にディレクトリをつくりました。構成は下記になります。

Desktop/
├ webapp/
    ├ containers
      └ nginx
        └ Dockerfile
        └ nginx.conf
    ├ enviroment
      └ db.env
    ├ Dockerfile
    ├ docker-compose.yml
    ├ Gemfile
    ├ Gemfile.lock

今回はコンテナを3つ作ります。1つがDB用、2つ目がwebサーバー用、3つ目がappサーバー用(rails)です。なのでDockerfileを2つ用意する必要があります(前回はrailsとdbでDockerfileが1つでした)。またpumaはrails標準装備ですが、nginxはrails標準装備ではないので別途設定が必要です。

そして補足ですが、railsで使うアプリケーションサーバはpumaかuniconが使われることが多いです。この2つの違いはマルチプロセスとマルチスレッドという通信処理の仕方です。(※詳しくはPumaの本当の力を引き出すの記事をみてください)。処理速度に関してはpumaのほうが優れていることが多く、rails5以降標準搭載されているpumaを使うのが良いかと思います。

②ファイルに必要な記述を書く

1つ1つファイルの説明をします。ただGemfileの記述は前回同様なので省きます。Gemfile.lockも空でよいので説明省きます。

Dockerfile(ruby用)

Dockerfile
FROM ruby:2.6.6
RUN apt-get update && apt-get install -y lsb-release \
      build-essential \
      libpq-dev \
      nodejs &&\
      curl -o- -L https://yarnpkg.com/install.sh | bash \
      && apt remove -y libmariadb-dev-compat libmariadb-dev

RUN wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-common_8.0.18-1debian10_amd64.deb \
    https://dev.mysql.com/get/Downloads/MySQL-8.0/libmysqlclient21_8.0.18-1debian10_amd64.deb \
    https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-community-client-core_8.0.18-1debian10_amd64.deb \
    https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-community-client_8.0.18-1debian10_amd64.deb \
    https://dev.mysql.com/get/Downloads/MySQL-8.0/libmysqlclient-dev_8.0.18-1debian10_amd64.deb

RUN dpkg -i mysql-common_8.0.18-1debian10_amd64.deb \
    libmysqlclient21_8.0.18-1debian10_amd64.deb \
    mysql-community-client-core_8.0.18-1debian10_amd64.deb \
    mysql-community-client_8.0.18-1debian10_amd64.deb \
    libmysqlclient-dev_8.0.18-1debian10_amd64.deb

RUN mkdir /webapp
WORKDIR /webapp

ADD Gemfile /webapp/Gemfile
ADD Gemfile.lock /webapp/Gemfile.lock

RUN bundle install

RUN mkdir -p tmp/sockets

特に前回と比べて変更があった2点を説明します。
1つ目は「apt-get install -y lsb-release \・・・」「apt remove -y libmariadb-dev-compat libmariadb-dev」「RUN wget」「RUN dpkg」のところは、mysqlのエラー対策です。ここで結構苦戦したのですが、mysqlはバージョンによって認証に使われるプラグインが異なるそうです。そのバージョンによる認証エラーを回避するために上記の記述が必要です。(※参考:LinuxベースのDockerからMySQL 8.0に接続するための記述
もちろんdocker-compose.ymlでmysqlのバージョン変更したり、その他設定で変更できるかもしれませんが、自分の場合うまくいかず、この方法で解決しました。こちらもし他に良い設定があったら変更するかもしれないです。

2つ目は、最後の「RUN mkdir -p tmp/sockets」の箇所です。これはソケット通信に必要なファイルです。ソケット通信とは複数のプロセスをネットワークでつなぐときに使う通信です。今回はnginxとpumaをつなぐためにソケット通信を使います。

Dockerfile(nginx用)・nginx.conf

container/nginx/Dockerfile
FROM nginx

RUN rm -f /etc/nginx/conf.d/*
ADD nginx.conf /etc/nginx/conf.d/webapp.conf
CMD /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.conf
container/nginx/nginx.conf
upstream webapp {
  server unix:///webapp/tmp/sockets/puma.sock;
}

server {
  listen 80;
  server_name example.com localhost;

  access_log /var/log/nginx/access.log;
  error_log  /var/log/nginx/error.log;

  root /webapp/public;

  client_max_body_size 100m;
  error_page 404             /404.html;
  error_page 505 502 503 504 /500.html;
  try_files  $uri/index.html $uri @webapp;
  keepalive_timeout 5;

  location @webapp {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_pass http://webapp;
  }
}

上記2つは、@eightyさんの[Docker + Rails + Puma + Nginx + MySQL]の記事をコピペさせていただきました。。。。
ただ内容は、自分のために解説したいです。

1つ目はnginxのDockerfileです。FROMでnginxのイメージを呼びます。nginxのイメージで自動的にnginxの設定ファイルができるのですが、今回は自分でファイルを作り、それを反映させたいので、RUN以下で一回ファイルを消し、ADDで自分の作ったファイルをコンテナ内に反映させます。CMDでビルドが完了したらnginxを起動するように指示しています。

2つ目がeginxの設定ファイルです。upstream以下でnginxからpumaにソケット通信を送ることを指定しています。server以下でポート、IPを指定(今回はlocalhost)、ログをどこに残すか、ドキュメントルート(公開するHTMLや画像の設置場所)の指定、エラーページの際の対応が記してあります。「location @webapp」でリバースプロキシの設定をしています。リバースプロキシとは、webサーバーとインターネットの中間に立ち、webサーバーのアクセスをコントロールするものです


docker-compose.yml

version: '3'
services:
  app:
    build:
      context: .
    env_file:
      - ./environments/db.env
    command: bundle exec puma -C config/puma.rb
    volumes:
      - .:/webapp
      - public-data:/webapp/public
      - tmp-data:/webapp/tmp
      - log-data:/webapp/log
    depends_on:
      - db
  db:
    image: mysql:8.0
    env_file:
      - ./environments/db.env
    volumes:
      - db-data:/var/lib/mysql
  web:
    build:
      context: containers/nginx
    volumes:
      - public-data:/webapp/public
      - tmp-data:/webapp/tmp
    ports:
      - 80:80
    depends_on:
      - app
volumes:
  public-data:
  tmp-data:
  log-data:
  db-data:

こちらも前回との変更点を説明します。serviceが3つに分岐しました(前回は2つ)。dbとweb(webサーバー用)とapp(アプリケーション用)の3つです。dbに関しては前回と変更ほぼないので説明省略します。appとwebに関しては前回1つにまとめていたのを、今回2つに分けた感じです。以下説明です。

・appとweb: env_fileでuserとpasswordが書いてあるファイルの場所を指定しています。webサーバーと同じ環境変数を使うので、ファイルを別途作りそこを指定しました。
・web: buildするのはeginx用のDockerfileなので指定の仕方注意です。
・web: depend_onもwebサーバーはアプリケーションサーバと関係を構築するので、指定の仕方注意です。
・app: commandでpumaを実行させています
volumes関連に関しては「ホストファイル:コンテナファイル」という順序で関連付けられています。


③docker-composeを実行 && rails newをする

ファイルがそろったら「docker-compose」と「rails new」をしましょう。
コマンド指定で一気にやってもいいですし、コンテナを起動して中に入り込んでからrails newをしても大丈夫です。
ただ1点注意が必要です。コンテナの指定はwebではなく、appです。(※railsがあるのがアプリケーションサーバなので当たり前といえば当たり前なのですが、rails+dbだけのコンテナ構築に慣れていると、webコンテナに入ってしまう恐れがあります。私だけかもですが、、、)。

ターミナル
$ docker-compose up -d
$ docker-compose exec app bash
root@35356af5# rails new

④必要なファイルの編集

database.ymlとpuma.rbの編集、そしてmysqlの設定をしておきましょう。

database.yml


(省略)
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: <%= ENV.fetch('MYSQL_USER') { 'root' } %>
  password: <%= ENV.fetch('MYSQL_PASSWORD') { 'password' } %>
  host: db

development:
  <<: *default
  database: webapp_development

test:
  <<: *default
  database: webapp_test


ここは前回とほぼ同じなので問題ないと思います。

puma.rb
hreads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }.to_i
threads threads_count, threads_count
environment ENV.fetch("RAILS_ENV") { "development" }
plugin :tmp_restart

app_root = File.expand_path("../..", __FILE__)
bind "unix://#{app_root}/tmp/sockets/puma.sock"

stdout_redirect "#{app_root}/log/puma.stdout.log", "#{app_root}/log/puma.stderr.log", true

ここは基本どのサイトみてもコピペで問題ないとのことです。
ただ1点注意が必要です。上記の記述では削除していますが、「por ENV.fetch("PORT") { 3000 }」と記載してあることが多いのです。間違っていないのですが、rails sした際にalready existエラーが出る場合はここの記述消しましょう。rails sのデフォルトが3000ポートで、ここで指定したpuma起動のポートと同じになります。そのためrails sするとすでに起動しているpumaが邪魔をして、エラーがでる恐れがあります。

※自分はここで悩みました。他の設定が悪いのか、rails sの起動の仕方が悪いなど、もしかすると他の原因も考えられます。今回は上記の記述削除で対応できました。またrails sの起動時に別ポートで指定するやり方でも対応できました。

ターミナル
docker-compose exec db mysql -u root -p -e"cat grant_user.sql"
db/grant_user.sql
GRANT ALL PRIVILEGES ON *.* TO 'user_name'@'%';
FLUSH PRIVILEGES;

上記をターミナルで入力し、mysqlに権限を付与しましょう。意味はgrant_user.sqlに設定したファイルを開き、そのファイルに書かれている内容をroot権限(コンテナ内はデフォルトでルート権限)で許可するといった意味です。入力するとパスワードを求められますがmysqlのrootuserのパスワードを入力すると認証されます。(※ここもコピペです。)

⑤データベース作成・サーバー起動

ここまでくればあとは「rails db:create」「rails s」をコンテナで実行すれば終了です。
※railsのサーバーを起動すると、「puma.sockets already exist」といったエラーが出る可能性がありますが、その場合はtmp/sockets/にあるpuma.socketを削除すれば問題ないです。

感想・まとめ

ここまで淡々と書いてきましたが、やっているときはたくさんのエラーに出会いました。エラーについて調べてるうちにネットワークやサーバーの知識も増えていき結果的に良かったです。そして最終的にみるとほとんどコピペですね笑。ただ大まかな流れと書いてあるコードの8割は理解できたので少し、進歩したかなと思います。

最初は自分の力だけでなんとかしようとしていましたが、未経験で知識のない自分がゼロからやるっていうのも少し無駄なことの気がしたので、初挑戦のことはコピペでもいいのでまず動かしてみるというところを意識したいです。

参考になった教材

「米国AI開発者がゼロから教えるDocker講座」 
https://www.udemy.com/course/aidocker/
→初心者がDockerを学ぶならこれ!!!めちゃくちゃわかりやすい!!!linuxの基礎からDockerでの環境構築を網羅しています。今回の環境構築もこの教材をベースにしています(もちろんrailsのバージョンとかdbなど自分なりに変えているので同じではないです)もしDocker全然わかないという人はこの講座をぜひ買ってみてください。

「いまさらだけどDockerに入門したので分かりやすくまとめてみた」 
https://qiita.com/gold-kou/items/44860fbda1a34a001fc1
→すごく細かく網羅しています。リファラル的によくみさせていただいてます。

「Docker/Kubernetes 実践コンテナ開発入門 --著 山田 明憲」 
→実践的な書籍、あまりにも初学者だと少しむずかしいかも。→ 基礎覚え得たあとに見返したら非常に良かったです!

「たった1日で基本が身に付く! Docker/Kubernetes超入門 --著」
→初学者が書籍で学びたい場合はこれがとっかかりやすい。

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

[Rails]enumの使い方

はじめに

アプリ開発でActive Hashではなくenumを使ってみたので軽くまとめてみました。

目次

1.テーブルの設定
2.モデルの設定
3.ビューファイルの設定

1. テーブルの設定

今回はgenderというカラムにenumを使っていきます。
enumを使う際はカラム型をinteger型にする必要があります。

カラム名 カラム型
gender integer

2. モデルの設定

モデルファイルにデータを記述します。
enumは以下のようなハッシュの形で定義します。

enum gender: { man: 0, woman: 1, other: 2 }

3. ビューファイルの設定

今回はラジオボタンとして表示しました。
第一引数にカラム名、第二引数にモデルで定義した値を記述します。

<div class="field">
  <%= f.label :man %>
  <%= f.radio_button :gender, :man %>
  <%= f.label :woman %>
  <%= f.radio_button :gender, :woman %>
  <%= f.label :other %>
  <%= f.radio_button :gender, :other %>
</div>
manが選ばれたときのデータベースへの保存の流れ

ビューでmanをキーとして送信→コントローラー→モデルで送られてきたキーを元に番号を探す→データベースに数値で保存

参考リンク

https://madogiwa0124.hatenablog.com/entry/2017/12/24/222156

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

rails test dbのみdrop

circle ciとローカル環境でテスト結果が異なるので、念のためtest用のdbをdropしてからmigrateしてみました

rake db:drop RAILS_ENV=test
rake db:create RAILS_ENV=test
rake db:schema:load RAILS_ENV=test

参考記事

Rails 4: How to reset test database?

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

herokuでGoogle Cloud のサービスアカウントキーを設定する

はじめに

Ruby on Railsでポートフォリオを作成しているRails初学者です。以前、以下の記事でGoogle Cloud Vision APIを使った簡単な画像解析を実装しました。

Railsで画像プレビュー時にGoogle Cloud Vision APIに連携し、データラベルを取得する

しかし、heroku本番環境でうまく起動しない・・・(+ +)
おそらく認証周りがうまくいってないようだなぁというのはわかったのですが、直すのに案外時間がかかってしまったので、覚書として残しておきます。

原因

herokuに各種プログラムファイルを投入する際、gitを使用しています。

terminal
git push heroku master

つまりは、githubと同じ情報をheroku側にpushしています。
githubにキー情報をもつファイルなどは上げないように設定をしているので(.gitignore)、結果的にherokuにもキー情報をもつファイルはアップロードされません。
結果、Google cloud vision APIで接続の際に必要な、サービスアカウントキーを持つjsonファイルもheroku側には投入されていませんでした。

今回はこの、情報をうまく渡すための方法について見ていきます。

解決策

今回行うのは、環境変数としてherokuに渡しておき、そこから呼び出すという作業です。
ファイル自体をherokuのコンテナ上に置くのではなく、必要なキー情報を変数に設定します。

herokuの設定

1.herokuにアクセス
まずは、herokuの画面にアクセスし、設定するアプリを選択します。

2.Settingsにアクセス
画面内のタブ、Settingsをクリック

3.Reveal Config Varsをクリック
Settings内にある、Reveal Config Varsのボタンをクリック
スクリーンショット 2020-10-14 17.43.29.png

4.環境変数を設定
3.のボタンを押すと、設定済みの環境変数が出てくるので、そこに新たに
GOOGLE_CREDENTIALS(任意の文字列でOK)と、サービスアカウントキーファイル内の全てをコピペし登録します。

5.herokuを再起動
環境変数を設定した後、heroku restartで再起動してください

controllerの設定

controllerもこれに合わせて設定していきます。

XXXX_controller.rb
:
    #Vision APIの設定
    if Rails.env.production?
      config.credentials = JSON.parse(ENV.fetch('GOOGLE_CREDENTIALS'))
    else
      config.credentials = ENV["GOOGLE_APPLICATION_CREDENTIALS"]
    end
:

今回は本番環境の場合、herokuに設定した環境変数を取得し、
JSONファイルとしてconfigに設定するように変更しました。

以上で、herokuでもGoogle Cloud Vision APIが使えるようになりました!

終わりに

簡単な設定にもかかわらず時間がかかってしまいました・・・
herokuのログをキチンと確認すること、またログの情報が不十分であれば、
以下の設定をし、詳細情報を確認してみるとわかるかと思います。
https://qiita.com/YujiNaito/items/3102ad59124d38433b2e

また、この環境変数から強引にやるが正解なのかどうかは不安です・・
セキュリティ的にOKなのかな?もっといい方法はありそうですね・・・
これよりもいい方法があるよ!などありましたら、ぜひコメントいただけますと幸いです。

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

「英数6文字以内」「全角のみ使用可能」「空欄ではエラーになる」というバリデーションをかけた

2020/10/15 この記事には間違いがあります。修正します。

結論

以下を利用した。

with_options

条件付きバリデーションをグループ化できる。do endで囲って使用する。

presence: true

空でないことを確認する。

format:

withオプションに記述した正規表現が送られた値とマッチしているか検証する。

/\A[ぁ-んァ-ン一-龥]+\z/

Unicodeにおける範囲でひらがな、カタカナ、漢字と一致しているか調べる。

/[a-z\d]{6,}/i

大文字小文字可能で、英字もしくは数字6文字以上であるか確認する。
{6,20}とすれば6文字以上20字いないと指定できる。

message

ここにエラーの時に出るメッセージを記述する。

コード

models/user.rb
  with_options presence: true, format: { with: /\A[ぁ-んァ-ン一-龥]+\z/, message: 'に全角文字を使用してください' } do
    validates :family_name
    validates :first_name
  end

  validates :password, format: { with: /[a-z\d]{6,}/i, message: "は6文字以上の英数字が使えます" }

end

参考文献

Railsガイドのformatヘルパーの欄をご覧ください。
https://railsguides.jp/active_record_validations.html
基本的な正規表現一覧
https://murashun.jp/blog/20190215-01.html

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

パスの種類

パス

パスとはディレクトリやファイルの場所を示す文字列のことです。
ディレクトリは階層ごとに/(スラッシュ)で区切ります。パスの指定方法は、
絶対パス相対パス の2つがあります。

パス.png

FinderなどのGUIとパスで示すことの違いは、
地図を元に場所を指差すのか、その場所の住所を伝えるのか、という違いと似ていますね。

次は、 絶対パス相対パス について説明します。

絶対パス

絶対パスは ルートディレクトリから指定するパス です。
Macの全ディレクトリにおけるルートディレクトリは /(スラッシュ)です。
全てのディレクトリやファイルはここから辿っていきます。
そのため、絶対パスで指定するときにはパスの一番最初に/(スラッシュ)を指定します。

例:絶対パス
/Users/ユーザ名/Desktop

ここで、一番始めの/(スラッシュ)はルートディレクトリを指し、2番目以降の/は階層の区切りを表している点を混同しないように注意して下さい。

また、/Users/ユーザ名はホームディレクトリであり、~と表すことができるため、ホームディレクトリより下層にあるディレクトリのパスは以下のような絶対パスで示すこともできます。

例:絶対パス
~/Desktop

絶対.png

絶対パスは、どのディレクトリで作業していても指定した場所に移動できます。しかし、パスをルートディレクトリからたどって指定する必要があるため、記述が長くなってしまう場合もあります。

相対パス

相対パスは カレントディレクトリから指定するパス です。
ルートディレクトリから指定しないため、パスの始めに/(スラッシュ)をつけてはいけません。

カレントディレクトリ直下のディレクトリやファイルであれば、どのようなディレクトリ階層にあるのか指定することなく簡単にパスの指定ができます。

相対パス
# カレントディレクトリがホームディレクトリの場合にデスクトップの場所を指定する
Desktop

# カレントディレクトリがホームディレクトリの場合にデスクトップにあるファイルの場所を指定する
Desktop/メモ.txt

相対.png

相対パスは、記述をシンプルにパスの指定が可能となるメリットがあります。しかし、カレントディレクトリがどこにあるのかによって、指定するパスを変更する必要があります。

これらのパスは、階層を示す方法として必要な知識ですが、ターミナルでは
パスのみだと何も処理を命令することができません。
パスはPCへの命令と合わせることで使用します。

まとめ

絶対パスは、ルートディレクトリから指定するパスのこと。
相対パスは 、カレントディレクトリから指定するパスのこと。

例えるなら、誰かに道案内をするときに「東京都〇〇区△△市...」と直接住所を伝えるのが絶対パス。相手の居る現在地から考え「そこからまっすぐ進んで2つ先の角を左に...」のように伝えるのが相対パスであるといえます。

以上。

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

親要素に紐づく子要素を同時に削除する方法

Railsにおいてreviewモデルの削除機能に関して、元々は問題なく機能しておりましたが、commentモデル実装後にエラーが発生しました。
原因解明したので共有いたします。

開発環境

Ruby 2.6.5
Rails 6.0.3.3

問題発生時の実装内容

reveiwを親、commentを子としてルーティングをネストしております。

config/routes.rb
resources :reviews do
    resources :comments, only: [:create, :destroy] 
end

reviewが削除されるように実装しておりました。
comment実装前はこのまま削除ができました。

views/reviews/show.html.erb
<%= link_to review_path(id: @review.id), method: :delete do %>
    <div>レビュー削除</div>
    <div>こちらからレビューの削除ができます。</div>
<% end %>

修正箇所

commentをreviewの子要素として実装したため、review削除時に同時にcommentも削除されるよう実装しなければなりません。
そのため、models/review.rbを以下のように修正します。

models/review.rb
has_many :comments

↓↓↓

models/review.rb
has_many :comments, dependent: :destroy

こちらで削除機能実装完了です。

参考

https://qiita.com/Tsh-43879562/items/fbc968453a7063776637

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

【Rails】ImageMagick(RMajick)を導入する方法

ImageMajickとは

ImageMagick(イメージマジック)は画像を操作したり表示したりするためのソフトウェア。
GIF、JPEG、PNG、PDF、TIFFなど100種類以上の画像ファイルフォーマットに対応しており、プログラム上からの画像の変換・編集などに必要な多数の機能を備えている。
「画像のアップロード → サムネイル生成 」など、画像を加工・変形するWEBサービスを組みたい場合に使う。

Imagemagickの使い方日本語マニュアル

導入

諸々の画像処理をするため、ImageMajickを使いたい。

ただこれはRubyのものではなく、
RubyだとRMagickというgemで使えるようになるらしいのでこちらを入れる。

# 追加
gem 'rmagick'

# => bundle install

ただ、以下のようなエラーが起きる。

Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

    current directory: /Users/uenoyuuki/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/rmagick-4.0.0/ext/RMagick
/Users/uenoyuuki/.rbenv/versions/2.5.0/bin/ruby -r ./siteconf20190916-2480-i0d2pg.rb extconf.rb
checking for brew... yes
checking for clang... yes
checking for pkg-config... yes


ERROR: Can't install RMagick 4.0.0. Can't find ImageMagick with pkg-config


*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers.  Check the mkmf.log file for more details.  You may
need configuration options.

Provided configuration options:
        --with-opt-dir
        --without-opt-dir
        --with-opt-include
        --without-opt-include=${opt-dir}/include
        --with-opt-lib
        --without-opt-lib=${opt-dir}/lib
        --with-make-prog
        --without-make-prog
        --srcdir=.
        --curdir
        --ruby=/Users/uenoyuuki/.rbenv/versions/2.5.0/bin/$(RUBY_BASE_NAME)

To see why this extension failed to compile, please check the mkmf.log which can be found here:

  /Users/uenoyuuki/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/extensions/x86_64-darwin-18/2.5.0-static/rmagick-4.0.0/mkmf.log

extconf failed, exit code 1

Gem files will remain installed in /Users/uenoyuuki/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/gems/rmagick-4.0.0 for inspection.
Results logged to /Users/uenoyuuki/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/extensions/x86_64-darwin-18/2.5.0-static/rmagick-4.0.0/gem_make.out

An error occurred while installing rmagick (4.0.0), and Bundler cannot continue.
Make sure that `gem install rmagick -v '4.0.0' --source 'https://rubygems.org/'` succeeds before bundling.

先にImagaMajick自体のインストールが必要らしい。

OSがAmazon-Linuxなので、yumを使ってインストールする。

$ sudo yum -y install ImageMagick ImageMagick-devel
# 再度追加
gem 'rmagick'

# => bundle install

成功…!

失敗談

ImageMagickを入れるまでの失敗として、
今までパッケージマネージャをノリで使っていたため、
それぞれの違いをわかっておらず、変に時間がかかった。

# Amazon-Linuxでは使えない

# Mac OS
$ brew install imagemagick@6

# Ubunts
$ sudo apt-get install imagemagick libmagick++-dev

なんのOSか分からない!なんてことはないはずだが、
最悪これでもOSを確認できる。

$ cat /etc/*-release

参考

Active StorageのVariantの指定方法いろいろ
RailsでRMagickを使う
[Gem] RMagick をCentOSでインストール
Cloud9でrmagickを使おうとしたらエラーって解決した話
aptコマンドのインストールができない

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

JavaScript リロードしないと動作しない問題

記事の対象者

Railsアプリにおいて、JQueryを使用して投稿を分けて表示させるタブを実装。
実装したはいいが、リロードしないと正常に動作しない問題が発生、、。
Turbolinksはそのままに、解決する方法とその理由を示したいと思います。

他の記事で解決策はあったものの、「なぜ?」が解消されず附に落ちなかった為、
Rails定番の参考書「現場Rails」の引用と独り言を添えて、初学者向けの記事にしてみました。

初学者の為、解釈が間違っていれば、ご指摘頂けると幸いです。

リロードしないと正常に動作しないタブ部分のjsファイルのコード

tab.js
$(function() {
  let tabs = $(".menu-tab");
  $(".menu-tab").on("click", function() {

.
(省略)
.

})

コードは間違ってないはずだが、なぜかタブの切り替えができない。
他の記事で以下の解決策が示されていました。

解決方法

以下のように、document.addEventListener("turbolinks:load", function() {})を加える。

document.addEventListener("turbolinks:load", function() {
$(function() {
  let tabs = $(".menu-tab");
  $(".menu-tab").on("click", function() {
.
(省略)
.
})

リロードせずともタブの切り替えができ、タブごとの投稿を表示させることができた。解決。
原因は、turbolinksによりイベントが実行されないらしい。。ん??
初学者でない方は、おそらくこれで説明されて理解できるが、初学者の私はあまり附に落ちない。(turbolinksを理解していれば附に落ちますが、私は理解しておりませんでした。)

以下、現場RailsのTurbolinks部分の説明を引用しながら、上の「turbolinksによりイベントが実行されない」原因を理解します。

「turbolinksによりイベントが実行されない」理由

まず、turbolinksとは?

Railsが提供するJavaScriptの中には、ページ遷移を高速化する仕組みもあります。それがTurbolinksです。Turbolinksはすべてのリンククリックに対するページ遷移を自動的にAjaxすることで高速化を図ります。
仕組みを簡単に説明すると、Turbolinksはa要素のクリックイベントをフックして、遷移先のページをAjaxで取得します。そして、取得したページが要求するJavaScriptやCSSが現在のものと同一であれば現在のものをそのまま利用し、title要素やbody要素のみを置き換えます。リクエストごとにJavaScriptやCSSをブラウザが評価しなくなるため、パフォーマンスを向上させることができるのです。title要素やbody要素のみを置き換えるだけなので、ページ遷移は発生しませんが、...
引用:現場で使えるRuby on Rails 速習実践ガイドp340

高速化を図る為の仕組みで、ページ遷移を発生させず置き換えて表示させる仕組みということか。ふーん。

turbolinks:loadとは?

Turbolinksは、ページ遷移や戻る、進むといったブラウザの動作をフックして動作する形になるため、ブラウザが用意しているイベントだけでは、意図したとおりの処理を実現できないことがあります。
そのため、 Turbolinksは自身の処理状態に応じてイベントを発行するようになっています。例えば、「turbolinks:load」イベントは初回のページ表示時やTurbolinksによりページの状態が遷移した際に発火するイベントです。
引用:現場で使えるRuby on Rails 速習実践ガイドp342

ブラウザが用意しているイベントでは実現できない場合は、自身の処理状態に応じてイベントを発行させる記述が必要ということか。「turbolinks:load」は、その例でこれを記述することによって、ページ表示・遷移時(=処理状態)にイベントが発火できるということか?
今回の場合は、ブラウザが用意しているイベントでは実現できないのだな。

8-3 2-1 ブラウザのページ遷移が発生しないことが多くなる
「ページが表示される際、DOMの用意ができたタイミングで何らかの処理を実行したい」といったことはよくあります。(省略)...jQueryの「$(document).ready()」がありますが、Tubolinksによるページ遷移の場合はうまく機能しません。なぜなら実際にはブラウザのページ遷移が発生しておらず、イベントが発火しない為です。
引用:現場で使えるRuby on Rails 速習実践ガイドp342

上でいう、何らかの処理(jQueryの「$(document).ready())は今回のケースに合致するな。。
お!ここに「実際にはブラウザのページ遷移が発生しておらずイベントが発火しない」と書かれていますね!!
今回の場合も、ページ遷移が発生しない結果イベントが発火しないから、表示できなかったわけですね。

たとえば、Turbolinks環境下において、次のJavascriptコードが読み込まれる画面があるとしましょう。この画面を、ブラウザ(タブ)で、このアプリケーション内で最初に開くページとしてアクセスするならば、この処理は実行され、「Hello,World」と表示されます。しかし、アプリケーションの別の画面のリンクを辿って到達した画面にこのスクリプトがあっても実行されないのです。
引用:現場で使えるRuby on Rails 速習実践ガイドp342

windows.onload = function(){
 console.log('Hello World!');
};

確かに最初からタブのページを表示させた場合は、動作したけれど、別の画面からタブのページにきた時はリロードしないと表示できなかった!!この状況だったんです、先生!!

この問題は、前述したTurbolinksが提供するイベントturbolinks:loadを利用することで解決します。
引用:現場で使えるRuby on Rails 速習実践ガイドp343

document.addEventListener("turbolinks:load", function() {
windows.onload = function(){
 console.log('Hello World!');
});

上で挙げた解決法と同じことを言っていますね!!

逆に言えば、Turbolinksを利用している場合は、このようなTurbolinks専用のイベントを使わないとJavaScriptを正しく動かすことができないということです。つまり、Turbolinksに依存したJavaScriptを書くことになります。
引用:現場で使えるRuby on Rails 速習実践ガイドp343

最後に結論が書いてありますね。

「Turbolinksを利用している場合は、このようなTurbolinks専用のイベントを使わないとJavaScriptを正しく動かすことができない」

解決方法にあげたコードを追加する理由はこれですね。以上です。

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

deviseを使ったログインユーザーと未ログインユーザーの遷移分け

何をしたいか

ログインをした後に見せたいホーム画面的なものをroot_pathに設定していたので
ログインしていないユーザーはアプリの紹介ページに飛ぶように設定をします

記述

このページに書いてある通りdeviseを使ったものになります。
まだdeviseを入れてない方は入れてからこのページに戻ってきてください。
さて本題に入ります
まずコントローラーの記述を変えます。

photos_controller.rb
class PhotosController < ApplicationController
  before_action :move_to_index #ここを追加で記述

  def index    
  end
#ここから下を追加で記述
  private

  def move_to_index
    unless user_signed_in?
      redirect_to controller: :homes, action: :index
    end
  end

end

何をしているか上から解説します

before_action :move_to_index

before_actionはコントローラーの全てのアクションが実行される前に何らかの処理を行う時に使用するものです
そのbefore_actionにmove_to_indexというメソッドを指定しています。
メソッドなのでここは皆さんで記述が違います
じゃぁそのメソッドはどこで定義してあるの??それは後ほど解説します。

private

クラス外から呼び出すことのできないメソッドのことです。
Rubyでは、privateと記述した以下のコードがプライベートメソッドになります。
僕の解釈はこのコントローラー内でしか使用できないメソッドと解釈しています。違ったらすみません…

def move_to_index

ここでmove_to_indexを定義しています。
先ほどのbefore_action :move_to_indexに繋がるわけです
ではそのmove_to_indexではどのようなことをしているのか見てきます

unless user_signed_in?

user_signed_in?はdeviseを入れることで使えるヘルパーメソッドです
ユーザーがログイン済みかどうか判断します
そこにunless 〜がないならのような意味です
この単語がくると、ログインしていなければ〜で次の行に進みます

redirect_to controller: :homes, action: :index

少し文が長いので
redirect_toにまず注目ですこれは、指定したURLに遷移させることができるメソッドです
なので

controller.rb
redirect_to "http://www.○○○○.com"

でもできるし

controller.rb
redirect_to root_path

のようにPrefix名も指定できます

controller.rb
redirect_to controller: :homes, action: :index

最後に指定したコントローラーのアクションを指定することもできます

他にもまだできるので是非検索してみてください

これで流れとしては
indexが読み込まれる前にbefore_actionで先にmobe_to_indexメソッドを読みます。その中にはユーザーがログインしていなければ、ここに遷移すると設定ができました。

ルーティング

コントローラーにて

redirect_to controller: :homes, action: :index

と最後記述しているの
homesコントローラーのindexアクションが呼ばれます

routes.rb
get '/homes/home', to:'homes#index'

を記述します
/homes/homeはURL名の指定です
スクリーンショット 2020-10-14 15.13.00.png
こんな感じになっています。
そしてhomes#index
homesコントローラーのindexアクションを指定します
これで終わりです

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

Raisアクションコントローラーにおけるnewとcreateの違い

初投稿です。

復習でnewとcreateの違いがごちゃごちゃになったときがあったので
備忘録として投稿させて頂きます。

コントローラーアクションnewとcreateの違い

どちらも作成という意味です。
ですが大きな違いは2つあります。

1つ目はidを与えるかどうか

newアクションにはIDを与えません。
また、newアクション専用のページに遷移する事が多いです。
例えばTweetの新規投稿、メルカリなら出品ページとして理解するのが良いと思います。

逆にcreateアクションにはその投稿に対してIDを与える
例えばTweetで投稿したらその時の投稿者や投稿した時間などが記載されていると思います。
これは投稿した瞬間にIDが与えられモデルからDBに保存される様になっています。
ここから、編集したり削除する事もできますがこれらはIDがあるからこそできるのです。

アクションコントローラーの基本的な使い方

newアクション

  def new
    @tweet = Tweet.new
  end


createアクション

  def create
    Tweet.create(tweet_params)
  end

2つ目はHTTPメソッドが違う
ターミナルでrake routes(rails routesでも可)で確認したら出てきます。

createアクション
tweets POST   /tweets(.:format)                                                                        tweets#create

newアクション
new_tweet GET    /tweets/new(.:format)                                                                    tweets#new

HTTPメソッドは4種類あります。以下を参照して下さい。

HTTPメソッド どのような時に用いられるリクエストか

GET     ページを表示する操作のみを行う時
POST    データを登録する操作をする時
PUT     データを変更する操作をする時
DELETE  データを削除する操作を行う時

以上となります。

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

Rails form_withの動きについて(newアクション編)

form_withの引数

データーベースに保存する場合、form_withの引数にはモデルクラスのインスタンスを指定します。
※()は省略可能です。
モデルクラスのインスタンスとは保存したいテーブルのクラスのインスタンスのことです。
今回はitemsテーブルに新たにレコードを作成したいので、コントローラー側で下記のように記述します。

items_controller.rb
def new
  @item = Item.new
end
item.rb
<%= form_with model: @item , local: true do |f| %>

この@itemをform_withの引数に指定するわけです。

コントローラーで作成したインスタンスがnewメソッドで新たに作成されて何も情報を持っていなければ自動的にcreateアクションへ、findメソッドなどで作成され、すでに情報を持っている場合はupdateアクションへ自動的に振り分けてくれます。

newメソッド何も作成されていない場合

先ほども述べた通り、newメソッドで新たに作成されて何も情報を持っていなければ自動的にcreateアクションへ行きますが、空のインスタンスが作成されていない場合以下の様にRouting Errorが起こります。
スクリーンショット 2020-10-14 12.55.39.png

インスタンスを正しく作成しないとnewアクションがうまく作動せずHTTPメソッドがPOSTに切り替わってしまうということがわかった。

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

gretelを用いたパンくず機能の実装方法

スクリーンショット 2020-10-14 12.49.19.png

What: パンくず機能とは

パンくず機能とはウェブページの上部でよく見かけるこの表示のことです!!
スクリーンショット 2020-10-14 12.49.19.png

Why: なぜパンくず機能を実装するのか

パンくず機能とはウェブページにおいてユーザーが現在どのページにいるかを視覚的に確認しやすくするための機能です。

How: どうやって実装するのか

step 1: gemfileの導入

ここでは'gem gretel'をgemfileに追加し、bundle installを実行しましょう。

gem 'gretel'
$ bundle install

step 2: 設定ファイルの作成

bundle installが完了したらrails generate gretel:installを実行しましょう。
すると、configディレクトリにbreadcrumbs.rbが生成されます。
これが設定ファイルになります。

$ rails generate gretel:install

step 3: 設定ファイルの記述

生成されたbreadcrumbs.rbに記述していきます。

今回はアイテム変数を用いて階層構造になっているカテゴリの親、子、孫要素をそれぞえ取得して表示させたいと思います。
:warning:ここで一点注意なのですが、ビューで引数に@item変数を引き渡すことに加えて、子要素以降のcrumbのparentに変数itemを追記しないとエラーが発生します!
(原因はわからず、、教えていただけると幸いです!)

crumb :root do
  link 'FreeMa', root_path
end

crumb :parent_category do |item|
  link item.category.parent.parent.name, root_path
  parent :root
end

crumb :child_category do |item|
  link item.category.parent.name, root_path
  parent :parent_category, item
end

crumb :grandchild_category do |item|
  link item.category.name, root_path
  parent :child_category, item
end

crumb :current_product do |item|
  link item.name
  parent :grandchild_category, item
end

step 4: ビューの記述

    - breadcrumb :parent_category, @item
    - breadcrumb :child_category, @item, class: 'content'
    - breadcrumb :grandchild_category, @item, class: 'content'
    - breadcrumb :current_product, @item, class: 'current'
    = breadcrumbs separator: "  &rsaquo;  "

step 5: ビューの調整

cssで見た目を整えれば、、、

完成!!

かなり説明を省いてしまいましたが
公式ドキュメントに詳しい説明がありますので、是非一読を!
【参考記事】
パンくずリストの実装
【Rails】gretelを使ってパンくずリストを作成
一番わかりやすいパンくずの実装(gem 'gretel')

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

【Rails】 gemのransackを用いた検索機能の実装

経緯

現在絶賛作成中のポートフォリオで、前回はあいまい検索機能の実装した。
ので、次はgemのransackを用いた検索機能の実装をしようと思い作成。参考になる記事は多く有ったが、それでもチェックボックスでの検索等では結構詰まってしまったので、誰かの参考になればと思い記載しておく。

前回の記事も必要で有れば参照して見てください。
【Rails】 あいまい検索機能の付け方

環境

ruby 2.6.5
Rails 6.0.3.2
haml使用

イメージ図

ファイル名
完成図はこんな感じ

手順

1、gemの導入
2、検索フォームのビュー作成
3、コントローラーに設定
4、検索結果のビュー作成

の4つの手順になります。

gemの導入

先ずは、サクっとgemを入れていきましょう。

Gemfile.
gem 'ransack'

変な間違いが、ないように一番下に記載するのが望ましいです。

入力が終わったら、
ターミナルで% bundle install して % rails s忘れずに行いましょう。
rails sしないと反映されないので忘れずに!

これで、gemの導入は終了です。

検索フォームのビュー作成

先ずは、コードから
構成は、①キーワードでの検索、②値段での検索、③状態の検索、④配送料の検索の構成にしてあります。

index.html.haml
.title-box
  %p.title 詳細検索
.detail_search--box
  = search_form_for(@q,url: detail_search_items_path) do |f|
    .detail-keyword
      .detail-keyword--box
        %i.fas.fa-plus
        %p.wd キーワードを追加する
      = f.search_field :name_cont, placeholder: "例)バイク", class: "detail-keyword--form"
    .detail-price
      .detail-price--label
        %i.fas.fa-coins
        %p.wd 価格
      .detail-price--forms
        = f.search_field :price_gteq, placeholder: "¥300以上", min:300, class: "price-min"
        %p.wd= f.search_field :price_lteq, placeholder: "¥9999999以下", max:9999999, class: "price-max"
    .detail-status
      .detail-status--label
        %i.fas.fa-paperclip
        %p.wd 商品の状態
      .detail-status--checkbox
        .checkboxes
          = f.check_box :status_id_eq_any, { multiple: true }, 1, ''
          = '新品、未使用'
        .checkboxes
          = f.check_box :status_id_eq_any, { multiple: true }, 2, ''
          = '未使用に近い'
        .checkboxes
          = f.check_box :status_id_eq_any, { multiple: true }, 3, ''
          = '目立った傷や汚れなし'
        .checkboxes
          = f.check_box :status_id_eq_any, { multiple: true }, 4, ''
          = 'やや傷や汚れあり'
        .checkboxes
          = f.check_box :status_id_eq_any, { multiple: true }, 5, ''
          = '傷や汚れあり'
        .checkboxes
          = f.check_box :status_id_eq_any, { multiple: true }, 6, ''
          = '全体的に状態が悪い'
    .detail-deliveryFee
      .detail-deliveryFee--label
        %i.fas.fa-truck
        %p.wd 配送料の負担
      .detail-deliveryFee--checkbox
        .checkboxes
          = f.check_box :delivery_fee_id_eq_any, { multiple: true }, 1, ''
          = '送料込み(出品者負担)'
        .checkboxes
          = f.check_box :delivery_fee_id_eq_any, { multiple: true }, 2, ''
          = '着払い(購入者負担)'
    .detail-btn
      = f.submit "検索", class: "sbt-btn"

では、コード事に説明していきます。

= search_form_for(@q,url: detail_search_items_path) do |f|
普通のフォームを作る際は form_for や form_with を使いますが、Ransackで検索フォームを作る場合、search_form_forメソッドを利用します。
まぁ、これはRansackを用いる場合は、search_form_for を使うんだと言う程度の理解で良いと思います。

次に、search_form_forの引数に@qを取りました。@qのクエリ情報を元に検索を行っていきます。
これは後程、コントローラーで定義していきます。

そして、urlの設定部分ですが、これは検索結果を表示させてい場所へのパスを入力しますので適宜変えてください。今回はdetail_search.html.hamlに検索結果を表示させていので、ルーティングで設定されるplefixを書きます。plefixをパスとして書く時は文字の最後に_pathをつけるような書き方をします。
調べ方は、ターミナルで %rails routes です。


①キーワードでの検索
コードで言うとこの部分

.detail-keyword
  .detail-keyword--box
    %i.fas.fa-plus
    %p.wd キーワードを追加する
  = f.search_field :name_cont, placeholder: "例)バイク", class: "detail-keyword--form"

Ransackを用いた検索で特徴的なのが、後ろについている「:name_cont」の_contの部分です。
ちなみに、:nameはカラム名です。なので、適宜変更してください。また、どのテーブル(モデル)のカラムのデータを取得するかは、コントローラーにて設定します。
話を戻しますが、これはnameカラムに対してLike句を使った部分一致検索を行うという意味になります。分かりやすくイメージしやすく言うと、nameカラムの中に(例えば)みかんと言うキーワードが入ったデータを検索して抽出すると言う意味です。

_contの部分をRansackでは述語(predicate)といい、よく使いそうな述語をいくつか記載しておきます。

述語 意味
*_eq 完全に一致したものを抽出します。
*_in 与えられた配列に含まれるものを抽出します。
*_cont 文字列が含まれるものを抽出します。
*_lteq ある値より小さいものを抽出します。
*_gteq ある値より大きなものを抽出します。


②値段での検索
コードで言うとこの部分

.detail-price
  .detail-price--label
    %i.fas.fa-coins
    %p.wd 価格
  .detail-price--forms
    = f.number_field :price_gteq, placeholder: "¥300以上", min:300, class: "price-min"
    %p.wd 〜
    = f.number_field :price_lteq, placeholder: "¥9999999以下", max:9999999, class: "price-max"

ここでの説明が必要なのは、後ろについている「:price_gteq」の_gteqの部分と、「:price_lteq」の_lteqの部分でしょうか。
これは上記の表にも書かれているように、
_gteqは、ある値より大きなものを抽出、
_lteqは、ある値より小さいものを抽出すると言う意味です。
要は、priceカラムの、(例えば)300よりも大きいもの2000より小さいものを抽出すると言う意味です。

③状態の検索
コードで言うとこの部分

.checkboxes
  = f.check_box :status_id_eq_any, { multiple: true }, 1, ''
  = '新品、未使用'

  (略)

.checkboxes
  = f.check_box :status_id_eq_any, { multiple: true }, 6, ''
  = '全体的に状態が悪い'

ここはちょっとややこしいと言うか、僕もちゃんと理解している訳でない為拙い説明になるかもです。

先ずは、後ろについている「:status_id_eq_any」の_eq_anyの部分です。
_eqの部分は、これは上記の表にも書かれているように、
_eqは、完全に一致したものを抽出と言う意味です。じゃあ、_anyはと言うと複数の場合にはこれを付けなくてはいけません。今回、チェックボックスは6つあるので、_eq_any となる訳です。
そして、「multiple: true」も同様の理由で必要です。チェックボックスを複数使う場合は、これを記載しないといけません。これを記載する事で、データの変数が配列として認識されます。
実際にパラメーターで送られているデータです:["1", "", "", "", "", ""]
数字で記載されているものが、チェックボックスがチェックされたものです。

要は、チェックボックスを複数使う場合は、_anyをつける事、multiple: trueを記載する事と覚えて置いてください。

次に、1, '' この部分です。
これは、チェックボックスがチェックされた場合、1というデータを返し、チェックボックスがチェックされなかった場合''と返すという意味です。
''??って何だと思いますが、要はチェックボックスがチェックされなかったからなんのデータも送りませんよっと言う意味です。空と言った方が分かりやすいですかね。
では、この数字の意味は言うと、今回はidの番号ですね。
今回はActiveHashと言うgemを使って、こんな感じでデータを入れています。
↓↓↓
ファイル名
数字は、このidの番号になります。

ActiveHashはこちらの記事を見れば簡単に出来ます。
Railsのgem 'active_hash'で都道府県データを作成してみた

改めて、パラメーターで送られているデータを使って説明すると、
["1", "", "", "", "", ""]
id:1 の新品、未使用というチェックボックスだけがチェックされて、残りの5つはチェックされていないので ''となっています。
なので、status_idカラムの中の新品、未使用と言うデータと一致したものを抽出します。

これで、なんとなくでも分かって頂ければ幸いです。

④配送料の検索は割愛します。③状態の検索とやっている事が全く一緒なので。



コントローラーに設定

先ずは、コードから

item_controller.rb
def index #indexは、検索フォームのビュー
  @q = Item.ransack(params[:q])
end

def detail_search #detail_searchは、検索結果のビュー
  @q = Item.ransack(params[:q])
  @items = @q.result(distinct: true)
end

params[:q]で検索フォームで受け取ったパラメータを受け取り、Item.ransack(params[:q])とすると、受け取ったパラメータ(検索データ)を元に検索結果のオブジェクトを作成することが出来ます。
そして、そのオブジェクトに対して、@items = @q.resultとすると検索結果を取得する事ができます。

分かりにくですが、入力したデータを受け取り、検索オブジェクトを作って、検索結果を出力してるんだなっという認識をしていただけたら大丈夫です。

そして、distinct: trueについてですが、distinctはSQLにある重複を排除する機能です。trueにしておくことで結果から重複した内容のものを排除できます。



検索結果のビュー作成

後は、検索結果のビューを作成して(ここでは、detail_search.html.hamlと言うファイルですが)、eachメソッドを使って出力すればオッケーです。

detail_search.html.haml
.contents__box
  - @items.each do |item|
  ここより下は今自分が作っているものに照らし合わせて作成お願いします。




最後に

一応SCSSも添付しておきます。

*****.scss
.title-box{
  width: 40%;
  height: 60px;
  border: 1px solid #EEEEEE;
  background-color: red;
  box-shadow: 1px 1px 1px rgba(1,0,0,0.4);
  margin-left: 40%;
  margin-top: 40px;
  padding: 14px 3px 0 0;
  .title{
    color: #fff;
    font-size: 20px;
    font-weight: bold;
    text-align: center;
  }
}

.detail_search--box{
  margin-left: 40%;
  margin-top: 5px;
  width: 40%;
  border: 1px solid #EEEEEE;
  background-color: #fff;
  box-shadow: 1px 1px 1px rgba(1,0,0,0.1);
  .detail-keyword{
    margin-top: 20px;
    &--box{
      display: flex;
      margin-left: 15px;
      .fa-plus{
        margin: 3px 5px 0 0;
      }
    }
    &--form{
      width: 90%;
      height: 40px;
      margin-left: 15px;
      margin-top: 5px;
      padding-left: 5px;
      border: 1px solid #cccccc;
      border-radius: 5px 5px 5px 5px / 5px 5px 5px 5px;
    }
  }
  .detail-price{
    margin-top: 25px;
    &--label{
      display: flex;
      margin-left: 15px;
      .fa-coins{
        margin: 3px 5px 0 0;
      }
    }
    &--forms{
      margin-top: 5px;
      .price-min{
        width: 90%;
        height: 40px;
        margin-left: 15px;
        border: 1px solid #cccccc;
        border-radius: 5px 5px 5px 5px / 5px 5px 5px 5px;
        padding-left: 5px;
      }
      .wd{
        margin-left: 15px;
        color: #AAAAAA;
      }
      .price-max{
        width: 90%;
        height: 40px;
        margin-left: 15px;
        border: 1px solid #cccccc;
        border-radius: 5px 5px 5px 5px / 5px 5px 5px 5px;
        padding-left: 5px;
      }
    }
  }
  .detail-status{
    margin-top: 25px;
    &--label{
      display: flex;
      margin-left: 15px;
      .fa-paperclip{
        margin: 3px 5px 0 0;
      }
    }
    &--checkbox{
      margin-top: 5px;
      .checkboxes{
        margin-left: 15px;
      }
    }
  }
  .detail-deliveryFee{
    margin-top: 25px;
    &--label{
      display: flex;
      margin-left: 15px;
      .fa-truck{
        margin: 3px 5px 0 0;
      }
    }
    &--checkbox{
      margin-top: 5px;
      .checkboxes{
        margin-left: 15px;
      }
    }
  }

  .detail-btn{
    margin-top: 20px;
    .sbt-btn{
      width: 60%;
      height: 35px;
      margin: 15px 0 20px 45px;
      border: none;
      border-radius: 10px;
    }
    .sbt-btn:hover{
      opacity: 0.5 ;
      background-color: #C0C0C0;
    }
  }
}

後は、今回はアイコンを使っているのでgem 'font-awesome-sass'の導入も必要ですね。これに関しては必要な方は簡単なので下記の記事から行ってください。
rails font-awesome-sass導入方法

これで上記の最初の方に添付した画像のようになるはずです!
実装出来なかったなどの不備が有ればご連絡ください!

ありがとうございました。

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

【Rails】pry-byebugがブレークポイントをスルーして止まってくれない問題

開発環境

Docker: v19.03.13
Ruby: v2.5.7
Rails: v5.2.4.4
pry: v0.13.1
pry-byebug: v3.9.0
PostgreSQL: psql (PostgreSQL) 13.0 (Debian 13.0-1.pgdg100+1)

内容

Docker環境にて、Ruby on Rails の Gem Pry-byebugを導入し、処理を止めて変数やパラメータ、処理の流れを確認していたりしてたのですが急に止まってくれなくなりました。。。
本当に。急に。
コンソール上の表示では、ブレークポイントで=>マークは付くのですが下のように停止してくれずにブレークポイントをスルーしてレンダリングが始まってしまう状況に陥りました。
スクリーンショット 2020-10-14 9.47.02.png
[1] pry(#<HomesController>)>と、デバッグ時のコマンド入力できそうな部分も表示はされるのですが何もしていないのにそのままスルーされてレンダリング...
初めての挙動でしたので、ネット上で色々と調べてみたのですがどこにも情報が載ってなく、2日程ハマりました...

解決策

結論から申し上げますと、アプリケーションルートフォルダ直下にあるtmpを削除することで正常動作するようになりました。
どうして、tmpフォルダを削除したのかというところですがネット上で他の言語も含めて情報を見ていたらキャッシュtmpに保存されていると知りまして、「もしや、この影響で不具合が起きてるのでは?? キャッシュなら削除したって問題ない??Gitで管理してるし不具合起きたら戻せば良いよね...」と思い、削除してみたら当たりました。笑
tmpって、Temporary File(=一時ファイル)を指しているんですね...勉強になります。笑
こういうフォルダやファイルのネーミングからヒントを得られましたね。意味を知っておくことも重要なんだなと感じました。

Railsガイドを見ても、同じようにアクションキャッシュなどを格納するフォルダと書いてあります。
ただ、失敗したなと思うのは Railsガイドには

rails tmp:cache:clearで、tmp/cacheを空にします。
rails tmp:sockets:clearで、tmp/socketsを空にします。
rails tmp:screenshots:clearで、tmp/screenshotsを空にします。
rails tmp:clearで、cache、sockets、screenshotディレクトリを空にします。
rails tmp:createで、cache、sockets、pidsのtmpディレクトリを作成します。

と、記載してありました。

一気にフォルダを消すのではなく、このコマンドを実行して切り分け行えたらもっと理解を深められたなぁと反省しております。
正常動作に戻ってしまったので原因に関しては掴めませんでしたが、同じような状況になられましたらお試し頂けたらと思います。

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

【rails】三項演算子

三項演算子について学習したためアウトプットいたします。

この記事を読むと三項演算子の意味、使い方を理解できます。

前提条件として

条件式を分岐させる「if, else」の使い方を知った上で記事を読むことをオススメします。
わからない方は検索してみてください。

三項演算子とは?

三項演算子とは、条件を分岐させるをif, else, ~endを使わずに記述する方法です。

メリットとしては、コードの量を少なくしてすっきりさせることができます。

一方デメリットとしては、
・視覚的に見てわかりにくい。
・式が複雑化すると非常にわかりにくい。が挙げられます(あくまで個人的な感想です)

三項演算子の使い方

【真偽値式】 ? 【真の場合に評価する式】 : 【偽の場合に評価する式】

これだけだと意味がわかりませんよね。例を出していきます。

<%= @group.name.blank? ? "このグループの名前はありません" : @group.name %>

【真偽値式】  
ここの部分は真偽を確かめる式を入れる場所です。
この場合は@groupにnameがついていないか?と検証しています

【真の場合に評価する式】
真偽値式の場所で定義した式が正しかった場合の式を書きます。
この場合は「@group.name.blank?」が正しい場合。つまりグループに名前がない場合どのようなことを表すかです。
今回は"このグループの名前はありません"と定義しています

【偽の場合に評価する式】
真偽値式の場所で定義した式が正しくなかった場合の式を書きます。
この場合は「@group.name.blank?」が正しくなかった場合。つまりグループに名前があった場合どのようなことを表すかです。
今回は@group.nameと定義しています

if elseで表すとよりも遥かにコードが少ない

if~ elseを使っても同じことを表せます。

<% if @group.name.blank? %>
  <p>このグループの名前はありません<p>
<% else %>
  <p><%= @group.name %></p>
<% end %>

三項演算子が1行で済んだのに対し、こちらは4行かかってしまいます。
ここが大きな違いです。

ただ、個人的には、if~else~endの方が視覚的にコードが理解できるので私はこちらを使います。
(三項演算子はコードを見てじっくり考えないと気づかなかったです?)

以上になります。

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

ディレクトリの種類

ディレクトリ

ディレクトリとはコンピュータ上で複数のファイルを整理するためのファイルの入れ物のことです。簡単に言ってしまえば、 フォルダ のことを指します。

ディレクトリにはいくつか種類があります。今回は、「ルートディレクトリ」、「カレントディレクトリ」、「ホームディレクトリ」を説明します。

アイコン.png

アイコン2.png

ルートディレクトリ

ディレクトリは階層構造になっているので、あるディレクトリは他のディレクトリに属しています。ルートディレクトリはその 階層構造の一番上にあるディレクトリのことです。

top.png

カレントディレクトリ

ターミナルで 現在作業中となるディレクトリのことをカレントディレクトリと呼びます。ターミナルではここを基準に、PCに命令を出していきます。カレントディレクトリは先ほどターミナルで~と表示されていました。

ターミナルでは必要に応じて作業するディレクトリを移動しコマンドを実行していきます。移動するたびにカレントディレクトリが指し表すディレクトリは変わります。

ホームディレクトリ

ホームディレクトリは、 新規にターミナルを立ち上げた場合に作業中となるディレクトリのことです。Macでのデフォルトのホームディレクトリは/Users/ユーザ名となり、ターミナルでは~で表されます。

これらの説明からターミナルの画面を見て確認してみましょう。

ターミ.png

この画面上ではカレントディレクトリは~になっているので、
現在作業中のディレクトリ、つまり 現在のカレントディレクトリは
ホームディレクトリを指している ということになります。

まとめ

ディレクトリとはコンピュータ上で複数のファイルを整理するためのファイルの入れ物のこと。
ホームディレクトリは、 新規にターミナルを立ち上げた場合に作業中となるディレクトリのこと。
カレントディレクトリは、ターミナルで現在作業中となるディレクトリのこと。

以上

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

Railsでマイグレーション時にファイル名を間違えた時の対処法

マイグレーション作成時ファイル名を間違えた?

とても簡単!

config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password:
  socket: /tmp/mysql.sock

development:
  <<: *default
  database: anyone2_development

~省略~
test:
  <<: *default
  database: anyone2_test

#
~省略~
production:
  <<: *default
  database: anyone2_production
  username: anyone2
  password: <%= ENV['ANYONE_DATABASE_PASSWORD'] %>

anyone2という所を本当はanyoneとしたかった訳なので該当箇所を全て変更します

config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password:
  socket: /tmp/mysql.sock

development:
  <<: *default
  database: anyone_development

~省略~
test:
  <<: *default
  database: anyone_test

#
~省略~
production:
  <<: *default
  database: anyone_production
  username: anyone
  password: <%= ENV['ANYONE_DATABASE_PASSWORD'] %>

その後再び

ターミナル
rails db:create

ここで注意点があって、このままだとMySQLやらのデータベースにanyone2anyoneの2つともデータベースに残ってしまっている状態なので、先ほどrails db:createした後にもう一度database.ymlの記述をanyone2の時の状態に戻し、ターミナルで

ターミナル
rails db:drop

を記述すると該当のデータベースが削除された状態になります!

現場からは以上です!

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

「オブジェクト指向実践ガイド」を読んでみたので備忘録

はじめに

「オブジェクト指向実践ガイド」を読んでみていいなと思ったので、自分用のメモ。まだ途中です。
1年くらい前にも読んで良書だと思っていたけど、改めて読み返すと学ぶことが豊富にある。

「オブジェクト指向設計実践ガイド」メモ(目次ごと)

第1章

1.1 設計の賞賛

変更がないアプリケーションはない。どんなアプリケーションでも変化は訪れる。
変更が容易なアプリケーションは書いていて楽しい。逆はコストがかかり手がつけられなくなっていく
部品が「オブジェクト」であり、相互作用はオブジェクト間で受け渡される「メッセージ」である。
=>これが重要です。

設計とはコードの構成のこと。つまりアプリケーションそのもの。

1.2 設計の道具

オブジェクト指向の設計の道具

設計原則
SOLID原則
=>有名なやつです。 コード書くときに意識はしているけど体現するのは難しいです。

設計パターン
GoF、デザインパターン

便利な道具だが、初心者が意図を取り違え、本来の意図にそぐわない設計をしてしまうことも。

1.3 設計の行為

設計が失敗する原因は設計が十分ではないから。
Rubyは簡単で、誰でも書くことができる。しかし、その反面、設計されていないアプリケーションは、失敗しやすい。

また、オブジェクト指向設計の手法は知っているが、適用方法がわかっていないプログラマーは別の失敗にぶつかる。

おわりに(本文とは関係ないつぶやき)

やっぱり良書と呼ばれているものは、学びが多いなと感じる。

  • リーダブルコード
  • リファクタリングRuby
  • 達人プログラマーの道
  • SQLアンチパターン 

などなど。
これらの本も時間あったらアウトプットがてらまとめてみたいな。

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

オブジェクト指向実践ガイドを読んでみたので備忘録

はじめに

「オブジェクト指向実践ガイド」を読んでみていいなと思ったので、自分用のメモ。まだ途中です。
1年くらい前にも読んで良書だと思っていたけど、改めて読み返すと学ぶことが豊富にある。

「オブジェクト指向設計実践ガイド」メモ(目次ごと)

第1章

1.1 設計の賞賛

変更がないアプリケーションはない。どんなアプリケーションでも変化は訪れる。
変更が容易なアプリケーションは書いていて楽しい。逆はコストがかかり手がつけられなくなっていく
部品が「オブジェクト」であり、相互作用はオブジェクト間で受け渡される「メッセージ」である。
=>これが重要です。

設計とはコードの構成のこと。つまりアプリケーションそのもの。

1.2 設計の道具

オブジェクト指向の設計の道具

設計原則
SOLID原則
=>有名なやつです。 コード書くときに意識はしているけど体現するのは難しいです。

設計パターン
GoF、デザインパターン

便利な道具だが、初心者が意図を取り違え、本来の意図にそぐわない設計をしてしまうことも。

1.3 設計の行為

設計が失敗する原因は設計が十分ではないから。
Rubyは簡単で、誰でも書くことができる。しかし、その反面、設計されていないアプリケーションは、失敗しやすい。

また、オブジェクト指向設計の手法は知っているが、適用方法がわかっていないプログラマーは別の失敗にぶつかる。

おわりに(本文とは関係ないつぶやき)

やっぱり良書と呼ばれているものは、学びが多いなと感じる。

  • リーダブルコード
  • リファクタリングRuby
  • 達人プログラマーの道
  • SQLアンチパターン 

などなど。
これらの本も時間あったらアウトプットがてらまとめてみたいな。

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

【Rails】利用規約とかプライバシーポリシーなど、単純に静的なページへのリンクを貼る方法

個人開発をしていると利用規約とかプライバシーポリシーを作りますよね。
そのとき、わざわざそのためにコントローラーを用意して、ルーティングを書いて、、とかめんどくさいですよね。
そんな時は、high_voltageというgemを使います!

実装手順

1.Gemをインストール

Gemfileに'high_voltage'を追記して

$ docker-compose run app bundle install

環境構築でDockerを使っています。Dockerfileやdocker-compose.ymlの書き方によっては、Gemfileを書き換えた場合、buildからやり直す必要があります。この辺のことは今回は割愛します。

2.viewを作る

app/views/pages ディレクトリがなければ作成します。

$ mkdir -p app/views/pages

リンクさせたいページのファイルを作成、今回は利用規約をhamlで作っていきます。テンプレートエンジンは適時置き換えてください。

$ touch app/views/pages/terms.html.haml

内容を書きます。

tearms.html.haml
 .term-wrapper
    %h1.uk-text-center 利用規約
    %p この利用規約(以下,「本規約」といいます。)は,プロつく!(以下,「当事務局」といいます。)がこのウェブサイト上で提供するサービス(以下,「本サービス」といいます。)の利用条件を定めるものです。登録ユーザーの皆さま(以下,「ユーザー」といいます。)には,本規約に従って,本サービスをご利用いただきます。
    %h2 第1条(適用)
    %ol
      %li 本規約は,ユーザーと当事務局との間の本サービスの利用に関わる一切の関係に適用されるものとします。
      %li 当事務局は本サービスに関し,本規約のほか,ご利用にあたってのルール等,各種の定め(以下,「個別規定」といいます。)をすることがあります。これら個別規定はその名称のいかんに関わらず,本規約の一部を構成するものとします。
      %li 本規約の規定が前条の個別規定の規定と矛盾する場合には,個別規定において特段の定めなき限り,個別規定の規定が優先されるものとします。
    %h2 第2条(利用登録)
    %ol

......(省略)

3.リンクを貼る(完成)

リンクを貼るときは、page_about('terms')などとしてパスを書けます。

home.html.haml
= link_to '利用規約', page_path('terms')

ルーティングを見てみると、

Prefix Verb URI Pattern    Controller#Action
  page GET  /pages/*id     high_voltage/pages#show

となっているのがわかります。

これでとりあえずは利用規約ページは完成します!!

階層を変える

デフォルトだと https://hogehoge.com/pages/terms となるので、これを hogehoge.com/termsに変えたいときは、config/initializers/high_voltage.rb を作成し、以下のように記述します。

high_voltage.rb
HighVoltage.configure do |config|
  config.route_drawer = HighVoltage::RouteDrawers::Root
end

ルーティングを見てみると、

Prefix Verb URI Pattern    Controller#Action
  page GET  /*id           high_voltage/pages#show

となっており、pagesがなくなっていることが分かります。

最後まで読んでいただきありがとうございます!

日々学習したことをアウトプットしております!!ご指摘などあればコメントいただけますと幸いです!!

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