Vue.js学習メモ(親から子への値受け渡し)
Vue.jsの勉強では、タスクを管理するアプリを想定しています。 既にタスクのデータは追加されていて、タスク一覧に表示されているとします。 今回は、タスク一覧からタスクをクリックして、タスク詳細のモーダルを表示する実装を行いたいと思います。
親コンポーネント(index.vue)→子コンポーネント(TaskDetailModal.vue) 引き渡すデータ:タスクの情報(タイトル/title、詳細/description)
実装例
index.vue
<template> <div v-for="task in tasks" :key="task.id" :id="'task-' + task.id" class="bg-white border shadow-sm rounded my-2 p-4" @click="handleShowTaskDetailModal(task)" > </template> <script> import TaskDetailModal from "./components/TaskDetailModal" export default { name: "TaskIndex", components: { TaskDetailModal }, data() { return { tasks: [], taskDetail: {}, isVisibleTaskDetailModal: false } },
TaskDetailModal.vue
<template> <div class="modal-header"> <h5 class="modal-title">{{ task.title }}</h5> <button type="button" class="close" @click="handleCloseModal"> <span>×</span> </button> </div> <div class="modal-body" v-if="task.description"> <p>{{ task.description }}</p> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" @click="handleCloseModal">閉じる</button> </div> </template> <script> export default { name: "TaskDetailModal", props: { task: { title: { type: String, required: true }, description: { type: String, required: true } } }, } </script>
親コンポーネントから子コンポーネントにデータを渡す場合
1)子コンポーネントをインポートし、componentsプロパティに登録
import TaskDetailModal from "./components/TaskDetailModal" export default { name: "TaskIndex", components: { TaskDetailModal },
2)子コンポーネントに渡すデータをdataプロパティで定義
data() { return { tasks: [], taskDetail: {}, isVisibleTaskDetailModal: false } },
3)データを子コンポーネントタグにバインド 今回は複数のタスクを表示するため、v-forを使う (:keyはv-bind:keyの略記)
<div v-for="task in tasks" :key="task.id" :id="'task-' + task.id" class="bg-white border shadow-sm rounded my-2 p-4" @click="handleShowTaskDetailModal(task)" >
4)子コンポーネントでpropsプロパティを使ってデータを受け取る
props: { task: { title: { type: String, required: true }, description: { type: String, required: true } } },
5)プロパティで設定された値を表示
<div class="modal-header"> <h5 class="modal-title">{{ task.title }}</h5> <button type="button" class="close" @click="handleCloseModal"> <span>×</span> </button> </div> <div class="modal-body" v-if="task.description"> <p>{{ task.description }}</p> </div>
長くなったので、逆の子から親への値受け渡しについては明日書きます。
どうしても時間がかかってしまうので、サクッとブログ書けるようになりたいですねー
今後のブログ更新について
こんな去年の年末から更新してないブログを見ている人はまずいないでしょうが、
改めてブログ書いていこうと思います。
以下、要約
- このブログは、私が学んだプログラミング技術について雑にまとめていくものです。
- アウトプット力を高めるために書いてます。
- 更新日は、定時退社推奨日(私は基本定時退社ですが)である水曜日、土曜日、日曜日に何かしら書いていきます。
- 技術以外の日々の感想も書こうと思いますが、折角Noteのアカウントも作っていたので、そっちで書こうかなと思います。
また、三日坊主になるかもしれませんが、1ヶ月後の私はブログを継続させていることでしょう(未来完了)。
建築設計1年目でプログラミングを通して作りたいと思った機能
はじめに
この記事は「RUNTEQ Advent Calendar 2020( https://qiita.com/advent-calendar/2020/runteq )」のアドベントカレンダー9日目の記事として書いています。
どうも初めまして。一応ブログは作ってはみましたが、2ヶ月くらい放置していた人間です。建設系の設計部1年目社員として働きながら、RUNTEQでプログラミングの学習(Rails)をしています。アドバイスや反応を頂けたら幸いです🙏
勢いでアドベントカレンダーに参加し、今の自分で書けそうな読む価値のありそうな記事は何かなと思い悩んだ結果、仕事の中でこんなアプリがあったら仕事が楽になるのにと思ったことについて書くことにしました。色々アイデアはあったのですが、アプリとして作れそうな物は今回紹介できる3つに絞られました。
最初に言っておくと、かなり今勤めている会社にローカライズされてしまっていて、他の会社でも使えるような一般的なアプリ案ではないかもしれませんが、よろしくお願い致します。
前提知識
- 今勤めているのは化学系プラントの会社(中小企業)
- 創業から数十年経過しており、平均年齢は40才以上
- 業務の資料作成はOutlookのみで、一部マクロがあったりする
- 最近のITツールやアプリの使用(slackなど)は殆ど行われていない様子(使いたくても使わせてもらえない?)
- 紙が多い
1 物量計算アプリ
用途:作成する機器の面積・体積、数量などを図面から計算・集計
目的:計算・集計にかかる時間を減らし、計算ミスの発生を防ぐ
背景:
- 所定の性能を満たす機器を作成するのが設計の仕事であり、そのためには様々な計算を行う必要
- 計算に必要な値は紙の図面を用いて集計
- 仮に計算ミスが発生した場合、作り直しにかなりの費用と時間がかかる
- ミスに気づかないまま現場に納入してしまうと、後で設置時や運転時に重大な事故が発生する
- 現状、そのような事故は過去に起こってないようだが、何度も検算や作り直しは発生していた様子
- 客先からの要望で改造する必要が発生すると、面倒な計算を一からやり直ししなければならない
機能:
- 図面の指定した範囲の面積・体積を計算
- 図面の指定した範囲の重量を計算
- 図面内に存在する指定した記号の数を集計
- 対象の図面が紙や画像化されたPDFでも集計できるように、画像認識による入力が可能
- 計算した値は所定の書式にまとめて出力する(excelなど)ことが可能
要するに、物量計算は設計の要であると同時に、最も業務で手間がかかる作業であるということです。建設は設計のミスがあると、全体の工程に影響が出る可能性が高く、また改めて業者に材料と作成の発注をかける必要があるので、コストもかかってしまいます。これをもっと効率化且つミスのない正確な計算ができるようになればと、そのような余分なコストが発生しません。
図面を作成する際にCADを用いて作成するので、CADの機能を用いてAPIで計算・集計を行ってしまえばいいのではないかとも思いましたが、そのような機能付きのCAD(3DCADなど)を全ての会社が使える(使いこなせる)わけではないので、このようなアプリは結構需要があるのではないかと思います。
2 検査写真管理アプリ
用途:検査写真の撮影、保存、(共同)編集、整理などを行ってくれる
目的:検査写真の作成・整理にかかる時間を短縮
背景:
- 作成を外部の会社に依頼した機器には、こちらが希望した通りの性能になっているか検査を行う必要があり、検査時に指摘箇所があった場合は写真を撮影、それをまとめて会社に報告して修正してもらうことになっている。
- その撮った写真の整理方法が、会社規程のExcelシートに画像を一つずつ貼り付け、別用紙に書いておいた指摘事項を横に記載していくというもの。加えて、指摘事項だけまとめた表も別途作成。
- 上の方法の場合、指摘箇所の画像を探す手間が発生・一つずつ画像を貼っていくしかない・指摘事項は2度書かなければならないなどの面倒な作業が発生してしまう。
機能:
- スマホで撮影した写真に、番号・場所・指摘箇所・修正が必要かなどの情報を追加できる。
- 与えた情報を元に写真の並び替えや検索が可能。
- 2名以上の人が同じ検査ファイルを編集することが可能。
- 設定した書式で整理した写真の出力が可能。
- 写真に記載した情報だけをまとめて書式に出力することができる。
建設業において、検査写真の管理は課題の一つであるようで、検索したら既に検査写真を管理するアプリはあるようです。もしかしたら、それらのアプリを導入した方がいいのかもしれません。
実際、自分は業務で2回作成しましたが、かなり面倒でした。特に大変な中間検査と呼ばれる検査では、
- 2班に別れて全体を確認。
- 指摘箇所は全部で100は超えてくる。
- 班を別れて作成するため、同じ個所を指摘しているがあり、最終的にはそれらを一つにまとめる。
- 検査後の修正チェック時には、検査個所をまとめた資料を印刷し(60〜80ページ分のA4)を片手に現場を見て回る。
といった業務を行っており、整理が大変でした。現場で指摘箇所を大量の紙束の中から探すのが手間というのもあり、非常に効率が悪いと思った次第です。
3 機器台帳作成アプリ
用途:画像認識を使用した機器台帳の作成
目的:機器台帳作成の効率化
背景:
- 現在進行形で行っている業務で、各機器のモデルや型式、電圧や電流値などが書かれている銘板を見て、それをまとめた資料を作成。
- 機器によって書かれている項目が異なる他、同じ機器であっても案件ごとに項目が異なっている場合があり、何を書けばいいか分からない。
- 現場見て回って、銘板のメモを取るのが面倒だった。現場の人が予め写真を撮影してくれていたが、その撮影時点で台帳を作成できればと考えた。
機能:
- 画像認識による銘板記載項目の入力。
- 機器の製造社によって銘板記載項目の表記に揺れがあるため、流量=Flowと変換してくれる。
- 不要な項目を設定することでその項目の入力を飛ばしてくれる。
- 入力したデータは設定した書式で整理・出力することが可能
2の検査写真アプリと共通する点が多いです。異なるのは、画像認識を使って銘板記載事項の入力を省略するという点です。問題点も基本的には2と同じですが、案件ごとに記載項目が変わってくる場合が想定されるため、項目の選択や不必要な項目は読み取らないなどの機能も必要かもしれません。
言語について
肝心の言語については、フロント側はHTMLとCSS、一部JavaScript。サーバー側は基本Ruby、計算や画像認識の箇所はPython辺りになるのかなと勝手に思っています。実際にポートフォリオとして作成することが決まった際に、詰めて考えていく必要のあるところです。初学者なので、この辺りの認識が間違えていたらご教授願えればと思います。
共通の想定される課題
- 上の課題は自分が思っているだけで、他の人たちは改善すべき課題と思っていない。そのため、上のアプリは余計な物を作成しているだけになってしまう点。
- 改善すべき課題と思っていても、新しいアプリを導入して操作を覚えるが面倒だとされて、結局使ってもらえらない。
- 自分で新しい物を作るよりは、既存のアプリを導入した方が効率化を計れる。
上の課題はアプリによる効率化全てに言えることかもしれません。アプリ制作者側はできるだけユーザーに使ってもらえるようなアプリを制作する必要がありますが、全く使う気がないユーザーのためにアプリを作ることはできないわけですし。
終わりに
現時点の自分では、技術的な点で皆さんにgiveできる記事を書くのは難しいと思ったので、今働いている会社の設計業務の中でアプリに効率化できそうなことをまとめて見ました。また、近々作成するであろう自身のポートフォリオ作成時にも役に立つのではと思い、この題材を記事にしようとした点もあります。
建設業だけに限りませんが、IT化が進んでいない業界や会社は世の中にごまんとあるのでしょう。今であればもっと効率の良い方法で同じ結果をえられるのに、今までの方法を踏襲してきているパターンが殆どだと思います。そのような状態をアプリ制作を通して、少しでもましな状態にできれば素敵だな自分は思います(その割にブログ記事の更新頻度がアレですが…)。
来年のアドベントカレンダーはしっかりとした技術的な記事、もしくは作成済の上のアプリのどれかをどのように作成したか、実用しているかについて書いていることでしょう(多分)!
できれば来年まで覚えていて、「おっ、ちゃんと有言実行してる」または「やっぱり忘れてんじゃん(笑)」と確認して頂ける方を募集していますので、よろしくお願い致します。
では、皆さん良い年末年始をお過ごし下さい🎄🎍
皆さんRUNTEQで学習しよう!
2カ月間の勉強でしでかしたミス その1
ブログの更新はこの2カ月全くやってなかった一方で、学習の方は進めていたので、
その中でやってしまったミスを思い出せる範囲で書き残して行きます。
1)@消し忘れ
スクールで作成中のアプリで、コメント編集・削除のajax 化を行った後、テストを行ったら下のエラーが出て、何時間も難儀してました。
1) コメント コメントのCRUD コメントの削除 コメントを削除できること Failure/Error: within("#comment-#{comment_by_me.id}") do page.accept_confirm { find('.js-delete-comment-button').click } end Capybara::ElementNotFound: Unable to find css "#comment-1" [Screenshot]: tmp/screenshots/failures_r_spec_example_groups_nested_3_crud_nested_3_コメントを削除できること_123.png
掲示板にコメントを投稿できるようになっているのですが、コメントを投稿した直後はidが残っている一方で、リロードや別のページに移動してから戻ると、idが消えてました。そのせいでコメントのidが見つからず、削除できなくなってました。
原因
<tr id="comment-<%= @comment.id %>" >
コメント全体を上のtrタグでidをつけているのですが、本来はcomment.idの前に@は入りません。これが原因でコメントのidがうまくいってなかったようです。
2)コピペする時は要注意
1)よりも時間が遡っていますが、掲示板にコメントを保存・投稿できるようにする機能を実装した時のミスです。コメントを投稿しても全く反応せず、binding.pryで検証した結果、下のメッセージが帰ってきました。
[2] pry(#<CommentsController>)> ↳ app/controllers/comments_controller.rb:20 User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 11], ["LIMIT", 1]] ↳ app/controllers/comments_controller.rb:20 (0.1ms) rollback transaction ↳ app/controllers/comments_controller.rb:20 Redirected to http://localhost:3000/comments/55 Completed 302 Found in 6395ms (ActiveRecord: 1.1ms)
ちゃんとコメントが入っていることはbinding.pryで確認していたので、ストロングパラメータやバリデーション辺りが怪しいです。
原因
comments_controller.rb class CommentsController < ApplicationController before_action :require_login, only: %i[create index show] def show @board = Board.includes(:user).find(params[:id]) @comments = @board.comments.includes(:user).all @comment = @board.comments.build(user_id: current_user.id) if current_user end def index @comments = Comment.all.includes(:user).order(created_at: :desc) end def create @board = Board.find(params[:board_id]) @comments = @board.comments.includes(:board_id).all @comment = @board.comments.build(comment_params) @comment.user_id = current_user.id binding.pry if @comment.save flash[:success] = t('defaults.message.created', item: Comment.model_name.human) redirect_back(fallback_location: root_path) else flash.now[:danger] = t('defaults.message.not_created', item: Comment.model_name.human) redirect_back(fallback_location: root_path) @comment = @board.comments.build(comment_params) end end private def comment_params params.require(:comment).permit(:body, :user_id, :board_id) end end
予測は当たっていて、ストロングパラメータでboard.idをmergeしていないのが原因でした。ただ、私はさらにどこからか引っ張ってきた下のコードを書き、更に無駄な時間を浪費します。
def comment_params params.require(:comment).permit(:body).merge(params.permit(:user_id,:board_id))
end
上のコードだと、コメントの保存はできても、コメント作成失敗時にロールバックが発生して、エラーメッセージが表示されませんでした。正しいコードは次のコードです。
def comment_params params.require(:comment).permit(:body).merge(board_id:params[:board_id])
end
ストロングパラメータのmergeを調べればすぐに出てくるようなコードです。逆に修正前のコードはどこからコピってきたのか今では思い出せません。誰かのコードをコピペする時はしっかりそのコードが合っているかどうか調べましょう。
3)コピペする時は要注意 その2
コメント編集のajax化を行っている時にやってしまったミスです。コメントの編集ボタンを押して非同期で編集フォームを表示させようとしてjsファイルを書いていたのですが、ボタンを押してもうまくイベントが発火しない状態に陥ってました。
色々と調べて、passive:falseだのstopPropagationだの試していましたがうまく行きませんでした。最終的にはイベントが発火するようになりましたが、うまく行かなかった理由は本当にしょうもないミスです。
この時も参考にしたコードをコピペしてjsファイルに貼っていたのですが、修正前はコメントが```~#コメント更新ボタン~```となっていました。しかし、jsファイルのコメントの書き方は```~//コメント更新ボタン~```または/*コメント更新ボタン*/です。
まあ、一応ProgateでJavaScript学んでいたのですが、期間空いてしまって忘れてたんですよ...
結論 コピペする時は本当にそのコードが正しいか見極めてから行う
当方、エンジニア目指してる途中の初心者なので、検索したら出てくるコードが正しいか判断できる知識がまだありませんが、怪しいところがあったらしっかりと調べてから使うようにします。
まだまだミスはありますが、今回はこの3つにしておきます。今まで学んできたこともまとめていければと思っていますし、その過程で自分のやったミスを思い出したり、学習を進めていく中でまたミスが発生することもあるので、それらについてまた記録しておきたいですね。正直、こんなミスするかと言われたら否定できませんが、もしかしたら自分と同じような初心者の方に役立つことがあるかもしれませんし。
とりあえず、ブログ更新という名のアウトプットを頑張って行きたいと思います。
Railsチュートリアル 第14章 メモ書き
プログラミングの学習をとりあえず挙げていくと言ったくせに、
すぐに三日坊主になってしまった人です。
プログラミングの学習自体は続けてました。
チュートリアルのメモ書きは13章まで上げていましたが、14章もメモに書くだけ書いて放置していたので、上げておきます。
○フォローとアンフォロー
・フォロー中→following
フォロワー達→followed
・relationshipカラムでフォローとフォロワーの関係を構築
→follower_idとfollowed_id
・複合キーインデックス
→ add_index :relationships, [:follower_id, :followed_id], unique: true
follower_idとfollowed_idの組み合わせが必ずユニークであることを保証
・外部キー:
2つのデータベーステーブルを繋ぐid
場合によっては以下のようにクラス名を明示しなければならない。
has_many :active_relationships, class_name: "Relationship"
belongs_to :followed, class_name: "User"
・has_many_through:
has_many :followeds, through: :active_relationships
だとrelationshipテーブルのfollowed_idを使って対象のユーザーを取得。
但し、followedsでは文法的に正しくないため、:sourceパラメーターを使って、
「following配列の元はfollowed idの集合である」ことrailsに示す。
has_many :following, through: :active_relationships, source: :followed
・# ユーザーをフォローする
def follow(other_user)
f ollowing << other_user
end
・# ユーザーをフォロー解除する
def unfollow(other_user)
active_relationships.find_by(followed_id: other_user.id).destroy
end
・# 現在のユーザーがフォローしてたらtrueを返す
def following?(other_user)
following.include?(other_user)
end
・複数のルーティング設定:
resources :users do
member do
get :following, :followers
end
end
→users/1/following やusers/1/followed
Idの指定をしない場合、memberではなくcollection
・AjaxによるHTML の表示
form_with(model: ..., remote: true)
local→remoteに
・ステータスフィード
1)フォローしているユーザーのマイクロポストがフィードに含まれていること。
2)自分自身のマイクロポストもフィードに含まれていること。
3)フォローしていないユーザーのマイクロポストがフィードに含まれていないこ
と。
・Railsは低級なクエリを呼び出せる
def feed
following_ids = "SELECT followed_id FROM relationships
WHERE follower_id = :user_id"
Micropost.where("user_id IN (#{following_ids})
OR user_id = :user_id", user_id: id)
end
Railsチュートリアル 第13章 メモ書き
○マイクロポストの実装
・Micropostモデルは内容を保存するcontent属性(text型)と、特定のユーザーとマイクロポストを関連付けするuser_id属性(integer)の2つから成る
・$ rails generate model Micropost content:text user:references
→AplicationRecordを継承したモデルが生成
+user:referencesでbelongs_toも追加
・マイグレーションファイルも同時に生成
Userモデルとの違いは以下2つのコードが追加されている点
t.references :user, foreign_key: true
add_index :microposts[:user_id, :created_at]
・バリデーション:
存在性と長さの2つ
validates :user_id, presence: true
validates :content, presence: true, length: { maximum: 140 }
・関連付け:
それぞれのマイクロポストは一人のユーザーに関連付けられる
+それぞれのユーザーは複数のマイクロポストと関連付けられる
→belongs_to/has_manyによる関連付け
user.microposts.create
user.microposts.create!
user.microposts.build
上3つに代表されるメソッドが使用可能に
・Micropostの投稿を降順にする場合:
default_scope -> { order(created_at: :desc) }
※->(ラムダ式):ブロックを引数に取り、callメソッドが呼ばれた時、
ブロック内の処理を評価する
・has_many :microposts,dependent: :destroy
→マイクロポストがその所有者と一緒に破棄されることを保証する
・id="micropost-<%= micropost.id %>:
将来的にJavaScript でマイクロポストを操作する場合に有効
・マイクロポスト作成・削除にはログインが必要→ logged_in_userメソッドをApplication コントローラに
・Micropost.where("user_id = ?", id)
→?でSQLクエリに代入される前にidがエスケープで、SQLインジェクションというセキュリティホールを避ける
・マイクロポストの削除は投稿ユーザーと管理者のみに限定
・request.referrer:一つ前のURLを返す
・Railsでファイルをアップロードする場合はActiveStorageを使う。
rails active_storage:install
※但し、フォーマット機能やバリデーション機能は実装されていないため、gem :'active_storage_validations'をインストールする
・has_one_attachedで1つのマイクロポストに一つの画像(has_many_attachedで複数の画像)
Railsチュートリアル 第12章 メモ書き
○パスワードの再設定
基本的に11章のパスワード有効化と同じ
Forget passwordリンク→フォームにメアド
→再設定用のリンク付きメールが届く
→再設定の確認フォーム
・再設定の手順
1)キーはフォームに入力されたメアド
2)メアドがデータベースにあれば再設定用トークンとダイジェストを生成
3)ダイジェストはデータベースに保存、トークンはメアドと一緒に有効化リンクに含める
4)ユーザーがリンクをクリックすれば、メアドをキーとして探し、データベース内のダイジェストと比較
5)認証成功時にパスワード変更用のフォームを表示
・Password resetsをRESTfullに使う
→edit、new、action、updateが、ActiveRecord オブジェクトではないため、自前でルーティングやアクションを書いていく。
・セキュリティ的な問題から次の2点が必要
1)トークンのハッシュ化
2)再設定のリンク期限を短くする
→データベースにreset_digestと
reset_sent_at属性の追加
・キーにメアドを使うため
f.hidden_field :email, @user.email
でページ内に保存
・パスワード更新(update):
必要な項目は次の4つ
1)再設定の有効期限が切れていないか
2)無効なパスワードであれば失敗させ、その理由を示す
3)新しいパスワードが空文字列になっていないか
4)新しいパスワードが正しければ更新
・reset_sent_at < 2.hours.ago:
パスワード再設定メールの送信時刻が、現在時刻より2時間以上前(早い)の場合を示す。“<”は少ないではなく、早いと解釈する