ActiveRecord::NotNullViolationt

ActiveRecord::NotNullViolationt

...postal_code doesn’t have a default value...

 

今度はこんなエラーが。

つまり"postal_code"がnull(空)で登録されようとしてることでのエラー。

 

原因は

1、カラム名の間違い

2、ストロングパラメーターに入ってない

3、(今回はformオブジェクトだったので)modelファイルにattr_accessor で値を設定してない

4、同じmodelファイルに作ったsaveメソッドにデータを保存する処理が記述されていない

 

と思い確認してみるとずべて問題なかった。

 

ふと思い出し、ターミナルでも確認してみると

Unpermitted parameters: :hoge, :postal-code, :building

問題あった。

 

ここでは本来"postal_code"のはずなのにアンダーバーがハイフンになっていた。

調査の結果、下記のtext_field の名称に誤りがあった。

 

<%= f.text_field 'postal-code', class:"input-default", id:"postal-code", placeholder:"例)123-4567", maxlength:"8" %>

 

ほんと、アンダーバーとハイフンは間違えやすいので気をつけよう。

 

ということでもし

 

ActiveRecord::NotNullViolationt

..~ doesn’t have a default value...

 

のようなエラーが起きたら

1、カラム名の間違い

2、ストロングパラメーターに入ってない

3、(今回はformオブジェクトだったので)modelファイルにattr_accessor で値を設定してない

4、同じmodelファイルに作ったsaveメソッドにデータを保存する処理が記述されていない

 5、ヘルパーメソッド内ののtext_field の値が間違っている

 

と調べていこう。

 

ActiveModel::ForbiddenAttributesError

ActiveModel::ForbiddenAttributesError in PurchasesController#create

ActiveModel::ForbiddenAttributesError

Extracted source (around line #9):
7
8
9
10
11
12
              
def create
@item = Item.find(params[:item_id])
Purchase.create(purchase_params)
User_private.create(user_private_params)
 
# if @purchase.save
 

Rails.root: /Users/tak/projects/furima-32036

調べてみるとストロングパラメーター関連のエラーようだ

このPurchaseモデルは他の二つのモデルのid管理をするためのもので、テーブルの中に入力して保存するパラメーターはない。

だからストロングパラメーターでpermit するものがなかったので記述しなかった。

 

params.merge(user_id: current_user.id, item_id: @item.id)


 これでエラーが起きてしまったので、色々考えた結果何もなくてもpermit の記述は必要らしく以下のようにするとエラーがなくなった。

 

params.permit().merge(user_id: current_user.id, item_id: @item.id)
 

 


 次から次へとエラーの嵐でなかなか進まない。

けど負けない!ということで引き続き頑張る。

 

メソッド内の処理をまとめる

下記のようなRailsの記述。

 

@tweet = Tweet.find(params[:id])

が何度も出ていてなんとも Dry じゃない。

 

before_actionを使ってまとめられるのでまとめていく。

 

class TweetController < ApplicationController

def show
@tweet = Tweet.find(params[:id])
end

def edit
@tweet = Tweet.find(params[:id])
redirect_to root_path unless current_user.id == @tweet.user.id
end

def update
@tweet = Tweet.find(params[:id])
if @tweet.update(tweet_params)
redirect_to tweet_path(@tweet.id)
else
render :edit
end
end

def destroy
@tweet = Tweet.find(params[:id])
if current_user.id == @tweet.user.id
if @tweet.destroy
redirect_to root_path
else
render :show
end
else
redirect_to root_path
end
end

private

def tweet_params
params.require(:tweet).permit(:image, :name, :text, :detail, :price).merge(user_id: current_user.id)
end
end

 

@tweet = Tweet.find(params[:id]) をまとめていく。

まずは @tweet = Tweet.find(params[:id]) をメソッドとして定義する。

それを before_action で呼び込むと黄色い記述のようになる。

 

 

class TweetController < ApplicationController
before_action :set_tweet, only: [:show, :edit, :update, :destroy]

def show
end

def edit
redirect_to root_path unless current_user.id == @tweet.user.id
end

def update
if @tweet.update(tweet_params)
redirect_to tweet_path(@tweet.id)
else
render :edit
end
end

def destroy
if current_user.id == @tweet.user.id
if @tweet.destroy
redirect_to root_path
else
render :show
end
else
redirect_to root_path
end
end

private

def set_tweet
@tweet = Tweet.find(params[:id])
end
end

 

さらに青い記述の

redirect_to root_path unless current_user.id == @tweet.user.id 

if current_user.id == @tweet.user.id

else
redirect_to root_path
end

は同じ内容なのでこれもまとめられる。

黄色の記述と同じように新たにメソッドを定義してbefore_actionを使うと…

 

class TweetController < ApplicationController
before_action :set_tweet, only: [:show, :edit, :update, :destroy]
before_action :correct_user?, only: [:edit, :destroy]


def show
end

def edit
end

def update
if @tweet.update(tweet_params)
redirect_to tweet_path(@tweet.id)
else
render :edit
end
end

def destroy
if @tweet.destroy
redirect_to root_path
else
render :show
end
end

private

def set_tweet
@tweet = Tweet.find(params[:id])
end

def correct_user?
redirect_to root_path unless current_user.id == @tweet.user.id
end
end

 

 だいぶすっきりしたのではないだろうか。

というところで今日はここまで。

 

明日も頑張る。

 

 

 

編集画面で情報を変更すると全てのレコードが変更される謎現象が起きた

 

 写真を投稿できるアプリケーションについて学んでいるとき。

その投稿した写真の詳細を編集する詳細ページを実装していたのだが、なぜか一つの写真のデータを変更するとそのテーブルの全てのカラムが編集したデータと同じになってしまった。

User_id から写真から何から何まで…

 

一体何が原因なんだと考えてみた。

・そのフォームのform_with のパス

・コントローラーのid 

・まさかfile_field の記述?

 

そしてコントローラーの

redirect_to item_path(currentuser.id)

なんでcurrent_user?? 

編集して更新したらその写真データの詳細画面に戻るからitem.id が必要だろう、と思い @item.id に変更すると機能が正常に戻り、編集して更新するとその更新したレコードだけ変更されるようになった。

 

def update
@item = Item.find(params[:id])
if @item.update(item_params)
redirect_to item_path(current_user.id)
else
render :edit
end
end

↓ これで修正された

 

def update
@item = Item.find(params[:id])
if @item.update(item_params)
redirect_to item_path(@item.id)
else
render :edit
end
end

 

 しかしながら、current_user.id が原因であるならそのcurrent_user.id と同じ item.id の詳細ページに飛ぶはずだと思ったが。

 

ターミナルをみてみると、Update されたあと、さらにごちゃごちゃモデムがロードされて勝手に色々と変わっていた。

 

原因を探ろうと思ったが、SQLに関しては不勉強でその場で解読出来なかったのと、その時に出てきた処理文を残しておかなかったため、結局原因不明になってしまった。

 

データベースについてしっかり学ばなければと決意した1日だった。

 

 

 

 

SyntaxError Invalid char `\x08' in expression

SyntaxError in ItemsController#index

Invalid char `\x08' in expression  

{ id: 7, mahjong: 'チートイツ' },
{ id: 8, mahjong: '一気通貫' },
{ id: 9, mahjong: 'トイトイ' },
{ id: 10, mahjong: '小三元' }
 
 
 

今回はこちらのエラー。

Invalid char `\x08' in expression  

構文エラーということで、上の赤い部分がエラーとなっていた。

チェックしていくと半角英数記号スペース問題なし。

え?と思い、念のためルーティングやアソシエーションに問題があるのかと確認するも問題なし。

手詰まって ”Invalid char `\x08' in expression" で検索してみると、こちらのサイトで原因が判明。

 

https://tattaka-s.hatenablog.com/entry/2019/07/06/153703 

 

どうやら目に見えないスペースが出来てしまうバグ?みたいなものらしい。

実際、{ id: 9, mahjong: 'トイトイ' }, の }, 

この波括弧とカンマの間に見た目のスペースはないはずなのに空スペースが一つあった。

それを消すとエラー解消できたけれど、見た目にわからないエラーがあるのか、とちょっと戦慄。

本当に情報サイトには感謝。

 

今回は見た目にわからないスペースだったので手間取ってしまったが、次回は負けない。

VSCodeだと"Zenkaku"という全角スペースには色をつけてくれる拡張パックがあるので

今回のパターンでは役に立たないけど、入れてない人は入れるべし。

 

さて、また明日もがんばろう。

 

 

 

正規表現によるパスワードのバリデーションについて

正規表現、難しい。

 

現在、railsのユーザー登録時のバリデーションで苦戦中。

rails は devise があるのだけれどそのままではパスワードの安全性はないに等しいのでせめてもう少しバリデーションを付け足したい。

 

ということでこちら。

validates :password, format: { with: /\A(?=.*?[a-z])(?=.*?\d)[a-z\d]{8,}+\z/i }

 

これはざっくり言うとパスワードが英数混合で8文字以上で設定されているかチェックする記述。

8文字未満やそれ以外の文字だと登録できないようにしている。

 

/\A(?=.*?[a-z])(?=.*?\d)[a-z\d]{8,}+\z/i

そしてこの部分。何を書いてるのか分解してみる。

 

① "/ "正規表現 "/

この2つのピンクのスラッシュ。

正規表現は二つのスラッシュを囲むことで効果を発揮する宣言みたいなもの?だから、必ずつける。

 

② \A

これは文字列の最初にマッチする。

つまりパスワードの最初からチェックするぞと言うこと。

 

③(?=.*?[a-z])

これはさらに分解する。

 ■ (? = 〇〇 )

 これは先読みもしくは look-ahead といわれ、〇〇の文字列の直前の位置を指している。

 

 

 ■ . 

 このドットは改行を除く任意の1文字である。

 

 ■ *?

 このアスタリスクと赤ハテナは最小量指定子という難しい名前がついている。

これは具体例を見た方が早いので下記を見てみる。

irb(main):012:0> word = "aassddffaassddff"
=> "aassddffaassddff"
irb(main):013:0> word.match(/a.*s/)
=> #<MatchData "aassddffaass">
irb(main):014:0> word.match(/a.*?s/)
=> #<MatchData "aas">
irb(main):015:0>

 まず word = "aassddffaassddff" を定義する。

次に /a.*s/ という正規表現で文字をマッチさせると"aassddffaass" が戻ってくる。

まず a.*s は始まりの文字が a で終わりは s の文字列を指し、さらに a と s の間には .*があるため a〇〇sという文字列をマッチさせる記述となる。

( * はこれだけだと直前の文字を0回以上繰り返すという正規表現。つまり .* だと任意の文字の繰り返しとなる)

つまり今回マッチするのは、

aas, aass, aassddffaas, aassddffaass 

となる。

a.*s のようにするとマッチする最大の文字列を戻す。(これは最大量指定子と呼ばれている)

 

さて、/a.*?s/ はどうかというと"aas"が戻ってくる。

今回はマッチする最小の文字が戻されている。

* だけだとマッチする最大の文字列を戻すけれど、 *? だとマッチする最小の文字列を戻すという意味になる。

 

■ [a-z]

そもそも [ ] はこの角括弧の中の文字のいずれか一つを指すというもので、今回は小文字のアルファベッド a から z までのいずれかの文字を意味している。

 

ということでまず .*?[a-z] の意味は任意の文字0回以上と a ~ z の文字の組み合わせということになる。(例えば、任意の文字は0回も該当するので a だけでも成立する)

結果、(?=.*?[a-z]) は任意の文字0回以上と a ~ z の文字の組み合わせた文字列の直前の空白を指すことになる。(すなわちこの場合はa ~ zのアルファベッドが含まれていないとダメと言うことになる)

 

④ (?=.*?\d)

まず /d は数字を指している。

あとは③と同じで .*?\d は任意の文字0回以上と数字の組み合わせとなる。

つまり(?=.*?\d)は任意の文字0回以上と数字の組み合わせた文字列の直前の空白を差すこととなる。

 

⑤ [a-z\d]

これは角括弧の中のa~zまたは数字のいずれか一つを意味している。

 

 {8,}

これは本来の形は { x, y }という形で、この直前の文字が少なくても x 回、多くても y 回出現するとマッチすると言う意味になる。

(例えば、[a-z]{5,10} は小文字アルファベッドa-zが5回以上10回以下でマッチすると言うことなので、skduf, audshgg, jsdkirotuq, 374ghjuijsa31,kseuf1923845 にはマッチするが、asd, TRddTU, er567865, 1111111111111111 はマッチしない)

そして{x,} の形になるとこの直前の文字が少なくても x 回以上出現すればマッチすると言うことになるので、{8,} は直前の文字が少なくても 8回以上出現すればマッチするということになる。

 

⑦ +

直前の文字が1回以上繰り返すものにマッチするいう意味。

 

⑧ /z

これは文字列の最後にマッチする。

つまりパスワードの最後までチェックするぞと言うこと。

 

⑨ i 

最後のこの i はオプションで大文字・小文字を区別しないというものなので[a-z]も記述もこのオプションで大文字小文字アルファベットのいずれかの一文字となる。

 

 

 

/\A(?=.*?[a-z])(?=.*?\d)[a-z\d]{8,}+\z/i

①〜⑨をつなげて考えてみると、

 

・文字列の最初から始めるよ。(\A)

 

・その最初の文字列は任意の文字0回以上とa ~ z の文字一つ、もしくは数字一つの文字列の直前の位置からスタートした文字列だよ((?=.*?[a-z])(?=.*?\d))

 

・a-z、もしくは数字がいずれか一つ([a-z\d])

・直前の文字(a-z、もしくは数字がいずれか一つ)の繰り返し(+)出現して

 

・全部で8文字以上の文字列が出現し、(\z)

 

・最後の文字まa-z、もしくは数字がいずれか一つだよ。

 

・そして大文字小文字の区別はないよ。

 

 ⇩

 

 

 

文字列の最初は任意の文字0回以上とa ~ z の文字一つ、もしくは数字一つの文字列の直前の位置からスタートした文字列で、a-z もしくは数字がいずれか一つと直前の文字(a-z、もしくは数字がいずれか一つ)の繰り返しが8回最後まで出現すると({8,}+\z)マッチし、大文字小文字は区別しない。

 

 

(スラッシュで正規表現だと宣言し、

(?=.*?[a-z])(?=.*?\d)は始まりの位置を、

\Aはその位置からスタートした時の最初の文字からマッチしていくと言う宣言を、

[a-z\d]で文字は英数どちらかを指定し、

{8,}+\z でそれが8回以上最後まで繰り返されるとマッチする。

i そして大文字小文字は区別しないというオプションがついている)

 

 

他にも大文字小文字区別をつけるなら、i オプションを消して

/\A(?=.*?[a-zA-Z])(?=.*?\d)[a-zA-Z\d]{8,}+\z/

 

英小文字大文字数字をそれぞれ1種類以上含む5文字以上とするなら

/\A(?=.*?[a-z])(?=.*?[A-Z])(?=.*?\d)[a-zA-Z\d]{5,}+\z/

 

 記号を加えたいならこちらのページを参照させていただくと良いでしょう。

https://qiita.com/mpyw/items/886218e7b418dfed254b

 

また他にも下記を参考にさせていただきました。

・基本的にRuby 2.7.0 リファレンスマニュアル

・いろいろ検証するのに使わせていただいたこちらのページ

https://rubular.com/

・先読みに関しては主にこちらを

https://techracho.bpsinc.jp/hachi8833/2018_11_20/63564

・最小量指定子の理解はこちらをhttps://www.javadrive.jp/perl/regex/repeat/index8.html

 

もし見ていただいた方がいたら読みにくくてごめんなさい。

 

さて、また頑張ろう。

シンボル

まず、シンボルについて

Ruby 2.7.0 リファレンスマニュアル を見てみると

 

Rubyの内部実装では、メソッド名や変数名、定数名、クラス名などの`名前'を整数で管理しています。これは名前を直接文字列として処理するよりも速度面で有利だからです。そしてその整数をRubyのコード上で表現したものがシンボルです。

シンボルは、ソース上では文字列のように見え、内部では整数として扱われる、両者を仲立ちするような存在です。

名前を管理するという役割上、シンボルと文字列は一対一に対応します。また、文字列と違い、immutable (変更不可)であり、同値ならば必ず同一です。 

 

Ruby 2.7.0 リファレンスマニュアルより

https://docs.ruby-lang.org/ja/latest/class/Symbol.html

 

 となっている。

 

irbで過去のようにしてみると下記のようになる

irb(main):001:0> :coron.object_id == :coron.object_id
=> true
irb(main):002:0> "coron".object_id == "coron".object_id
=> false

 

シンボルは『同値ならば同一』がわかる。

:coron は何度記述しても全部同じ。

 

逆にダブルクォテーションで囲んだ文字列は全く同じ記述でも中身が違うことになる。

"coron" は何度記述しても全てが異なるものということになる。

 

じゃあ、どんなときに分ければいいの?と疑問に思うが正直よくわからない。

 

ただ、Rubyのホームページの中の記述を見てみると

『シンボルを使うか文字列を使うかで迷ったなら、 ハッシュのキーのようにオブジェクトを識別したいのか、 それとも前述の”george”などのようにコンテンツを表したいのかを、 選択の指針にしてください。』 Rubyホームページより(https://www.ruby-lang.org/ja/documentation/ruby-from-other-languages/

ということらしい。

 

 

結局わかったことはシンボルは『同値ならば同一』だということ。

正直調べるほど、キーワード引数なども出てきてピンとこなくなりそうなので今回はここまで。

 

ここに関してはもっとわかるようになってからまた文字に起こしてみようと思う。