Arale

アパレル、バリスタを経て未経験からのプログラマーになった男の勉強ログ

三項演算子

無事にプログミングスクールを卒業し、就職しました。

そちらの詳しい話は今回は割愛いたしますが、

現在は職場の開発言語がphpのため、phpの学習を行なっております。

その中で三項演算子が出てきました。

まずは下記の記述をご覧ください。

isset($_GET["a"])?$_GET["a"]."だしん":"何かしゃべって!"

if文の条件を簡略化したものでした。

この場合だと$_GET["a"]で取得した情報が(真)であれば、

「〇〇だしん」を表示する。

$_GET["a"]で取得した情報が(偽)であれば、

「何かしゃべって!」を表示する。

この場合の真偽は$_GET["a"]に情報があるかないかです。

."だしん"の前についている.(ドット)は文字列を結合します。

rubyでいう+の役割です。

isset(□□)?〇〇:XX
// □□は分岐のための条件を
// 〇〇 条件が正しい場合に出力する値
// XX 条件が間違っている場合に出力する値
// issetは引数に指定した変数に値がセットされいれば、True。そうでなければFalseを返す関数

// 上記と全く同じ意味だが、記述量に圧倒的差がある
if (isset($_GET['a'])) {
    print $_GET['a']."だしん";
} else {
    print "何かしゃべって!";
}

form_withメソッドのアウトプット

HTMLではこのように実装していた

<form action="/posts" method="post">

  <input type="text" name="コメント">

  <input type="submit" value="投稿する">

</form>

action属性は送信URLを指定する際に書くが、

HTML5以降からは必須では無くなった。

コードを解析するとどこに情報が集約されているのか分かるので、

あまり好ましくはない。

そこでRailsのヘルパーメソッドを用いてHTMLを表示する

ヘルパーメソッド

rails5.1以降からはform_withメソッドを用いてフォームを追加する

それ以前まではform_tagやform_forを用いてフォームを追加していた。

あまり違いを気にしていなかったが、違いを今回調べてみました。

form_tagメソッド

関連するモデルがなく、データを保存する必要がない場合

<%= form_tag('/main, method: :post') do %>

  <input type="text" name="penname">

  <input type="submit">

<% end %>

form_forメソッド

関連するモデルがあり、データを保存する必要がある場合に用いる

<%= form_for(@user) do |f| %>

  <%= f.text_field :name %>

  <%= f.submit %>

<% end %>

ヘルパーメソッド内にブロック変数fを用いているのが分かる。

form_withでも見慣れた記述ですね。

form_withの記述

データを保存しない記述?!(この辺りがまだ曖昧です)

<%= form_with url: "/posts", method: :post, local: true do |f| %>

  <%= f.text_field :name %>

  <%= f.submit %>

<% end %>

url: フォームの情報を送るリクエストのパス(投稿先)を指定。

method: httpメソッドを指定。初期値はpostなので、postメソッドの場合は省略可

local: ローカル送信を無効にするかどうか。trueにすると無効

 

データをモデルに保存する記述

<%= form_with(model: @user, local: true) do |f| %>

  <%= f.text_field :name %>

  <%= f.submit %>

<% end %>

model: モデルオプションで指定されたインスタンス変数の状態により、

リクエストを送るアクションを判断

アクションにより、paramsでデータを渡す必要がある

①ストロングパラメーター

  • 意図しないデータの読み書きを防ぎ、受け取るパラメーターを制限する

②requireメソッド

  • 送信されたパラメーターの情報を持つparamsが、使用できるメソッド
  • パラメーターからどの情報を取得するのかを選択する。

③permitメソッド

  • 取得したいキーを指定し、指定したキーと値のセットのみを取得する

①②③を踏まえた上での記述

private

def item_params

    params.require(:item).permit(:name, :text, :category_id, :price, image)

end

itemモデルから商品名/説明/カテゴリー/値段/商品画像を取得

プライベートメソッドでClass外から呼び出さないように、可読性の向上を。

def create

  item.create(item_params)

end

item_paramsというストロングパラメーターを定義し、

createアクションの引数に使用し、itemsテーブルへと保存できるようになりました。

newアクションで作成された既存のものをcreateアクションに渡してます。

私が今作成しているオリアプのupdateアクションにも既存のデータは渡されますね。

参考サイトを見るとインスタンス変数の中身からアクションを選別し、

自動で振り分けてくれる。なので、ビューファイルも同じもので出来る。

この二つが大きなメリットそうですね。

まだまだ細かいメソッドなどは把握しきれてないので、

オリジナルアプリに検証したいと思います。

大いに参考にしたサイト

pikawaka.com

qiita.com

_と.の違い

条件分岐の際に疑問と思ったのです

  def destroy
    if @item.user == current_user.id
      @item.destroy
      redirect_to root_path
    end
  end

現在のユーザーが出品者だった場合のみ削除可能にする。

削除完了したら、トップページに遷移する。

しかし、このままだと出品者以外のユーザーがトップページに遷移しないかもしれません。

なので、redirect_to root_pathをif文の中ではなく、外に記述します。

  def destroy
    if @item.user_id == current_user.id
      @item.destroy
    end
    redirect_to root_path
  end

そして@item.user_idに修正

current_user.idにidが付いているので、

@item.userにもidが付いてないと正しく比較できない

usersテーブルのidだから.idではなく、_idでないといけないのかな

と思って聞いてみたら、結論としてはどちらでも大丈夫ということでした。

詳しく書くと

@item.user_idの場合 → itemsテーブルからuser_idを取得する

@item.user.idの場合 → itemsテーブルとアソシエーションを組んでいるusersテーブルから該当するidを取得する

Google Map をJavaScriptで表示しよう

お店の位置情報を埋め込みで表示させたい

現在、作成しているオリジナルアプリケーションは店舗情報を必要としています。

来店されるお客様にも文字列だけの情報だけでなく、

マップを表示してより具体的な情報を提供したいです。

Googleの仕様変更により、ここ数年はクレジットカードの登録も必須となったみたいです。

昔はAPIキーすらいらない記事を拝見しましたが、10数年前の話なのであてになりません。

API取得、キー制約を設定、カード登録、ドメイン指定、コードを記述

上記の必要な情報を登録し、APIキーもコピーしました。

ところが、どんだけ記述してもポッカリと空白が発生する。

もしくは、空白すら領域にすら反映されませんでした。

CSSとHTML両方の記述が必要!?

数10種類のサイトから情報を得て、

コードも記入しましたが、表示されません。

CSS設定をしない限り、表示されない。

下記サイトの投稿でようやく判明しました。

めでたく表示はされましたが、表示したい店舗情報ではありません。

これから、表示したい店舗になるようコードを書き直します。

追記

Embed APIがアクセスマップとしては優秀だった

下記参考サイトに記載がある通り、簡潔に表示できました。

緯度を調整する方法は後日調べてみて発信したいと考えてます。

非常に参考にさせていただいたURL

mono96.jp

maps.multisoup.co.jp

フォームで改行して入力した情報を別のページでも改行が反映されるように表示する

フォームで入力した情報を別ページで表示する

// bootstrap5でCardを使用
// itemsテーブルに保存された情報をページに表示
  <div class="card-body">
    <h5 class="card-title"><%= @item.name %></h5>
    <p class="card-text"><%= @item.text %></p>
    <p class="card-text"><small>¥<%= @item.price %>(税込)</small></p>
    <%= link_to "カートに入れる", "", class: "btn btn-outline-secondary btn-sm" %>
  </div>

現在の記述はこのような表示となっております。

f:id:Arale:20220128135554p:plain

商品登録する際のフォームでは商品説明文は改行してます。

しかし、改行が反映されておらず、非常に読みづらい文章となっています。

改行を反映させる記述

結論から申し上げると正規表現simple_formatメソッドを使用する

// 先ほどの記述でテキストを表示する部分を編集
<p class="card-text"><%= simple_format(@item.text) %></p>

私は正規表現だと正しく改行が行われなかったので、

強制的に"p"タグを挿入するsimple_formatメソッドを使用しました。

更にここの改行スペースを調整したい場合はCSSを以下のように追記すると可能みたいです。

/* pタグの"card-textプロパティ指定する" */

. card-text p {
 /* 適応したいスタイル */
}

こちらは必要であれば行います。

現在はフォームで改行した箇所が正しく反映されてます

f:id:Arale:20220128135713p:plain

参考にしたURL

sashimistudio.site

qiita.com

Bootstrapのcardを元に一覧表示機能を実装

BootstrapのCardで一覧表示

フロント実装のフレームワークで重宝しているBootstrap5ですが、

Cardを使用して商品を横並びしたいと考えてました。

ところが、複数の商品を登録すると商品が縦に1列で並んでしまうので、

望んでいたデザインではありません。

f:id:Arale:20220127155622p:plain

このように縦型になってしまいます。

CSSを編集してみる

/* app/views/items/scss */
/* Cardの親要素 */
. container {
  display: flex;
  justify-content : space-between;
}

これで横並びになるかなと思ったのですが、

更新しても1mmも変わってません。

新たな記述を加える

色々検索してみたら、どうやらrowクラスの

要素を入れたら横並びになるとのこと。

eachメソッドの前にrowクラスの

要素を追記しました。

f:id:Arale:20220127160216p:plain

横並びにはなりましたが、惜しい…

モザイクなので分かりませんが、

余白が全くなく隣接している状態です。

商品が増える毎に圧迫感があるページ表示になってしまいます。

そして画像の左右だけ中途半端に余白があり、

見栄えもよろしくありません。

更に記述を加えて組み合わせる

<!-- app/views/items/index.html.erb -->
<div class="container">
      <div class="row">
        <% @items.each do |item| %>
          <div class="col-12 col-md-6 col-lg-4">
            <div class="card" style="width: 18rem;">
               /* 以下の記述略 */
            </div>
         </div>
       <% end %>
     </div>
</div>

新たにeachメソッドの後にcolクラスを追記しました。

グリッドと呼ばれるBootstrapが多く使用される理由の機能の一つなのですが、

この記述を加えることで求めていた通りの横並びとなりました。

f:id:Arale:20220127161127p:plain

まだまだ使用方法は模索中ですが、

一旦これにて問題は解決しました。

非常に参考にしたURL

qiita.com

deviseで一般ユーザーと管理者とで分ける

管理者(admin)と利用者でユーザーを分ける

自分で1からWebアプリケーションを作成しています。

今回、私が作成したいのはパンの取り置き(予約)サイトです。

トップページにはご予約方法や商品一覧を表示させたいと考えてます。

管理者だけが商品の追加、編集、削除を行いたいと考えてます。

そこで他の一般のユーザーの方にはそうならないように条件分岐する予定です。

が、機能の導入の前にDB設計で躓きました。

ただでさえ、最終理想のWebアプリケーションはER図でのテーブルが非常に多く、乱雑な状態でした。

元々あるusersテーブルにadmin機能だけ追加出来ないか?

と考え、調べに調べました…

deviseでユーザー管理機能を導入し、管理者を設定するにはどうすれば良いのか。

boolean型(カラム)をusersテーブルに追加する

f:id:Arale:20220125105418p:plain

# app/db/migrate 内のuserテーブルの記述
    create_table :users do |t|
      ## Database authenticatable
      t.string :nickname,           null: false
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""
      t.string :family_name,        null: false
      t.string :first_name,         null: false
      t.string :phonenumber,        null: false
      t.boolean :admin,                          default: false

boolean、初めて出てきた用語です。

直訳すると「真、または、偽」

default: falseはなぜfalseなのかは分かりませんが、

偽で初期設定をしている。と今の私は無理矢理納得しました。

管理者を登録する

# app/db/seeds.rb
User.create!(
  nickname: "*************",
  email: "*************",
  password: "*************",
  password_confirmation: "*************",
  family_name: "*************",
  first_name: "*************",
  phonenumber: "*************",
  admin: true
)

seeds.rbファイルを初めて触りました。

色々調べたけど、テスト環境で使うファイルと端的に認識しました。

そしてここでのadminはtrueとなっています。

さて、ここで記述した情報をusersテーブルに保存したいと思います。

rails db:seed

無事にテーブルに保存されており、ローカル環境でバッチリログインできました。

しかし、このままだと本番環境では機能しないみたいです。

下記を参考にさせていただき、本番は鍵にして動作確認します。

qiita.com

上記のコマンドに出てたコマンドで反映されませんでした。

結論として

heroku run rake db:seed

#heroku上で行うコマンドでないと実行できませんでした。

参考にしたURL

nllllll.com

ccbaxy.xyz

qiita.com

qiita.com