20210908のRailsに関する記事は24件です。

railsチュートリアル第4章 クラス継承

クラスについて学ぶとき、superclassメソッドを使ってクラス階層を調べてみるとよくわかります。 >> s = String.new("foobar") => "foobar" >> s.class # 変数sのクラスを調べる => String >> s.class.superclass # Stringクラスの親クラスを調べる => Object >> s.class.superclass.superclass # Ruby 1.9からBasicObjectが導入 => BasicObject >> s.class.superclass.superclass.superclass => nil StringクラスのスーパークラスはObjectクラス ObjectクラスのスーパークラスはBasicObjectクラス BasicObjectクラスはスーパークラスを持たないことがわかる。 この図式は、すべての Ruby のオブジェクトにおいて成り立ちます クラス階層をたどっていくと、 Rubyにおけるすべてのクラスは最終的にスーパークラスを持たないBasicObjectクラスを継承する。 "Rubyではあらゆるものがオブジェクトである" ということの技術的な意味になる。 BasicObject   ↑ Object   ↑ String >> class Word >> def palindrome?(string) >> string == string.reverse >> end >> end => :palindrome? >> w = Word.new # Wordオブジェクトを作成する => #<Word:0x22d0b20> >> w.palindrome?("foobar") => false >> w.palindrome?("level") => true 少し不自然に思えるならば、勘が鋭い 文字列を引数に取るメソッドを作るためだけに、わざわざ新しいクラスを作るのは変 Wordクラスは Stringクラスを継承するのが自然 コンソールでWordクラスを定義する。 >> class Word < String # WordクラスはStringクラスを継承する >> # 文字列が回文であればtrueを返す >> def palindrome? >> self == self.reverse # selfは文字列自身を表します >> end >> end => :palindrome? 継承のためのRubyの Word < String 記法 >> s = Word.new("level") # 新しいWordを作成し、"level" で初期化する => "level" >> s.palindrome? # Wordが回文かどうかを調べるメソッド => true >> s.length # WordはStringで扱える全てのメソッドを継承している => 5 WordクラスはStringクラスを継承しているので、コンソールを使ってクラス階層 >> s.class => Word >> s.class.superclass => String >> s.class.superclass.superclass => Object 階層  BasicObject  ↑ Object ↑ String ↑ Word となっている。 Wordクラスの中から自分自身が持つ単語にアクセスすることで行なっていることにご注目 Wordクラスの中では、selfはオブジェクト自身を指します。 self == self.reverse self == reverse 演習 1.Range,Hash,Symbolクラスの継承階層を調べろ。 >> s = Range.new(1, 5) => 1..5 >> s.class => Range >> s.class.superclass => Object >> s.class.superclass.superclass => BasicObject >> s.class.superclass.superclass.superclass => nil >> s = {"a" => "b", "c" => "d", "e" => "f" } => {"a"=>"b", "c"=>"d", "e"=>"f"} >> s.class => Hash >> s.class.superclass => Object >> s.class.superclass.superclass => BasicObject >> s.class.superclass.superclass.superclass => nil >> s = :symbol => :symbol >> s.class => Symbol >> s.class.superclass => Object >> s.class.superclass.superclass => BasicObject >> s.class.superclass.superclass.superclass => nil 全てBasicObjectクラスに繋がっている。 2.self.reverseのselfを省略し、reverseと書いて動くことを確認しろ。 >> class Word < String >> def palindrome? >> self == reverse >> end >> end => :palindrome? >> s = Word.new("level") => "level" >> s.palindrome? => true
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】いいね順・投稿数順など ◯◯順の考え方・方法

はじめに ランキング順で表示する際の考え方についてつまづいてしまったので、 考え方を残しておきます。 前提 投稿、いいね、タグ それぞれの機能は作成済みとします。  方法 投稿に紐づくいいね順 まず、posts テーブルと likesテーブルには、以下のようなデータが入っているとします。 まずやることは、2つのテーブルを合体させます。 likesテーブルのpost_idとpostsテーブルのidは、同じになるはずです。 "postに紐づくいいねを、多い順に並べる" ↓ "likesテーブルのpost_idの数を集計し、多い順に並べる" と言うことになります。 likesテーブルにはそもそもいいねをもらったpostのidが存在します。 likesのidは、いいねするたびに増えていきます。 post_idはlikesテーブルの中では重複するものであり、ひとつの投稿に着目すると、 その投稿がいいねされるたびにlikesテーブルの特定のpost_idは増えていきます。 だから、likesテーブルに存在するpost_idを数えれば、どのpostがどのくらいいいねをもらっているかがわかり、比較できるのです。 上記記事を参考に、 @posts = Post.find(Like.group(:post_id).order('count(post_id) desc').limit(3).pluck(:post_id)) と書くことができます。 #likeモデルのpost_idカラムを指定してまとめる Post.find(Like.group(:post_id) #post_idの多い順に並べる .order('count(post_id) desc') #並び替えたものの上位3つのpost_idを抽出する .limit(3).pluck(:post_id)) タグに紐づく投稿順 こちらも、いいねと同じ考え方でいけます。 まず、postとtagを結ぶpost_tagモデルが存在します。 今回行いたいのは、postに紐づくタグの中で、より多くのpostを保有するタグを順番に並べたいです。 簡単に言うと、よく使われるタグを順番に並べたいです。 post_tagテーブルと、tagテーブルは以下の通りです。 これを合体します。 今回は、post_tagテーブルのidと、tagsテーブルのtag_idが一致するはずです。 tagに紐づいているpostの数を比較したいので、 今回はpost_tagsテーブルの、tag_idの数を集計して、多い順に並べれば良いです。 postとtagのセットの情報が、post_tagsテーブルに保管されるので、 post_tagsテーブルのtag_idで頻出のタグは、より多くのpostに紐づいていると言うことです。 実際には、 @tags = Tag.find(PostTag.group(:tag_id).order('count(tag_id) desc').limit(10).pluck(:tag_id)) と書くことができます。 #Postモデルのtag_idカラムを指定してまとめる Tag.find(PostTag.group(:tag_id) #tag_idを数え数の多い順に並び替える .order('count(tag_id) desc') #並び替えたものの上位10個のtag_idを抽出する .limit(10).pluck(:tag_id)) いいねもタグも、最終的に複数のidをpluckで取り出しているので、 @posts, @tagsなどのインスタンス変数に格納し、ビューでeach文を使用してデータを一覧表示すればOKです。 groupメソッドについても確認する必要がありました。 しっかり理解ができれば、色々簡単に応用ができます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】renderの基本形 / 省略形 / collection / local_assign.fetch

概要 今回はrenderに関して軽くまとめておく。(メモ) 基礎的なことだけど、見たときなんだ??となったので。 renderに関して 基本形 基本となる形は以下。 <%= render partial: "card", locals: {book: @book} %> 省略形 PF制作した際には下記を使用してた。 これは基本ではなく、省略形のパターンと知りました。 <%= render partial: "card", book: @book %> ちなみに、省略ももっとあるらしい。 <%= render @books %> 実務で基本形を使用していた理由は、 locals: {} にしておくと、RubyMineの補完やコードジャンプがより正確になるというメリットのため。 RubyMineは便利です。笑 collection collectionを使うことで each文を使用せずに繰り返しの処理ができるみたい。 <%= render partial: "card", collection: @books => 上記はつまり下記に書き換えれる。 <% @books.each do |book| %> <%= render partial: 'card', locals: {book: book} %> <% end %> このようにしてeach文をわざわざ書かなくてもeach文を走らせることができる。 local_assigns.fetch local_assigns.fetchを使用することによって特定の状況に限ってパーシャルに渡すことが可能です。 falseである時は表示がされない状況です。 local_assigns.fetch(:なんでもいい, false(or true)) 以下の前提とした場合で説明します。 books/index.html.erb users/index.html.erb _card.html.erbを 表示したい 表示したくない レンダリングされるファイル先でlocal_assigns.fetchをfalseに設定しておきます。 _card.html.erb <% if local_assigns.fetch(:show_course, false) %> <%= render partial: "book_card", collection: books%> <% end %> 表示したいbooks/index.html.erbファイルで、 _card.html.erbファイルをレンダリングする際にlocals: {show_course: true}でshow_couserをtureにします。 books/index.html.erb <%= render partial: "card", collection: @books, locals: {show_course: true} %> その逆で。表示したくないusers/index.html.erbなら、locals: {show_course: true}は入りません。 users/index.html.erb <%= render partial: "card", collection: @books %> ※単純にlocalsに { show_course: false }とかでもいけると思います。 これに関しては、文献が全くないので先輩情報。ありがたや。 参考文献
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】アソシエーションでnilを許可する

はじめに SNSサイトを作成中、投稿にキャンプサイト(未入力or1件まで)を紐付けようと思い、以下の通りにしたところ、 キャンプサイトが未入力時に、バリデーションで弾かれ、投稿ができなかっため、対処法を残しておきます。 前提 Postモデル user_id image_id camp_site_id(FK) body CampSiteモデル site_name やりたいこと キャンプサイトの登録は任意で、Postを投稿したい やったこと camp_site.rb has_many :posts post.rb belongs_to :camp_site, optional: true "optional: true" がなかったために投稿時のcamp_site_idのnilが許可されず エラーが表示されていました。 belongs_toが成り立たなくなるため、通常では、nilは許可されないそうです。 そのため、"optional: true"を記載してあげて、nilを許可する必要があります。 終わりに 深く理解していなかったために、初歩的な段階でつまづいてしまいました。 1から復習すること、些細なことでも調べ直すことが大切だと痛感しました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

railsチュートリアル 第4章 rubyにおけるクラス

Rubyにおけるクラス Rubyではあらゆるものがオブジェクト この節では実際にオブジェクトをいくつか定義してみる。 メソッドをまとめるのにクラスを使っています クラスからインスタンスが生成されることでオブジェクトが作成 コンストラクタ これまで示した多くの例の中でも、クラスを使ってオブジェクトのインスタンスを作成してきたのです。 例えばダブルクォートを使って文字列のインスタンスを作成しました。 これは文字列のオブジェクトを暗黙で作成するリテラルコンストラクタです。 >> s = "foobar" # ダブルクォートは実は文字列のコンストラクタ => "foobar" >> s.class => String 文字列がclassメソッドに応答しており、その文字列が所属するクラスを単に返している。 明示的に同等の名前付きコンストラクタを使う。 名前付きコンストラクタは、クラス名に対してnewメソッドを呼び出す。 >> s = String.new("foobar") # 文字列の名前付きコンストラクタ => "foobar" >> s.class => String >> s == "foobar" => true リテラルコンストラクタと等価ですが、動作の内容が明確に示されています 配列でも、文字列と同様にインスタンスを生成できます。 >> a = Array.new([1, 3, 2]) => [1, 3, 2] ハッシュの場合は若干異なる。 Array.new は配列の初期値を引数に取りますが、 Hash.new はハッシュのデフォルト 値を引数に取る。 これは、キーが存在しない場合のデフォルト値です。 >> h = Hash.new => {} >> h[:foo] # 存在しないキー (:foo) の値にアクセスしてみる => nil >> h = Hash.new(0) # 存在しないキーのデフォルト値をnilから0にする => {} >> h[:foo] => 0 メソッドがクラス自身に対して呼び出されるとき、このメソッドをクラスメソッド クラスのnewメソッドを呼び出した結果は、そのクラスのオブジェクトであり、これはクラスのインスタンスとも呼ぶ。 lengthのように、インスタンスに対して呼び出すメソッドはインスタンスメソッドと呼ぶ。 演習 1.リテラルコンストラクタとは? 隠れてインスタンスを作成 newメソッドを使わずインスタンスを作成することかな。 2.Rangeクラスとnewメソッドを使って、1から10の範囲オブジェクトを作れ。 >> Range.new(1,10) => 1..10 3.比較演算子==を使って、上記2つの課題で作ったそれぞれのオブジェクトが同じであることを確認しろ。 a = Range.new(1,10) => 1..10 >> b = 1..10 => 1..10 >> a == b => true
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

railsチュートリアル第4章 ハッシュとシンボル

ハッシュとシンボル ハッシュは本質的には配列と同じ インデックスとして整数値以外のものも使える点が配列と異なる >> user = {} # {}は空のハッシュ => {} >> user["first_name"] = "Michael" # キーが "first_name" で値が "Michael" => "Michael" >> user["last_name"] = "Hartl" # キーが "last_name" で値が "Hartl" => "Hartl" >> user["first_name"] # 要素へのアクセスは配列の場合と似ている => "Michael" >> user # ハッシュのリテラル表記 => {"last_name"=>"Hartl", "first_name"=>"Michael"} ハッシュは、キーと値のペアを波カッコで囲んで表記 ハッシュの波カッコは、ブロックの波カッコとは違う。 ハッシュは配列と似ているが、重要な違いとして、ハッシュでは要素の「並び順」が保証されない もし要素の順序が重要である場合は、配列を使う必要があり >> user = { "first_name" => "Michael", "last_name" => "Hartl" } => {"last_name"=>"Hartl", "first_name"=>"Michael"} キーと値をハッシュロケットと呼ばれる=> によってリテラル表現するほうが簡単 Rubyにおける慣習として、ハッシュの最初と最後に空白を追加 ハッシュのキーとして文字列を使っていましたが、Railsでは文字列よりもシンボルを使う方が普通 シンボルは文字列と似ていますが、クォートで囲む代わりにコロンが前に置かれている点 >> "name".split('') => ["n", "a", "m", "e"] >> :name.split('') NoMethodError: undefined method `split' for :name:Symbol >> "foobar".reverse => "raboof" >> :foobar.reverse NoMethodError: undefined method `reverse' for :foobar:Symbol >> :foo-bar NameError: undefined local variable or method `bar' for main:Object >> :2foo SyntaxError >> user = { :name => "Michael Hartl", :email => "michael@example.com" } => {:name=>"Michael Hartl", :email=>"michael@example.com"} >> user[:name] # :name に対応する値にアクセスする => "Michael Hartl" >> user[:password] # 未定義のキーに対応する値にアクセスする => nil 未定義のハッシュ値は単純にnilである >> h1 = { :name => "Michael Hartl", :email => "michael@example.com" } => {:name=>"Michael Hartl", :email=>"michael@example.com"} >> h2 = { name: "Michael Hartl", email: "michael@example.com" } => {:name=>"Michael Hartl", :email=>"michael@example.com"} >> h1 == h2 => true シンボルとハッシュロケットの組み合わせを、次のようにキーの名前の(前ではなく)後にコロンを置き、その後に値が続くように置き換えたもの { name: "Michael Hartl", email: "michael@example.com" } { :name => "Michael Hartl" }と{ name: "Michael Hartl" }は同じ。 ハッシュの中のハッシュ >> params = {} # 'params' というハッシュを定義する ('parameters' の略)。 => {} >> params[:user] = { name: "Michael Hartl", email: "mhartl@example.com" } => {:name=>"Michael Hartl", :email=>"mhartl@example.com"} >> params => {:user=>{:name=>"Michael Hartl", :email=>"mhartl@example.com"}} >> params[:user][:email] => "mhartl@example.com" Railsでは、このようなハッシュのハッシュ(またはネストされたハッシュ)が大量 >> flash = { success: "It worked!", danger: "It failed." } => {:success=>"It worked!", :danger=>"It failed."} >> flash.each do |key, value| ?> puts "Key #{key.inspect} has value #{value.inspect}" >> end Key :success has value "It worked!" Key :danger has value "It failed." eachメソッドでは、ブロックの変数は1つだけですが、ハッシュのeachメソッドでは、ブロックの変数はキーと値の2つになっていることに注意 >> puts (1..5).to_a # 配列を文字列として出力 1 2 3 4 5 >> puts (1..5).to_a.inspect # 配列のリテラルを出力 [1, 2, 3, 4, 5] >> puts :name, :name.inspect name :name >> puts "It worked!", "It worked!".inspect It worked! "It worked!" オブジェクトを表示するためにinspectを使うことは非常によくあることなので、 pメソッドというショートカット >> p :name # 'puts :name.inspect' と同じ :name 演習 1.ハッシュを作れ >> a = { 'one' => 'uno', 'two' => 'dos', 'three' => 'tres' } => {"one"=>"uno", "two"=>"dos", "three"=>"tres"} >> a.each do |key,value| ?> puts "#{key}のスペイン語は#{value}" >> end oneのスペイン語はuno twoのスペイン語はdos threeのスペイン語はtr 2.3つのハッシュを作成,キーを追加し、適当な値,ハッシュのハッシュの作成,ハッシュのハッシュを調べていき、正しい値を表示しろ >> person1 = { :first => 'rinngo', :last => 'gorira' } => {:first=>"rinngo", :last=>"gorira"} >> person2 = { :first => 'rappa', :last => 'panntu' } => {:first=>"rappa", :last=>"panntu"} >> person3 = { :first => 'tumiki', :last => 'kitutuki' } => {:first=>"tumiki", :last=>"kitutuki"} >> params = {} => {} >> params[:father] = person1 => {:first=>"rinngo", :last=>"gorira"} >> params[:mother] = person2 => {:first=>"rappa", :last=>"panntu"} >> params[:child] = person3 => {:first=>"tumiki", :last=>"kitutuki"} >> params[:father][:first] => "rinngo" 3.ハッシュを定義しろ >> user = {} => {} >> user[:name] = "irohanihoheto" => "irohanihoheto" >> user[:email] = "tirinuruwo.com" => "tirinuruwo.com" >> user[:password_digest] = ("a".."z").to_a.shuffle[0..15].join => "zpgxqoifcmsrnayb" >> user => {:name=>"irohanihoheto", :email=>"tirinuruwo.com", :password_digest=>"zpgxqoifcmsrnayb"} ("a".."z")..to_a.shuffle[0..15].join でランダムな十六文字の文字列を作成できた。 4.merge メソッドの意味、{ "a" => 100, "b" => 200 }.merge({ "b" => 300 }) がどういう結果を示すか? mergeは複数のハッシュを結合させるメソッドらしい。 このことから { "a" => 100, "b" => 300 }という結果が返ってくると予測する >> { "a" => 100, "b" => 200 }.merge({ "b" => 300 }) => {"a"=>100, "b"=>300} 予測と合ってた。よかった。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】投稿者のみに削除ボタン表示(メモ)

環境 Rails: 6.1.3 ruby: 3.0.0 mac: OS 前提 投稿機能、ログイン機能実装済み 方法 ビューに記述 削除ボタン設置前に、投稿者本人か確認するため、if logged_in? && current_user.id == post.user_idを記述。 今ログインしているユーザーidと投稿idが一致した場合にのみ削除ボタンが表示されます。 app/views/posts/index/html.erb <% if logged_in? && current_user.id == post.user_id %> <%= link_to '削除', post_path(post.id),method: :delete, data: { confirm: '本当にいいですか?' } %> <% end %> こちらの場合も同様の手順で投稿者のみに削除ボタンが表示されます。 app/views/comments/_comment.html.erb <% if logged_in? && current_user.id == comment.user_id %> <%= link_to '削除', [comment.post, comment],method: :delete,data: { confirm: "本当に削除してもよろしいですか?" } %> <% end %> 以上になります。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails] 条件分岐について

初めに この記事の対象者 ・条件分岐に混乱しているヒト、復習がしたいヒト 環境 ・Macbook Air (Retina, 13-inch,2019) ・プロセッサ 1.6GHz デュアルコアIntel Core i5 ・メモリ 8GB 2133 Mhz LPDDR3 ・MacOS Big Sur バージョン 11.5.2 記事の目次 1)どういうときに使うのか 2)例 3)最後に どういうときに使うのか 条件を設定してその条件を満たしていないか、満たしているかで処理を決めたいときにつかう。 (遊園地でジェットコースターに乗るときを例にとってイメージしてみよう) 身長が160cmのヒトが遊園地のジェットコースターに乗るとき。このジェットコースターは乗車するのに身長が 155cm以上でないと乗れないです。 (条件分岐のイメージ) A(身長):160cm 1)条件: A<155  → 処理:乗車不可 2)条件: A>155 →  処理:乗車できる 条件分岐の方法 使い方 if 条件式1   処理 **(条件に満たしたときの処理を書くところ)** elseif 条件式2   処理 **(条件1に当てはまらず、条件2に満たしたときの処理を書くところ)** else   処理 **(上の条件のどれにも当てはまらないときの処理を書くところ)** end (例:上の遊園地を例に条件分岐を書いてみよう!) friend = {} ←名前と身長を保存するために配置 puts "お友達の名前は?" friend[:name] = gets.chomp ←入力した文字を名前として保存する puts "お友達の身長は?" friend[:height] = gets.to_i ←入力した数字を身長として保存する if friend[:height] >= 155 puts "#{friend[:name]}さんは乗車できます" else puts "#{friend[:name]}さんは乗車できません!" end 最後に ・演算子が苦手なので、壁にぶつかったときにうまくここを使ってアウトプットしなきゃなと思った。。 ・ここまで読んでくださってありがとうございます!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails参考にした記事一覧

フォローフォロワー機能 【Ruby on Rails】フォロー・フォロワー機能の実装 Railsでフォロー機能を作る方法 [Rails]Ajaxを用いて非同期でフォロー機能の実装 【Rails】Ajaxを用いた非同期フォロー機能の実装 日本語化 deviseを日本語化する deviseをi18nを使って日本語化する [初学者]Railsのi18nによる日本語化対応 Railsのバリデーションエラーのメッセージの日本語化 rubocop RuboCop is 何? 【Rails】RuboCopの基本的な使用方法と出力の見方 コメント機能 Railsでコメント機能をつくってみよう [Rails]Ajaxを用いて非同期でコメント機能の実装 [Rails]コメント機能のAjax(非同期通信)について いいね機能 [Rails]いいね機能の非同期での実装!!! 【Rails×Ajax】いいね機能ハンズオン Railsでいいね機能のAjax処理を実装してみた RailsでAjaxで「いいね!」機能を実装する。 通知機能 【Rails】通知機能を誰でも実装できるように解説する【いいね、コメント、フォロー】 [Ruby on rails] 通知機能実装 コメント(非同期通信)の通知機能 [Rails]通知機能の実装 【Rails】通知機能の実装 検索機能 Railsで検索機能を実装する方法 railsで検索フォームを作ろう!! 【Rails】カテゴリ検索機能の実装で学んだこと [Rails]多階層カテゴリーから商品を検索・一覧表示する機能 単体テスト・統合テスト RSpecを導入して単体テストコードを記述する 【Rails】テストの準備からモデル単体テストまで【RSpec】 [Rails]RSpecでモデルのテスト(FactoryBot使用) 初めてRSpecでRailsアプリのモデルをテストする 【Ruby on Rails】モデルの単体テストコードについてまとめ(RSpec) 【Rails6】RSpecによる検索機能(ransack)の結合テストの実装 テストコード一覧 @narimiya
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

rails assets:precompile RAILS_ENV=productionでエラー

Compiling... Compilation failed: Though the "loose" option was set to "false" in your @babel/preset-env config, it will not be used for @babel/plugin-proposal-private-property-in-object since the "loose" mode option was set to "true" for @babel/plugin-proposal-class-properties. The "loose" option must be the same for @babel/plugin-proposal-class-properties, @babel/plugin-proposal-private-methods and @babel/plugin-proposal-private-property-in-object (when they are enabled): you can silence this warning by explicitly adding ["@babel/plugin-proposal-private-property-in-object", { "loose": true }] to the "plugins" section of your Babel config. ModuleNotFoundError: Module not found: Error: Can't resolve '/public/assets/images/coffee_gif.gif' in '/var/www/coffee_passport/app/javascript/packs/components/static_pages' at factory.create (/var/www/coffee_passport/node_modules/webpack/lib/Compilation.js:925:10) at factory (/var/www/coffee_passport/node_modules/webpack/lib/NormalModuleFactory.js:401:22) at resolver (/var/www/coffee_passport/node_modules/webpack/lib/NormalModuleFactory.js:130:21) at asyncLib.parallel (/var/www/coffee_passport/node_modules/webpack/lib/NormalModuleFactory.js:224:22) at /var/www/coffee_passport/node_modules/neo-async/async.js:2830:7 at /var/www/coffee_passport/node_modules/neo-async/async.js:6877:13 resolve '/public/assets/images/coffee_gif.gif' in '/var/www/coffee_passport/app/javascript/packs/components/static_pages' using description file: /var/www/coffee_passport/package.json (relative path: ./app/javascript/packs/components/static_pages) Field 'browser' doesn't contain a valid alias configuration No description file found no extension Field 'browser' doesn't contain a valid alias configuration /public/assets/images/coffee_gif.gif doesn't exist Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif.svg doesn't exist Though the "loose" option was set to "false" in your @babel/preset-env config, it will not be used for @babel/plugin-proposal-private-methods since the "loose" mode option was set to "true" for @babel/plugin-proposal-private-property-in-object. The "loose" option must be the same for @babel/plugin-proposal-class-properties, @babel/plugin-proposal-private-methods and @babel/plugin-proposal-private-property-in-object (when they are enabled): you can silence this warning by explicitly adding ["@babel/plugin-proposal-private-methods", { "loose": true }] to the "plugins" section of your Babel config. とエラーがでて この記事にある通り、 package.jsonと webpack.config.jsを色々書かないと行けない… でもいまのrails プロジェクトには、webpack.config.js ファイルは無い。 を1から勉強することにします。 解決できた。。。 .gitignoreに /public/assets/ を設定していた。。 vueファイルから画像を読み込む際に assets以下の画像がなぜか読み込めなかったので public/assets/images/以下に画像を設定していたが、 .gitignoreに /public/assets/ を設定していたので、commit ,pushできず以上のように本番環境でエラーが起きていた。 くそ単純だった。。 なんか依存関係とかかと思って間違ったアプローチしてた。。。 本番環境でのブラウザで Webpacker::Manifest::MissingEntryError in Sessions#new Showing /var/www/coffee_passport/app/views/sessions/new.html.erb where line #3 raised: Webpacker can't find app_explain in /var/www/coffee_passport/public/packs/manifest.json. Possible causes: 1. You want to set webpacker.yml value of compile to true for your environment unless you are using the webpack -w or the webpack-dev-server. 2. webpack has not yet re-run to reflect updates. 3. You have misconfigured Webpacker's config/webpacker.yml file. 4. Your webpack configuration is not creating a manifest. Your manifest contains: こんなエラー起きていたが、 Webpacker can't find app_explain in /var/www/coffee_passport/public/packs/manifest.json. Possible causes: とある。 /var/www/coffee_passport/public/packs/manifest.json. もgit ignoreにしてるのでそりゃそうだ。。。 /public/packs /public/packs-test をはずした。。 めっちゃコミット対象のファイルが増えた。。。1000ファイルくらい。。まぁいいや。 rails assets:precompile RAILS_ENV=production も上手くいった。 解決できたと思ったが、 だが本番環境のブラウザで でvueファイルが読み込まれてない。。。 ちゃんと production.rbは config.assets.compile = true になってる。 /public/assets/express もgit ignoreから削除 var finalhandler = require('finalhandler'); var Router = require('./router'); var methods = require('methods'); var middleware = require('./middleware/init'); var query = require('./middleware/query'); var debug = require('debug')('express:application'); var View = require('./view'); var http = require('http'); var compileETag = require('./utils').compileETag; var compileQueryParser = require('./utils').compileQueryParser; var compileTrust = require('./utils').compileTrust; var deprecate = require('depd')('express'); var flatten = require('array-flatten'); var merge = require('utils-merge'); var resolve = require('path').resolve; var setPrototypeOf = require('setprototypeof') var slice = Array.prototype.slice; こういった大事そうな記述をignoreしちゃってたからね。 再度、git pull やrails assets:precompile RAILS_ENV=production を実行して以上なかったが、 やっぱりさっきのエラーになる。 Routing Error No route matches [GET] "/logout" あとついでに本番環境のrailsのほうでエラーが起きた。 なんで、js関係ないやろ。。。 route.rb delete '/logout', to: 'sessions#destroy' app/views/users/config.html.erb <div class="user-config-child"> <%= link_to "ログアウト", "/logout",method: :delete,data: {confirm: "本当にログア ウトしますか?"} %> </div> とエラーが表示された。。。 なんで。。。 getリクエストになってるの。。。 同じことに悩んでるひといた。 なるほど、js関係あるのか。。。 jsが上手く動作しないと、deleteやpostが正常に動作しないっぽい。。。 まずはEC2インスタンスを再起動 してもだめだった。。。 さっき、js関係のファイルをcommitして、pushしたから それが原因とかしらんぞ。。。 application.js // This file is automatically compiled by Webpack, along with any other files // present in this directory. You're encouraged to place your actual application logic in // a relevant structure within app/javascript and only use these pack files to reference // that code so it'll be compiled. require("@rails/ujs").start() // require("turbolinks").start() require("@rails/activestorage").start() require("channels") require("../bgswitcher") require("../card") require("./tag") require("../slide") require('./preview') //= require rails-ujs config/webpacker.yml production: <<: *default # Production depends on precompilation of packs prior to booting for performance. compile: true # Extract and emit a css file extract_css: true # Cache manifest.json for performance cache_manifest: true の compile: trueに変更。 し、git pull と rails assets:precompile RAILS_ENV=productionを実行 上手くいった。 それでも Failed to load resource: the server responded with a status of 404 (Not Found) となった。。 $ git rm --cached -r 削除したいディレクトリ $ git rm --cached ファイル名 らしいので、 git rm --cached -r public/assets/express git rm --cached -r public/packs/js を実行して だけどエラーは変わらず。 git rm --cached -r public/packs/media/images rm 'public/packs/media/images/coffee_gif-2c7fb49d.gif' rm 'public/packs/media/images/coffee_gif-d678c3db.gif' rm 'public/packs/media/images/post-9de5d393.png' rm 'public/packs/media/images/post-eef7a77c.png' rm 'public/packs/media/images/sold_item1-37df37e4.png' rm 'public/packs/media/images/sold_item1-4b5a14d6.png' rm 'public/packs/media/images/sold_item2-4d76be86.png' rm 'public/packs/media/images/sold_item2-fd0ae8c3.png' rm 'public/packs/media/images/sold_item3-49860077.png' rm 'public/packs/media/images/sold_item3-6b06935f.png' rm 'public/packs/media/images/sold_item4-2189bb94.png' rm 'public/packs/media/images/sold_item4-fb614d95.png' これも機械的に生成されるファイルをっぽいのでgit ignoreにしてみた。 ハッシュ値的なものがついたファイルをgit ignoreに設定したけど、 この画像を見る限りは、ハッシュ値的なのがついてるのをリクエストしてるからやっぱりgit ignoreしないほうがいいかも okuramasafumiさんから 機械的に生成されたファイルをコミットすると、それらの生成元となったファイルが変更されるたびに生成後のファイルもコミットしなくてはならなくなってしまいますね。 「機械的に生成」するタイミングをデプロイの最中にすれば、それらファイルをコミットせずに本番環境に配置できますね。 と教えてもらった。 まぁでも機械的に生成されるファイルは必要そう。 だけども、それらの生成元となったファイルが変更されるたびに生成後のファイルもコミットしなくてはならなくなってしまう。 いったんアプリが動くようになってから 「機械的に生成」するタイミングをデプロイの最中にする設定にしよう。 [ec2-user@ip-10-0-10-10 coffee_passport]$ bin/webpack Hash: d3f8ab57fb922d915fd8 Version: webpack 4.46.0 Time: 11012ms Built at: 2021/09/08 12:51:38 Asset Size Chunks Chunk Names js/app_explain-5a7231ef4c979894f42c.js 429 KiB app_explain [emitted] [immutable] app_explain js/app_explain-5a7231ef4c979894f42c.js.map 517 KiB app_explain [emitted] [dev] app_explain js/application-dfb9624df34e242f6e62.js 98 KiB application [emitted] [immutable] application js/application-dfb9624df34e242f6e62.js.map 111 KiB application [emitted] [dev] application js/components/Home-e1516e065f068d648e91.js 11.6 KiB components/Home [emitted] [immutable] components/Home js/components/Home-e1516e065f068d648e91.js.map 8.91 KiB components/Home [emitted] [dev] components/Home js/components/about_coffee_passport-1f2f9c1fa17c2466f484.js 15.3 KiB components/about_coffee_passport [emitted] [immutable] components/about_coffee_passport js/components/about_coffee_passport-1f2f9c1fa17c2466f484.js.map 12.9 KiB components/about_coffee_passport [emitted] [dev] components/about_coffee_passport js/components/contact-2a05cf54345ca48f4e5f.js 13.3 KiB components/contact [emitted] [immutable] components/contact js/components/contact-2a05cf54345ca48f4e5f.js.map 10.9 KiB components/contact [emitted] [dev] components/contact js/components/drinks/show-b39aaf6af666ca3e95e9.js 18.3 KiB components/drinks/show [emitted] [immutable] components/drinks/show js/components/drinks/show-b39aaf6af666ca3e95e9.js.map 16.6 KiB components/drinks/show [emitted] [dev] components/drinks/show js/components/footer-7fcae9b44f17ccfd1a70.js 12.2 KiB components/footer [emitted] [immutable] components/footer js/components/footer-7fcae9b44f17ccfd1a70.js.map 9.72 KiB components/footer [emitted] [dev] components/footer js/components/like/likeButton-a63697a1a2de0157ecc0.js 114 KiB components/like/likeButton [emitted] [immutable] components/like/likeButton js/components/like/likeButton-a63697a1a2de0157ecc0.js.map 109 KiB components/like/likeButton [emitted] [dev] components/like/likeButton js/components/search-f6a1db8eff7db36ddf7d.js 7.98 KiB components/search [emitted] [immutable] components/search js/components/search-f6a1db8eff7db36ddf7d.js.map 7.47 KiB components/search [emitted] [dev] components/search js/components/static_pages/appExplain-ab8244c5fa09a192c036.js 102 KiB components/static_pages/appExplain [emitted] [immutable] components/static_pages/appExplain js/components/static_pages/appExplain-ab8244c5fa09a192c036.js.map 114 KiB components/static_pages/appExplain [emitted] [dev] components/static_pages/appExplain js/components/users/user-f652ad467bfb62cde895.js 552 KiB components/users/user [emitted] [immutable] components/users/user js/components/users/user-f652ad467bfb62cde895.js.map 627 KiB components/users/user [emitted] [dev] components/users/user js/footer-239c963857612400ee59.js 654 KiB footer [emitted] [immutable] footer js/footer-239c963857612400ee59.js.map 739 KiB footer [emitted] [dev] footer js/hello_vue-1cb3206e3283b6162462.js 785 KiB hello_vue [emitted] [immutable] hello_vue js/hello_vue-1cb3206e3283b6162462.js.map 889 KiB hello_vue [emitted] [dev] hello_vue js/preview-48d6e11d740ebbf574e4.js 7.02 KiB preview [emitted] [immutable] preview js/preview-48d6e11d740ebbf574e4.js.map 7.25 KiB preview [emitted] [dev] preview js/router/router-9aea5533c2f9d9ac037c.js 648 KiB router/router [emitted] [immutable] router/router js/router/router-9aea5533c2f9d9ac037c.js.map 736 KiB router/router [emitted] [dev] router/router js/tag-389e82f3c1e99bbf9eec.js 10.5 KiB tag [emitted] [immutable] tag js/tag-389e82f3c1e99bbf9eec.js.map 11.1 KiB tag [emitted] [dev] tag manifest.json 6.37 KiB [emitted] media/images/coffee_gif-d678c3db.gif 346 KiB [emitted] media/images/post-eef7a77c.png 542 KiB [emitted] media/images/sold_item1-37df37e4.png 616 KiB [emitted] media/images/sold_item2-4d76be86.png 531 KiB [emitted] media/images/sold_item3-6b06935f.png 579 KiB [emitted] media/images/sold_item4-fb614d95.png 740 KiB [emitted] Entrypoint app_explain = js/app_explain-5a7231ef4c979894f42c.js js/app_explain-5a7231ef4c979894f42c.js.map Entrypoint application = js/application-dfb9624df34e242f6e62.js js/application-dfb9624df34e242f6e62.js.map Entrypoint components/about_coffee_passport = js/components/about_coffee_passport-1f2f9c1fa17c2466f484.js js/components/about_coffee_passport-1f2f9c1fa17c2466f484.js.map Entrypoint components/contact = js/components/contact-2a05cf54345ca48f4e5f.js js/components/contact-2a05cf54345ca48f4e5f.js.map Entrypoint components/drinks/show = js/components/drinks/show-b39aaf6af666ca3e95e9.js js/components/drinks/show-b39aaf6af666ca3e95e9.js.map Entrypoint components/footer = js/components/footer-7fcae9b44f17ccfd1a70.js js/components/footer-7fcae9b44f17ccfd1a70.js.map Entrypoint components/Home = js/components/Home-e1516e065f068d648e91.js js/components/Home-e1516e065f068d648e91.js.map Entrypoint components/like/likeButton = js/components/like/likeButton-a63697a1a2de0157ecc0.js js/components/like/likeButton-a63697a1a2de0157ecc0.js.map Entrypoint components/search = js/components/search-f6a1db8eff7db36ddf7d.js js/components/search-f6a1db8eff7db36ddf7d.js.map Entrypoint components/static_pages/appExplain = js/components/static_pages/appExplain-ab8244c5fa09a192c036.js js/components/static_pages/appExplain-ab8244c5fa09a192c036.js.map Entrypoint components/users/user = js/components/users/user-f652ad467bfb62cde895.js js/components/users/user-f652ad467bfb62cde895.js.map Entrypoint footer = js/footer-239c963857612400ee59.js js/footer-239c963857612400ee59.js.map Entrypoint hello_vue = js/hello_vue-1cb3206e3283b6162462.js js/hello_vue-1cb3206e3283b6162462.js.map Entrypoint preview = js/preview-48d6e11d740ebbf574e4.js js/preview-48d6e11d740ebbf574e4.js.map Entrypoint router/router = js/router/router-9aea5533c2f9d9ac037c.js js/router/router-9aea5533c2f9d9ac037c.js.map Entrypoint tag = js/tag-389e82f3c1e99bbf9eec.js js/tag-389e82f3c1e99bbf9eec.js.map [./app/javascript/app.vue] 1.04 KiB {hello_vue} [built] [./app/javascript/app.vue?vue&type=script&lang=js&] 364 bytes {hello_vue} [built] [./app/javascript/app.vue?vue&type=template&id=6fb8108a&] 201 bytes {hello_vue} [built] [./app/javascript/bgswitcher.js] 11.8 KiB {application} [built] [./app/javascript/card.js] 2.66 KiB {application} [built] [./app/javascript/channels sync recursive _channel.js$] ./app/javascript/channels sync _channel.js$ 160 bytes {application} [built] [./app/javascript/channels/index.js] 211 bytes {application} [built] [./app/javascript/packs/app_explain.js] 389 bytes {app_explain} [built] [./app/javascript/packs/application.js] 885 bytes {application} [built] [./app/javascript/packs/footer.js] 222 bytes {footer} [built] [./app/javascript/packs/hello_vue.js] 2.23 KiB {hello_vue} [built] [./app/javascript/packs/preview.js] 3.15 KiB {preview} {application} [built] [./app/javascript/packs/router/router.js] 554 bytes {router/router} {footer} {hello_vue} [built] [./app/javascript/packs/tag.js] 6.68 KiB {tag} {application} [built] [./app/javascript/slide.js] 1.13 KiB {application} [built] + 102 hidden modules を実行したら新しいハッシュ値が生成された。これいけんじゃね? よっしゃいけた!!!!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby on Rails でオリジナルアプリを作ってみた

はじめに はじめまして。閲覧いただきありがとうございます。 今回、Ruby on Rails を用いてポートフォリオを作成いたしましたので開発の経緯・工夫・苦悩などをまとめさせていただきます。 尚、機能面の紹介等は Github と重複する為、一部割愛しています。 関連URL アプリ : https://medimov1.herokuapp.com Github: https://github.com/minasenanami/medimo アプリ概要 「看護に関する情報・知識を記録・共有」をテーマにしたアプリで主な機能は以下となっております。 看護に関する記事の作成・編集・削除機能 記事は「公開・下書き・非公開」の公開範囲の選択が可能 「いいね」・「保存」機能を実装し「保存」した記事は一覧で閲覧が可能です。 記事のタイトル or タグ検索機能 使用技術 言語 : Ruby ( 2.7.2 ) フレームワーク : Ruby on Rails (6.1.4.1) フロントエンド : HTML&CSS/Bootstrap/Javascript DB : PostgreSQL テスト : RSpec インフラ : Heroku(ステージング環境 → 本番環境)+AWS(S3) ソースコード管理:GitHub(Projects のカンバン方式で issues を作成しタスクを管理) アプリの制作背景 看護師として 5 年ほど勤務していた際に、教育担当や新人の方から以下の相談が多々ありました。 1. 毎日課題が多い ・ 翌日の担当患者さんの病態生理の把握 ・ 薬剤治療前後の注意点 ・ 検査値・項目の理解 etc... 2. ネットは一般向けな内容なので欲しい情報に至るまでに時間がかかる 3. ケア・業務内容の種類が多く頻度の少ない物は忘れてしまう この課題は私の職場だけでなく他病棟や病院単位でも問題としてよく耳にしていました。 そこで、日々の「学び・体験」を共有する場所を作ることができれば、各課題に対し解決の一助になるのではないかと思い制作に取り組みました。 機能一覧 主な機能は以下となっております。 機能 Gem 1 ログイン・ログアウト devise 2 アカウント登録、設定変更 devise 3 ユーザーアイコン登録 ActiveStorage 4 記事検索 ransack 5 記事投稿欄 ActionText 6 ページネーション kaminari 7 レスポンシブ Bootstrap 8 テスト実装 RSpec / Faker / FactoryBot 9 フォーマッター Rubocop 10 ゲストログイン x 11 記事投稿機能(CRUD) x 12 いいね機能(非同期) x 13 保存機能(非同期) x 14 タグ機能 x 15 記事の公開範囲の設定 x 工夫した事 アプリ作成時に工夫した点は以下の5点です。 利用ユーザー層の選定から考えて UI を決定 メインユーザーは自分ではなく他者なのでサービスを作る気持ちで利用者の想定から着手 メインターゲットは「看護師・20代・女性」を想定 アプリーのカラーは女性向けのサイトや好まれるカラーパレットなどを調べて選定 実際に配色サンプルを見てもらいフィードバックをもらう 最終的に下記の配色でデザイン markdown ではなく Action Text を導入 日常的に PC を使うという人が少ない PCの使用用途は限定的でレポートの作成・必要な資料集めなどが多い markdown は学習コストが掛り敬遠材料になる 実際にどちらが良いか聞いた所「覚えられる気がしない」との回答 仮にmarkdownを覚えたとしても他で転用する機会も無い スマホでmarkdown記法での実装をするとキーボードの切り替えが多く不便 上記の結果から直感的に操作できる Action Text を導入しました 記事に公開範囲を設けたこと 情報の共有以外の用途としてメモとしても利用できるようにするため 既存のメモアプリにメモすると他の情報と混ざり探すのに手間取る経験あり 業務的な内容は非公開でメモ代わりに使用し情報の一元化を図る為設けました マルチデバイスでのデバッグ iPhoneとmacをlocale環境で共有 PCとスマホの表示デザインの崩れや調整を同時に行い後戻り作業を減らす スマホ上の動作も確認できるので異常を見つけやすい 実務でのチーム開発を意識した開発 Git, GitHub を用いたソース管理 Projects のカンバン方式でタスクを管理 issue・ブランチをタスクごとに作成し、作業を進めました 苦労したこと アプリ作成時に特に苦労したのは以下の2点です 1. ActionTextのバリテーションの設定 2. ActionText使用時のActive_Stroge_Blobsの未使用データの増殖 ActionTextのバリテーションの設定 投稿機能で使用するActionTextはデフォルトだと様々なファイルが添付可能な状態なので、添付ファイルを画像のみに制限する必要がありました。 しかし、ActionText のバリテーションに関する情報自体が少なく、Railsガイドを読んでも詳細な情報が見付けられず、Rails 側でどのように処理するれば良いのか悩みました。 というのもActionTextで添付された画像群をどのように取得すれば良いのかが分からない状態でした。 解決策 [ 概要 ] 現状をメンターの方に相談し質問をさせていただき参考文献を頂きました。 その結果今回はActionTextの元であるtrixつまりJavaScript 側で添付の制限をする事にしました 制限内容は以下の3点です ファイルタイプ (jpeg, png, jpg) 上限枚数 10枚/回 画像容量の上限 5MB/枚 参照元はこちらです => Handling attachments in Action Text in Rails 6 ※JavaScriptで処理した理由は次の苦労した事の内容と一部重複するのでそちらでご説明いたします。 実装 app/javascript/trix-editor-overrides.jsファイルを作成 上記のファイルをapp/javascript/packs/application.jsにインポートする trix-editor-overrides.js window.addEventListener("trix-file-accept", function (event) { const acceptedTypes = ["image/jpeg", "image/png", "image/jpg"]; // 添付画像ファイルの拡張子の選別処理 if (!acceptedTypes.includes(event.file.type)) { event.preventDefault(); alert("画像ファイル以外は投稿できません"); } // 1枚の画像の容量制限の設置 const maxFileSize = 1024 * 1024 * 5; // 5MB if (event.file.size > maxFileSize) { event.preventDefault(); alert("5MB以上の画像は投稿できません"); } // 画像の枚数制限処理 const maxFileCount = 9; const fileCount = document.getElementsByTagName("figure").length; if (fileCount > maxFileCount) { event.preventDefault(); alert("1回の投稿では10枚が上限です"); } }); app/javascript/packs/application.js import "../trix-editor-overrides" 実際に6MBの画像を添付してみます 他の条件の時も同様にalertが出て無事に画像の添付を拒否してくれるようになりました! ActionText使用時のActive_Stroge_Blobsの未使用データの増殖 問題は以下です。 ファイルを添付した瞬間にDB(Active_stroge_blobs)に保存される 作成時に添付した画像を差し替えた場合も画像使用の有無を問わず保持され続ける 添付したファイルが画像以外のファイル(csv,mp4)などもDBに保存される 解決策 [ 概要 ] [ 1, 2 ]はデプロイ時にS3を利用するので、実運用を考えた際には無用なコストになると思い不使用なデータは削除する必要がありました。 [ 3 ]への事前対策として上記のように添付制限をJavascriptで実装する事にしました。 実装 実装内容は以下です 未使用のデータを削除する処理を作成 削除処理を行うタイミングを決める 未使用データの削除処理の実装 ActionTextは画像を添付した瞬間に下記の画像のようにDBに添付されます。 metadataカラムが埋まっている場合は記事の削除・画像を差し替え時に自動で削除されます。 使用されている画像に関してはmetadataカラムが埋まり、未使用データのmetadataカラムはNULLのままです この NULL になっているデータを削除を実施する処理が下記です ActiveStorage::Blob.includes(:variant_records, :preview_image_attachment).unattached.each(&:purge) if ActiveStorage::Blob.unattached.any? # 使用されていないデータの数を取得 pry(main)> ActiveStorage::Blob.unattached.count # => 6 # 上記のデータを削除する pry(main)> ActiveStorage::Blob.unattached.find_each(&:purge) Disk Storage (0.5ms) Deleted file from key: xxxxxxxxxxxxxxxxx Disk Storage (0.1ms) Deleted files by key prefix: variants/xxxxxxxxxxxxxxxxxxxxx/ # 対象の回数分上記の処理が行われ => nil 処理の結果 未使用データが綺麗に削除されました! 今回はこちら(SmartHR TechBlogさん)の記事を参考にさせていただきました。 削除処理のタイミングを決める 削除する処理は実装できたのでこの処理を実装するタイミングを決める必要がありました。 最初は削除できているか確認したかったので仮として下記のようにマイページに遷移した際に未使用データが存在すれば処理を行うという風にしていました。 xx_controller.rb def show check_blobs @user = User.with_attached_avatar.find(params[:id]) 省略 end private def check_blobs ActiveStorage::Blob.includes(:variant_records, :preview_image_attachment).unattached.each(&:purge) if ActiveStorage::Blob.unattached.any? end 動作として問題がない事は確認できたのですが、ここで行う処理として正しいのか心配になったのでメンターの方に相談し get(ページ遷移)してるのに、裏で削除処理が走るのはあまり好ましくない! とアドバイスをいただけたので、今回はheroku scheduler にて行う事にしました。 heroku schedulerの実装 実装内容は以下です。 Pipelineを使用しているのでアプリ名を指定しherokuにアドオンを追加 ( heroku addons:create scheduler:standard -a アプリ名) 不要データを削除するrakeタスクの作成 lib/tasks/clean_active_storage_blobs.rb namespace :clean_active_storage_blobs do desc "ActionTextに添付したが使用しなかった画像データを削除" task metadata: :environment do ActiveStorage::Blob.includes(:variant_records, :preview_image_attachment).unattached.each(&:purge) if ActiveStorage::Blob.unattached.any? end end # 作成したタスクの確認 % be rake -T .... rake clean_active_storage_blobs:metadata # ActionTextに添付したが使用しなかった画像データを削除 3, 作成したrakeタスクをheroku schedulerに登録 以上でheroku schedulerに定期処理を持たせる事ができ、不要なデータに悩まされる事がなくなりました! 今後の課題 現在非公開記事は作成者のみの閲覧になっているので、記事のurlを知っている人は閲覧できるようにしたいです。 そのために現状のidのurlからハッシュ形式にした推測しにくい形に変えていく必要があると感じました。 適宜不具合やバグがあれば発見次第修繕。 作成後の感想 設計やデザインを1から考えたアプリが、日毎に形になっていく過程は、とても楽しかったです。 実装時に思うように行かず悩む事もありましたが自力で解決し、必要なタイミングで相談・質問を行うことで大変でしたが、同時に物作りの楽しさを感じました。 色々な方々が「1番の勉強は自分でアプリを作ること」と仰る意味がわかったような気がしました。 今後はRails × Vue.jsのようなモダンなフロントにも触れていきたいです。 長い記事になってしまいましたが、ここまで読んで頂きありがとうございました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】wheneverを使ってバッチを定時処理にする

はじめに Ruby on Railsは初心者ですが、RPGでの開発時にもバッチ処理はよく使っていました。 勝手に処理を行ってくれるからとても便利なものですよね。 本記事では過去の経験からバッチ処理について軽く触れた後、wheneverを使用した定時処理化についてまとめております。 「早く実装したいよ!」という方は画面右のメニューから【バッチ処理を作る】までスキップしてください。 Ruby on Railsに関しては完全に初心者ですので、至らない点もあるかと思います。 誤りがございましたらお手数ですがコメント欄や編集リクエストにてご指摘いただけますと幸いです。 バッチ処理と定時処理 少し勉強したことがある方だと、バッチ処理と定時処理を混同している方も多いのではないでしょうか。 この2つは異なる意味を持ち、「バッチプログラムを定時処理している」というとわかりやすいと思います。 バッチ処理...複数の処理(プログラム)を1つのまとまりとしたもの 定時処理...決まった時間に行われる処理 例えば、顧客からの発注データを受け取った時に、データベースの更新など決まった処理を行うのも、定時ではありませんがバッチ処理です。 バッチ処理が定時に行われることが多い要因として、 人間の手が介入することなく自動でどんどん実行してくれる (エラーハンドリングで人間の判断を求めることはあります) 大量のデータを処理することが多いため、負荷が高くなることや、処理の途中でファイル操作されることを防ぐため、業務終了後に行う といったものがあります。 本記事の目標は「バッチプログラムを定時処理にする」ことです。 そのため、実装するためには以下の2つのステップに分けて理解する必要があります。 1.バッチ処理を作る 2.スケジュールを設定する(定時処理にする) では、順番に確認していきます。 バッチ処理を作る ここではバッチプログラムの作成と実行方法を理解します。 プログラムの作成 <作成手順> 1.app/libの配下に「batch」フォルダを作成する 2.処理内容が伝わりやすいプログラム名でファイルを作成する(今回はdata_createとする) 3.処理を記述する <ポイント> 最後に処理した内容や件数をメッセージとして表示させると実用性が高まります。 app/lib/batch/data_create.rb class Batch::DataCreate def self.data_create success = 0 error = 0 xxx.each do |xxx|    : if xxx.save success += 1 else error += 1 end end p "#{success}件のデータを作成しました" p "エラーは#{error}件です" end end バッチを実行する 1.config/application.rbに下記を追記し、バッチファイルを読み込むようにします。 config/application.rb : class Application < Rails::Application config.paths.add 'lib', eager_load: true # この行を追加 : end : バッチを実行してみます。 Terminal bundle exec rails runner Batch::DataCreate.data_create プログラムに記述したメッセージが出力されていれば成功です。 スケジュールを設定する ここでは耳馴染みのない言葉が多く登場します。 用語を確認したのち、設定を行っていきたいと思います。 用語を理解する cron 設定されたスケジュールで定期的にプログラムを実行してくれるUNIX系OSの常駐プログラム。 crontab スケジュールの追加、変更、削除を行うコマンド。 このコマンドの実行によってcrontabファイルというものに、どのプログラムをいつ実行するかが記録される。このスケジュールをもとにcronがプログラムを実行する。 whenever crontabファイルの設定をrails上で記述できるようにするGem。 crontabコマンドだけで設定することもできますが、rails上で設定ファイルを管理できることからも、本記事ではwheneverでの設定をまとめていきます。 wheneverで設定する ここから実際にwheneverでの設定を行っていきますが、記述されている内容は「毎日2分毎にdata_createプログラムを実行する」ものです。 本記事の最後にスケジュールの設定方法をまとめておりますので、そちらを確認しながらご自身の環境に合わせて適宜変更を行い設定してください。 1.Gemファイルに下記を追加し、bundle installする gem 'whenever', require: false 2.下記コマンドを実行し、スケジュールファイルを生成する Terminal bundle exec wheneverize 3.生成されたスケジュールファイル(config/schedule.rb)の最後に下記を追記 config/schedule.rb : : require File.expand_path(File.dirname(__FILE__) + "/environment") rails_env = Rails.env.to_sym set :environment, rails_env set :output, 'log/cron.log' #以下、適宜変更してください every 2.minute do   begin runner "Batch::DataCreate.data_create" rescue => e Rails.logger.error("aborted rails runner") raise e end end ターミナルにてbundle exec wheneverを実行し、cron構文に誤りがないか確認する。(この時点では設定は適用されません) 3.設定を適用する Terminal bundle exec whenever --update-crontab [write] crontab file updatedと出力されれば適用されています。 補足:ターミナルにてcrontab -lを実行すると、適用された設定を確認できます。 4.cronを使う cronを起動することで設定したスケジュールでプログラムが実行されます。 以下、cronの使用に関するコマンドをまとめます。 #cronの起動 sudo systemctl start crond #cronの停止 sudo systemctl stop crond #cronの再起動 sudo systemctl restart crond #cronの起動状態の確認(Active: active (running)」と表示されていれば起動中) sudo systemctl status crond #ログの確認(-fをつけるとリアルタイムで監視している状態になる。終わるときはCtrl + C) sudo tail -f log/cron.log    #ログファイルの場所はschedule.rbで指定している スケジュールの設定方法 wheneverを使うことでcronの構文を知らずともスケジュールは設定することができます。 しかし、schedule.rbで記述した内容に誤りがないか、実際にcronの記述で確認できるとより信頼性が増します。 ここではcronの記述を理解したのち、wheneverでの記述法を確認していきたいと思います。 cron構文を理解する まずはルールを確認します。 cronの構文は「分 時 日 月 曜日 [実行するコマンドやプログラム]」の形で表現され、それぞれの指定の間は半角スペースで区切ります 時間の表記は午前午後の指定ではなく24時間表記で指定します 曜日は日曜日を0とし、土曜日の6まで対応しています(日曜日は7でも表現できます) 数字の代わりに*を入力すると指定なしと判断されます 各指定は「,」で区切ることでリスト形式で行うこともできます 各指定は「-」を使うことで範囲形式で行うこともできます リスト形式と範囲形式を同時に指定することもできます 各指定の後に「/」を使うことで一定の間隔を指定することもできます @rebootや@yearlyなどを使うことで、再起動時や毎年などの指定もできます すべてのパターンをテストすることが難しいため、構文のみ記載していきます。 誤りがある場合はご指摘ください。 #毎月1日の23時59分に実行する 59 23 1 * * [コマンド] #毎週月曜日の13時に実行する 00 13 * * 1 [コマンド] #5分おきに実行する */5 * * * * [コマンド] #毎日10時と18時に実行する 0 10,18 * * * [コマンド] #毎日10時・11時・18時・19時・20時に実行する 0 10,11,18-20 * * * [コマンド] #毎日10時から18時の間に1時間おきに実行する 0 10-18/1 * * * [コマンド] #毎週月から金曜日の0時に実行する 0 0 * * 1-5 [コマンド] wheneverでの記述方法 ※Gighubから引用しております。 #3時間毎 every 3.hours do : end #毎日午前4時30分に実行する every 1.day, at: '4:30 am' do : end #毎日午前4時30分と午後6時に実行する every 1.day, at: ['4:30 am', '6:00 pm'] do : end #1時間おきに実行する every :hour do : end #毎週日曜日の午後12時に実行する every :sunday, at: '12pm' do : end #毎月27日から31日の0時0分に実行する every '0 0 27-31 * *' do : end その他にも色々な記述方法がありますが、cronの構文を理解できているなら、最後のevery '* * * * *' doの記述さえ覚えておけばある程度のスケジュールは設定できそうですね。 まとめ 以上、バッチ処理の定時処理化について学びました! 今後絶対必要な知識になるので、もっと理解を深めていきたいと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】wheneverを使ったバッチの定時処理化を理解する

はじめに Ruby on Railsは初心者ですが、RPGでの開発時にもバッチ処理はよく使っていました。 勝手に処理を行ってくれるからとても便利なものですよね。 本記事では過去の経験からバッチ処理について軽く触れた後、wheneverを使用した定時処理化についてまとめております。 「早く実装したいよ!」という方は画面右のメニューから【バッチ処理を作る】までスキップしてください。 Ruby on Railsに関しては完全に初心者ですので、至らない点もあるかと思います。 誤りがございましたらお手数ですがコメント欄や編集リクエストにてご指摘いただけますと幸いです。 バッチ処理と定時処理 少し勉強したことがある方だと、バッチ処理と定時処理を混同している方も多いのではないでしょうか。 この2つは異なる意味を持ち、「バッチプログラムを定時処理している」というとわかりやすいと思います。 バッチ処理...複数の処理(プログラム)を1つのまとまりとしたもの 定時処理...決まった時間に行われる処理 例えば、顧客からの発注データを受け取った時に、データベースの更新など決まった処理を行うのも、定時ではありませんがバッチ処理です。 バッチ処理が定時に行われることが多い要因として、 人間の手が介入することなく自動でどんどん実行してくれる (エラーハンドリングで人間の判断を求めることはあります) 大量のデータを処理することが多いため、負荷が高くなることや、処理の途中でファイル操作されることを防ぐため、業務終了後に行う といったものがあります。 本記事の目標は「バッチプログラムを定時処理にする」ことです。 そのため、実装するためには以下の2つのステップに分けて理解する必要があります。 1.バッチ処理を作る 2.スケジュールを設定する(定時処理にする) では、順番に確認していきます。 バッチ処理を作る ここではバッチプログラムの作成と実行方法を理解します。 プログラムの作成 <作成手順> 1.app/libの配下に「batch」フォルダを作成する 2.処理内容が伝わりやすいプログラム名でファイルを作成する(今回はdata_createとする) 3.処理を記述する <ポイント> 最後に処理した内容や件数をメッセージとして表示させると実用性が高まります。 app/lib/batch/data_create.rb class Batch::DataCreate def self.data_create success = 0 error = 0 xxx.each do |xxx|    : if xxx.save success += 1 else error += 1 end end p "#{success}件のデータを作成しました" p "エラーは#{error}件です" end end バッチを実行する 1.config/application.rbに下記を追記し、バッチファイルを読み込むようにします。 config/application.rb : class Application < Rails::Application config.paths.add 'lib', eager_load: true # この行を追加 : end : バッチを実行してみます。 Terminal bundle exec rails runner Batch::DataCreate.data_create プログラムに記述したメッセージが出力されていれば成功です。 スケジュールを設定する ここでは耳馴染みのない言葉が多く登場します。 用語を確認したのち、設定を行っていきたいと思います。 用語を理解する cron 設定されたスケジュールで定期的にプログラムを実行してくれるUNIX系OSの常駐プログラム。 crontab スケジュールの追加、変更、削除を行うコマンド。 このコマンドの実行によってcrontabファイルというものに、どのプログラムをいつ実行するかが記録される。このスケジュールをもとにcronがプログラムを実行する。 whenever crontabファイルの設定をrails上で記述できるようにするGem。 crontabコマンドだけで設定することもできますが、rails上で設定ファイルを管理できることからも、本記事ではwheneverでの設定をまとめていきます。 wheneverで設定する ここから実際にwheneverでの設定を行っていきますが、記述されている内容は「毎日2分毎にdata_createプログラムを実行する」ものです。 本記事の最後にスケジュールの設定方法をまとめておりますので、そちらを確認しながらご自身の環境に合わせて適宜変更を行い設定してください。 1.Gemファイルに下記を追加し、bundle installする gem 'whenever', require: false 2.下記コマンドを実行し、スケジュールファイルを生成する Terminal bundle exec wheneverize 3.生成されたスケジュールファイル(config/schedule.rb)の最後に下記を追記 config/schedule.rb : : require File.expand_path(File.dirname(__FILE__) + "/environment") rails_env = Rails.env.to_sym set :environment, rails_env set :output, 'log/cron.log' #以下、適宜変更してください every 2.minute do   begin runner "Batch::DataCreate.data_create" rescue => e Rails.logger.error("aborted rails runner") raise e end end ターミナルにてbundle exec wheneverを実行し、cron構文に誤りがないか確認する。(この時点では設定は適用されません) 3.設定を適用する Terminal bundle exec whenever --update-crontab [write] crontab file updatedと出力されれば適用されています。 補足:ターミナルにてcrontab -lを実行すると、適用された設定を確認できます。 4.cronを使う cronを起動することで設定したスケジュールでプログラムが実行されます。 以下、cronの使用に関するコマンドをまとめます。 #cronの起動 sudo systemctl start crond #cronの停止 sudo systemctl stop crond #cronの再起動 sudo systemctl restart crond #cronの起動状態の確認(Active: active (running)」と表示されていれば起動中) sudo systemctl status crond #ログの確認(-fをつけるとリアルタイムで監視している状態になる。終わるときはCtrl + C) sudo tail -f log/cron.log    #ログファイルの場所はschedule.rbで指定している スケジュールの設定方法 wheneverを使うことでcronの構文を知らずともスケジュールは設定することができます。 しかし、schedule.rbで記述した内容に誤りがないか、実際にcronの記述で確認できるとより信頼性が増します。 ここではcronの記述を理解したのち、wheneverでの記述法を確認していきたいと思います。 cron構文を理解する まずはルールを確認します。 cronの構文は「分 時 日 月 曜日 [実行するコマンドやプログラム]」の形で表現され、それぞれの指定の間は半角スペースで区切ります 時間の表記は午前午後の指定ではなく24時間表記で指定します 曜日は日曜日を0とし、土曜日の6まで対応しています(日曜日は7でも表現できます) 数字の代わりに*を入力すると指定なしと判断されます 各指定は「,」で区切ることでリスト形式で行うこともできます 各指定は「-」を使うことで範囲形式で行うこともできます リスト形式と範囲形式を同時に指定することもできます 各指定の後に「/」を使うことで一定の間隔を指定することもできます @rebootや@yearlyなどを使うことで、再起動時や毎年などの指定もできます すべてのパターンをテストすることが難しいため、構文のみ記載していきます。 誤りがある場合はご指摘ください。 #毎月1日の23時59分に実行する 59 23 1 * * [コマンド] #毎週月曜日の13時に実行する 00 13 * * 1 [コマンド] #5分おきに実行する */5 * * * * [コマンド] #毎日10時と18時に実行する 0 10,18 * * * [コマンド] #毎日10時・11時・18時・19時・20時に実行する 0 10,11,18-20 * * * [コマンド] #毎日10時から18時の間に1時間おきに実行する 0 10-18/1 * * * [コマンド] #毎週月から金曜日の0時に実行する 0 0 * * 1-5 [コマンド] wheneverでの記述方法 ※Gighubから引用しております。 #3時間毎 every 3.hours do : end #毎日午前4時30分に実行する every 1.day, at: '4:30 am' do : end #毎日午前4時30分と午後6時に実行する every 1.day, at: ['4:30 am', '6:00 pm'] do : end #1時間おきに実行する every :hour do : end #毎週日曜日の午後12時に実行する every :sunday, at: '12pm' do : end #毎月27日から31日の0時0分に実行する every '0 0 27-31 * *' do : end その他にも色々な記述方法がありますが、cronの構文を理解できているなら、最後のevery '* * * * *' doの記述さえ覚えておけばある程度のスケジュールは設定できそうですね。 まとめ 以上、バッチ処理の定時処理化について学びました! 今後絶対必要な知識になるので、もっと理解を深めていきたいと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

(異常系)Rspec Userモデルの単体テストの手順

今回は異常系テストについて書いていきます。 前回はこちら その①Rspec Userモデルの単体テストの手順 その②(正常系)Rspec Userモデルの単体テストの手順 Userモデルの正常系テストについて書いていきます。  ここではバリデーションに関するテストを実装致します。 異常系テストとは、 対象が想定外のことを起こして、きちんと対処できるか確認する作業 正常系テストがユーザーが開発者の意図する操作を行った時の 挙動を確認するテストコードならばその逆。 開発者の意図しない操作を行った場合の挙動を調べます! 正常系テストがうまくいったときで 異常系テストがうまくいかなかったときですね。 雛形 spec/models/user_spec.rb require 'rails_helper' describe User do before do @user = FactoryBot.build(:user) end describe 'ユーザー新規登録' do context '新規登録がうまくいくとき' do it "nicknameとemail、passwordとpassword_confirmationが存在すれば登録できる" do end it "nicknameが6文字以下で登録できる" do end it "passwordが6文字以上であれば登録できる" do end end context '新規登録がうまくいかないとき' do it "nicknameが空だと登録できない" do end it "nicknameが7文字以上であれば登録できない" do end it "emailが空では登録できない" do end it "重複したemailが存在する場合登録できない" do end it "passwordが空では登録できない" do end it "passwordが5文字以下であれば登録できない" do end it "passwordが存在してもpassword_confirmationが空では登録できない" do end end end end テストコードの記述 be_validマッチャを使用します。 itとendの中に記述していきます。(正常系と一緒) expectのインスタンスが正しく保存されることを確認できます。 expect(インスタンス).to be_validのように使用してください。 spec/models/user_spec.rb require 'rails_helper' describe User do before do @user = FactoryBot.build(:user) end describe 'ユーザー新規登録' do context '新規登録がうまくいくとき' do it "nicknameとemail、passwordとpassword_confirmationが存在すれば登録できる" do end it "nicknameが6文字以下で登録できる" do end it "passwordが6文字以上であれば登録できる" do end end context '新規登録がうまくいかないとき' do it 'nicknameが空では登録できない' do @user.nickname = '' @user.valid? expect(@user.errors.full_messages).to include("Nickname can't be blank") end it 'nicknameが7文字以上では登録できない' do @user.nickname = 'aaaaaaa' @user.valid? expect(@user.errors.full_messages).to include('Nickname is too long (maximum is 6 characters)') end it 'nicknameが空では登録できない' do @user.nickname = '' @user.valid? expect(@user.errors.full_messages).to include("Nickname can't be blank") end it '重複したemailが存在する場合登録できない' do @user.save another_user = FactoryBot.build(:user) another_user.email = @user.email another_user.valid? expect(another_user.errors.full_messages).to include('Email has already been taken') end it 'passwordが空では登録できない' do @user.password = '' @user.valid? expect(@user.errors.full_messages).to include("Password can't be blank") end it 'passwordが5文字以下では登録できない' do @user.password = '00000' @user.password_confirmation = '00000' @user.valid? expect(@user.errors.full_messages).to include('Password is too short (minimum is 6 characters)') end it 'passwordとpassword_confirmationが不一致では登録できない' do @user.password_confirmation = '' @user.valid? expect(@user.errors.full_messages).to include("Password confirmation doesn't match Password") end end end end それと単体テストで気をつけてほしいのは、endの数 doとendの数は同じ分あります。 doの数が10ならばendの数も10あります。一つend抜けるとエラーになってしまうので要注意です。 validは日本語で「正しい」を意味します。 valid?とすることで「正しいかどうか」を判定するメソッドとなります。 作成したデータが正しく保存される場合はtrueを、保存されない場合はfalseを返します。 また、保存されない場合は「なぜ保存されないのか」のエラーメッセージも生成します。 もし、エラーメッセージが出てきたらbinding.pryを用いて確認します!。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Active Storageでsvgを表示する【Rails】

svg画像をActive Storageでattachしてから表示する際に少々手こずったのでメモ svgがimgタグで表示されない Model hoge.rb class Hoge < ApplicationRecord has_one_attached :image ... end View = tag.img src: url_for(@hoge.image) これだと画像として表示されない。 これを解決するには、まずRailsがデフォルトでHTTPヘッダーのContent-Dispositionをattachmentとしているリストから"image/svg+xml"を消して、inlineを許可する。 config/initializer/storage.rb Rails.application.config.active_storage.content_types_to_serve_as_binary.delete("image/svg+xml") Rails.application.config.active_storage.content_types_allowed_inline << "image/svg+xml" N+1 単にrails_storage_proxy_pathとするだけだとその都度 SELECT `active_storage_blobs`.* FROM `active_storage_blobs` WHERE `active_storage_blobs`.`id` = <hoge.id> LIMIT 1 とされてしまいN+1問題が起きる。 これを解決するには、<attachment_name>_url属性をモデルに追加して hoge.rb attribute :image_url def image_url return self.image.attached? ? url_for(self.image) : "#" end with_attached_<attachment_name>する。 Hoge.<queries>.with_attached_image するとSQLのWHERE以下がイコールからIN <list>に変わる。 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

コントローラー内の処理のカテゴリー

自分でもあやふな部分があるので復習も兼ねて! まずコントローラーとは? ・リクエストに対する処理をする場所 ・処理をした後クライアントにレスポンスとして返す場所 コントローラー内での処理のカテゴリー ・コントローラー内での処理のカテゴリーをアクションと言います!  基本的な7つのアクションが、、、   ・index→一覧表示(トップページ) ・new→新規投稿ページ ・create→データの投稿 ・show→個別詳細ページ ・edit→投稿編集ページ ・update→データの編集 ・destroy→データの削除 例えば、クライアントからトップページが見たああああああい!!とリクエストが来た場合はコントローラー内のindexアクションが動きます! トップページの表示がリクエストで来ていた場合の記述の仕方↓ def index end 以上!!                          
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby on Rails】バリデーションが効かなかったときの原因追求をした話

対象者 バリデーションを使っている方 バリデーションが効かない不具合が発生している方 目的 バリデーションを使って投稿が失敗するようにすること 実際の手順と実例 1.前提 上記記事を参考に実装 Articleモデル(記事の投稿)、Tagモデル、ArticleTagモデル(中間テーブル)実装中 title,bodyはArticleのカラム、tag_nameはTagのカラム  下記のようにバリデーションを設定したが投稿ができてしまう、、、 model/tag.rb class Tag < ApplicationRecord has_many :articles, through: :article_tags has_many :article_tags validates :tag_name, presence: true end 2.結論(解決策) 下記のようにコントローラーを変更 before app/tags_controller.rb def create @article = Article.new(article_params) @article.user = current_user tag_list = params[:article][:tag_name].split("/") if @article.save @article.tags_save(tag_list) flash.now[:notice] = "投稿されました" redirect_to article_path(@article) else @user = current_user flash.now[:alert] = "投稿に失敗しました" render :new end end after app/tags_controller.rb def create @article = Article.new(article_params) @article.user = current_user tag_list = params[:article][:tag_name].split("/") #下記の部分を追加 if tag_list == [] tag = Tag.new() tag.tag_name = "" tag.save @user = current_user flash.now[:alert] = "投稿に失敗しました" render :new #上記の部分を追加 elsif @article.save @article.tags_save(tag_list) flash.now[:notice] = "投稿されました" redirect_to article_path(@article) else @user = current_user flash.now[:alert] = "投稿に失敗しました" render :new end end ※上記のコントローラーで使用しているtags_save(tag_list)はArticleモデルで定義したものです。 app/model/articles.rb def tags_save(tag_list) if !tags.nil? article_tags_records = ArticleTag.where(article_id: id) article_tags_records.destroy_all end tag_list.each do |tag| inspected_tag = Tag.where(tag_name: tag).first_or_create #① tags << inspected_tag end end 3.原因 @article.saveで保存が行われてしまっている beforeの書き方だと先にarticleの内容が保存されてしまっており、 tag_saveも””空欄が保存され、そのまま通過してしまっている [7] pry(main)> tag.tag_name = "" => "" 空欄だと投稿は失敗ですよということを表すために、 下記の記述を追加 app/tags_controller.rb if tag_list == [] #タグが空欄だったときの条件付け tag = Tag.new() tag.tag_name = "" #タグ名が空欄であることを定義 tag.save #セーブされ、ここでバリデーションが作動する @user = current_user flash.now[:alert] = "投稿に失敗しました" render :new elsif (中略)        end バリデーションが作動するのは.saveされたとき!ということを学びました、、!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails enumの使い方

enumとは enumは列挙型でカラム(列)で文字列を順番に出力していくものです。 そしてそれぞれに数字を割り当てて意味を持たせます。 例えばある処理をして処理の流れを表現できます。 0が「未入力」、1が「入力中」、2が「処理中」、3が「処理済」 というように 処理の流れを表現できます。 ⚫︎補足 Rubyにはenumはなくrails 4.1以降から導入されたみたいです。 enumを使うと? Enumを使うことにより数値で修正が簡単になり、module側で変更するだけで 全体に変更が反映されます。 意味を持った文字を入れて、DB は数字で管理し保存しておくことができます。 そして値を決めることによって不正なアクセスが入らないようにします。 データベースの中身が見れるschema.rbで見てみましょう。 schema.rb ActiveRecord::Schema.define(version: 2021_01_17_095549) do create_table “staffs", fcharset: "utf8", force: :cascade do |t| t.string “name” t.string “job” t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false end これをenumにすると app/models/staff.rb class Staff < ApplicationRecord enum name: { Taro: 0, Jiro: 1, Saburo: 2, Yonro: 3 } みたいになります。 nameカラム(integer型)の中の4人の名前をそれぞれ紐づけます。 nameカラムにtaroを入れたら0がデータとして入ります。 シンボルと文字列で定義 enumはシンボルと文字列で定義ができます。 class Student < ApplicationRecord # シンボルで定義 enum school_class: [ :A, :B, :C, :D ] # 文字列で定義 enum blood_type: [ "A", "B", “C”, “D” ] end Rubyの配列と同じで添字と定数が紐付きます。 Student.create(school_class: ‘A’) データベースに0が保存される Student.create(school_class: ‘B’) データベースに1が保存される 型による使い方 integer,boolean,型による使い方、 確認、検索、更新メソッド など他にもいろいろな使い方があります。 この資料から確認してみてください。 https://pikawaka.com/rails/enum ⚫︎参考資料 https://pikawaka.com/rails/enum https://techacademy.jp/magazine/31545 https://web-camp.io/magazine/archives/16862 https://qiita.com/kitsunecat/items/ddc13b95814650c4471e
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails enumの使い方

enumとは enumは列挙型でカラム(列)で文字列を順番に出力していくものです。 そしてそれぞれに数字を割り当てて意味を持たせます。 例えばある処理をして処理の流れを表現できます。 0が「未入力」、1が「入力中」、2が「処理中」、3が「処理済」 というように 処理の流れを表現できます。 ⚫︎補足 Rubyにはenumはなくrails 4.1以降から導入されたみたいです。 enumを使うと? Enumを使うことにより数値で修正が簡単になり、module側で変更するだけで 全体に変更が反映されます。 意味を持った文字を入れて、DB は数字で管理し保存しておくことができます。 そして値を決めることによって不正なアクセスが入らないようにします。 データベースの中身が見れるschema.rbで見てみましょう。 schema.rb ActiveRecord::Schema.define(version: 2021_01_17_095549) do create_table “staffs", fcharset: "utf8", force: :cascade do |t| t.string “name” t.string “job” t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false end これをenumにすると app/models/staff.rb class Staff < ApplicationRecord enum name: { Taro: 0, Jiro: 1, Saburo: 2, Yonro: 3 } みたいになります。 nameカラム(integer型)の中の4人の名前をそれぞれ紐づけます。 nameカラムにtaroを入れたら0がデータとして入ります。 シンボルと文字列で定義 enumはシンボルと文字列で定義ができます。 class Student < ApplicationRecord # シンボルで定義 enum school_class: [ :A, :B, :C, :D ] # 文字列で定義 enum blood_type: [ "A", "B", “C”, “D” ] end Rubyの配列と同じで添字と定数が紐付きます。 Student.create(school_class: ‘A’) データベースに0が保存される Student.create(school_class: ‘B’) データベースに1が保存される 型による使い方 integer,boolean,型による使い方、 確認、検索、更新メソッド など他にもいろいろな使い方があります。 この資料から確認してみてください。 https://pikawaka.com/rails/enum ⚫︎参考資料 https://pikawaka.com/rails/enum https://techacademy.jp/magazine/31545 https://web-camp.io/magazine/archives/16862 https://qiita.com/kitsunecat/items/ddc13b95814650c4471e
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

rails assets:precompile RAILS_ENV=productionでエラー

本番環境へのデプロイ時に rails assets:precompile RAILS_ENV=production を実行すると、 Compiling... Compilation failed: Though the "loose" option was set to "false" in your @babel/preset-env config, it will not be used for @babel/plugin-proposal-private-property-in-object since the "loose" mode option was set to "true" for @babel/plugin-proposal-class-properties. The "loose" option must be the same for @babel/plugin-proposal-class-properties, @babel/plugin-proposal-private-methods and @babel/plugin-proposal-private-property-in-object (when they are enabled): you can silence this warning by explicitly adding ["@babel/plugin-proposal-private-property-in-object", { "loose": true }] to the "plugins" section of your Babel config. ModuleNotFoundError: Module not found: Error: Can't resolve '/public/assets/images/coffee_gif.gif' in '/var/www/coffee_passport/app/javascript/packs/components/static_pages' at factory.create (/var/www/coffee_passport/node_modules/webpack/lib/Compilation.js:925:10) at factory (/var/www/coffee_passport/node_modules/webpack/lib/NormalModuleFactory.js:401:22) at resolver (/var/www/coffee_passport/node_modules/webpack/lib/NormalModuleFactory.js:130:21) at asyncLib.parallel (/var/www/coffee_passport/node_modules/webpack/lib/NormalModuleFactory.js:224:22) at /var/www/coffee_passport/node_modules/neo-async/async.js:2830:7 at /var/www/coffee_passport/node_modules/neo-async/async.js:6877:13 resolve '/public/assets/images/coffee_gif.gif' in '/var/www/coffee_passport/app/javascript/packs/components/static_pages' using description file: /var/www/coffee_passport/package.json (relative path: ./app/javascript/packs/components/static_pages) Field 'browser' doesn't contain a valid alias configuration No description file found no extension Field 'browser' doesn't contain a valid alias configuration /public/assets/images/coffee_gif.gif doesn't exist Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif.svg doesn't exist Though the "loose" option was set to "false" in your @babel/preset-env config, it will not be used for @babel/plugin-proposal-private-methods since the "loose" mode option was set to "true" for @babel/plugin-proposal-private-property-in-object. The "loose" option must be the same for @babel/plugin-proposal-class-properties, @babel/plugin-proposal-private-methods and @babel/plugin-proposal-private-property-in-object (when they are enabled): you can silence this warning by explicitly adding ["@babel/plugin-proposal-private-methods", { "loose": true }] to the "plugins" section of your Babel config. とエラーがでた。 デプロイするときに rails assets:precompile RAILS_ENV=production を実行時に以上のようなエラーがでた。。。 babel/preset-env 設定で "loose" オプションが "false" に設定されていますが、@babel/plugin-proposal-class-properties の "loose" モードオプションが "true" に設定されているため、@babel/plugin-proposal-private-property-in-object では使用されません。 loose" オプションは、@babel/plugin-proposal-class-properties、@babel/plugin-proposal-private-methods、および @babel/plugin-proposal-property-in-object (これらが有効な場合) で同じでなければなりません。 ["@babel/plugin-proposal-property-in-object", { "loose": true }] を「プラグイン」セクションに明示的に追加することで、この警告を消すことができます。 をBabel設定の「plugins」セクションに追加してください。 ちょっと何言ってるか分からない(サンド冨澤風) var/www/coffee_passport/app/javascript/packs/components/static_pages' の '/public/assets/images/coffee_gif.gif' を解決します。 記述ファイルを使用しています。/var/www/coffee_passport/package.json (相対パス: ./app/javascript/packs/components/static_pages) フィールド 'browser' に有効なエイリアス構成が含まれていません。 記述ファイルがありません 拡張子がない 多分問題はこっちなのかな。。。 一旦こっちの問題を解決したいと思います。 [ec2-user@ip-10-0-10-10 coffee_passport]$ vi package.json を実行して package.json "name": "coffee_passport", "private": true, "dependencies": { "@rails/actioncable": "^6.0.0-alpha", "@rails/activestorage": "^6.0.0-alpha", "@rails/ujs": "^6.0.0-alpha", "@rails/webpacker": "4.3.0", "axios": "^0.21.1", "rails-ujs": "^5.2.6", "turbolinks": "^5.2.0", "vue": "^2.6.12", "vue-axios": "^3.2.4", "vue-carousel": "^0.18.0", "vue-eslint-parser": "^7.6.0", "vue-js-modal": "^2.0.1", "vue-loader": "^15.9.6", "vue-router": "^3.5.1", "vue-template-compiler": "^2.6.12", "vue-youtube": "^1.4.0", "vuex": "^3.6.2" }, "version": "0.1.0", "devDependencies": { "@webpack-cli/serve": "^1.5.2", "webpack-dev-server": "^3.11.2" } } わからないけど、vueファイルに色々記述して、画像をvueファイルのほうで読み込むために public/assets/images配下に画像を設置してたので、 上手くいかなかった的な? production.rbで設定が必要な感じ?? そもそもなぜpublic/assets/images配下に画像を設置してたのかというと、app/assets配下の画像をvueファイルのほうで読み込もうとするとめんどくさかったから。。。 とのことですのでconfig/environments/production.rb に以上の記述をした。 したら、 [ec2-user@ip-10-0-10-10 coffee_passport]$ rails assets:precompile RAILS_ENV=production yarn install v1.22.5 warning package-lock.json found. Your project contains lock files generated by tools other than Yarn. It is advised not to mix package managers in order to avoid resolution inconsistencies caused by unsynchronized lock files. To clear this warning, remove package-lock.json. [1/4] Resolving packages... [2/4] Fetching packages... info fsevents@2.1.3: The platform "linux" is incompatible with this module. info "fsevents@2.1.3" is an optional dependency and failed compatibility check. Excluding it from installation. info fsevents@1.2.13: The platform "linux" is incompatible with this module. info "fsevents@1.2.13" is an optional dependency and failed compatibility check. Excluding it from installation. [3/4] Linking dependencies... warning " > vue-eslint-parser@7.6.0" has unmet peer dependency "eslint@>=5.0.0". warning " > vue-loader@15.9.6" has unmet peer dependency "css-loader@*". warning " > vue-loader@15.9.6" has unmet peer dependency "webpack@^3.0.0 || ^4.1.0 || ^5.0.0-0". warning " > @webpack-cli/serve@1.5.2" has unmet peer dependency "webpack-cli@4.x.x". warning " > webpack-dev-server@3.11.2" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0". warning "webpack-dev-server > webpack-dev-middleware@3.7.3" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0". [4/4] Building fresh packages... Done in 4.78s. yarn install v1.22.5 warning package-lock.json found. Your project contains lock files generated by tools other than Yarn. It is advised not to mix package managers in order to avoid resolution inconsistencies caused by unsynchronized lock files. To clear this warning, remove package-lock.json. [1/4] Resolving packages... [2/4] Fetching packages... info fsevents@2.1.3: The platform "linux" is incompatible with this module. info "fsevents@2.1.3" is an optional dependency and failed compatibility check. Excluding it from installation. info fsevents@1.2.13: The platform "linux" is incompatible with this module. info "fsevents@1.2.13" is an optional dependency and failed compatibility check. Excluding it from installation. [3/4] Linking dependencies... warning " > vue-eslint-parser@7.6.0" has unmet peer dependency "eslint@>=5.0.0". warning " > vue-loader@15.9.6" has unmet peer dependency "css-loader@*". warning " > vue-loader@15.9.6" has unmet peer dependency "webpack@^3.0.0 || ^4.1.0 || ^5.0.0-0". warning " > @webpack-cli/serve@1.5.2" has unmet peer dependency "webpack-cli@4.x.x". warning " > webpack-dev-server@3.11.2" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0". warning "webpack-dev-server > webpack-dev-middleware@3.7.3" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0". [4/4] Building fresh packages... Done in 4.22s. Everything's up-to-date. Nothing to do こんなかんじでエラーは表示されなくなった!! だがしかし、、、 Webpacker::Manifest::MissingEntryError in Sessions#new Showing /var/www/coffee_passport/app/views/sessions/new.html.erb where line #3 raised: Webpacker can't find app_explain in /var/www/coffee_passport/public/packs/manifest.json. Possible causes: 1. You want to set webpacker.yml value of compile to true for your environment unless you are using the webpack -w or the webpack-dev-server. 2. webpack has not yet re-run to reflect updates. 3. You have misconfigured Webpacker's config/webpacker.yml file. 4. Your webpack configuration is not creating a manifest. Your manifest contains: { "application.js": "/packs/js/application-3538e0dca107d3630558.js", "application.js.map": "/packs/js/application-3538e0dca107d3630558.js.map", "components/Home.js": "/packs/js/components/Home-ad21ec7dc038d47a3482.js", "components/Home.js.map": "/packs/js/components/Home-ad21ec7dc038d47a3482.js.map", "components/about_coffee_passport.js": "/packs/js/components/about_coffee_passport-912426bccd01134649c6.js", "components/about_coffee_passport.js.map": "/packs/js/components/about_coffee_passport-912426bccd01134649c6.js.map", "components/contact.js": "/packs/js/components/contact-b1ef171175665ddc89b8.js", "components/contact.js.map": "/packs/js/components/contact-b1ef171175665ddc89b8.js.map", "components/drinks/show.js": "/packs/js/components/drinks/show-92ef61f08e34c84f0e6b.js", "components/drinks/show.js.map": "/packs/js/components/drinks/show-92ef61f08e34c84f0e6b.js.map", "components/footer.js": "/packs/js/components/footer-ce242222576e7516708a.js", "components/footer.js.map": "/packs/js/components/footer-ce242222576e7516708a.js.map", "components/like/likeButton.js": "/packs/js/components/like/likeButton-e09e38a35194597b646d.js", "components/like/likeButton.js.map": "/packs/js/components/like/likeButton-e09e38a35194597b646d.js.map", "components/search.js": "/packs/js/components/search-3a946d78542c0511990c.js", "components/search.js.map": "/packs/js/components/search-3a946d78542c0511990c.js.map", "entrypoints": { "application": { "js": [ "/packs/js/application-3538e0dca107d3630558.j 本番環境でこのようなエラーに、、、 rails assets:precompile RAILS_ENV=production がうまくいかなかったのかな。。。 app/javascript/packs/app_explain.js import Vue from 'vue' import appExplain from '../packs/components/static_pages/appExplain.vue' document.addEventListener('DOMContentLoaded', () => { var app = new Vue({ el: '#app-explain', components: { "app_explain": appExplain }, render: h => h(appExplain) }).$mount() //document.body.appendChild(appExplain.$el) }) app/javascript/components/static_pages/appExplain.vue <template> <div> <div class="top-explain"> <div class="explain-wrapper"> <img class="" :src="require('/public/assets/images/coffee_gif.gif')"> <div class="explain-wrapper-title"> <h3 class="explain-wrapper-title" >Von Voyage!</h3> <p class="">Coffee Passportとはあなたが出会ったコーヒーの記録を共有できるサービスです</p> </div> </div> <div class="explain-wrapper"> <ruby> <h3 class="explain-wrapper-title">出会ったコーヒーをシェアしよう</h3> <rt class="explain-wrapper-title-en">share your favorite coffee</rt> </ruby> <p class="explain-wrapper-info"> 出会ったコーヒーの感想を記録して共有しましょう。 その投稿が、素敵なコーヒーを求めてる誰かのヒントになるでしょう。 </p> <img class="explain-post-img" :src="require('/public/assets/images/post.png')" > </div> <div class="explain-wrapper"> <ruby> <h3 class="explain-wrapper-title">コーヒーを探す旅へ</h3> <rt class="explain-wrapper-title-en">vayage to find coffee</rt> </ruby> <p class="explain-wrapper-info"> お気に入りのコーヒーに出会いたいときは、検索してみましょう。 コーヒーの名前、コク、酸味、産地、加工法などで検索できます。 </p> </div> <div class="explain-wrapper"> <ruby> <h3 class="explain-wrapper-title">素敵なコーヒーがあなたの手元に</h3> <rt class="explain-wrapper-title-en">special coffee will come to your house</rt> </ruby> <p class="explain-wrapper-info"> コーヒーを家でも楽しみたいなら、素敵なコーヒーのラインナップを 取り揃えておりますので、ぜひお求めください。 </p> <!-- <video :src="require('/public/assets/images/buy.mp4')" autoplay muted> --> <carousel :per-page="1" :autoplay=true :loop=true :autoplayTimeout=1500> <slide> <img class="sold-item-explain" :src="require('/public/assets/images/sold_item1.png')"> </slide> <slide> <img class="sold-item-explain" :src="require('/public/assets/images/sold_item2.png')"> </slide> <slide> <img class="sold-item-explain" :src="require('/public/assets/images/sold_item3.png')"> </slide> <slide> <img class="sold-item-explain" :src="require('/public/assets/images/sold_item4.png')"> </slide> </carousel> </div> <div class="explain-wrapper"> <ruby> <h3 class="explain-wrapper-title">いいねやコメントで盛り上がろう</h3> <rt class="explain-wrapper-title-en">smash that like button and comment </rt> </ruby> <p class="explain-wrapper-info"> 気に入った投稿に「いいね」を押したり、コメントして 一杯のコーヒーが生み出すコミュニティに参加しましょう。 </p> </div> </div> </div> </template> <script> import { Carousel, Slide } from 'vue-carousel'; export default { components: { Carousel, Slide } } </script> app/views/sessions/new.html.erb <div id="app-explain"> <%= javascript_pack_tag 'app_explain' %> </div> このような感じで自作vueファイルをerbに表示させていました。。。 まぁ恐らくだが、production.rb の production.rb config.serve_static_assets = true config.serve_static_files = true config.public_file_server.enabled = true ここが問題な気がする。。。 しかしこの部分を削除したら、さっきのようなエラーがでるが、、。。。 本番環境でpublic以下の画像を参照するときは色々設定が必要じゃないか説。 この説が無理だったら、なんとかvueファイルのほうで app/asset/images以下の画像を読み込めるように設定します。 ってことで production.rb config.public_file_server.enabled = true だけを記述。 rails assets:precompile RAILS_ENV=production は問題なし。。 だけどエラー変わらず。 production.rb の設定を元に戻して、 [ec2-user@ip-10-0-10-10 coffee_passport]$ rails assets:precompile RAILS_ENV=production yarn install v1.22.5 warning package-lock.json found. Your project contains lock files generated by tools other than Yarn. It is advised not to mix package managers in order to avoid resolution inconsistencies caused by unsynchronized lock files. To clear this warning, remove package-lock.json. [1/4] Resolving packages... [2/4] Fetching packages... info fsevents@2.1.3: The platform "linux" is incompatible with this module. info "fsevents@2.1.3" is an optional dependency and failed compatibility check. Excluding it from installation. info fsevents@1.2.13: The platform "linux" is incompatible with this module. info "fsevents@1.2.13" is an optional dependency and failed compatibility check. Excluding it from installation. [3/4] Linking dependencies... warning " > vue-eslint-parser@7.6.0" has unmet peer dependency "eslint@>=5.0.0". warning " > vue-loader@15.9.6" has unmet peer dependency "css-loader@*". warning " > vue-loader@15.9.6" has unmet peer dependency "webpack@^3.0.0 || ^4.1.0 || ^5.0.0-0". warning " > @webpack-cli/serve@1.5.2" has unmet peer dependency "webpack-cli@4.x.x". warning " > webpack-dev-server@3.11.2" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0". warning "webpack-dev-server > webpack-dev-middleware@3.7.3" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0". [4/4] Building fresh packages... Done in 4.53s. yarn install v1.22.5 warning package-lock.json found. Your project contains lock files generated by tools other than Yarn. It is advised not to mix package managers in order to avoid resolution inconsistencies caused by unsynchronized lock files. To clear this warning, remove package-lock.json. [1/4] Resolving packages... [2/4] Fetching packages... info fsevents@2.1.3: The platform "linux" is incompatible with this module. info "fsevents@2.1.3" is an optional dependency and failed compatibility check. Excluding it from installation. info fsevents@1.2.13: The platform "linux" is incompatible with this module. info "fsevents@1.2.13" is an optional dependency and failed compatibility check. Excluding it from installation. [3/4] Linking dependencies... warning " > vue-eslint-parser@7.6.0" has unmet peer dependency "eslint@>=5.0.0". warning " > vue-loader@15.9.6" has unmet peer dependency "css-loader@*". warning " > vue-loader@15.9.6" has unmet peer dependency "webpack@^3.0.0 || ^4.1.0 || ^5.0.0-0". warning " > @webpack-cli/serve@1.5.2" has unmet peer dependency "webpack-cli@4.x.x". warning " > webpack-dev-server@3.11.2" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0". warning "webpack-dev-server > webpack-dev-middleware@3.7.3" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0". [4/4] Building fresh packages... Done in 4.30s. Everything's up-to-date. Nothing to do と、エラーが起きなかった。。。なんで。。。 もちろんgit pull origin masterも実行して、ちゃんと変更を反映させてる。。。。 [ec2-user@ip-10-0-10-10 environments]$ vim production.rb production.rb Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. host = 'http://18.179.97.156' Rails.application.routes.default_url_options = {host: host,protocol: 'http'} config.action_mailer.raise_delivery_errors = true config.action_mailer.delivery_method = :smtp ActionMailer::Base.smtp_settings = { #enable: true, address: 'smtp.sendgrid.net', port: 587, domain: 'gmail.com', authentication: :plain, user_name: "apikey", password: ENV['SENDGRID_PASSWORD'], enable_starttls_auto: true #openssl_verify_mode: 'peer', #ssl: 465, #tls: false } # publicディレクトリ以下に置かれたあらゆるアセットは # アプリケーション、またはWebサーバーによって静的な # ファイルとして取り扱われます。 # Code is not reloaded between requests. config.cache_classes = true # Eager load code on boot. This eager loads most of Rails and # your application in memory, allowing both threaded web servers # and those relying on copy on write to perform better. # Rake tasks automatically ignore this option for performance. config.eager_load = true # Full error reports are disabled and caching is turned on. config.consider_all_requests_local = true config.action_controller.perform_caching = true # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). config.require_master_key = true # マスターキーの指定もれを防ぐために必要 # Disable serving static files from the `/public` folder by default since # Apache or NGINX already handles this. しっかりと、反映できてる。。。 んーー、なぜ以前の ModuleNotFoundError: Module not found: Error: Can't resolve '/public/assets/images/coffee_gif.gif' in '/var/www/coffee_passport/app/javascript/packs/components/static_pages' at factory.create (/var/www/coffee_passport/node_modules/webpack/lib/Compilation.js:925:10) at factory (/var/www/coffee_passport/node_modules/webpack/lib/NormalModuleFactory.js:401:22) at resolver (/var/www/coffee_passport/node_modules/webpack/lib/NormalModuleFactory.js:130:21) at asyncLib.parallel (/var/www/coffee_passport/node_modules/webpack/lib/NormalModuleFactory.js:224:22) at /var/www/coffee_passport/node_modules/neo-async/async.js:2830:7 at /var/www/coffee_passport/node_modules/neo-async/async.js:6877:13 が rails assets:precompile RAILS_ENV=production 時に起きないのかが気になる。。 ちなみに本番環境の app.vue <router-link to="/user" @click.native="getUserId(drink.user_id)"> も機能してない。。。 ユーザーの詳細ページをrouter-linkで表示させたいが、全く反応しない。。。。 一旦git reset productionを弄る前の状態に戻す。一応。 git reset --hard nsdjfnsff みたいな感じ、 git push origin +master  をして完全に戻ったが 本番環境で git pull origin masterをしても Already up to date. となって変更が反映されていない。。 色々すったもんだあったあとに、 本番環境で rails assets:precompile RAILS_ENV=production を実行したら、 Compiling... Compilation failed: Though the "loose" option was set to "false" in your @babel/preset-env config, it will not be used for @babel/plugin-proposal-private-property-in-object since the "loose" mode option was set to "true" for @babel/plugin-proposal-class-properties. The "loose" option must be the same for @babel/plugin-proposal-class-properties, @babel/plugin-proposal-private-methods and @babel/plugin-proposal-private-property-in-object (when they are enabled): you can silence this warning by explicitly adding ["@babel/plugin-proposal-private-property-in-object", { "loose": true }] to the "plugins" section of your Babel config. Though the "loose" option was set to "false" in your @babel/preset-env config, it will not be used for @babel/plugin-proposal-private-methods since the "loose" mode option was set to "true" for @babel/plugin-proposal-private-property-in-object. The "loose" option must be the same for @babel/plugin-proposal-class-properties, @babel/plugin-proposal-private-methods and @babel/plugin-proposal-private-property-in-object (when they are enabled): you can silence this warning by explicitly adding ["@babel/plugin-proposal-private-methods", { "loose": true }] to the "plugins" section of your Babel config. ModuleNotFoundError: Module not found: Error: Can't resolve '/public/assets/images/coffee_gif.gif' in '/var/www/coffee_passport/app/javascript/packs/components/static_pages' at factory.create (/var/www/coffee_passport/node_modules/webpack/lib/Compilation.js:925:10) at factory (/var/www/coffee_passport/node_modules/webpack/lib/NormalModuleFactory.js:401:22) at resolver (/var/www/coffee_passport/node_modules/webpack/lib/NormalModuleFactory.js:130:21) at asyncLib.parallel (/var/www/coffee_passport/node_modules/webpack/lib/NormalModuleFactory.js:224:22) at /var/www/coffee_passport/node_modules/neo-async/async.js:2830:7 at /var/www/coffee_passport/node_modules/neo-async/async.js:6877:13 at normalResolver.resolve (/var/www/coffee_passport/node_modules/webpack/lib/NormalModuleFactory.js:214:25) at doResolve (/var/www/coffee_passport/node_modules/enhanced-resolve/lib/Resolver.js:213:14) at hook.callAsync (/var/www/coffee_passport/node_modules/enhanced-resolve/lib/Resolver.js:285:5) at _fn0 (eval at create (/var/www/coffee_passport/node_modules/tapable/lib/HookCodeFactory.js:33:10), :15:1) at resolver.doResolve (/var/www/coffee_passport/node_modules/enhanced-resolve/lib/UnsafeCachePlugin.js:44:7) at hook.callAsync (/var/www/coffee_passport/node_modules/enhanced-resolve/lib/Resolver.js:285:5) at _fn0 (eval at create (/var/www/coffee_passport/node_modules/tapable/lib/HookCodeFactory.js:33:10), :15:1) at hook.callAsync (/var/www/coffee_passport/node_modules/enhanced-resolve/lib/Resolver.js:285:5) at _fn0 (eval at create (/var/www/coffee_passport/node_modules/tapable/lib/HookCodeFactory.js:33:10), :27:1) at resolver.doResolve (/var/www/coffee_passport/node_modules/enhanced-resolve/lib/DescriptionFilePlugin.js:67:43) at hook.callAsync (/var/www/coffee_passport/node_modules/enhanced-resolve/lib/Resolver.js:285:5) at _fn44 (eval at create (/var/www/coffee_passport/node_modules/tapable/lib/HookCodeFactory.js:33:10), :16:1) at resolver.doResolve._ignoreErrors (/var/www/coffee_passport/node_modules/enhanced-resolve/lib/RootPlugin.js:60:9) at hook.callAsync (/var/www/coffee_passport/node_modules/enhanced-resolve/lib/Resolver.js:285:5) at _fn0 (eval at create (/var/www/coffee_passport/node_modules/tapable/lib/HookCodeFactory.js:33:10), :27:1) at resolver.doResolve (/var/www/coffee_passport/node_modules/enhanced-resolve/lib/DescriptionFilePlugin.js:67:43) at hook.callAsync (/var/www/coffee_passport/node_modules/enhanced-resolve/lib/Resolver.js:285:5) at _fn1 (eval at create (/var/www/coffee_passport/node_modules/tapable/lib/HookCodeFactory.js:33:10), :16:1) at hook.callAsync (/var/www/coffee_passport/node_modules/enhanced-resolve/lib/Resolver.js:285:5) at _fn0 (eval at create (/var/www/coffee_passport/node_modules/tapable/lib/HookCodeFactory.js:33:10), :15:1) at fs.stat (/var/www/coffee_passport/node_modules/enhanced-resolve/lib/DirectoryExistsPlugin.js:27:15) at process.nextTick (/var/www/coffee_passport/node_modules/enhanced-resolve/lib/CachedInputFileSystem.js:85:15) at process._tickCallback (internal/process/next_tick.js:61:11) resolve '/public/assets/images/coffee_gif.gif' in '/var/www/coffee_passport/app/javascript/packs/components/static_pages' using description file: /var/www/coffee_passport/package.json (relative path: ./app/javascript/packs/components/static_pages) Field 'browser' doesn't contain a valid alias configuration No description file found no extension Field 'browser' doesn't contain a valid alias configuration /public/assets/images/coffee_gif.gif doesn't exist .vue Field 'browser' doesn't contain a valid alias configuration /public/assets/images/coffee_gif.gif.vue doesn't exist .mjs Field 'browser' doesn't contain a valid alias configuration /public/assets/images/coffee_gif.gif.mjs doesn't exist .js Field 'browser' doesn't contain a valid alias configuration /public/assets/images/coffee_gif.gif.js doesn't exist .sass Field 'browser' doesn't contain a valid alias configuration /public/assets/images/coffee_gif.gif.sass doesn't exist .scss Field 'browser' doesn't contain a valid alias configuration /public/assets/images/coffee_gif.gif.scss doesn't exist .css Field 'browser' doesn't contain a valid alias configuration /public/assets/images/coffee_gif.gif.css doesn't exist .module.sass Field 'browser' doesn't contain a valid alias configuration /public/assets/images/coffee_gif.gif.module.sass doesn't exist .module.scss Field 'browser' doesn't contain a valid alias configuration /public/assets/images/coffee_gif.gif.module.scss doesn't exist .module.css Field 'browser' doesn't contain a valid alias configuration /public/assets/images/coffee_gif.gif.module.css doesn't exist .png Field 'browser' doesn't contain a valid alias configuration /public/assets/images/coffee_gif.gif.png doesn't exist .svg Field 'browser' doesn't contain a valid alias configuration /public/assets/images/coffee_gif.gif.svg doesn't exist .gif Field 'browser' doesn't contain a valid alias configuration /public/assets/images/coffee_gif.gif.gif doesn't exist .jpeg Field 'browser' doesn't contain a valid alias configuration /public/assets/images/coffee_gif.gif.jpeg doesn't exist .jpg Field 'browser' doesn't contain a valid alias configuration /public/assets/images/coffee_gif.gif.jpg doesn't exist as directory /public/assets/images/coffee_gif.gif doesn't exist root path /var/www/coffee_passport using description file: /var/www/coffee_passport/package.json (relative path: ./public/assets/images/coffee_gif.gif) no extension Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif doesn't exist .vue Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif.vue doesn't exist .mjs Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif.mjs doesn't exist .js Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif.js doesn't exist .sass Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif.sass doesn't exist .scss Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif.scss doesn't exist .css Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif.css doesn't exist .module.sass Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif.module.sass doesn't exist .module.scss Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif.module.scss doesn't exist .module.css Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif.module.css doesn't exist .png Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif.png doesn't exist .svg Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif.svg doesn't exist .gif Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif.gif doesn't exist .jpeg Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif.jpeg doesn't exist .jpg Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif.jpg doesn't exist as directory /var/www/coffee_passport/public/assets/images/coffee_gif.gif doesn't exist 本番環境のアプリのブラウザでも Webpacker::Manifest::MissingEntryError in Sessions#new Showing /var/www/coffee_passport/app/views/sessions/new.html.erb where line #3 raised: Webpacker can't find app_explain in /var/www/coffee_passport/public/packs/manifest.json. Possible causes: 1. You want to set webpacker.yml value of compile to true for your environment unless you are using the webpack -w or the webpack-dev-server. 2. webpack has not yet re-run to reflect updates. 3. You have misconfigured Webpacker's config/webpacker.yml file. 4. Your webpack configuration is not creating a manifest. Your manifest contains: { "application.js": "/packs/js/application-3538e0dca107d3630558.js", "application.js.map": "/packs/js/application-3538e0dca107d3630558.js.map", "components/Home.js": "/packs/js/components/Home-ad21ec7dc038d47a3482.js", "components/Home.js.map": "/packs/js/components/Home-ad21ec7dc038d47a3482.js.map", "components/about_coffee_passport.js": "/packs/js/components/about_coffee_passport-912426bccd01134649c6.js", "components/about_coffee_passport.js.map": "/packs/js/components/about_coffee_passport-912426bccd01134649c6.js.map", "components/contact.js": "/packs/js/components/contact-b1ef171175665ddc89b8.js", "components/contact.js.map": "/packs/js/components/contact-b1ef171175665ddc89b8.js.map", "components/drinks/show.js": "/packs/js/components/drinks/show-92ef61f08e34c84f0e6b.js", "components/drinks/show.js.map": "/packs/js/components/drinks/show-92ef61f08e34c84f0e6b.js.map", "components/footer.js": "/packs/js/components/footer-ce242222576e7516708a.js", "components/footer.js.map": "/packs/js/components/footer-ce242222576e7516708a.js.map", "components/like/likeButton.js": "/packs/js/components/like/likeButton-e09e38a35194597b646d.js", "components/like/likeButton.js.map": "/packs/js/components/like/likeButton-e09e38a35194597b646d.js.map", "components/search.js": "/packs/js/components/search-3a946d78542c0511990c.js", "components/search.js.map": "/packs/js/components/search-3a946d78542c0511990c.js.map", "entrypoints": { "application": { "js": [ "/packs/js/application-3538e0dca107d3630558.js" ], "js.map": [ "/packs/js/application-3538e0dca107d3630558.js.map" ] }, "components/about_coffee_passport": { "js": [ "/packs/js/components/about_coffee_passport-912426bccd01134649c6.js" ], "js.map": [ "/packs/js/components/about_coffee_passport-912426bccd01134649c6.js.map" ] }, "components/contact": { "js": [ "/packs/js/components/contact-b1ef171175665ddc89b8.js" ], "js.map": [ "/packs/js/components/contact-b1ef171175665ddc89b8.js.map" ] }, "components/drinks/show": { "js": [ "/packs/js/components/drinks/show-92ef61f08e34c84f0e6b.js" ], "js.map": [ "/packs/js/components/drinks/show-92ef61f08e34c84f0e6b.js.map" ] }, "components/footer": { "js": [ "/packs/js/components/footer-ce242222576e7516708a.js" ], "js.map": [ "/packs/js/components/footer-ce242222576e7516708a.js.map" ] }, "components/Home": { "js": [ "/packs/js/components/Home-ad21ec7dc038d47a3482.js" ], "js.map": [ "/packs/js/components/Home-ad21ec7dc038d47a3482.js.map" ] }, "components/like/likeButton": { "js": [ "/packs/js/components/like/likeButton-e09e38a35194597b646d.js" ], "js.map": [ "/packs/js/components/like/likeButton-e09e38a35194597b646d.js.map" ] }, "components/search": { "js": [ "/packs/js/components/search-3a946d78542c0511990c.js" ], "js.map": [ "/packs/js/components/search-3a946d78542c0511990c.js.map" ] }, "footer": { "js": [ "/packs/js/footer-b04804ecee29760096bf.js" ], "js.map": [ "/packs/js/footer-b04804ecee29760096bf.js.map" ] }, "hello_vue": { "js": [ "/packs/js/hello_vue-58d59e5ab7981f9e89a0.js" ], "js.map": [ "/packs/js/hello_vue-58d59e5ab7981f9e89a0.js.map" ] }, "preview": { "js": [ "/packs/js/preview-f0475e1207aa006fdf05.js" ], "js.map": [ "/packs/js/preview-f0475e1207aa006fdf05.js.map" ] }, "router/router": { "js": [ "/packs/js/router/router-3ad8b6d61d35ff908058.js" ], "js.map": [ "/packs/js/router/router-3ad8b6d61d35ff908058.js.map" ] }, "tag": { "js": [ "/packs/js/tag-d8add757194386926360.js" ], "js.map": [ "/packs/js/tag-d8add757194386926360.js.map" ] } }, "footer.js": "/packs/js/footer-b04804ecee29760096bf.js", "footer.js.map": "/packs/js/footer-b04804ecee29760096bf.js.map", "hello_vue.js": "/packs/js/hello_vue-58d59e5ab7981f9e89a0.js", "hello_vue.js.map": "/packs/js/hello_vue-58d59e5ab7981f9e89a0.js.map", "preview.js": "/packs/js/preview-f0475e1207aa006fdf05.js", "preview.js.map": "/packs/js/preview-f0475e1207aa006fdf05.js.map", "router/router.js": "/packs/js/router/router-3ad8b6d61d35ff908058.js", "router/router.js.map": "/packs/js/router/router-3ad8b6d61d35ff908058.js.map", "tag.js": "/packs/js/tag-d8add757194386926360.js", "tag.js.map": "/packs/js/tag-d8add757194386926360.js.map" } Extracted source (around line #3): 1 2 3 4 5 6 こんなかんじのエラーが表示されてる。 [ec2-user@ip-10-0-10-10 coffee_passport]$ rails assets:precompile RAILS_ENV=production yarn install v1.22.5 warning package-lock.json found. Your project contains lock files generated by tools other than Yarn. It is advised not to mix package managers in order to avoid resolution inconsistencies caused by unsynchronized lock files. To clear this warning, remove package-lock.json. [1/4] Resolving packages... [2/4] Fetching packages... info fsevents@2.1.3: The platform "linux" is incompatible with this module. info "fsevents@2.1.3" is an optional dependency and failed compatibility check. Excluding it from installation. info fsevents@1.2.13: The platform "linux" is incompatible with this module. info "fsevents@1.2.13" is an optional dependency and failed compatibility check. Excluding it from installation. [3/4] Linking dependencies... warning " > vue-eslint-parser@7.6.0" has unmet peer dependency "eslint@>=5.0.0". warning " > vue-loader@15.9.6" has unmet peer dependency "css-loader@*". warning " > vue-loader@15.9.6" has unmet peer dependency "webpack@^3.0.0 || ^4.1.0 || ^5.0.0-0". warning " > @webpack-cli/serve@1.5.2" has unmet peer dependency "webpack-cli@4.x.x". warning " > webpack-dev-server@3.11.2" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0". warning "webpack-dev-server > webpack-dev-middleware@3.7.3" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0". [4/4] Building fresh packages... Done in 4.61s. yarn install v1.22.5 warning package-lock.json found. Your project contains lock files generated by tools other than Yarn. It is advised not to mix package managers in order to avoid resolution inconsistencies caused by unsynchronized lock files. To clear this warning, remove package-lock.json. [1/4] Resolving packages... [2/4] Fetching packages... info fsevents@2.1.3: The platform "linux" is incompatible with this module. info "fsevents@2.1.3" is an optional dependency and failed compatibility check. Excluding it from installation. info fsevents@1.2.13: The platform "linux" is incompatible with this module. info "fsevents@1.2.13" is an optional dependency and failed compatibility check. Excluding it from installation. [3/4] Linking dependencies... warning " > vue-eslint-parser@7.6.0" has unmet peer dependency "eslint@>=5.0.0". warning " > vue-loader@15.9.6" has unmet peer dependency "css-loader@*". warning " > vue-loader@15.9.6" has unmet peer dependency "webpack@^3.0.0 || ^4.1.0 || ^5.0.0-0". warning " > @webpack-cli/serve@1.5.2" has unmet peer dependency "webpack-cli@4.x.x". warning " > webpack-dev-server@3.11.2" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0". warning "webpack-dev-server > webpack-dev-middleware@3.7.3" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0". [4/4] Building fresh packages... Done in 4.19s. Compiling... Compilation failed: Though the "loose" option was set to "false" in your @babel/preset-env config, it will not be used for @babel/plugin-proposal-private-property-in-object since the "loose" mode option was set to "true" for @babel/plugin-proposal-class-properties. The "loose" option must be the same for @babel/plugin-proposal-class-properties, @babel/plugin-proposal-private-methods and @babel/plugin-proposal-private-property-in-object (when they are enabled): you can silence this warning by explicitly adding ["@babel/plugin-proposal-private-property-in-object", { "loose": true }] to the "plugins" section of your Babel config. Though the "loose" option was set to "false" in your @babel/preset-env config, it will not be used for @babel/plugin-proposal-private-methods since the "loose" mode option was set to "true" for @babel/plugin-proposal-private-property-in-object. The "loose" option must be the same for @babel/plugin-proposal-class-properties, @babel/plugin-proposal-private-methods and @babel/plugin-proposal-private-property-in-object (when they are enabled): you can silence this warning by explicitly adding ["@babel/plugin-proposal-private-methods", { "loose": true }] to the "plugins" section of your Babel config. ModuleNotFoundError: Module not found: Error: Can't resolve '/public/assets/images/coffee_gif.gif' in '/var/www/coffee_passport/app/javascript/packs/components/static_pages' at factory.create (/var/www/coffee_passport/node_modules/webpack/lib/Compilation.js:925:10) at factory (/var/www/coffee_passport/node_modules/webpack/lib/NormalModuleFactory.js:401:22) at resolver (/var/www/coffee_passport/node_modules/webpack/lib/NormalModuleFactory.js:130:21) at asyncLib.parallel (/var/www/coffee_passport/node_modules/webpack/lib/NormalModuleFactory.js:224:22) at /var/www/coffee_passport/node_modules/neo-async/async.js:2830:7 at /var/www/coffee_passport/node_modules/neo-async/async.js:6877:13 at normalResolver.resolve (/var/www/coffee_passport/node_modules/webpack/lib/NormalModuleFactory.js:214:25) at doResolve (/var/www/coffee_passport/node_modules/enhanced-resolve/lib/Resolver.js:213:14) at hook.callAsync (/var/www/coffee_passport/node_modules/enhanced-resolve/lib/Resolver.js:285:5) at _fn0 (eval at create (/var/www/coffee_passport/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:15:1) at resolver.doResolve (/var/www/coffee_passport/node_modules/enhanced-resolve/lib/UnsafeCachePlugin.js:44:7) at hook.callAsync (/var/www/coffee_passport/node_modules/enhanced-resolve/lib/Resolver.js:285:5) at _fn0 (eval at create (/var/www/coffee_passport/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:15:1) at hook.callAsync (/var/www/coffee_passport/node_modules/enhanced-resolve/lib/Resolver.js:285:5) at _fn0 (eval at create (/var/www/coffee_passport/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:27:1) at resolver.doResolve (/var/www/coffee_passport/node_modules/enhanced-resolve/lib/DescriptionFilePlugin.js:67:43) at hook.callAsync (/var/www/coffee_passport/node_modules/enhanced-resolve/lib/Resolver.js:285:5) at _fn44 (eval at create (/var/www/coffee_passport/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:16:1) at resolver.doResolve._ignoreErrors (/var/www/coffee_passport/node_modules/enhanced-resolve/lib/RootPlugin.js:60:9) at hook.callAsync (/var/www/coffee_passport/node_modules/enhanced-resolve/lib/Resolver.js:285:5) at _fn0 (eval at create (/var/www/coffee_passport/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:27:1) at resolver.doResolve (/var/www/coffee_passport/node_modules/enhanced-resolve/lib/DescriptionFilePlugin.js:67:43) at hook.callAsync (/var/www/coffee_passport/node_modules/enhanced-resolve/lib/Resolver.js:285:5) at _fn1 (eval at create (/var/www/coffee_passport/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:16:1) at hook.callAsync (/var/www/coffee_passport/node_modules/enhanced-resolve/lib/Resolver.js:285:5) at _fn0 (eval at create (/var/www/coffee_passport/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:15:1) at fs.stat (/var/www/coffee_passport/node_modules/enhanced-resolve/lib/DirectoryExistsPlugin.js:27:15) at process.nextTick (/var/www/coffee_passport/node_modules/enhanced-resolve/lib/CachedInputFileSystem.js:85:15) at process._tickCallback (internal/process/next_tick.js:61:11) resolve '/public/assets/images/coffee_gif.gif' in '/var/www/coffee_passport/app/javascript/packs/components/static_pages' using description file: /var/www/coffee_passport/package.json (relative path: ./app/javascript/packs/components/static_pages) Field 'browser' doesn't contain a valid alias configuration No description file found no extension Field 'browser' doesn't contain a valid alias configuration /public/assets/images/coffee_gif.gif doesn't exist .vue Field 'browser' doesn't contain a valid alias configuration /public/assets/images/coffee_gif.gif.vue doesn't exist .mjs Field 'browser' doesn't contain a valid alias configuration /public/assets/images/coffee_gif.gif.mjs doesn't exist .js Field 'browser' doesn't contain a valid alias configuration /public/assets/images/coffee_gif.gif.js doesn't exist .sass Field 'browser' doesn't contain a valid alias configuration /public/assets/images/coffee_gif.gif.sass doesn't exist .scss Field 'browser' doesn't contain a valid alias configuration /public/assets/images/coffee_gif.gif.scss doesn't exist .css Field 'browser' doesn't contain a valid alias configuration /public/assets/images/coffee_gif.gif.css doesn't exist .module.sass Field 'browser' doesn't contain a valid alias configuration /public/assets/images/coffee_gif.gif.module.sass doesn't exist .module.scss Field 'browser' doesn't contain a valid alias configuration /public/assets/images/coffee_gif.gif.module.scss doesn't exist .module.css Field 'browser' doesn't contain a valid alias configuration /public/assets/images/coffee_gif.gif.module.css doesn't exist .png Field 'browser' doesn't contain a valid alias configuration /public/assets/images/coffee_gif.gif.png doesn't exist .svg Field 'browser' doesn't contain a valid alias configuration /public/assets/images/coffee_gif.gif.svg doesn't exist .gif Field 'browser' doesn't contain a valid alias configuration /public/assets/images/coffee_gif.gif.gif doesn't exist .jpeg Field 'browser' doesn't contain a valid alias configuration /public/assets/images/coffee_gif.gif.jpeg doesn't exist .jpg Field 'browser' doesn't contain a valid alias configuration /public/assets/images/coffee_gif.gif.jpg doesn't exist as directory /public/assets/images/coffee_gif.gif doesn't exist root path /var/www/coffee_passport using description file: /var/www/coffee_passport/package.json (relative path: ./public/assets/images/coffee_gif.gif) no extension Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif doesn't exist .vue Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif.vue doesn't exist .mjs Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif.mjs doesn't exist .js Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif.js doesn't exist .sass Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif.sass doesn't exist .scss Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif.scss doesn't exist .css Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif.css doesn't exist .module.sass Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif.module.sass doesn't exist .module.scss Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif.module.scss doesn't exist .module.css Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif.module.css doesn't exist .png Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif.png doesn't exist .svg Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif.svg doesn't exist .gif Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif.gif doesn't exist .jpeg Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif.jpeg doesn't exist .jpg Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif.jpg doesn't exist as directory /var/www/coffee_passport/public/assets/images/coffee_gif.gif doesn't exist [ec2-user@ip-10-0-10-10 coffee_passport]$ rails assets:precompile RAILS_ENV=production yarn install v1.22.5 warning package-lock.json found. Your project contains lock files generated by tools other than Yarn. It is advised not to mix package managers in order to avoid resolution inconsistencies caused by unsynchronized lock files. To clear this warning, remove package-lock.json. [1/4] Resolving packages... [2/4] Fetching packages... info fsevents@2.1.3: The platform "linux" is incompatible with this module. info "fsevents@2.1.3" is an optional dependency and failed compatibility check. Excluding it from installation. info fsevents@1.2.13: The platform "linux" is incompatible with this module. info "fsevents@1.2.13" is an optional dependency and failed compatibility check. Excluding it from installation. [3/4] Linking dependencies... warning " > vue-eslint-parser@7.6.0" has unmet peer dependency "eslint@>=5.0.0". warning " > vue-loader@15.9.6" has unmet peer dependency "css-loader@*". warning " > vue-loader@15.9.6" has unmet peer dependency "webpack@^3.0.0 || ^4.1.0 || ^5.0.0-0". warning " > @webpack-cli/serve@1.5.2" has unmet peer dependency "webpack-cli@4.x.x". warning " > webpack-dev-server@3.11.2" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0". warning "webpack-dev-server > webpack-dev-middleware@3.7.3" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0". [4/4] Building fresh packages... Done in 4.47s. yarn install v1.22.5 warning package-lock.json found. Your project contains lock files generated by tools other than Yarn. It is advised not to mix package managers in order to avoid resolution inconsistencies caused by unsynchronized lock files. To clear this warning, remove package-lock.json. [1/4] Resolving packages... [2/4] Fetching packages... info fsevents@2.1.3: The platform "linux" is incompatible with this module. info "fsevents@2.1.3" is an optional dependency and failed compatibility check. Excluding it from installation. info fsevents@1.2.13: The platform "linux" is incompatible with this module. info "fsevents@1.2.13" is an optional dependency and failed compatibility check. Excluding it from installation. [3/4] Linking dependencies... warning " > vue-eslint-parser@7.6.0" has unmet peer dependency "eslint@>=5.0.0". warning " > vue-loader@15.9.6" has unmet peer dependency "css-loader@*". warning " > vue-loader@15.9.6" has unmet peer dependency "webpack@^3.0.0 || ^4.1.0 || ^5.0.0-0". warning " > @webpack-cli/serve@1.5.2" has unmet peer dependency "webpack-cli@4.x.x". warning " > webpack-dev-server@3.11.2" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0". warning "webpack-dev-server > webpack-dev-middleware@3.7.3" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0". [4/4] Building fresh packages... Done in 4.15s. Everything's up-to-date. Nothing to do 一回目のrails assets:precompile RAILS_ENV=production はエラーが表示されるのに、 二回目はエラーが表示されない。。。なんで。。。 改めて質問、一回目のエラーが起きてる前提でエラー解決, EC2のターミナルで、 ModuleNotFoundError: Module not found: Error: Can't resolve '/public/assets/images/coffee_gif.gif' in '/var/www/coffee_passport/app/javascript/packs/components/static_pages' と Though the "loose" option was set to "false" in your @babel/preset-env config, it will not be used for @babel/plugin-proposal-private-methods since the "loose" mode option was set to "true" for @babel/plugin-proposal-private-property-in-object. The "loose" option must be the same for @babel/plugin-proposal-class-properties, @babel/plugin-proposal-private-methods and @babel/plugin-proposal-private-property-in-object (when they are enabled): you can silence this warning by explicitly adding ["@babel/plugin-proposal-private-methods", { "loose": true }] to the "plugins" section of your Babel config. と .jpg Field 'browser' doesn't contain a valid alias configuration /var/www/coffee_passport/public/assets/images/coffee_gif.gif.jpg doesn't exist as directory がrails assets:precompile RAILS_ENV=production 実行時に起こりました。 Webpacker::Manifest::MissingEntryError in Sessions#new Showing /var/www/coffee_passport/app/views/sessions/new.html.erb where line #3 raised: Webpacker can't find app_explain in /var/www/coffee_passport/public/packs/manifest.json. Possible causes: 1. You want to set webpacker.yml value of compile to true for your environment unless you are using the webpack -w or the webpack-dev-server. 2. webpack has not yet re-run to reflect updates. 3. You have misconfigured Webpacker's config/webpacker.yml file. 4. Your webpack configuration is not creating a manifest. Your manifest contains: とブラウザに表示されてるエラーを を解決。 app/view/sessions/new.html.erb <div id="app-explain"> <%= javascript_pack_tag 'app_explain' %> </div> この部分がエラーになってる。 まぁこれはコンパイルをしたらエラー解決できそうだけど、 がrails assets:precompile RAILS_ENV=production のエラーが解決できないと無理だね。 開発環境では上手くいってるのに、本番環境で以上のようなエラーが起こってしまいます。 package.json package.json { "name": "coffee_passport", "private": true, "dependencies": { "@rails/actioncable": "^6.0.0-alpha", "@rails/activestorage": "^6.0.0-alpha", "@rails/ujs": "^6.0.0-alpha", "@rails/webpacker": "4.3.0", "axios": "^0.21.1", "rails-ujs": "^5.2.6", "turbolinks": "^5.2.0", "vue": "^2.6.12", "vue-axios": "^3.2.4", "vue-carousel": "^0.18.0", "vue-eslint-parser": "^7.6.0", "vue-js-modal": "^2.0.1", "vue-loader": "^15.9.6", "vue-router": "^3.5.1", "vue-template-compiler": "^2.6.12", "vue-youtube": "^1.4.0", "vuex": "^3.6.2" }, "version": "0.1.0", "devDependencies": { "@webpack-cli/serve": "^1.5.2", "webpack-dev-server": "^3.11.2" } } ~ [ec2-user@ip-10-0-10-10 coffee_passport]$ npm install --production npm WARN read-shrinkwrap This version of npm is compatible with lockfileVersion@1, but package-lock.json was generated for lockfileVersion@2. I'll try to do my best with it! [ .................] / loadIdealTree:loadAllDepsIntoIdealTree: WARN read-shrinkwrap This version of npm is compatib[ .................] - loadIdealTree:loadAllDepsIntoIdealTree: WARN read-shrinkwrap This version of[ .................] - loadIdealTree:loadAllDepsIntoIdealTree: WARN read-shrinkwrap This version of n[ .................] - loadIdealTree:loadAllDepsIntoIdealTree: WARN read-shrinkwrap This version of n[ .................] - loadIdealTree:loadAllDepsIntoIdealTree: WARN read-shrinkwrap This version of[ .................] - loadIdealTree:loadAllDepsIntoIdealTree: WARN read-shrinkwrap This version [ .................] | loadIdealTree:loadAllDepsIntoIdealTree: WARN read-shrinkwrap This versionpm WARN deprecated chokidar@2.1.8: Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies. npm WARN deprecated fsevents@1.2.13: fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2. npm WARN rm not removing /var/www/coffee_passport/node_modules/.bin/rimraf as it wasn't installed by /var/www/coffee_passport/node_modules/rimraf npm WARN rm not removing /var/www/coffee_passport/node_modules/.bin/semver as it wasn't installed by /var/www/coffee_passport/node_modules/semver npm WARN rm not removing /var/www/coffee_passport/node_modules/.bin/mkdirp as it wasn't installed by /var/www/coffee_passport/node_modules/mkdirp npm WARN rm not removing /var/www/coffee_passport/node_modules/.bin/cssesc as it wasn't installed by /var/www/coffee_passport/node_modules/cssesc node-sass@4.14.1 install /var/www/coffee_passport/node_modules/node-sass node scripts/install.js Downloading binary from https://github.com/sass/node-sass/releases/download/v4.14.1/linux-x64-64_binding.node Download complete Binary saved to /var/www/coffee_passport/node_modules/node-sass/vendor/linux-x64-64/binding.node Caching binary to /home/ec2-user/.npm/node-sass/4.14.1/linux-x64-64_binding.node core-js@3.16.4 postinstall /var/www/coffee_passport/node_modules/core-js node -e "try{require('./postinstall')}catch(e){}" Thank you for using core-js ( https://github.com/zloirock/core-js ) for polyfilling JavaScript standard library! The project needs your help! Please consider supporting of core-js: https://opencollective.com/core-js https://patreon.com/zloirock https://paypal.me/zloirock bitcoin: bc1qlea7544qtsmj2rayg0lthvza9fau63ux0fstcz Also, the author of core-js ( https://github.com/zloirock ) is looking for a good job -) node-sass@4.14.1 postinstall /var/www/coffee_passport/node_modules/node-sass node scripts/build.js Binary found at /var/www/coffee_passport/node_modules/node-sass/vendor/linux-x64-64/binding.node Testing binary Binary is fine npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@^1.2.7 (node_modules/watchpack-chokidar2/node_modules/chokidar/node_modules/fsevents): npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.13: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"}) npm WARN @webpack-cli/serve@1.5.2 requires a peer of webpack-cli@4.x.x but none is installed. You must install peer dependencies yourself. npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@2.1.3 (node_modules/watchpack/node_modules/fsevents): npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.1.3: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"}) added 72 packages from 21 contributors, removed 31 packages, updated 950 packages and audited 1184 packages in 55.046s 62 packages are looking for funding run npm fund for details found 8 vulnerabilities (2 moderate, 6 high) run npm audit fix to fix them, or npm audit for details を実行。 実行後にrails assets:precompile RAILS_ENV=production をしたら上記と一緒のエラー。 このあと再度、rails assets:precompile RAILS_ENV=production を実行したら [ec2-user@ip-10-0-10-10 coffee_passport]$ rails assets:precompile RAILS_ENV=production yarn install v1.22.5 warning package-lock.json found. Your project contains lock files generated by tools other than Yarn. It is advised not to mix package managers in order to avoid resolution inconsistencies caused by unsynchronized lock files. To clear this warning, remove package-lock.json. [1/4] Resolving packages... [2/4] Fetching packages... info fsevents@2.1.3: The platform "linux" is incompatible with this module. info "fsevents@2.1.3" is an optional dependency and failed compatibility check. Excluding it from installation. info fsevents@1.2.13: The platform "linux" is incompatible with this module. info "fsevents@1.2.13" is an optional dependency and failed compatibility check. Excluding it from installation. [3/4] Linking dependencies... warning " > vue-eslint-parser@7.6.0" has unmet peer dependency "eslint@>=5.0.0". warning " > vue-loader@15.9.6" has unmet peer dependency "css-loader@*". warning " > vue-loader@15.9.6" has unmet peer dependency "webpack@^3.0.0 || ^4.1.0 || ^5.0.0-0". warning " > @webpack-cli/serve@1.5.2" has unmet peer dependency "webpack-cli@4.x.x". warning " > webpack-dev-server@3.11.2" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0". warning "webpack-dev-server > webpack-dev-middleware@3.7.3" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0". [4/4] Building fresh packages... Done in 4.61s. yarn install v1.22.5 warning package-lock.json found. Your project contains lock files generated by tools other than Yarn. It is advised not to mix package managers in order to avoid resolution inconsistencies caused by unsynchronized lock files. To clear this warning, remove package-lock.json. [1/4] Resolving packages... [2/4] Fetching packages... info fsevents@2.1.3: The platform "linux" is incompatible with this module. info "fsevents@2.1.3" is an optional dependency and failed compatibility check. Excluding it from installation. info fsevents@1.2.13: The platform "linux" is incompatible with this module. info "fsevents@1.2.13" is an optional dependency and failed compatibility check. Excluding it from installation. [3/4] Linking dependencies... warning " > vue-eslint-parser@7.6.0" has unmet peer dependency "eslint@>=5.0.0". warning " > vue-loader@15.9.6" has unmet peer dependency "css-loader@*". warning " > vue-loader@15.9.6" has unmet peer dependency "webpack@^3.0.0 || ^4.1.0 || ^5.0.0-0". warning " > @webpack-cli/serve@1.5.2" has unmet peer dependency "webpack-cli@4.x.x". warning " > webpack-dev-server@3.11.2" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0". warning "webpack-dev-server > webpack-dev-middleware@3.7.3" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0". [4/4] Building fresh packages... Done in 4.16s. Everything's up-to-date. Nothing to do エラーが表示されなくなったが、ブラウザには Webpacker::Manifest::MissingEntryError in Sessions#new Showing /var/www/coffee_passport/app/views/sessions/new.html.erb where line #3 raised: Webpacker can't find app_explain in /var/www/coffee_passport/public/packs/manifest.json. Possible causes: 1. You want to set webpacker.yml value of compile to true for your environment unless you are using the webpack -w or the webpack-dev-server. 2. webpack has not yet re-run to reflect updates. 3. You have misconfigured Webpacker's config/webpacker.yml file. 4. Your webpack configuration is not creating a manifest. Your manifest contains: とブラウザに表示されてるエラーを を解決。 app/view/sessions/new.html.erb <div id="app-explain"> <%= javascript_pack_tag 'app_explain' %> </div> このように表示されてる。 yarn upgrade-interactive --latest を実行し、全部アップグレードしたら error webpack-dev-server@4.1.1: The engine "node" is incompatible with this module. Expected version ">= 12.13.0". Got "10.24.1" Done in 109.13s. Error: Found incompatible module. at MessageError.ExtendableBuiltin (/usr/share/yarn/lib/cli.js:721:66) at new MessageError (/usr/share/yarn/lib/cli.js:750:123) at checkOne (/usr/share/yarn/lib/cli.js:48059:11) at Object.check (/usr/share/yarn/lib/cli.js:48078:5) at /usr/share/yarn/lib/cli.js:7348:73 at Generator.next () at step (/usr/share/yarn/lib/cli.js:310:30) at /usr/share/yarn/lib/cli.js:321:13 このようなエラーが表示された。 nodeをアップグレードする必要する必要があるので、 [ec2-user@ip-10-0-10-10 coffee_passport]$ npm install -g n npm WARN checkPermissions Missing write access to /usr/lib/node_modules npm ERR! code EACCES npm ERR! syscall access npm ERR! path /usr/lib/node_modules npm ERR! errno -13 npm ERR! Error: EACCES: permission denied, access '/usr/lib/node_modules' npm ERR! { [Error: EACCES: permission denied, access '/usr/lib/node_modules'] npm ERR! stack: npm ERR! 'Error: EACCES: permission denied, access \'/usr/lib/node_modules\'', npm ERR! errno: -13, npm ERR! code: 'EACCES', npm ERR! syscall: 'access', npm ERR! path: '/usr/lib/node_modules' } npm ERR! npm ERR! The operation was rejected by your operating system. npm ERR! It is likely you do not have the permissions to access this file as the current user npm ERR! npm ERR! If you believe this might be a permissions issue, please double-check the npm ERR! permissions of the file and its containing directories, or try running npm ERR! the command again as root/Administrator. npm ERR! A complete log of this run can be found in: npm ERR! /home/ec2-user/.npm/_logs/2021-09-08T06_40_23_796Z-debug.log [ec2-user@ip-10-0-10-10 coffee_passport]$ sudo npm install -g n /usr/bin/n -> /usr/lib/node_modules/n/bin/n + n@7.3.1 added 1 package from 2 contributors in 0.299s sudo つけたらいけた。 [ec2-user@ip-10-0-10-10 coffee_passport]$ sudo n latest installing : node-v16.9.0 mkdir : /usr/local/n/versions/node/16.9.0 fetch : https://nodejs.org/dist/v16.9.0/node-v16.9.0-linux-x64.tar.xz installed : v16.9.0 to /usr/local/bin/node active : v10.24.1 at /bin/node https://docs.aws.amazon.com/ja_jp/sdk-for-javascript/v2/developer-guide/setting-up-node-on-ec2-instance.html を参考にnvmをインストールして、 nvmを使用して、最新の安定版のnodeを使いたいと思う。 node -e "console.log('Running Node.js ' + process.version)" Running Node.js v10.24.1 とりあえず、node14系を使うことにします。 [ec2-user@ip-10-0-10-10 ~]$ node -v v14.17.6 最新の安定版を使えました。 ってことで再度、 yarn upgrade-interactive --latest [ec2-user@ip-10-0-10-10 ~]$ yarn upgrade-interactive --latest yarn upgrade-interactive v1.22.5 success All of your dependencies are up to date. Done in 0.03s. 全部の依存関係がクリアされた??? 再度、rails assets:precompile RAILS_ENV=production を実行。 Though the "loose" option was set to "false" in your @babel/preset-env config, it will not be used for @babel/plugin-proposal-private-property-in-object since the "loose" mode option was set to "true" for @babel/plugin-proposal-class-properties. The "loose" option must be the same for @babel/plugin-proposal-class-properties, @babel/plugin-proposal-private-methods and @babel/plugin-proposal-private-property-in-object (when they are enabled): you can silence this warning by explicitly adding ["@babel/plugin-proposal-private-property-in-object", { "loose": true }] to the "plugins" section of your Babel config. ModuleNotFoundError: Module not found: Error: Can't resolve '/public/assets/images/coffee_gif.gif' in '/var/www/coffee_passport/app/javascript/packs/components/static_pages' at /var/www/coffee_passport/node_modules/webpack/lib/Compilation.js:925:10 at /var/www/coffee_passport/node_modules/webpack/lib/NormalModuleFactory.js:401:22 at /var/www/coffee_passport/node_modules/webpack/lib/NormalModuleFactory.js:130:21 at /var/www/coffee_passport/node_modules/webpack/lib/NormalModuleFactory.js:224:22 at /var/www/coffee_passport/node_modules/neo-async/async.js:2830:7 at /var/www/coffee_passport/node_modules/neo-async/async.js:6877:13 at /var/www/coffee_passport/node_modules/webpack/lib/NormalModuleFactory.js:214:25 at /var/www/coffee_passport/node_modules/enhanced-resolve/lib/Resolver.js:213:14 at /var/www/coffee_passport/node_modules/enhanced-resolve/lib/Resolver.js:285:5 at eval (eval at create (/var/www/coffee_passport/node_modules/tapable/lib/HookCodeFactory.js:33:10), :15:1) at /var/www/coffee_passport/node_modules/enhanced-resolve/lib/UnsafeCachePlugin.js:44:7 at /var/www/coffee_passport/node_modules/enhanced-resolve/lib/Resolver.js:285:5 at eval (eval at create (/var/www/coffee_passport/node_modules/tapable/lib/HookCodeFactory.js:33:10), :15:1) at /var/www/coffee_passport/node_modules/enhanced-resolve/lib/Resolver.js:285:5 at eval (eval at create (/var/www/coffee_passport/node_modules/tapable/lib/HookCodeFactory.js:33:10), :27:1) at /var/www/coffee_passport/node_modules/enhanced-resolve/lib/DescriptionFilePlugin.js:67:43 at /var/www/coffee_passport/node_modules/enhanced-resolve/lib/Resolver.js:285:5 at eval (eval at create (/var/www/coffee_passport/node_modules/tapable/lib/HookCodeFactory.js:33:10), :16:1) at /var/www/coffee_passport/node_modules/enhanced-resolve/lib/RootPlugin.js:60:9 at /var/www/coffee_passport/node_modules/enhanced-resolve/lib/Resolver.js:285:5 at eval (eval at create (/var/www/coffee_passport/node_modules/tapable/lib/HookCodeFactory.js:33:10), :27:1) at /var/www/coffee_passport/node_modules/enhanced-resolve/lib/DescriptionFilePlugin.js:67:43 at /var/www/coffee_passport/node_modules/enhanced-resolve/lib/Resolver.js:285:5 at eval (eval at create (/var/www/coffee_passport/node_modules/tapable/lib/HookCodeFactory.js:33:10), :16:1) at /var/www/coffee_passport/node_modules/enhanced-resolve/lib/Resolver.js:285:5 at eval (eval at create (/var/www/coffee_passport/node_modules/tapable/lib/HookCodeFactory.js:33:10), :15:1) at /var/www/coffee_passport/node_modules/enhanced-resolve/lib/DirectoryExistsPlugin.js:27:15 at /var/www/coffee_passport/node_modules/enhanced-resolve/lib/CachedInputFileSystem.js:85:15 at processTicksAndRejections (internal/process/task_queues.js:77:11) resolve '/public/assets/images/coffee_gif.gif' in '/var/www/coffee_passport/app/javascript/packs/components/static_pages' using description file: /var/www/coffee_passport/package.json (relative path: ./app/javascript/packs/components/static_pages) Field 'browser' doesn't contain a valid alias configuration クソ長いエラーが表示されたけど、抜粋するとこんなエラーがでた。。。 んーー、分からんん。。。。。 開発環境では ModuleNotFoundError: Module not found: Error: Can't resolve '/public/assets/images/coffee_gif.gif'  このようなエラーが表示されないので、、、、・。。。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

railsチュートリアル第4章 CSS

CSS、再び <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> Railsではスタイルシートを追加するための特別なメソッドを使っています。 stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' このメソッドを呼んでいます 第一に、丸カッコがありません。 Ruby では丸カッコは使用してもしなくてもいい。 次の2つの行は等価です。 # メソッド呼び出しの丸カッコは省略可能。 stylesheet_link_tag('application', media: 'all', 'data-turbolinks-track': 'reload') # 上は以下のように書いても同じ stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' media引数はハッシュのようだ。   ハッシュがメソッド呼び出しの最後の引数の場合は、波カッコを省略できる。 次の2つの行は等価です # 最後の引数がハッシュの場合、波カッコは省略可能。 stylesheet_link_tag 'application', { media: 'all', 'data-turbolinks-track': 'reload' } # 上は以下のように書いても同じ stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' これでなぜ動いているのか? stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' 上のコードには途中に改行が含まれている。 Rubyは改行と空白を区別していません。 行を分割した理由は、1行を80字以内に収めてソースコードを読みやすくするためです。 最初のコード stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' stylesheet_link_tagメソッドを2つの引数で呼んでいます。 最初の引数である文字列は、スタイルシートへのパスを示しています。 次の引数であるハッシュには2つの要素がある。 最初の要素はメディアタイプを示し、 次の要素はRails 4.0で追加されたturbolinksという機能をオンを示す。 <%= ... %> で囲まれているコードを実行した結果がERbのテンプレートに挿入されるようになります。 ブラウザ上でこのページのソースを表示すると、必要なスタイルシートが含まれていることを確認できます 読み込まれたCSSによって生成されたHTMLソース <link rel="stylesheet" media="all" href="/assets/application.self- f0d704deea029cf000697e2c0181ec173a1b474645466ed843eb5ee7bb215794.css?body=1" data-turbolinks-track="reload" />
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

railsチュートリアル第4章 ブロック

ブロック 配列と範囲はいずれも、ブロックを伴うさまざまなメソッドに対して使える。 >> (1..5).each { |i| puts 2 * i } 2 4 6 8 10 => 1..5 (1..5)に対してeachメソッドを呼び出す。 メソッドに渡されている{ |i| puts 2 * i }が、ブロックと呼ばれる部分 |i|では変数名が縦棒「|」に囲まれている。 ブロック変数に対して使うRubyの構文 範囲オブジェクトのeachメソッドは、iという1つのローカル変数を使ってブロックを操作 >> (1..5).each do |i| ?> puts 2 * i >> end 2 4 6 8 10 => 1..5 短い1行のブロックには波カッコを使う。 長い1行や複数行のブロックにはdo..end記法 iの代わりにnumberを使っている。 この変数(ブロック変数)の名前は固定されていません。 >> 3.times { puts "Betelgeuse!" } # 3.timesではブロックに変数を使っていない "Betelgeuse!" "Betelgeuse!" "Betelgeuse!" => 3 >> (1..5).map { |i| i**2 } # 「**」記法は冪乗 (べき乗) => [1, 4, 9, 16, 25] >> %w[a b c] # %w で文字列の配列を作成 => ["a", "b", "c"] >> %w[a b c].map { |char| char.upcase } => ["A", "B", "C"] >> %w[A B C].map { |char| char.downcase } => ["a", "b", "c"] >> %w[A B C].map { |char| char.downcase } => ["a", "b", "c"] >> %w[A B C].map(&:downcase) => ["a", "b", "c"] テストがブロックなっている test "should get home" do get static_pages_home_url assert_response :success assert_select "title", "Ruby on Rails Tutorial Sample App" end テストコードにdoというキーワードがあることに気付き そこからテストの本体が「そもそもブロックでできている 演習 1.2乗にせよ >> (0..16).each{ |i| puts i ** 2} 0 1 4 9 16 25 36 49 64 81 100 121 144 169 196 225 256 => 0..16 2.メソッドを定義してメソッドを使え。 >> def yeller(s) >> s.join.upcase >> end => :yeller >> yeller(['o', 'l', 'd']) => "OLD" mapを使いきれなかった。 一応書いてみた。 3.メソッドを定義して、メソッドを使え。 >> def random_subdomain >> b = ("a".."z").to_a.shuffle[0..15].join >> puts b >> end => :random_subdomain >> random_subdomain uztpyrijhcvesxnl => nil 一応できたと思う。 4.コードを書き換えろ >> def string_shuffle(s) >> s.split('').shuffle.join >> end => :string_shuffle >> string_shuffle("foobar") => "arfoob" >> string_shuffle("foobar") => "ooabfr" >> string_shuffle("foobar") => "bfooar"
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

railsチュートリアル7章進めたときの覚書

この章では何するの? ユーザー登録機能を追加するよ HTML フォームを使ってWebアプリケーションに登録情報を送信 ユーザーを新規作成して情報をデータベースに保存 作成されたユーザーの新しいプロフィールを表示できるようにするために、ユーザーを表示するためのページを作成 ユーザー用のRESTアーキテクチャを実装する第一歩を踏み出すよ サイトにdebug情報の追加 ビルトインの debugメソッドとparams変数を使い、デバッグ用の情報が表示されるようになる。 <%= debug(params) if Rails.env.development? %> 開発環境だけでdebug情報を出力したいときは下記コード追加。 if Rails.env.development? logサンプル --- !ruby/object:ActionController::Parameters parameters: !ruby/hash:ActiveSupport::HashWithIndifferentAccess controller: static_pages action: home permitted: false Usersリソース RESTの原則に従う場合、リソースへの参照はリソース名とユニークなIDを使うのが普通 ユーザーをリソースとみなす場合、id=1のユーザーを参照するということは、/users/1というURLに対してGETリクエストを発行するということを意味する。 users/1 のurlを有効にするために下記追加 config/routes.rb resources :users ユーザーのURLを生成するための多数の名前付きルート(5.3.3)と共に、RESTfulなUsersリソースで必要となるすべてのアクションが利用できるようになる プロフィール表示用のviewファイルの作成 app/views/users/show.html.erb <%= @user.name %>, <%= @user.email %> Usersコントローラに show アクション追加 app/controllers/users_controller.rb class UsersController < ApplicationController #追加 def show @user = User.find(params[:id]) end def new end end debuggerメソッド コントローラーにdebuggerを追加すると、railsのコンソール上でデバッグできる app/controllers/users_controller.rb class UsersController < ApplicationController def show @user = User.find(params[:id]) debugger #これ追加 end def new end end ctrl + dで抜けれる formの実装 form_withヘルパーメソッドを使用する エラーメッセージについて railsは無効な内容の送信によって元のページに戻されると、CSSクラスfield_with_errorsを持ったdivタグでエラー箇所を自動的に囲んでくれる機能がある。 form用のテスト #コントローラーの作成 $rails generate integration_test users_signup ユーザー登録ボタンを押したときに(ユーザー情報が無効であるために)ユーザーが作成されないことを確認する。 getメソッドを使ってユーザー登録ページにアクセス get signup_path フォーム送信をテストするためには、 users_pathに対してPOSTリクエストを送信する flash 登録完了後に表示されるページにメッセージを表示し(この場合は新規ユーザーへのウェルカムメッセージ)、2度目以降にはそのページにメッセージを表示しないようにする。 上記のような情報を表示するためにrailsでは、flashという特殊な変数を使う。 flash変数に代入したメッセージは、リダイレクトした直後のページで表示できるようになる。 ユーザーが作成されたことを確認するテスト assert_differenceメソッドを使いテストする assert_no_differenceと同様に、このメソッドは第一引数に文字列('User.count')を取り、assert_differenceブロック内の処理を実行する直前と、実行した直後のUser.countの値を比較する。 ここでrails tしたら下記のエラーが出た ERROR["test_invalid_signup_information", #<Minitest::Reporters::Suite:0x000055eba2f5b2c8 @name="UsersSignupTest">, 1.2418686970013368] test_invalid_signup_information#UsersSignupTest (1.24s) Nokogiri::CSS::SyntaxError: Nokogiri::CSS::SyntaxError: unexpected '#' after '[#<Nokogiri::CSS::Node:0x000055eba2f4a4f0 @type=:ELEMENT_NAME, @value=["div"]>]' test/integration/users_signup_test.rb:14:in `block in <class:UsersSignupTest>' Finished in 1.31543s 15 tests, 30 assertions, 0 failures, 1 errors, 0 skips エラーを吐いているコードはどうやら下記で、CSS::SyntaxErrorと出ているのでcss周りのエラーの模様。 users_signup_test.rb assert_select 'div#<CSS id for error explanation>' assert_select 'div.<CSS class for field with error>' assert_selectは、特定のHTMLタグが存在するかどうかをテストするメソッドだった。 そのため、下記のように修正。無事テストがとおる。 users_signup_test.rb #error explanationのid名を指定 assert_select 'div#error_explanation' #field with errorのときのクラス名を指定 assert_select 'div.field_with_errors' 本番環境でのSSL この章で制作したユーザー登録フォームで送信すると、名前やメールアドレス、パスワードといったデータがネットワーク越しに流されていく。 これを修正するために、Transport Layer Security(TLS)を使う。 TLS: ローカルのサーバーからネットワークに流れる前に、大事な情報を暗号化する技術 方法 production.rbに一行修正を加える 具体的には、configに「本番環境ではSSLを使うようにする」という設定をする config/environments/production.rb config.force_ssl = true #一行追加 次に、遠隔にあるサーバーのSSLをセットアップする。 本番用のWebサイトでSSLを使えるようにするためには、ドメイン毎にSSL証明書を購入し、セットアップする必要がある。 証明書周りは工数かかるが、HerokuのSSL証明書に便乗する方法でその作業をせずに済む。 独自ドメインの場合は証明書周りの作業必要。 本番環境用のサーバー WEBrickをPumaに置き換える。 理由は、WEBrickは簡単にセットアップできたり動せることが特長だが、著しいトラフィックを扱うことには適していないため。 Pumaは多数のリクエストを捌くことに適したRuby/Rackアプリケーション用のサーバーである。 Pumaのファイルを書き換え # Pumaの設定ファイル max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } threads min_threads_count, max_threads_count port ENV.fetch("PORT") { 3000 } environment ENV.fetch("RAILS_ENV") { ENV['RACK_ENV'] || "production" } pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } workers ENV.fetch("WEB_CONCURRENCY") { 2 } preload_app! plugin :tmp_restart ./Procfileを制作 Procfile web: bundle exec puma -C config/puma.rb DBを本番向けに設定 config/database.yml #下記追加 production: adapter: postgresql encoding: unicode # For details on connection pooling, see Rails configuration guide # https://railsguides.jp/configuring.html#データベース接続をプールする pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> database: sample_app_production username: sample_app password: <%= ENV['SAMPLE_APP_DATABASE_PASSWORD'] %>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Ajax]フォロー機能を非同期にした

はじめに 本記事では、フォロー機能を非同期通信にした方法を記述します。 以前にいいね機能について、非同期通信にした記事も投稿しておりますので、 ご参照ください。 前提 フォロー機能が同期通信できているものとします。 コード 早速ですが、該当箇所のコードを記載します。 コントローラー showページにフォローボタンやフォロワーを確認できるボタンがあります。 後述のモデルに合わせてfollowingsや`followersメソッドを作成します。 また、usersとfollowersなどに分けている方もいらっしゃいましたが、 私は、followingsや`followersに分けた方がわかりやすいと思ったため、こうしています。 users_controller.rb class UsersController < ApplicationController def show @user = User.find(params[:id]) @foods = @user.foods.order("created_at DESC") end def followings user = User.find(params[:id]) @users = user.followings end def followers user = User.find(params[:id]) @users = user.followers end 省略 end relationshipsテーブルは、userとuserの関係を示す、中間テーブルになります。 また、その関係を作る(create)、壊す(destroy)の2つが必要になります。 relationships_controller.rb class RelationshipsController < ApplicationController before_action :authenticate_user! def create @user = User.find(params[:user_id]) following = Relationship.create(follower_id: params[:user_id], following_id: current_user.id) end def destroy @user = User.find(params[:user_id]) following = Relationship.find_by(follower_id: params[:user_id], following_id: current_user.id) following.destroy end end モデル 同期通信と特に変わりはありません。 user.rb class User < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable has_many :foods, dependent: :destroy has_many :likes, dependent: :destroy has_many :liked_foods, through: :likes, source: :food has_many :relationships, foreign_key: :following_id has_many :followings, through: :relationships, source: :follower has_many :reverse_of_relationships, class_name: 'Relationship', foreign_key: :follower_id has_many :followers, through: :reverse_of_relationships, source: :following has_one_attached :icon has_many :comments def already_liked?(food) self.likes.exists?(food_id: food) end def is_followed_by?(user) reverse_of_relationships.find_by(following_id: user.id).present? end end ここも同期通信と特に変わりはありません。 relationship.rb class Relationship < ApplicationRecord belongs_to :following ,class_name: "User" belongs_to :follower, class_name: "User" end ビュー show.html.erb 記述が長いので、部分テンプレートです。 ちなみに、クラス名を class="mypage-follow-contents-<%= @user.id %>" にしないと、誰をフォローするのかわからないままですので、 エラーが出続けることになります。 <div class="mypage-intro-topright"> <div class="mypage-follow-contents-<%= @user.id %>"> <%= render partial:"relationships/relationship", lacals: {user: @user} %> </div> </div> followers.html.erbフォロワーの一覧を確認できるページ。ここはあまり関係ないと思います。 <div class="followers-contents"> <div class="row d-flex justify-content-center"> <div class="col-10 mt-5"> <h1>FOLLOWERS</h1> <h2 class="followers-contents-title">Nickname</h2> <% @users.each do |user| %> <%= link_to user_path(user) do %> <%= user.nickname %> <% end %> <% if user != current_user %> <% if user.is_followed_by?(current_user) %> <%=link_to user_relationships_path(user), method: :delete do %> <button type="button" class="btn btn btn-danger">フォロー解除</button> <% end %> <% else %> <%=link_to user_relationships_path(user), method: :post do %> <button type="button" class="btn btn btn-primary">フォロー</button> <% end %> <% end %> <% end %> <% end %> </div> </div> </div> followings.html.erbフォローしている人を確認できるページ。ここはあまり関係ないと思います。 <div class="followings-contents"> <div class="row d-flex justify-content-center"> <div class="col-10 mt-5"> <h1>FOLLOWING</h1> <h2 class="followings-contents-title">Nickname</h2> <% @users.each do |user| %> <%= link_to user_path(user) do %> <%= user.nickname %> <% end %> <% if user != current_user %> <% if user.is_followed_by?(current_user) %> <%=link_to user_relationships_path(user), method: :delete do %> <button type="button" class="btn btn btn-danger">フォロー解除</button> <% end %> <% else %> <%=link_to user_relationships_path(user), method: :post do %> <button type="button" class="btn btn btn-primary">フォロー</button> <% end %> <% end %> <% end %> <% end %> </div> </div> </div> _relationship.html.erb show.html.erbにあった部分テンプレートです。 remote: trueこれが特に大事です。 というか非同期通信のスタートがこれなんではないかというぐらい重要です。 これにより、非同期通信をOKするものになり、リクエストがjs形式になります。 そのため、後ほど出てきますが、 ファイルはjs.erbファイルということになります。 <div class="mypage-followcount-btn"> <%= link_to followings_user_path(@user) do %> <button class="btn btn-mypage-follow">フォロー <i class="fas fa-angle-right fa-position-right"> <%= @user.followings.count %> </i> </button> <% end %> <%= link_to followers_user_path(@user) do %> <button class="btn btn-mypage-follow">フォロワー <i class="fas fa-angle-right fa-position-right"> <%= @user.followers.count %> </i> </button> <% end %> <% if user_signed_in? && @user == current_user %> <div class="mypage-introduction-edit"> <%= link_to edit_user_path(current_user) do %> <button class="btn btn-mypage-introduction-edit">プロフィール編集 <i class="fas fa-user-edit"></i> </button> <% end %> </div> <% else %> <%# <% unless @user == current_user %> <div class="mypage-follow-btn"> <% if @user.is_followed_by?(current_user) %> <%= link_to user_relationships_path(@user), method: :delete, remote: true do %> <button class="btn btn-follow-delete">フォロー中</button> <% end %> <% else %> <%= link_to user_relationships_path(@user), method: :post, remote: true do %> <button class="btn btn-follow-create">フォローする</button> <% end %> <% end %> </div> <% end %> </div> create.js.erbフォロー jについては、以下にも記載したので省略します。 $('.mypage-follow-contents-<%= @user.id %>').html("<%= j(render partial: 'relationships/relationship', locals: {user: @user}) %>") 部分テンプレートにより、 前述の以下の部分に進みます。 <% if @user.is_followed_by?(current_user) %> <%= link_to user_relationships_path(@user), method: :delete, remote: true do %> <button class="btn btn-follow-delete">フォロー中</button> <% end %> <% else %> <%= link_to user_relationships_path(@user), method: :post, remote: true do %> <button class="btn btn-follow-create">フォローする</button> <% end %> <% end %> destroy.js.erbフォロー解除 create.js.erbと同じです。 $('.mypage-follow-contents-<%= @user.id %>').html("<%= j(render partial: 'relationships/relationship', locals: {user: @user}) %>") 以上です。 いかがでしょうか。 終わりに 非同期通信、終わってみれば「簡単」だと思いますが、 できるまでは難しかったなというのが、印象でした。 アプリケーションにおいて非同期化してしまった方が良いものは全て非同期化した方が良さそうですね。 以下、参考サイトです。 [Rails]Ajaxを用いて非同期でフォロー機能の実装 【Rails】Ajaxを用いた非同期フォロー機能の実装 Railsで実装したフォロー機能の非同期化がうまくいかない。 Ruby on Rails チュートリアル 明日も頑張ります!!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む