Dockerイメージについて(メモ)
Dockerイメージとは
Dockerイメージ
- コンテナ実行に必要なファイルをまとめたファイルシステム
- AUFSなどの特殊なファイルシステムが使用される
AUFSとはストレージドライバーでHDなどにストレージのデータを書き込むためのソフトウェアのこと。
Dockerで使用できるストレージドライバーの一種。
レイヤーという階層構造で特殊なファイルシステム(らしい) - イメージ上のデータはレイヤーで構成され読み取り専用
Dcokerイメージのファイルシステム
文章だけではわかりづらいが、Dockerイメージは階層構造でデータが管理されている。
各層のことをレイヤーと呼ぶ。
基本的にコマンドを実行するたびに積み上げていく仕組みとなっている。
レイヤーは全て読み取り専用となる。
Dockerイメージを基にコンテナを起動すると、新たに読み書き可能なコンテナレイヤーという層が作られる。
このコンテナレイヤーでファイルの追加削除やパッケージの追加や削除を行い、それをもとにイメージを作成することも可能。
ただし、過去のレイヤーで削除したファイルなど、追加時点のレイヤーには残ってしまうため、イメージ全体のサイズは変わらない。
Dockerのメリットである、軽量ですぐに環境を立ち上げられるからかけ離れてしまう。
複数のイメージで継承関係を作れる
CentOSのベースイメージを持ったイメージにRubyのイメージを継承させ、CentOSとRubyのレイヤーを一つのイメージにまとめられる。
さらにRailsのイメージを継承させて、CentOS,Ruby,Railsのまとまったイメージを作れる。
同じDockerイメージを継承するメリットとしては、
①CentOS,Rubyがまとまったイメージ
②CentOS,MySQLがまとまったイメージ
①と②ともにCentOSは同じなので、CentOSは同じデータを利用してくれる。
同じレイヤーを使用している場合、同じレイヤーのデータを参照してくれる。
そのためレイヤーがダブることなく、イメージサイズが小さくなりやすい。
ローカル上にダウンロードしているDockerイメージ一覧表示
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest feb5d9fea6a5 3 months ago 13.3kB sample/webrick latest 2ffdacbd6685 4 months ago 864MB ruby 2.7 89699f4d76cf 4 months ago 864MB docker/whalesay latest 6b362a9f73eb 6 years ago 247MB
左から順に
REPOSITORY・・・どのリポジトリからダウンロードしたかものを表しています。
TAG・・・どのタグをダウンロードしたのか確認できる
IMAGE ID・・・イメージを識別するためのID
CREATED・・・いつ作成したか
SIZE・・・サイズ
イメージにタグ付を剃るコマンド
ローカル上に存在するイメージのみ可能。
まずエイリアスとするパターン
$ docker tag docker/whalesay test_whalesay
- tag・・・タグ付けするサブコマンド
- docker/whalesay・・・元となるイメージ名
- test_whalesay・・・新しいイメージ名
実行後
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest feb5d9fea6a5 3 months ago 13.3kB sample/webrick latest 2ffdacbd6685 4 months ago 864MB ruby 2.7 89699f4d76cf 4 months ago 864MB test_whalesay latest 6b362a9f73eb 6 years ago 247MB // 増えた docker/whalesay latest 6b362a9f73eb 6 years ago 247MB
タグ付は上記のコマンドに:TAGとすればできる。
$ docker tag docker/whalesay test_whalesay:ver1 $ doker images REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest feb5d9fea6a5 3 months ago 13.3kB sample/webrick latest 2ffdacbd6685 4 months ago 864MB ruby 2.7 89699f4d76cf 4 months ago 864MB docker/whalesay latest 6b362a9f73eb 6 years ago 247MB test_whalesay latest 6b362a9f73eb 6 years ago 247MB test_whalesay ver1 6b362a9f73eb 6 years ago 247MB // ここ
IMAGE IDが同じなので、ショートカット的な状態。
イメージの詳細情報を表示するコマンド
$ docker inspect test_whalesay
- inspect・・・イメージの詳細情報を表示するサブコマンド
- test_whalesay・・・対象のイメージ名かイメージIDでも可能
たくさんの情報が出てくるので割愛
ローカルのイメージを削除する方法
$ docker rmi docker/whalesay
- rmi・・・イメージの削除をするサブコマンド
- test_whalesay・・・対象のイメージ名かイメージIDでも可能
$ docker rmi -f docker/whalesay
- -f・・・矯正削除する場合に
-f
をつける
すでに削除したいイメージが含まれた状態で作成されたコンテナが存在する場合に、使用する。
またはコンテナを削除してからイメージを削除する方法もある。
$ docker rmi docker/whalesay Untagged: docker/whalesay:latest Untagged: docker/whalesay@sha256:178598e51a26abbc958b8a2e48825c90bc22e641de3d31e18aaf55f3258ba93b $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest feb5d9fea6a5 3 months ago 13.3kB sample/webrick latest 2ffdacbd6685 4 months ago 864MB ruby 2.7 89699f4d76cf 4 months ago 864MB test_whalesay latest 6b362a9f73eb 6 years ago 247MB test_whalesay ver1 6b362a9f73eb 6 years ago 247MB
本家のwhalesayがなくなりました。
イメージを取得(pull)するコマンド
$ docker pull docker/whalesay
- pull・・・イメージの削除をするサブコマンド
- docker/whalesay・・・対象のイメージ名
Docker Hub上にあるイメージを取得してくるコマンド
タグを指定しない場合、latestタグを取得してくるが、必ずしも最新バージョンがlatestであるということではない点を注意する必要がある。
$ docker pull docker/whalesay Using default tag: latest latest: Pulling from docker/whalesay Image docker.io/docker/whalesay:latest uses outdated schema1 manifest format. Please upgrade to a schema2 image for better future compatibility. More information at https://docs.docker.com/registry/spec/deprecated-schema-v1/ e190868d63f8: Already exists 909cd34c6fd7: Already exists 0b9bfabab7c1: Already exists a3ed95caeb02: Already exists 00bf65475aba: Already exists c57b6bcc83e3: Already exists 8978f6879e2f: Already exists 8eed3712d2cf: Already exists Digest: sha256:178598e51a26abbc958b8a2e48825c90bc22e641de3d31e18aaf55f3258ba93b Status: Downloaded newer image for docker/whalesay:latest docker.io/docker/whalesay:latest $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest feb5d9fea6a5 3 months ago 13.3kB sample/webrick latest 2ffdacbd6685 4 months ago 864MB ruby 2.7 89699f4d76cf 4 months ago 864MB docker/whalesay latest 6b362a9f73eb 6 years ago 247MB // 増えてる test_whalesay latest 6b362a9f73eb 6 years ago 247MB test_whalesay ver1 6b362a9f73eb 6 years ago 247MB
Docker動作確認(Docker Desktop)
Dockerの動作確認
動作確認前に必要なもの
- Docker Desktopのインストール
- ターミナル
コマンド
$ docker run hello-world Unable to find image 'hello-world:latest' locally latest: Pulling from library/hello-world 2db29710123e: Pull complete Digest: sa256:975f4b14f326b05db86e16de00144f9c12257553bba9484fed41f9b6f2257800 Status: Downloaded newer image for hello-world:latest Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. (amd64) 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash Share images, automate workflows, and more with a free Docker ID: https://hub.docker.com/ For more examples and ideas, visit: https://docs.docker.com/get-started/
Hello form Docker!と出れば成功
$ docker run hello-world hello
- docker
dockerコマンド - run
サブコマンド - hello-world
イメージの指定
流れ
①DockerクライアントがDockerデーモンへhello-worldのイメージを取ってきてと指示する。
②Dockerデーモンがインターネットを通じてDocker Hubへ頼まれたイメージを取りに行く。
③DockerデーモンがDockerクライアントへ取得したイメージをPC上へ保存して、実行をする
PC上にイメージが存在する場合はイメージを取りに行かず、Dockerデーモンがイメージを実行する。
docker runのコマンドは複数コマンドを実行している
$ docker run hello-world hello // docker pull: イメージの取得 // docker create: コンテナの作成 // docker start: コンテナの起動
docker run は上記3つのコマンドを一括して行っている
Docker Hubとは
- Dockerイメージのレジストリサービス
- Dockerイメージの公開、検索、ダウンロードをすることができる
Docker Hub
公式が提供しているイメージや、公式ではない作成されたイメージなどが提供されている。
自身でもアップ可能。
使用する場合はなるべく公式のイメージを選んだほうがよさそうだが、信頼できそうな作成者のものかどうかを調べて使うのもよさそう。
公式かどうか判断は画像のOfficial Imageがあるかどうか
イメージのタグ付
Docker Hubのイメージの中にTagsというタブがあり、その中でバージョンなどのタグを指定できる。
タグはイメージの後ろに:で区切って指定をする。
$ docker run hello-world hello
上記の場合だとタグをつけていないので、自動的にlatestタグのイメージがダウンロードされている。
$ docker run hello-world hello:latest
でも同じ結果を得られる
Docker入門メモ
Dockerとは
- コンテナ型仮想環境を作成、実行、管理するためのプラットフォーム
- Dockerのソフトウェアを使い、素早くコンテナを起動して様々なアプリを実行することができる
- 異なる設定環境のPCでも簡単に同じ仮想環境を再現できる
- DockerはGo言語で書かれている
Dockerの用語
Dockerイメージ
Dockerコンテナを作成するための雛形となるもの。
Dockerイメージは、アプリケーション、ライブラリ、設定ファイルなど、アプリケーションを実行するのに必要なものを一式にまとめたもの。
出来上がったアプリケーションをDockerイメージとして保存して、別のサーバーへ持っていくことで同じ環境を別のサーバーでも再現することが可能
Dockerコンテナ
Dockerイメージをもとに作成されるコンテナ型仮想環境のことをDockerコンテナ、またはコンテナと呼ぶ
イメージからコンテナを作成することで、何度でも同じ仮想環境を作成することができる
コンテナを起動することで、イメージにセットアップしたアプリケーションの機能を提供することができる。
Docker Hub
Dockerイメージを保存するための機能などを提供しているサービス。
別の方が作成したイメージもダウンロードでき、コンテナとして動かすことができる
Docker Hubのようなイメージを補完できる機能を持ったものをレジストリと呼ぶ
ユースケース
- アプリケーション開発
- 検証環境、本番環境
- Webサーバー、DBサーバーの構築
- その他のミドルウェアの環境設定
Dockerを使うメリット
- プログラムの実行環境を素早く立ち上げられる
- 再現性のある環境を用意できる、違うPCやサーバー間で動かす場合も差異が生まれにくい
- 設定ファイルを共有することでプロジェクトメンバー間で同じ環境を立ち上げられる
インフラ環境のコードを定義したものをinfrastructure as code
と呼んだりする。
設定ファイルをもとに環境を作ることができ、設定ファイルを見れば何がインストールされているのかもわかる。 - PC環境を汚さずにすむ
npm ERR! ERESOLVE unable to resolve dependency treeの対処方法
npm ERR! ERESOLVE unable to resolve dependency treeの対処方法
SPAのブラウザバックのscroll復活をしたく、ためにしにreact-scroll-restorationを導入しようとしたらタイトルのエラーがでました。
react-scroll-restoration
結論
-save --legacy-peer-deps
をnpm installのあとにつければいいそうです。
実際のエラー
$ npm install react-scroll-restoration npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree npm ERR! npm ERR! While resolving: testApp@0.1.0 npm ERR! Found: react-router-dom@5.3.0 npm ERR! node_modules/react-router-dom npm ERR! react-router-dom@"^5.2.0" from the root project npm ERR! npm ERR! Could not resolve dependency: npm ERR! peer react-router-dom@"^4.0.0" from react-scroll-restoration@1.0.8 npm ERR! node_modules/react-scroll-restoration npm ERR! react-scroll-restoration@"*" from the root project npm ERR! npm ERR! Fix the upstream dependency conflict, or retry npm ERR! this command with --force, or --legacy-peer-deps npm ERR! to accept an incorrect (and potentially broken) dependency resolution. npm ERR! npm ERR! See /Users/userName/.npm/eresolve-report.txt for a full report. npm ERR! A complete log of this run can be found in: npm ERR! /Users/userName/.npm/_logs/2021-12-28T11_47_37_669Z-debug.log
npm ERR! Found: react-router-dom@5.3.0
↑因果関係があるライブラリの今使ってるバージョン
npm ERR! peer react-router-dom@"^4.0.0" from react-scroll-restoration@1.0.8
↑実際にさぽーとサポートしているバージョン
$ npm install react-scroll-restoration -save --legacy-peer-deps npm WARN EBADENGINE Unsupported engine { npm WARN EBADENGINE package: '@jest/types@27.0.6', npm WARN EBADENGINE required: { node: '^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0' }, npm WARN EBADENGINE current: { node: 'v12.10.0', npm: '7.16.0' } npm WARN EBADENGINE } npm WARN EBADENGINE Unsupported engine { npm WARN EBADENGINE package: 'diff-sequences@27.0.6', npm WARN EBADENGINE required: { node: '^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0' }, npm WARN EBADENGINE current: { node: 'v12.10.0', npm: '7.16.0' } npm WARN EBADENGINE } npm WARN EBADENGINE Unsupported engine { npm WARN EBADENGINE package: 'jest-diff@27.0.6', npm WARN EBADENGINE required: { node: '^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0' }, npm WARN EBADENGINE current: { node: 'v12.10.0', npm: '7.16.0' } npm WARN EBADENGINE } npm WARN EBADENGINE Unsupported engine { npm WARN EBADENGINE package: 'jest-get-type@27.0.6', npm WARN EBADENGINE required: { node: '^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0' }, npm WARN EBADENGINE current: { node: 'v12.10.0', npm: '7.16.0' } npm WARN EBADENGINE } npm WARN EBADENGINE Unsupported engine { npm WARN EBADENGINE package: 'pretty-format@27.0.6', npm WARN EBADENGINE required: { node: '^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0' }, npm WARN EBADENGINE current: { node: 'v12.10.0', npm: '7.16.0' } npm WARN EBADENGINE } added 1 package, and audited 2569 packages in 13s 166 packages are looking for funding run `npm fund` for details 43 vulnerabilities (27 moderate, 13 high, 3 critical) To address issues that do not require attention, run: npm audit fix To address all issues (including breaking changes), run: npm audit fix --force Run `npm audit` for details.
無理やり入れているのでWARN出まくってますが、とりあえずinstallはできました。
余談ですが、インストールしようとしていたreact-scroll-restorationはうまく機能しませんでした。
PostgreSQL導入で躓いた
postgresを導入して起動したかったけどできなかった
備忘録として残してます。
$ brew install postgresql
$ initdb /usr/local/var/postgres --encoding=UTF-8 --locale=ja_JP.UTF-8 The files belonging to this database system will be owned by user "username". This user must also own the server process. The database cluster will be initialized with locale "ja_JP.UTF-8". initdb: could not find suitable text search configuration for locale "ja_JP.UTF-8" The default text search configuration will be set to "simple". Data page checksums are disabled. initdb: directory "/usr/local/var/postgres" exists but is not empty If you want to create a new database system, either remove or empty the directory "/usr/local/var/postgres" or run initdb with an argument other than "/usr/local/var/postgres".
で、ここからDBの起動をしてエンコードを確認したかったのにこれ
$ postgres -D /usr/local/var/postgres 2021-12-28 08:55:23.530 JST [63749] FATAL: lock file "postmaster.pid" already exists 2021-12-28 08:55:23.530 JST [63749] HINT: Is another postmaster (PID 63717) running in data directory "/usr/local/var/postgres"?
Postgres が起動しなくなったら
ここを参照してみたものの治らず
$ psql psql: error: connection to server on socket "/tmp/.s.PGSQL.5432" failed: FATAL: database "username" does not exist
と思ったらデータベース作ってないので、最初は上記の文言が出るようです。
$ psql -l
でエンコードも確認ができました。
FirebaseとReactでページネーション
はじめに
受注のあったアプリをFirebase+React+Typescriptで開発中です。
ページネーションと書きましたが、実際は次へと前へのボタン二つで実装です。
(※そして少々回りくどいかもしれません!!申し訳ありません!!)
Firebaseのクエリでは本物ページネーションが難しいため、開発中のアプリはAlgoliaを導入しました。
Firebase+Algoliaの開発記事はまた書こうと思います。
流れ
今回使うメインのデータの型
interface USER { uid: string name: string createdAt: Date image: string }
今回用意するState
Stateの上が関連する説明として書いてます。
// fetchしたデータ、その時表示させる件数分しかsetしません const [ fetchData, setFetchData ] = useState<USER[]>([]) // ① // fetchDataで取得したデータの最初のtimestamp、ページを戻る場合に使う // ちなみにtimestamp(createdAt)は、Firebaseだと下記のデータが入る /* createdAt: { nanoseconds: 34000000 seconds: 1635892516 } */ const [ firstTime, setFirstTime ] = useState<Date>() // ② // fetchDataで取得したデータの最後のtimestamp,ページを進む場合に使う const [ lastTime, setLastTime ] = useState<Date>() // ③ // 全てのデータの最初のID const [ firstId, setFirstId ] = useState('') // ④ // 全てのデータの最後のID const [ lastId, setLastId ] = useState('') // ⑤
1.対象のデータをfetchして①のfirstTimeへsetする。
2.fetchしたデータの最初と最後のtimestamp(createdAt)をstateへset、最初の値を②のfirstTime、最後の値を③lastTimeへsetする。
3.fetchしたデータの最初と最後のID(uid)をstateへset、最初の値を④のfirstId、最後の値を⑤lastIdへsetする。
4.fetchしたデータに2でsetした最初と最後IDがあれば、ページを戻ったり進められないよう処理する。
※今回はフロント部分で矢印のボタンを制御するようにしました。
firstIdもlastIdも合致していない場合、どちらの矢印も表示させる
fetchDataの最初のデータのIDがfirstIdと合致している場合、戻る矢印は表示させない
fetchDataの最後のデータのIDがlastIdと合致している場合、進む矢印は表示させない
tsxで書くとこんな感じ
{ fetchData[0].uid != firstId && 戻る矢印 } { fetchData[fetchData.length - 1].uid != lastId && 進む矢印 }
5.次に進む場合は、2でsetした③lastTimeの次のリストからデータをfetchする。
この時FirebaseのメソッドでstartAfterを使う。
6.前に戻る場合は、2でsetした②firstTimeの手前のリストからデータをfetchする。
この時fetchするデータをlimitで制限している場合、進むとは違って、limitToLastというメソッドとendBeforeを掛け合わせて使う。
という感じです。
下準備が多く、わかりにくく申し訳ありません…
これいらないんじゃないの?とか別の方法があれば教えてもらえたら幸いです!
コード
ざっくりとまとめるとこんな感じです。
今回fetchするデータはcollectionのusersを9件ずつ取得することにしてます。
フロント部分は最小限ですし、CSSも当たってないのでデザインしてください。
Pagination.tsx import React, { useEffect, useState } from 'react' import { db } from '../../../firebase' // ディレクトリ適当です、アプリごと変わります interface USER { uid: string name: string createdAt: Date image: string } const Pagination = () => { const usersRef = db.collection('users') const [fetchData, setFetchData] = useState<USER[]>([]) const [firstTime, setFirstTime] = useState<Date>() const [lastTime, setLastTime] = useState<Date>() const [firstId, setFirstId] = useState('') const [lastId, setLastId] = useState('') useEffect(() => { fetchUsersData() }, []) // setStateをまとめてます const setMethod = (dataList: USER[]) => { setFirstTime(dataList[dataList.length - 1].createdAt) setLastTime(dataList[0].createdAt) setFirstId(dataList[dataList.length - 1].uid) setLastId(dataList[0].uid) } // 一番最初の9件を取りに行く const fetchUsersData = () => { let dataList: USER[] = [] usersRef .limit(9) .orderBy('createdAt', 'desc') .get() .then((snapshot) => { snapshot.forEach((doc) => { const data = doc.data() const newData = { uid: data.uid, name: data.name, createdAt: data.createdAt, image: data.image, } dataList.push(newData) }) setFetchData(dataList) setMethod(dataList) }) } // 次のページ分を取りに行く // startAfterが指定したcreatedAt以降のデータを取ってきてくれる const fetchNextUsersData = () => { let dataList: USER[] = [] usersRef .limit(9) .orderBy('createdAt', 'desc') .startAfter(lastTime) .get() .then((snapshot) => { snapshot.forEach((doc) => { const data = doc.data() const newData = { uid: data.uid, name: data.name, createdAt: data.createdAt, image: data.image, } dataList.push(newData) }) setFetchData(dataList) setMethod(dataList) }) } // 前のページ分を取りに行く // endBeforeとlimitToLastで指定したcreatedAtより手前のデータを取ってきてくれる const fetchPrevUsersData = () => { let dataList: USER[] = [] usersRef .limitToLast(9) .orderBy('createdAt', 'desc') .endBefore(firstTime) .get() .then((snapshot) => { snapshot.forEach((doc) => { const data = doc.data() const newData = { uid: data.uid, name: data.name, createdAt: data.createdAt, image: data.image, } dataList.push(newData) }) setFetchData(dataList) setMethod(dataList) }) } return ( <> {fetchData.map((fd: USER) => ( <div> <img src={fd.image} /> </div> ))} <div className='prevBtn'> {fetchData[0].uid != firstId && <img src={左矢印} onClick={() => fetchPrevUsersData()} />} </div> <div className='nextBtn'> {fetchData[fetchData.length - 1].uid != lastId && <img src={右矢印} onClick={() => fetchNextUsersData()} />} </div> </> ) } export default Pagination
これでうまく機能すると思います!
【Rails】アクセス数をカウントしたかったので、impressionistを導入
初めに
ブログを作成していたので、記事にアクセスした回数を確認したく、探してみたところimpressionistというgemを発見。
少しつまづいたのと、まだ仮実装ですが、見返せるように投稿しておきます。
開発環境
バージョン | |
---|---|
Ruby | 2.5.1 |
Rails | 5.2.3 |
impressionist | 1.6.1 |
impressionistのバージョンはRails5なら1.6.1でないとエラーが出るようです。
やり方
ざっくりとですが、カラムを作ったり、モデルにコードを書いたりします。
カウントしたい対象のテーブルにimpressions_countというカラムをintegerで作ります。
下記はあくまで例です。
class CreateUsers < ActiveRecord::Migration[5.1] def change create_table :users do |t| t.string :name t.integer :impressions_count, default: 0 t.timestamps end end end
gemをインストールしましょう。
gem
gem 'impressionist'
$ bundle install してimpressionistをgenerateします。
ターミナル
$ rails g impressionist Running via Spring preloader in process 134476 invoke active_record create db/migrate/20180804231718_create_impressions_table.rb create config/initializers/impression.rb
マイグレーションは下記が出来上がります。
migration.rb
class CreateImpressionsTable < ActiveRecord::Migration[5.1] def self.up create_table :impressions, :force => true do |t| t.string :impressionable_type t.integer :impressionable_id t.integer :user_id t.string :controller_name t.string :action_name t.string :view_name t.string :request_hash t.string :ip_address t.string :session_hash t.text :message t.text :referrer t.text :params t.timestamps end add_index :impressions, [:impressionable_type, :message, :impressionable_id], :name => "impressionable_type_message_index", :unique => false, :length => {:message => 255 } add_index :impressions, [:impressionable_type, :impressionable_id, :request_hash], :name => "poly_request_index", :unique => false add_index :impressions, [:impressionable_type, :impressionable_id, :ip_address], :name => "poly_ip_index", :unique => false add_index :impressions, [:impressionable_type, :impressionable_id, :session_hash], :name => "poly_session_index", :unique => false add_index :impressions, [:controller_name,:action_name,:request_hash], :name => "controlleraction_request_index", :unique => false add_index :impressions, [:controller_name,:action_name,:ip_address], :name => "controlleraction_ip_index", :unique => false add_index :impressions, [:controller_name,:action_name,:session_hash], :name => "controlleraction_session_index", :unique => false add_index :impressions, [:impressionable_type, :impressionable_id, :params], :name => "poly_params_request_index", :unique => false, :length => {:params => 255 } add_index :impressions, :user_id end def self.down drop_table :impressions end end
migrationしましょう。
ターミナル
$ rails db:migrate
モデルに:counter_cacheを設定
class User < ApplicationRecord is_impressionable counter_cache: true end
コントローラーに以下設定
def show @user = User.find(params[:id]) impressionist(@user, nil, :unique => [:session_hash]) end
今回はuserとしてますが、記事とかであればarticleでもいいですし、動画ならvideoとかですかね?
また、:unique => [:session_hash]は自分の場合一旦消しました。
おそらくこれが無いと、同一のユーザーがアクセスした分カウントされてしまうのだと思われます。
ですが、TypeError - can't quote Rack::Session::SessionIdといったエラーが出てしまい、一旦カウントができる状態で仮完了としました。
エラーの参考記事はこちらです。
ruby on rails - TypeError - can't quote Rack::Session::SessionId - Stack Overflow
あとはViewで呼び出せばOKです。
<%= @user.impressions_count %>
このあとランキングを作ろうと思ってます。