実装概要
- JavaScriptを使用して商品出品ページの販売価格を入力すると販売手数料(10%)と販売利益が自動で表示される機能の実装。
- データが保存され、エラーがある際はエラー文が表示される機能の実装。
jsファイルの作成
app/javascriptディレクトリ配下にitems_new.jsファイルを作成。
items_newファイルの読み込みができるように設定
items_new.jsファイルをアプリに「ピン留め(固定)」し、ページや機能の中で使えるようにするため下記コードを追記。
importmap.rb
# 中略
pin "items_new", to: "items_new.js"
items_new.jsの機能を実際に使うために読み込むコードを追記
app/javascript/application.js
# 中略
import "items_new"
items_new.jsファイルの編集
app/jabascript/items_new.js
document.addEventListener('DOMContentLoaded', () => {
const priceInput = document.getElementById("item-price");
const addTaxDom = document.getElementById("add-tax-price");
const profitDom = document.getElementById("profit");
priceInput.addEventListener("input", () => {
const inputValue = priceInput.value;
if (inputValue >= 300 && inputValue <= 9999999) {
const tax = Math.floor(inputValue * 0.1);
const profit = inputValue - tax;
addTaxDom.innerHTML = tax.toLocaleString();
profitDom.innerHTML = profit.toLocaleString();
} else {
addTaxDom.innerHTML = '';
profitDom.innerHTML = '';
}
});
});
JavaScriptの知識が浅く理解に苦労したためitems_new_jsで記述したコードの解説を記載していく
コードの説明
1. document.addEventListener('DOMContentLoaded', () => { ... });
-
意味:
- この部分は、HTML文書が完全に読み込まれた後、指定した関数を実行するためのコード。
-
詳細:
-
DOMContentLoaded
イベントは、ページのHTMLがすべて読み込まれたときに発火。このタイミングでJavaScriptのコードを実行することで、HTML要素に安全にアクセスできる。
-
2. const priceInput = document.getElementById("item-price");
-
意味:
-
priceInput
という変数に、IDがitem-price
のHTML要素を格納。
-
-
詳細:
-
document.getElementById
は、指定されたIDを持つ要素を取得するメソッド。この場合、販売価格を入力するためのテキストボックスを取得している。
-
3. const addTaxDom = document.getElementById("add-tax-price");
-
意味:
-
addTaxDom
変数に、IDがadd-tax-price
のHTML要素を格納。
-
-
詳細:
- ここでは、計算された販売手数料を表示するための要素を取得している。
4. const profitDom = document.getElementById("profit");
-
意味:
-
profitDom
変数に、IDがprofit
のHTML要素を格納。
-
-
詳細:
- ここでは、計算された販売利益を表示するための要素を取得している。
5. priceInput.addEventListener("input", () => { ... });
-
意味:
-
priceInput
要素に、ユーザーが値を入力するたびに発火するイベントリスナーを追加。
-
-
詳細:
-
"input"
イベントは、ユーザーがテキストボックスに文字を入力したときに発生。このイベントを使うことで、入力が行われるたびに計算を実行する。
-
6. const inputValue = priceInput.value;
-
意味:
- 現在の入力値を取得して、
inputValue
という変数に格納。
- 現在の入力値を取得して、
-
詳細:
-
.value
プロパティを使うことで、テキストボックスに入力された値を取得できる。
-
7. if (inputValue >= 300 && inputValue <= 9999999) { ... }
-
意味:
- 入力された値が300以上9999999以下であるかをチェックします。
-
詳細:
- この条件文は、入力値が販売価格として妥当かどうかを判断するために使われる。条件を満たさない場合は、販売手数料と利益を表示しないようにしている。
8. const tax = Math.floor(inputValue * 0.1);
-
意味:
- 入力値の10%を計算し、
tax
という変数に格納。
- 入力値の10%を計算し、
-
詳細:
-
Math.floor()
は、計算結果を小数点以下切り捨てて整数にする関数。これにより、販売手数料が整数として表示される。
-
9. const profit = inputValue - tax;
-
意味:
- 利益を計算し、
profit
という変数に格納。
- 利益を計算し、
-
詳細:
- 利益は、入力された販売価格から販売手数料を引いた値として計算される。
10. addTaxDom.innerHTML = tax.toLocaleString();
-
意味:
- 販売手数料をHTML要素に表示。
-
詳細:
-
toLocaleString()
メソッドを使って、3桁ごとにカンマで区切った形式で表示。これにより、視覚的に見やすくなる。
-
11. profitDom.innerHTML = profit.toLocaleString();
-
意味:
- 利益をHTML要素に表示。
-
詳細:
- 同様に、利益も3桁ごとにカンマで区切って表示。
12. else { ... }
-
意味:
- 入力値が範囲外の場合の処理を定義。
-
詳細:
- このブロックでは、入力値が適切な範囲でない場合、販売手数料と利益の表示を空にする。
13. addTaxDom.innerHTML = '';
-
意味:
- 販売手数料の表示を空にする。
-
詳細:
- 入力値が範囲外のとき、販売手数料の表示部分をクリアする。
14. profitDom.innerHTML = '';
-
意味:
- 利益の表示を空にする。
-
詳細:
- 同様に、利益の表示部分もクリアする。
商品出品ページの表示部分の実装が完了したので、次は商品データが保存されるようにする。
ルーティングの設定
config/routes.rb
# 中略
resources :items, only: [:index, :new, :create]
バリデーションの設定
app/models/item.rb
# 中略
validates :name, presence: true
validates :description, presence: true
validates :image, presence: true
validates :category_id, numericality: { other_than: 1, only_integer: true, message: "can't be blank" }
validates :status_id, numericality: { other_than: 1, only_integer: true, message: "can't be blank" }
validates :shipping_fee_id, numericality: { other_than: 1, only_integer: true, message: "can't be blank" }
validates :prefecture_id, numericality: { other_than: 1, only_integer: true, message: "can't be blank" }
validates :delivery_time_id, numericality: { other_than: 1, only_integer: true, message: "can't be blank" }
validates :price, presence: true, numericality: { greater_than_or_equal_to: 300, less_than_or_equal_to: 9999999 }
end
createメソッド内のコードを記述
app/controllers/items_controller.rb
def create
@item = Item.new(item_params)
if @item.save
redirect_to items_path
else
render :new, status: :unprocessable_entity
end
end
private
def item_params
params.require(:item).permit(:name, :image, :description, :category_id, :status_id, :shipping_fee_id, :prefecture_id, :delivery_time_id, :price).merge(user_id: current_user.id)
end
end
# 商品出品機能 #1でitem_params内のコード記述していたが併せて修正
未ログイン状態で商品出品ページに遷移しようとしてもログインページに遷移するよう設定
app/controllers/items_controller.rb
before_action :authenticate_user!, only: [:new, :create]
必要な情報を入力するとデータが保存され、エラーがある際はエラー文が表示されることを確認。
次回はitemモデルの単体テストを実施していきます!