Webエンジニア目指して#51

どうもワクチンマンです。1回目は筋肉注射による筋肉痛だけでした。2回目はどうなるかな

さてrailsであれこれしているうちのエラー備忘録です。

rails error_I18n::InvalidLocaleData

ymlファイルのインデントが間違っていた。下の例が動作する記述例

attributes以降がインデント一つ分余分だったときにエラーが出た
あとはキーの定義で間に半角スペースを挟んでおらず反映されなかった

ja:
  activerecord:
    models:
      schedule: スケジュール
    attributes:
      schedule:
        title: タイトル
        start: 開始日
        end: 終了日
        allday: 終日
        memo: メモ
        created_at: 作成日時
        updated_at: 更新日時

herokuのデプロイエラー

作ったアプリをgithubとherokuなるものを使って公開する際に、デプロイを実行したら以下のエラーが出た

Your bundle only supports platforms ["x86_64-darwin-18"] but your local platform
       is x86_64-linux. Add the current platform to the lockfile with `bundle lock
       --add-platform x86_64-linux` and try again.
       Bundler Output: Your bundle only supports platforms ["x86_64-darwin-18"] but your local platform
       is x86_64-linux. Add the current platform to the lockfile with `bundle lock
       --add-platform x86_64-linux` and try again.
 !
 !     Failed to install gems via Bundler.
 !
 !     Push rejected, failed to compile Ruby app.
 !     Push failed

なにやらlockfileのplatformがどうとか書いてあるのでgemfile.lockを覗いてみると、それっぽいのを発見
f:id:misokatsu_sand:20211012160734p:plain

エラー文の中にbundle lock --add-platform x86_64-linux実行してね、みたいなのがあるので実行するとlockファイルにx86_64-linuxが追加された(わざわざコマンド打つってことは直書きだとまずい?)

これでOK!

以上、ではでは。

Webエンジニア目指して#50

どうもTitanfall2最高マンです

ふとプレイ動画が回ってきて楽しそうだなあと思って入れてみましたが、ストーリーモードがめちゃくちゃおもしろいですね〜1週6時間くらいなのも気軽に見返しプレイができて◎

さて今回はrailsデバッグについて

pry-railsというgemを使うと、以下のようにactionの途中にbinding.pryを挟むとその時点で処理を一時停止しrails-consoleのように直接rubyを実行できる f:id:misokatsu_sand:20210921203133p:plain

変数の動きなど気になった際はこれで確認するのが良さそう

おわり、ではでは。

Webエンジニア目指して#49

どうも運動不足マンです。 出勤や構内を歩くのってかなり運動になっていたんだなあと感じてます。

さあ毎日やっていることが固定なのでネタが特にありません、技術的な話に参りましょう

rubyの課題は終わらせました。全て一発合格であまりにもさらっといって逆に不安です

というわけでrails編です。progateである程度はやったので思い出し+追加ですね

partial

htmlの共通パーツを作っておいて使い回せる
以下のようなやり方でできるが、viewsディレクトリにsharedフォルダを作りそこにpertialを格納するのが一般らしい

views/shared/_partial.html.erb

<p>partial</p>

views/main.html.erb

<%= render "shared/partial" %>

指定ファイルの.html.erbは省略でOK

sqliteのコマンド

$.tables 作成済テーブルの確認
$.schema テーブル名 テーブルの定義確認
ctrl+z .quitコマンドの代わり

CRUD処理の記述省略

こう書くと対象コントローラーに省略実装できる(actionは手動で記述が必要)

Rails.application.routes.draw do 
      resources :コントローラー名
end

さらに、メソッドでroute指定する際に以下のような例で指定できるようになる

 <%= link_to "ユーザー情報一覧", :users  %>

各アクションによって割り当てられるハッシュが違い、またupdateやdestroyなどのアクションはhttpメソッドを指定する必要があるためその都度確認したい

routing定義の確認

resourcesのように省略記述した際はroutes.rbでは詳細を確認できないため、
$rails routesCUIから確認する

なにやら色々出てくるので見たいところだけ抜粋 f:id:misokatsu_sand:20210907133315p:plain

form_forメソッド

progateではform_tagメソッドで下記のように記述しデータの受け渡し、データベースとのやりとりをしていた

<%= form_tag("/users/#{@user.id}/update",{multipart:true}) do %>
  <p>ユーザー名</p>
  <input name="name" value="<%= @user.name %>">
  <p>e-mail</p>
  <input name="email" value="<%= @user.email %>">
  <p>プロフィール画像</p>
  <input type="file" name="image">
  <p>-</p>
  <input type="submit" value="変更">
<% end %>

form_forを使えば、以下のように書けばその次のようにhtml変換される
(@users = User.all)

<%= form_for @user do |f| %>
  <%= f.text_field :name %>
<% end %>

<input type="text" name="user[name]" id="user_name">

paramsメソッド

今まではparams[:id]のようにform_tagメソッド内のname属性から拾った情報を使っていたが、form_forメソッドの場合は下記のように記述できる

@user = User.new(params.require(:user).permit(:name, :email))

paramsメソッドにはrequireメソッドとpermitメソッドがチェーンでき、
requireで対象テーブルのインスタンスを指定→permitで編集できるキーの指定をする。

これによって指定したオブジェクトでなければエラーを吐くため、意図しないキーの編集を防ぐことができるためストロングパラメータと呼ぶらしい

form_forめっちゃ便利...

created_atなどの時間情報を日本時間に変える

1.config/application.rbを開くとモジュールの中に入ったクラスが1つある
そこに下記の通り書いてある見本がある

# config.time_zone = "Central Time (US & Canada)"

これのコメントアウトを外してconfig.time_zone = 'Tokyo'に書き換える

2.config/initializersディレクトリにtime_formats.rbを作成し、以下のように書く

Time::DATE_FORMATS[:datetime_jp] = '%Y年 %m月%d日'

3.view中の時間を表示するオブジェクトに.to_s(:datetime_jp)をつける

<%= user.updated_at.to_s(:datetime_jp) %>
<%= user.created_at.to_s(:datetime_jp) %>

4.サーバーを再起動する
config/initializerはサーバー起動時に参照されるそう

結果 f:id:misokatsu_sand:20210910112720p:plain

updateメソッド

レコードに対して値の更新をするメソッド
これにもストロングパラメータを渡すのが良いらしい

@user.update(params.require(:user).permit(:name, :email))

data-confirm

link_toメソッドなどの引数にdata: { confirm: "メッセージ" }のように使うとポップアップアラートを表示させられる 下の例のようにdestroy処理などの不可逆処理の警告に使う

<%= link_to "削除", user, method: :delete, data: { confirm: "本当に削除しますか?" } %>

ちなみにこれは参照と同じリンク先になっているが、httpメソッドを指定することでdestroyアクションを呼び出すことになっている

モデルの関連付け(一対多)

railsではアソシエーションというらしい 例えばuserモデルにpostモデルを関連付けるなら、userに対し多数のpostを持つことになり、postに対し多数のuserは紐付かない。その場合は次のように書く

user.rb

class User < ApplicationRecord
  has_many :posts
end

post.rb

class Post < ApplicationRecord
  belongs_to :user
end

これを行うことで、あるuserのpostを全て表示したい場合は以前は以下のように書いていたが

@posts = Post.where(user_id: @user.id)

関連付けによって以下のように書けるようになる

@posts = @user.posts 

postのuserは以下のように書けるようになる

<%= @post.user.name %>

モデルの関連付け(多対多)

多対多の例は、postに対しuserのfavが追加されるパターン

favがあると1つのpostに対してのuserが一意に決まらないため、2つのテーブルだとfav用のカラムが半無限に増えてしまう(このpostにはこのユーザーがfavしました、のようなカラム)

このような多対多の場合はfavテーブルを作って中間テーブルにする。

下記が例

user.rb

class User < ApplicationRecord
  has_many :posts
  has_many :posts, through: fav
end

post.rb

class Post < ApplicationRecord
  belongs_to :user
  has_many :user, through: fav
end

fav.rb

class Fav < ApplicationRecord
  belongs_to :user
  belongs_to :post
end

has_many :favでも書けるが、例のようにthroughを使った書き方をするとpost<=>user間のダイレクトアクセスが可能となる

hidden_field

扱いたいが表示はしたくないパラメータがある場合に使える
下の例の場合は以前やったsession変数でもよさそう

<%= f.hidden_field :user_id, value: @user.id %>

renderメソッドで変数を渡す

以下のようにすると変数smpがtestパーシャルで使えるようになる

<%= render "shared/test", smp: @user %>

バリデーションなどのrailsメッセージを日本語化する

rails-i18nというgemで実装できる。 i18nはInternationalizationの略で、国際化の意味らしい

まずはgemfileに記述しbundle installする

gem 'rails-i18n'

config/application.rbに以下の記述をする

config.i18n.default_locale = :ja

これでエラー文が日本語化される f:id:misokatsu_sand:20210921153216p:plain

このNameやEmailなどのキーを日本語で表示するには、yamlという構造定義ファイルで定義する必要がある

config/localesディレクトリにja.ymlを作成し以下のように書く

ja:
  activerecord:
        models:
          user: ユーザー
        attributes:
          user:
            name: 名前
            email: メールアドレス
            age: 年齢
            introduction: 一言紹介

これでエラー文が日本語になった f:id:misokatsu_sand:20210921165229p:plain

この辺で区切ります。ではでは

rubyで擬似的に発火キーを実装する

rubyであれこれしてるんですが、cui上でenterを押したら処理開始〜のようなものに最適そうなメソッドが見つからず早3日...

ようやくそれっぽいのを編み出しました、自信作です

require 'io/console'でio/consoleライブラリを読み込んでSTDIN.getchを使えるようにする

getchgetsと違い入力中の文字が表示されない+最後に入力された一文字だけ取得される
これとwhileを組み合わせて、Enter(rawモードのため¥r)が入力されるまで何も表示させず入力ループを起こさせる

require 'io/console' #STDIN.getch利用のため

puts "1文字取得"
while (str1 = STDIN.getch) != "\r"
  #Enterの入力受付(キー入力は表示されない)
end

if str1 == "\r"
  p str1
  puts "Enterが入力されました"
end

以上

Webエンジニア目指して#48

どうもご無沙汰マンです。 ポテパンキャンプに入りました。ある程度独学した人間にとっては昔と違って旨味が激減してしまいましたが、当初よりの予定なのでいたしかたなし... 斡旋入社でキャッシュバックがめちゃ魅力的だったんだけどな、前職1年でやめるべきでした

さて未来に目を向けていきましょう、PostgreSQLなるRDBMSを導入しました。 今までSQliteだったので純粋なSQL文以外が微妙に違くてむずがゆい GUIが有料でまあまあ値が張るものしかないので嫌ですね〜

ではRubyの学習で新たに仕入れたものをメモしていきます

グローバル変数

変数にも種類があって、変数名の先頭を$にすると別rbを読み込んだ際に共有されるグローバル変数になる

testA.rb

local = "A"
$global = "A"

require_relative "variableB"

puts "ローカル変数"
puts local
puts "--------------------"
puts "グローバル変数"
puts $global

testB.rb

local = "B"
$global = "B"

実行結果
f:id:misokatsu_sand:20210802171945p:plain
testA.rbにて、$grobalを定義したあとにtestB.rbを読み込み、そこで$grobalの再定義がされるためputs $grobalの結果は"B"になった

クラス変数

@@変数名とすることでクラス内スコープの変数を定義できる
下の例のように継承しても共有できる

class Test
  @@class_name="クラス内定義"

  def set_name(name)
    @instance_name=name
    output()
  end

  def output
    puts "--------"
    puts "Testクラスによるインスタンスメソッド"
    puts "@@class_name=#{@@class_name}"
    puts "@instance_name=#{@instance_name}"
    puts "--------"
  end
end

class CopyTest < Test
  def output
    puts "CopyTestクラスによるインスタンスメソッド"
    puts "@@class_name=#{@@class_name}"
    puts "@instance_name=#{@instance_name}"
  end
end

testA=Test.new
testA.set_name("インスタンスA")

testB=CopyTest.new
testB.set_name("インスタンスB")

実行結果
f:id:misokatsu_sand:20210802182154p:plain
クラス変数の@@を@にしてみたり無くしてみたりしたが、動作しなかった。@@でちゃんとクラス変数として認識してくれるみたい

定数

変数名の頭を大文字にすると定数扱いになり、再定義ができなくなる。

Teisu = "定数"
puts Teisu
Teisu = "変更済定数"
puts Teisu

f:id:misokatsu_sand:20210802182625p:plain

配列の要素を追加する

array.push("")array << ""がある。 pushは複数要素を追加でき、<<は1つしか追加できない。 どちらも配列の末尾に追加される。

fruits1 = ["apple","banana","grape"]
p fruits1
fruits1 << "orange"
p fruits1
fruits2 = ["peach","lemon"]
fruits1.push *fruits2
p fruits1

実行結果 f:id:misokatsu_sand:20210803180145p:plain

並列の要素を削除する

array.delete_at(arrayNo.)で削除ができる

fruits1 = ["apple","banana","grape"]
p fruits1
fruits1.delete_at(0)
p fruits1
p fruits1[0]

実行結果
f:id:misokatsu_sand:20210803184323p:plain
削除した配列番号を参照すると[1]だった要素が表示されることから、nilにはならず左詰めになることがわかる。

ハッシュの要素を削除する

fruits={
  :name => "apple",
  :price => "500"
}

p fruits
p fruits[:name]

fruits.delete(:name)

p fruits
p fruits[:name]

実行結果
f:id:misokatsu_sand:20210804211019p:plain

ループ処理のnext

nextが処理されると現在のループ処理をスキップし次のループ処理へ飛ぶ

for i in 1..10 do
  if i%9==0
    p "9の倍数の出力でbreakによりループ処理を終了します"
    break
    p "出力確認"
  end

  if i%3==0
    p "3の倍数の出力はnextによりスキップされます"
    next
    p "出力確認"
  end

  p i
end

実行結果
f:id:misokatsu_sand:20210805113910p:plain
next及びbreakによりp "出力確認"は処理されない

例外処理

begin内でエラーが発生した際に、処理を終了させずrescure内の処理を実行し処理を継続させられる

begin
  number = 10 + nil
  p number
rescue
  puts $! #エラー文を表示
  puts $@ #エラー発生位置を表示
  p "エラー発生、例外処理を実行します"
end

p "end"

実行結果
f:id:misokatsu_sand:20210805115721p:plain
intにnilを足すことはできないためエラーが発生する。
それを検知しrescue内の処理が実行される。

モジュール

モジュールを定義してクラスへ適用(Mix-in)することができる 共通処理がある場合、同じコードを何回も書くことになるためモジュールでまとめるのがよさそう

module Math
  def add(a, b)
    return a + b
  end
end

class Number
  include Math #MathモジュールをMix-in

  attr_accessor :a , :b

  def initialize(a,b)
    @a = a
    @b = b
    puts "#{@a},#{@b}が生成されました"
  end
end

num = Number.new(6,1)
p num.add(num.a, num.b)

実行結果
f:id:misokatsu_sand:20210806095149p:plain

また、クラス以外でもモジュールは適用できる

module Math
  def add(a, b)
    return a + b
  end
end

num = {a:6, b:1}
num.extend(Math)
p num.add(num[:a], num[:b])

f:id:misokatsu_sand:20210806112157p:plain

ディレクトリ内のファイル名を検索・取得

rubyでファイルを上書きする際に、ファイルが存在するかどうかを確認したい1

Dir.glob("ディレクトリとファイル名(ワイルドカード可)")
これを使えばディレクトリに対してファイル名を検索し、引っかかったファイル名の文字列を配列におさめてくれる

なお、引っかからなかった場合は空の配列emptyになる

例:オブジェクトがemptyかどうかを真偽値で返す.empty?メソッドと合わせてみた

p "csvファイル名を入力してください"
file_name = gets.chomp

search_file = Dir.glob("./#{file_name}.csv")

if search_file.empty?
  p "該当するファイルがありません"
else
  p "以下のファイルが見つかりました"
  p search_file
end

整数の乱数生成

下の例の場合、0,1,2,3をランダムに生成する

rand(3)

トピックの内容が濃くなってきたのでこの辺で区切ります

ではでは。

brew updateでDL先のURLが403を連発する件

mysqlの導入に当たって環境構築で躓いたので備忘録。

terminalでbrew install mysqlを実行すると

curl: (22) The requested URL returned error: 403 Forbidden
Error: Failed to download resource "gettext"
Download failed: https://homebrew.bintray.com/bottles/gettext-0.21.big_sur.bottle.tar.gz
Warning: Bottle installation failed: building from source.

が出る。brew updateでも同様。

どうやら参照gitのリポジトリが古いらしい。

CLTを入れ直すといいらしいとの記事を見つけ実行。

sudo rm -rf /Library/Developer/CommandLineTools
xcode-select --install
sudo xcode-select -r

その後brew updateを実行すると新たなエラー文が。

Error: 
  homebrew-core is a shallow clone.
To `brew update`, first run:
  git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core fetch --unshallow

誘導に従ってgit -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core fetch --unshallowを実行。特にエラーはなく色々と処理が行われた。

その後brew updateを実行したら成功した。

これで無事brew install mysqlによってmysql 8.0.26のインストールが成功した。

以上

Webエンジニア目指して#47

とあるサイトの模写をしてます。得た知見をメモっていきます

文字を縦横軸の中央に配置

display:flex +
align-items:center +
justify-content: center

cssによるグラデーション

border-image: linear-gradient(to right, #fff 0%, #000 100%);

幅や座標に計算値を使う

width: calc(100% - 50px);

before,after疑似要素

参考記事
developer.mozilla.org

flexboxの要素間にスペースを設ける

display: flex +
justify-content: space-between

hover動作などスマホへのレスポンシブ表示時に不要なcssは@mediaでまとめると便利

どちらかというと知見

posituon:absoluteの要素に:hoverは効かない

どうやらそうらしい

cssで矢印を作る

角ボーダーを90度回転させると矢印になる

隣接セレクタにスタイル適用

p+p{margin-top:5px;} 上の例では、p要素が連続する場合にmarginが適用される

文字にグラデーション

background: -webkit-linear-gradient(0deg , #fff, #000);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;

ネガティブマージン

margin:-20px;のようにするとボックスから指定の値だけ要素が飛び出る

flex-boxで並べた要素を並べ替える

対象要素にorder:1;など

flex-boxの末端に要素を配置

align-self: flex-end; 親のalign-itemを無視できる。

一区切りついたのでここまで。ではでは