0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Rails】furimaアプリ 商品出品機能実装 #2

Posted at

実装概要

  • 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という変数に格納。
  • 詳細:
    • 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モデルの単体テストを実施していきます!

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?