- 投稿日:2019-10-12T23:45:29+09:00
Rails、Slimでflashメッセージがうまくだせない
Slimで新規登録に成功したらフラッシュメッセージを表示してindexに戻りたいのに次のように書いたらエラーが出る。
classを書かずにやると素テキストで成功メッセージが出るのでコントローラー側は大丈夫なはず。
app/controllers/blogs_controller.rbdef create @blog = Blog.create(blog_params) redirect_to blogs_path flash[:success] = 'add success' endindex.html.slim= flash[:success], class: 'alert alert-primary' h1 Blog articles = link_to '新規登録', new_blog_path, class: 'btn btn-primary' - @blogs.each do |blog| br = blog.id br = blog.title br = blog.articleerrorsyntax error, unexpected ':' ..._safe((flash[:success], class : 'alert alert-primary'))).to_... ... ^
いろいろぐぐり、試行錯誤した。
classの書き方が違っていた。
link_toのクラスの書き方が、「class: 'btn btn-primary'」だったから同じだと思っていたが違うみたい。ネットでいろいろぐぐったけど、Slimでflashのclassの書き方の参考が見つけられなかった。
これでエラーが取れたけど、ずっとフラッシュの緑枠がある。.alert.alert-success = flash[:success] h1 Blog articles勘違いしていた。if文を入れないと常にフラッシュが出てしまう。
flashでるときだけ値をコントローラーから勝手に渡してくれるような気がしていた。
if文を書く。
これでOK。- if flash[:success] .alert.alert-success = flash[:success] h1 Blog articles
- 投稿日:2019-10-12T23:41:11+09:00
AWS EC2インスタンスの作成手順
はじめに
EC2インスタンスの作成手順をメモする
EC2インスタンスの作成
- AWS マネジメントコンソールにログイン
- 下記画像のサービス→EC2をクリック
- インスタンスの作成をクリック
- AMIを選択 Amazon Linux AMIを選択する
- タイプの選択 図のように上から2つ目の無料枠を選択しておく。その後画像右下の【確認と作成】をクリック
- インスタンス作成の確認画面
- ここでは右下にある【起動】をクリック。
- キーペアをダウンロードする
- modalが表示されるので、【新しいキーペアの作成】を選択し、【キーペア名】を任意で入力後、キーペアのダウンロードを行う。
- 【インスタンスの作成】をクリック
- インスタンス一覧からインスタンスを選択
- 取得したElastic IPアドレスを紐づける 上図の【アクション】から【アドレスの関連付け】を選択
- 【アドレスの関連付け】ページにあるインスタンスには先ほどメモしたIDを入力、【プライベートID】には入力しない、【関連付け】をクリック
- インスタンス画面からElastic IPが紐づけられたことを確認する
ポートを開く
- インスタンス画面
- セキュリティグループのリンクをクリック
- 「インバウンド」タブの中の「編集」をクリック
- 開かれたモーダルで、ルールの追加」をクリック、タイプを「HTTP」、プロトコルを「TCP」、ポート範囲を「80」、送信元を「カスタム / 0.0.0.0/0, ::/0」に設定
EC2インスタンスへのログイン
$ cd ~ $ mv Downloads/鍵の名前.pem .ssh/ $ cd .ssh/ $ chmod 600 鍵の名前.pem $ ssh -i 鍵の名前.pem ec2-user@作成したEC2インスタンスと紐付けたElastic IP
- 投稿日:2019-10-12T23:30:36+09:00
【Rails】scaffoldを使用したアプリケーションの生成手順
先日、scaffoldを初めて使ってみたのですが、めちゃめちゃ便利だったので、使用手順を中心に記事を書かせていただきます。
おそらく「scaffoldってなんだ?」という方もいらっしゃると思うので、まずはscaffoldについて簡単に。
scaffoldとは?
Railsの開発に必要なルーティング、コントローラ、ビューの作成に加え、基本的なアクションの設定なども自動ですべてやってくれる便利ツールのこと
→もちろん、これを使って世の中に出すアプリケーションをつくるのは違う(というより無駄が多い)と思いますが、個人的には試しに機能を実装するための試作品をつくる上で、ベースとなるRailsのアプリケーションをなるべく工数かけずに作りたいと思っていたので、最近めちゃめちゃよく使っています。
ということで、以下scaffoldを使用したRailsアプリケーションの生成手順について記載します。
本当に簡単なので、もしよかったら実際に使ってみて下さい。scaffoldを使用したRailsアプリケーションの生成手順
<想定読者>
Railsを使用したアプリケーション開発の初学者
または、これからRailsを使用したアプリケーション開発を行いたいと考えている方<環境やバージョン>
・MacOS
・Rails 5.2.3まずは、通常通りrails newでrailsアプリケーションを作成しましょう。
※例ではtodoリストのアプリケーションをつくる想定で「todo_list」というアプリケーション名にしています。ターミナル$ rails new todo_listコマンドを使用して作成したアプリケーション(todo_lint)へ移動
ターミナル$ cd todo_listいよいよ本題のscaffoldを使用した各種ファイルの生成を行います。
scaffoldを使用する場合、ターミナルで以下のコマンドを入力します。
$ rails generate scaffold モデル名 カラム名1:データ型1 カラム名2:データ型 2 …
こうすることにより、ルーティング、コントローラ、ビューのファイルだけではなく、モデルやマイグレーションファイルの作成も自動で行なってくれます。
※例では、content、priority、limitの3つのカラムを作成するための設定を行なっています。ターミナル$ rails g scaffold todo content:text priority:string limit:dateこれでscaffoldを使用したRailsアプリケーションの雛形は作成できました。
最後に、作成されたマイグレーションファイルを元に、データベースのテーブル作成を実施しましょう。ターミナル$ rake db:migrate以上でscaffoldを使用したアプリケーションの生成手順は終了です。
ローカルのサーバにアクセスすると、以下のページが表示されるかと思います。
「ん?たしかに必要なファイルは作成されたけど、ビューファイルに記載された内容がブラウザに表示されない、、」という方↓
そうなんです。各種アクションやビューに対応したルーティングの設定はされていますが、rootの設定はされないので、そこは個別設定しましょう。
config/routes.rbroot to: "todos#index"すると、以下のようにビューがきちんと表示されたかと思います。
どうでした?簡単でしたよね?
ちなみに、今回作成したtodoリストの場合のその他のビューはこんな感じになります。
<todoの新規作成ページ>
それでは、最後になりましたが、今回使用したscaffoldで生成された(もしくは追加、変更された)ファイルを記載しますので、今後のアプリケーション開発の参考にしてみてください。
①コントローラ
・app/controllers/todos_controller.rb
※作成されたコントローラのファイルには、自動で「index」「show」「new」「edit」「create」「update」「destroy」の7つのアクションが定義されています。そのため、これらのアクションを呼び出してデータの参照、作成、変更、削除をすぐに行うことができます。②ルーティング
・config/routes.rb
※ファイルの中には「resources :todos」という記述が追加されており、上記のアクションに対応したルーティングが自動で設定されます。③ビュー
・app/views/todos/index.html.erb
・app/views/todos/edit.html.erb
・app/views/todos/show.html.erb
・app/views/todos/new.html.erb
・app/views/todos/_form.html.erb
※コントローラーで定義されたアクションに対応するビューファイルが全て作成されています。④モデル、およびマイグレーションファイル
・db/migrate/2019xxxxxxx_create_todos.rb
・app/models/todo.rb
※scaffoldを使用した各種ファイルの作成時に指定した情報を含む、モデルおよびマイグレーションファイルが自動生成されています。【参考記事】
覚えておくと超便利!Ruby on Railsのscaffoldの使い方【初心者向け】
https://techacademy.jp/magazine/7204
- 投稿日:2019-10-12T23:30:36+09:00
【Rails】scaffoldを使用したアプリケーションの作成手順
先日、scaffoldを初めて使ってみたのですが、めちゃめちゃ便利だったので、scaffoldを使用したRailsアプリケーションの作成手順を中心に記事を書かせていただきます。
おそらく「scaffoldってなんだ?」という方もいらっしゃると思うので、まずはscaffoldについて簡単に。
scaffoldとは?
Railsの開発に必要なルーティング、コントローラ、ビューの作成に加え、基本的なアクションの設定なども自動ですべてやってくれる便利ツールのこと
【個人的に感じたscaffoldの良さ】
①コントローラの作成だけでなく、7つの基本アクションも自動で設定してくれる
scaffoldで作成されたコントローラには、「index」「show」「new」「edit」「create」「update」「destroy」の7つのアクションが自動で定義されています。そのため、自分でアクションを設定しなくても、すぐにデータの参照や新規作成、変更、削除を行うことができます。②作成されたコントローラに対応するルーティングも自動で設定してくれる
scaffoldコマンド後のroutes.rbには、「resources :コントローラ名」という記述が追加されており、新たに作成されたコントローラに対応するルーティングが自動で設定されています。③コントローラで定義されたアクションに対応するビューも全て自動生成してくれる
scaffoldを使用した場合、コントローラで定義されたアクションに対応するビューファイルも全て自動で生成されます。④必要なモデルおよびマイグレーションファイルも自動生成してくれる
scaffoldでは、コマンド入力時に「カラム名:データ型」を指定すると、指定された情報を含むモデルおよびマイグレーションファイルを自動生成してくれます。
そのため、あとは「$ rake db:migrate」コマンドを入力するだけで、データベースのテーブルも簡単に作成できます。(この辺りの詳細は後ほど)→もちろん、scaffoldを使って世の中に出すアプリケーションをつくるのはちょっと違う(というより逆に無駄が多い)と思いますが、個人的には興味のある機能を試しに実装するための試作品をつくる上ではめちゃめちゃ便利だなと感じています。
ということで、以下scaffoldを使用したRailsアプリケーションの作成手順について記載します。
本当に簡単なので、もしよかったら実際に使ってみて下さい!scaffoldを使用したRailsアプリケーションの生成手順
<想定読者>
Railsを使用したアプリケーション開発の初学者
または、これからRailsを使用したアプリケーション開発を行いたいと考えている方<環境やバージョン>
・MacOS
・Rails 5.2.3<作成手順>
まずは、通常通りrails newでrailsアプリケーションを作成しましょう。
※例ではtodoリストのアプリケーションをつくる想定で「todo_list」というアプリケーション名にしています。ターミナル$ rails new todo_listコマンドを使用して作成したアプリケーション(todo_lint)へ移動
ターミナル$ cd todo_listいよいよ本題のscaffoldを使用した各種ファイルの生成を行います。
scaffoldを使用する場合、ターミナルで以下のコマンドを入力します。
$ rails generate scaffold モデル名 カラム名1:データ型1 カラム名2:データ型 2 …
こうすることにより、ルーティング、コントローラ、ビューのファイルだけではなく、モデルやマイグレーションファイルの作成も自動で行なってくれます。
※例では、content、priority、limitの3つのカラムを作成するための設定を行なっています。ターミナル$ rails g scaffold todo content:text priority:string limit:dateこれでscaffoldを使用したRailsアプリケーションの雛形は作成できました。
最後に、作成されたマイグレーションファイルを元に、データベースのテーブル作成を実施しましょう。ターミナル$ rake db:migrate以上でscaffoldを使用したアプリケーションの作成手順は終了です。
いかがでした?めちゃめちゃ簡単じゃないですか?ちなみに、ここでローカルのサーバにアクセスしてみると、以下のページが表示されるかと思います。
「ん?たしかに必要なファイルは作成されたけど、ビューファイルに記載された内容がブラウザに表示されない、、」という方↓
そうなんです。各種アクションやビューに対応したルーティングの設定はされていますが、rootの設定はされないので、そこは個別設定しましょう。
config/routes.rbroot to: "todos#index"すると、以下のようにビューがきちんと表示されたかと思います。
これでもう完璧ですね!
参考までにですが、今回作成したtodoリストの場合、その他のビューはこんな感じになります。
<todoの新規作成ページ>
それでは、最後になりましたが、今回使用したscaffoldで生成された(もしくは追加、変更された)ファイルを記載しますので、もし興味があれば今後のアプリケーション開発の参考にしてみてください。
①コントローラ
・app/controllers/todos_controller.rb②ルーティング
・config/routes.rb
※ファイルの中には「resources :todos」という記述が自動追加③ビュー
・app/views/todos/index.html.erb
・app/views/todos/edit.html.erb
・app/views/todos/show.html.erb
・app/views/todos/new.html.erb
・app/views/todos/_form.html.erb④モデル、およびマイグレーションファイル
・db/migrate/2019xxxxxxx_create_todos.rb
・app/models/todo.rb【参考記事】
覚えておくと超便利!Ruby on Railsのscaffoldの使い方【初心者向け】
https://techacademy.jp/magazine/7204
- 投稿日:2019-10-12T22:53:33+09:00
Active Recordの型変換はいつ実行されるのか?
上記の動作を知らずに実装していたらハマったのでメモします。
(ジャストなドキュメントを見つけられなかったためActive Recordのソースやその他記事等を確認しましたが、間違っている部分がありましたらご指摘ください)前提
- Rails 5.2.3
Task
というクラスがあり、tests
という属性を持っているとします。
tests
はRails上ではActiveSupport::TimeWithZone
として扱われます。
アプリケーションのデフォルトのタイムゾーンはTokyo
です。rails_console[2] pry(main)> Task.columns_hash["tests"].type => :datetime [5] pry(main)> Time.zone.name => "Tokyo"疑問
以下のアクション(
TasksController#index
)が実行された場合に# ??
の部分はどのような値(タイムゾーン)となるか?tasks_controller.rbclass TasksController < ApplicationController def index task = Task.new(tests: "2019/01/01") Time.use_zone("UTC"){ task.tests } puts task.tests # ?? end end正解
正解は
Tue, 01 Jan 2019 00:00:00 UTC +00:00
Tokyo
のタイムゾーンになると思っていたのでハマった。Active Recordの型変換
事前知識
Active Recordでは属性として入力された値を型変換することがあります。例えば属性にInteger型の
Task.id
があった場合で、idにInteger型以外の値が入力された場合でも、以下のように型変換して属性値として扱います。rails_console[1] pry(main)> task = Task.new => #<Task:0x00007f3a201cad70 id: nil, created_at: nil, updated_at: nil, tests: nil> [2] pry(main)> task.id = "1" => "1" [3] pry(main)> task.id => 1 [4] pry(main)> task.id = "2019/01/01" => "2019/01/01" [5] pry(main)> task.id => 2019型変換が実行されるタイミングは?
さて、上記の型変換が実行されるタイミングですが、これまで私は何となく、前述のケースでいえば以下(1)にようにモデルがインスタンス化されたときだと思っていました。しかし、今回調べたところ、正しくは、初めてその属性のアクセサメソッドが実行されたとき、のようです。
すなわち、以下(2)のタイミングのときにtask.tests
は TimeWithZone 型に変換されるようです。(1) task = Task.new(tests: "2019/01/01") (2) Time.use_zone("UTC"){ task.tests }では、 (1) ではどこまで処理が実行されるのかというと、アクセスメソッドを定義するまで、実行されるようです(他にも色々しているのでしょうが)。
以下、(1)(2)それそれが実行される流れを簡単にコードで追ってみようと思います。ソースコードを読んでみる
Model.new すると起きること
ActiveRecord
を継承したクラスがnew
される場合に実行されるコンストラクタはActiveRecord::Core
モジュール(includeされるクラスはActiveRecord::Base
クラス)のコンストラクタのようです。コードを抜粋して確認してみます。core.rb# New objects can be instantiated as either empty (pass no construction parameter) or pre-set with # attributes but not yet saved (pass a hash with key names matching the associated table column names). # In both instances, valid attribute keys are determined by the column names of the associated table -- # hence you can't have attributes that aren't part of the table columns. # # ==== Example: # # Instantiates a single new object # User.new(first_name: 'Jamie') def initialize(attributes = nil) self.class.define_attribute_methods @attributes = self.class._default_attributes.deep_dup init_internals initialize_internals_callback assign_attributes(attributes) if attributes yield self if block_given? _run_initialize_callbacks endhttps://github.com/rails/rails/blob/5-2-stable/activerecord/lib/active_record/core.rb
上記の
self.class.define_attribute_methods部分で属性のアクセサメソッドを定義していると想像できます。
さらにこの奥に進んでみると、ActiveRecord::AttributeMethods
モジュールの中でdefine_attribute_methods
が定義されていました。attribute_methods.rb# Generates all the attribute related methods for columns in the database # accessors, mutators and query methods. def define_attribute_methods # :nodoc: return false if @attribute_methods_generated # Use a mutex; we don't want two threads simultaneously trying to define # attribute methods. generated_attribute_methods.synchronize do return false if @attribute_methods_generated superclass.define_attribute_methods unless self == base_class super(attribute_names) @attribute_methods_generated = true end endhttps://github.com/rails/rails/blob/5-2-stable/activerecord/lib/active_record/attribute_methods.rb
この中の
superclass.define_attribute_methodsによって今度はActiveModelモジュールの方の同名のメソッドが呼ばれます。
attribute_methods.rbdef define_attribute_methods(*attr_names) attr_names.flatten.each { |attr_name| define_attribute_method(attr_name) } endhttps://github.com/rails/rails/blob/5-2-stable/activemodel/lib/active_model/attribute_methods.rb
この中での
define_attribute_method
メソッドがアクセサメソッドを定義していそうです。ここを追ってみると同じファイル内で以下のメソッドが定義されています。attribute_methods.rbdef define_attribute_method(attr_name) attribute_method_matchers.each do |matcher| method_name = matcher.method_name(attr_name) unless instance_method_already_implemented?(method_name) generate_method = "define_method_#{matcher.method_missing_target}" if respond_to?(generate_method, true) send(generate_method, attr_name.to_s) else define_proxy_call true, generated_attribute_methods, method_name, matcher.method_missing_target, attr_name.to_s end end end attribute_method_matchers_cache.clear endhttps://github.com/rails/rails/blob/5-2-stable/activemodel/lib/active_model/attribute_methods.rb
この中の
attribute_method_matchers
はActiveModel::AttributeMethods::ClassMethods::AttributeMethodMatcher
の配列となっており、これらは<Atrribute名>_in_database
等すべての属性に共通して使えるようにするメソッドのプレフィックス等が格納されていました。
今回は、それらの深追いはせず、属性名自体のアクセサメソッドの定義の動作を追います。
それについては、上記コードのsend(generate_method, attr_name.to_s)が呼ばれるようです。このとき引数は
generate_method # => define_method_attribute attr_name.to_s # => testsの通りでした。
define_method_attribute
メソッドが実行されるので、追ってみると以下で定義されていました。read.rbdef define_method_attribute(name) safe_name = name.unpack("h*".freeze).first temp_method = "__temp__#{safe_name}" ActiveRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name sync_with_transaction_state = "sync_with_transaction_state" if name == primary_key generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1 def #{temp_method} #{sync_with_transaction_state} name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name} _read_attribute(name) { |n| missing_attribute(n, caller) } end STR generated_attribute_methods.module_eval do alias_method name, temp_method undef_method temp_method end end上記により、 module_evalによりメソッドが動的に定義されている様子がわかります。
型変換が実行されるタイミング
さて、上記によりモデルが new されてアクセサメソッドが定義されるまでの流れは分かりました。話を戻して型変換が実際に実行される処理を確認してみたいと思います。すなわち、今回の例では(2)を実行すると起きること、です。
(1) task = Task.new(tests: "2019/01/01") (2) Time.use_zone("UTC"){ task.tests }(2)の
task.tests
(=Model.newしたときに動的に定義されたアクセサメソッド)を実行すると、上記で確認したように以下メソッドの内容が実行されることになります。read.rbdef #{temp_method} #{sync_with_transaction_state} name = ::ActiveRecord::AttributeMethods::AttrNames::ATTR_#{safe_name} _read_attribute(name) { |n| missing_attribute(n, caller) } end
_read_attribute(name)
が属性値を読み込んで値を返答している箇所と考えられるのでこの部分を追ってみると、同ファイルに定義されています。read.rbdef _read_attribute(attr_name) # :nodoc: @attributes.fetch_value(attr_name.to_s) { |n| yield n if block_given? } end
@attributes
はActiveModel::AttributeSet
クラスです。
fetch_value
メソッドを追ってみると、以下で定義されていました。attribute_set.rbdef fetch_value(name) self[name].value { |n| yield n if block_given? } endhttps://github.com/rails/rails/blob/5-2-stable/activemodel/lib/active_model/attribute_set.rb
self[name].value
は今回はWebブラウザからリクエストを送信しておりActiveModel::Attribute::FromUser
でした。
ここで実行されるvalue
メソッドを追うと以下の定義されていました。attribute.rbdef value # `defined?` is cheaper than `||=` when we get back falsy values @value = type_cast(value_before_type_cast) unless defined?(@value) @value endhttps://github.com/rails/rails/blob/5-2-stable/activemodel/lib/active_model/attribute.rb
さて、上記まで来るとかなり具体的なな処理が見えてきたように思います。
すなわち、
type_cast
メソッドで元々の入力値(value_before_type_cast
、今回では"2019/01/01"
)をキャストしている- 一度キャストして返答した値は再びキャストしない(
unless defined?(@value)
)と考えてよいでしょう。せっかくなので
type_cast
ももう少し追ってみようと思います。同ファイル内に以下の定義があります。attribute.rbclass FromUser < Attribute # :nodoc: def type_cast(value) type.cast(value) endhttps://github.com/rails/rails/blob/5-2-stable/activemodel/lib/active_model/attribute.rb
type.class
はActiveRecord::AttributeMethods::TimeZoneConversion::TimeZoneConverter
です。そのクラスのcast
メソッドを確認してみると以下の定義が見つかります。time_zone_conversion.rbdef cast(value) return if value.nil? if value.is_a?(Hash) set_time_zone_without_conversion(super) elsif value.respond_to?(:in_time_zone) begin super(user_input_in_time_zone(value)) || super rescue ArgumentError nil end else map_avoiding_infinite_recursion(super) { |v| cast(v) } end end今回
value
は"2019/01/01"
であり、Railsでは文字列が日時への変換対象のフォーマットを満たしていれば in_time_zoneメソッドで変換できるので、begin super(user_input_in_time_zone(value)) || super rescue ArgumentError nil endの処理が実行されます。
user_input_in_time_zone
メソッドを追うと、time_value.rbdef user_input_in_time_zone(value) value.in_time_zone endが、実行されていました。なるほど型変換の実体は in_time_zoneメソッドが実行されていわけですね。すなわちその時の
Time.zone
のタイムゾーンにしたがって値が変換されると理解できます。まとめ
さて、最初に戻って、以下のアクション(
TasksController#index
)が実行された場合に# ??
の部分がTue, 01 Jan 2019 00:00:00 UTC +00:00
となる理由は、
- (1) のタイミングでは各属性のアクセサメソッド等が定義されたたけで、実際にアクセサメソッド経由で取得される値の生成(型変換)はされていない
- (2) のタイミングではじめてアクセサメソッドが実行され、元々入力された値が(必要な場合に)型変換されて返答される
- 型変換は String#in_time_zone で実行されており、このときのタイムゾーンはUTCのためUTCのタイムゾーンで値が生成される
- 一度型変換された値は二度目以降にアクセサメソッドが実行された後は再度型変換されないため、(3)のタイミングではタイムゾーンがTokyoであっても(2)で生成されたUTCの値が読み出される
tasks_controller.rbclass TasksController < ApplicationController def index task = Task.new(tests: "2019/01/01") # (1) Time.use_zone("UTC"){ task.tests } # (2) puts task.tests # ?? (3) end end感想
長かった…。
参考
『メタプログラミングRuby』にも少しActive Recordの記載があった(ただし少しVersionが古いので今と違う部分があるかも)。
メタプログラミングRuby 第2版posted with amazlet at 19.10.12Paolo Perrotta
オライリージャパン
売り上げランキング: 85,250
- 投稿日:2019-10-12T22:49:48+09:00
【rails】bootstrapでページネーション機能を作成する
gemのインストール
kaminari
のgemをインストールします。gem 'kaminari' gem 'kaminari-bootstrap', '~> 3.0.1' #bootstrap3用$ bundle installインストール後、サーバーを再起動します。
ymlファイルの作成
config/locales
にkaminari_ja.yml
を作成し、以下を記載します。kaminari_ja.ymlja: views: pagination: first: "« 最初" last: "最後 »" previous: "‹ 前" next: "次 ›" truncate: "..."コントローラーの変更
class PostsController < ApplicationController def index @posts = Post.all end以下のように変更します。
PER = 5 #区切りたいところを決める class PostsController < ApplicationController def index @posts = Post.page(params[:page]).per(PER) endビューの変更
挿入したい箇所に以下を記入します。
<div class="paginate text-center"> <%= paginate @like_posts %> </div>完成
以上で、ページネーション機能が作成出来ます!
- 投稿日:2019-10-12T21:50:43+09:00
Gmailを用いた ActionMailer の使い方
はじめに
ActionMailerの実装は割と簡単にできたのですが、エラーコードが出ずにGmailの設定でかなりの時間を費やしてしまいました。
次にやるときには時間がかけずにすむようにまとめておきたいと思います。コーディング
コマンド(自動生成)
rails g mailer UserMailer create app/mailers/user_mailer.rb create app/mailers/application_mailer.rb invoke erb create app/views/user_mailer create app/views/layouts/mailer.text.erb create app/views/layouts/mailer.html.erb invoke test_unit create test/mailers/user_mailer_test.rb create test/mailers/previews/user_mailer_preview.rbMailer
app/mailers/application_mailer.rbclass ApplicationMailer < ActionMailer::Base default from: "from@example.com" layout 'mailer' endapp/mailers/user_mailer.rbclass UserMailer < ApplicationMailer default from: '~~~@gmail.com' # ここのメソッド名をメール文面の view ファイルの名前にする。 # user と url は呼び出し元の コントローラーのメソッドから渡される。 def user_create(user, url) # @user, @url に値を入れて view に渡す。 @user = user @url = url mail(to: "user.name", subject: "ユーザーを新規登録しました。") endController
user_controller.rbclass UsersController < ApplicationController def index end def new @user = User.new end def create @user = User.new(user_params) if @user.save @url = request.url + "/" + @user.id.to_s NotificationMailer.user_create(@user, @url).deliver redirect_to(user_path(@user)) else render :new end end def show @user = User.find(params[:id]) end def edit @user = User.find(params[:id]) end def update @user = User.find(params[:id]) if @user.update(user_params) @user = current_user @url = request.url NotificationMailer.user_update(@user, @url).deliver redirect_to(user_path(@user)) else render :new end end endView
メール本文のテンプレートはデフォルトで二種類の形式が提供されています。
views/user_create/user_create.html.erb<h1>UserMailer#user_create</h1> <p> <%= @user %> 様 </p> <p> <%= @url %>, find me in app/views/user_mailer/user_create.html.erb </p>views/user_create/user_create.text.erbUserMailer#user_create <%= @user %> 様 <%= @url %>, find me in app/views/user_mailer/user_create.text.erbGmail googleの設定(重要)
google 二段階認証プロセスの設定
https://myaccount.google.com/signinoptions/two-step-verification/enroll-welcomegoogle アプリパスワードの作成
https://security.google.com/settings/security/apppasswordsconfig/initializers/mail.rbActionMailer::Base.delivery_method = :smtp ActionMailer::Base.smtp_settings = { # address のところは変更しないので注意。自分はここでハマりました。 address: 'smtp.gmail.com', domain: 'gmail.com', port: 587, # user_name は自分のメールアドレスを記載。 user_name: 'Gmail のメールアドレス', # password は作成したアプリパスワードを記載。 password: 'Gmail のパスワード', authentication: 'plain', enable_starttls_auto: true }まとめ
駆け出しのエンジニアですので、何か不備がありましたらご連絡をお願いします。
参考
https://railsguides.jp/action_mailer_basics.html
https://qiita.com/hirotakasasaki/items/ec2ca5c611ed69b5e85e
https://thr3a.hatenablog.com/entry/20171202/1512175059
- 投稿日:2019-10-12T21:13:34+09:00
Rails ファイル添付機能 複数モデルでの共通化
はじめに
DRYの考え方を意識しはじめ、効率的なコーディングだと感じたので備忘録としてまとめます。
構成
UserモデルとPostモデルの両方にファイル添付機能を持たせたいとき、
Attachment_fileモデルに添付ファイルを格納して、
中間テーブルとしてUser_attachment_fileモデルとPost_attachment_fileモデルを設ける。
- Attachment_fileモデル
- Userモデル
- User_attachment_fileモデル
- Postモデル
- Post_attachment_fileモデル
Gemfile
下記を書いて、bundle install
gem 'carrierwave'コーディング
Model
- Attachment_fileモデル
- Userモデル
- User_attachment_fileモデル
- Postモデル
- Post_attachment_fileモデル
attachment_file.rbmount_uploader :file, FileUploader after_destroy :destory_intermediate has_many :user_attachment_files has_many :users, through: :user_attachment_files has_many :post_attachment_files has_many :posts, through: :post_attachment_files def destory_intermediate user_attachment_files.destroy if user_attachment_files.present? post_attachment_files.destroy if post_attachment_files.present? enduser.rbclass User < ActiveRecord::Base has_many :user_attachment_files, dependent: :destroy has_many :user_files, through: :user_attachment_files, dependent: :destroy enduser_attachment_file.rbclass UserAttachmentFile < ActiveRecord::Base belongs_to :user belongs_to :attachment_file endpost.rbclass Post < ActiveRecord::Base has_many :post_attachment_files, dependent: :destroy has_many :post_files, through: :post_attachment_files, dependent: :destroy endpost_attachment_file.rbclass PostAttachmentFile < ActiveRecord::Base belongs_to :post belongs_to :attachment_file endController
Attachment_fileモデル
Attachment_fileモデル
attachment_files_controller.rbclass AttachmentFilesController < ApplicationController def create @attachment_file = AttachmentFile.create!(file_params) respond_to do |format| format.html format.json {render json: @attachment_file } end end def destroy @attachment_file = AttachmentFile.find(params[:id]) if @attachment_file.destroy render :json => { result: 'success' } else render :json => { result: 'error' } end end private def file_params params.require(:attachment_file).permit(:id, :file) end endView
Dropzoneを使っています。ここでは詳細は割愛します。
(Dropzone.jsで複数ファイルアップロード後、削除したいファイルを指定したい:https://qiita.com/saekis/items/207379a056af73f143b7)
users/new.html.slimtr th = label :user, :user_file td #user_file_uploader.dropzone / ポイント table.files - for file in @user.attachment_files do tr id="file_row_#{file.id}" td = file.original_filename = hidden_field_tag nil, file.id, name:'user[attachment_file_ids][]' td = link_to file.file_url, download: file.original_filename do = fa_icon "download" |ダウンロード td = link_to '#', onclick: "#", file_id: file.id, remote: true do |削除Table
中間テーブル(User_attachment_file、Post_attachment_file)を持っているため、UserモデルとPostモデルではカラムを設ける必要はありません。
- Userモデル
- User_attachment_fileモデル
- Postモデル
- Post_attachment_fileモデル
- Attachment_fileモデル
schema.rb# Userモデル create_table "users", force: :cascade, options: do |t| t.datetime "created_at", null: false t.datetime "updated_at", null: false end # User_attachment_fileモデル create_table "user_attachment_files", force: :cascade, options: do |t| t.integer "user_id", limit: 4, null: false # ポイント t.integer "attachment_file_id", limit: 4, null: false # ポイント end # Postモデル create_table "posts", force: :cascade, options: do |t| t.datetime "created_at", null: false t.datetime "updated_at", null: false end # Post_attachment_fileモデル create_table "post_attachment_files", force: :cascade, options: do |t| t.integer "post_id", limit: 4, null: false # ポイント t.integer "attachment_file_id", limit: 4, null: false # ポイント end # Attachment_fileモデル create_table "attachment_files", force: :cascade, options: do |t| t.string "file", limit: 255 # ポイント t.string "original_filename", limit: 255 # ポイント t.datetime "created_at", null: false t.datetime "updated_at", null: false endまとめ
先輩のコードを見てこの方法を知りました。
人のコードを読むことの重要性を強く感じたので、コーディング → リファクタリング のサイクルを大切にしたいです。
- 投稿日:2019-10-12T20:41:11+09:00
【Rails】自分のアクティビティ一覧を表示する【通知機能の応用】
こんにちは!
ねこじょーかー(@nekojoker1234)と申します。先日、ゼロから独学で勉強して、Webサービス「Lookmine」を立ち上げました。
このサービスでは、以下のような通知機能を実装しています。
この機能を応用して、自分が「いいね、コメント、フォロー」した履歴を「アクティビティ」として一覧で見る機能を作りました。
やっぱり、誰にいいねをしたとか、誰に何のコメントをしたとかは一覧で見れたほうがいいですよね。
そんなわけで、実装方法をこの記事で解説することにしました。
通知機能の実装が終わっている前提なので、まだ通知機能が出来ていない人は、「通知機能を実装する方法」から読んでくださいね。
アクティビティ一覧画面の作成
アクティビティ一覧の画面を作っていきましょう。
まずは、アクティビティコントローラーの作成からです。$ rails g controller activities通知一覧の画面は
index
で作るので、ルーティングを追加しておきましょう。
他のメソッドは不要なので、only
を追加しています。config/routes.rbresources :activities, only: :index
index
アクションを実装します。app/controllers/activities_controller.rbclass NotificationsController < ApplicationController def index @activities = current_user.active_notifications.page(params[:page]).per(20) end endアクティビティの一覧を表示するために新しくテーブルを作る必要はなく、通知機能で使ったテーブルをそのまま流用します。
今回は、
active_notifications
で、自分が送った通知を取得します。通知機能の実装で、以下の記述をしたのを覚えていますか?
app/models/user.rbhas_many :active_notifications, class_name: 'Notification', foreign_key: 'visitor_id', dependent: :destroy has_many :passive_notifications, class_name: 'Notification', foreign_key: 'visited_id', dependent: :destroy通知機能のときは、
passive_notifications
を使って、相手に送った通知を取得していました。
今回は自分が送った通知を取得したいので、active_notifications
を使います。次に、画面の実装です。
index
の画面を作っていきましょう。app/views/activities/index.html.slim.col-md-6.mx-auto - if @activities.exists? - @activities.each do |activity| = render 'activities/activity', activity: activity - else p.text-center | アクティビティはありません自分が送った通知の分だけ、部分テンプレート
_activity.html.slim
を呼び出しています。app/views/activities/_activities.html.slim- visitor = activity.visitor - visited = activity.visited .form-inline span - case activity.action - when 'follow' then = link_to user_path(visited) do = image_tag avatar_url(visited).to_s, class: "icon_mini" strong = visited.name = "さんをフォローしました" - when 'like' then span = link_to post_path(activity.post) do = image_tag avatar_url(activity.post.user).to_s, class: "icon_mini" strong = activity.post.user.name + 'さんの投稿' = "にいいねしました" - when 'comment' then - if activity.post.user_id == visitor.id = link_to "あなたの投稿", activity.post, style: "font-weight: bold;" - else span = link_to post_path(activity.post) do = image_tag avatar_url(activity.post.user).to_s, class: "icon_mini" strong = activity.post.user.name + 'さんの投稿' = "にコメントしました" p.text-muted.mb-0 = Comment.find_by(id: activity.comment_id)&.comment .small.text-muted.text-right = time_ago_in_words(activity.created_at).upcase hrこれを実装すると、以下のアクティビティ一覧が出来上がります。
フォローは相手のプロフィールをリンクにしています。
コメントは、コメント先の投稿をリンクにしていて、自分の投稿に対するコメントは「あなたの投稿」という表現にしています。
自分の投稿なのに「〇〇さんの投稿にコメントしました」という表現は、違和感がありますよね。これで完成です!
お疲れさまでした!あわせて読みたい
- HTMLもわからない初心者が、独学で「投稿型SNSサービス」を作ったって本当?【193日間の死闘】
- Webプログラミング「経験0」の私が、「193日間の独学」でWebサービスを立ち上げた話(外部リンク)
筆者のブログ:https://nekojokerblog.com
- 投稿日:2019-10-12T20:34:46+09:00
可変クラスの作り方 Rails Slim
- 投稿日:2019-10-12T19:55:04+09:00
Rails new したらこんなメッセージが表示されたので、調べてみた1.【chromedriver-helper is deprecated after 2019-03-31.】2.【Ruby Sass has reached end-of-life and should no longer be used.】
環境
ruby '2.6.5'
gem 'rails', '~> 5.2.3'
gem 'mysql2', '>= 0.4.4', '< 0.6.0'メッセージ
+--------------------------------------------------------------------+ | | | NOTICE: chromedriver-helper is deprecated after 2019-03-31. | | | | Please update to use the 'webdrivers' gem instead. | | See https://github.com/flavorjones/chromedriver-helper/issues/83 | | | +--------------------------------------------------------------------+ Post-install message from sass: Ruby Sass has reached end-of-life and should no longer be used. * If you use Sass as a command-line tool, we recommend using Dart Sass, the new primary implementation: https://sass-lang.com/install * If you use Sass as a plug-in for a Ruby web framework, we recommend using the sassc gem: https://github.com/sass/sassc-ruby#readme * For more details, please refer to the Sass blog: https://sass-lang.com/blog/posts/7828841こんなメッセージが表示されたので、とりあえずGoogle翻訳に頼ってみました
- 翻訳
+--------------------------------------------------------------------+ | | | 注意:chromedriver-helperは2019-03-31以降廃止されます | | | | 代わりに 'webdrivers' gemを使用するように更新してください。 | | https://github.com/flavorjones/chromedriver-helper/issues/83 | | を御覧ください | +--------------------------------------------------------------------+ Post-install message from sass: Ruby Sassはサポート終了になったため、使用しないでください。 * Sassをコマンドラインツールとして使用する場合は、新しいDart Sassを使用することをお勧めします 主要な実装:https://sass-lang.com/install * SassをRuby Webフレームワークのプラグインとして使用する場合は、 sassc gem:https://github.com/sass/sassc-ruby#readme *詳細については、Sassブログを参照してください。 https://sass-lang.com/blog/posts/7828841ここで表示されているメッセージで言おうとしていることは以下の2つみたいです
- chromedriver-helper はサポート終わるから、代わりに
webdrivers
gem を使ってね- Ruby Sass はサポート終了になるから対応策を載せておくよ。それぞれ対応してね
ってことみたいです
1. chromedirver-helper から webdrivers へ移行する
Gemfileにデフォルトで
gem 'chromedriver-helper'
と記述されているので、gem 'webdirvers'
へ書き換えるGemfilegroup :test do # Adds support for Capybara system testing and selenium driver gem 'capybara', '>= 2.15' gem 'selenium-webdriver' # Easy installation and use of chromedriver to run system tests with Chrome # gem 'chromedriver-helper' # この行を削除 gem 'webdrivers' # この行を追加 end
chromedriver-helper
について、webdrivers
への詳しい移行手順を下の記事で載せてくれていますので、参考にさせてもらいました。サポートが終了したchromedriver-helperからwebdrivers gemに移行する手順 - Qiita
2.sass-rails から sassc-rails へ書き換える
Gemfileの
gem 'sass-rails', '...'
の部分をgem 'sassc-rails'
へ書き換えるGemfile# gem 'sass-rails', '~> 5.0' この行を削除 gem 'sassc-rails' # この行を追加保存後
bundle install
を実行これで先程のメッセージは表示されなくなりました。
【rails5】Ruby Sass is deprecated and will be unmaintained as of 26 March 2019. というメッセージ - Qiita
上記の記事を参考にしました。こちらの記事ではGemfile.lock
内のsass
となっている箇所の削除となっていますが、自分は削除を行わずbundle install
を実行してみました。Gemfile.lock# 省略 sassc (2.2.1) ffi (~> 1.9) sassc-rails (2.1.2) railties (>= 4.0.0) sassc (>= 2.0) sprockets (> 3.0) sprockets-rails tilt # 省略 DEPENDENCIES # 省略 sassc-rails # 以下省略
bundle install
後 Gemfile.lock ファイルを確認するとsass-rails
からsassc-rails
へ書き換わっている
rails server
を実行サーバーが起動したので、正常に動作してるっぽいです。
また何かあれば追記していこうと思います。参考
- 投稿日:2019-10-12T19:51:23+09:00
rootへのルーティング設定方法
目的
アプリの開発で仕様するrootメソッドの使い方をアウトプットを目的に備忘録的に残します。
ルーティング設定を行う
Railsアプリを作成、起動後「http://localhost:3000/」 にアクセスすると「public.index.html」に記載された内容が呼び出されています。
ただ、この状態はルートへアクセスしたときに用意したhtmlファイルを返しているだけです。もしルートにアクセスした場合に特定のアクションを実行させたい場合、「root」メソッドを使ったルーティングを設定する必要があります。
そこで、ルーティングを設定して特定のアクションを実行し、viewを表示する方法を紹介していきます。ルーティングの設定のため「config/routes.rb」ファイルを編集します。
indexアクションのビューをrootに設定されるように追記します。config/routes.rbroot to: 'home#index'まとめ
rootメソッドを定義することによって特定のアクションを実行することができます。
- 投稿日:2019-10-12T19:37:34+09:00
はじめてのPostgreSQL
この記事が対象とする読者
- PostgreSQLをはじめて使う人
Homebrew
を使ったインストールの仕方を簡潔にまとめます。インストールの流れ
1. ターミナルからインストール
まずは、以下のコマンドを入力・実行します。
$ brew install postgresql2. インストールの確認
正常にインストールできているかどうかを確認します。
バージョンを表す-V
は大文字なので注意です。$ postgres -V postgres (PostgreSQL) 11.53. PostgreSQLを起動
データベースとして使用するためには以下の起動のコマンドも必要です。
$ brew services start postgresql ==> Successfully started `postgresql` (label: homebrew.mxcl.postgresql)ここまで完了すればデータベースが作成できるようになるはずです!
さいごに
PostgreSQL初心者による初心者のためのQiitaでした。
簡単な工程なのですが、検索しながらやっていたら迷ってしまったので共有しておきます。少しでも参考になればうれしいです。
- 投稿日:2019-10-12T18:59:30+09:00
GAE(FE)にDocker環境上のRuby on Railsをデプロイする
はじめに: Dockerで開発したら手軽にデプロイまでしたい。
Ruby on Railsの開発で今や主流のDocker環境。
ネット上に環境構築の情報は豊富に転がっているし、local開発は出来たし、Herokuにもデプロイできた。でもやっぱりHerokuだとイマイチ速度が出ないし、
何よりAWSとかGCP使ってるほうがカッコイイ気がする!(小並感)圧倒的に情報不足なDockerに乗っけたままAWSやGCPにデプロイをする方法。
今回は既にHerokuで運用中のwebサービスをGAE環境に移し替えたのでその際に行った手順と、躓いた点を書いていこうと思います。自分自身も右往左往しながら、なんとかデプロイできたー!!動いたー!!
という感じなので、間違っている点や、改善点などが有りましたら是非色々とご教示いただけると助かります。前提
- 既にDocker+ docker-composeで環境構築済み、動作確認済みのRuby on Railsアプリケーションがある
- GCPアカウント及びプロジェクトが作成済
- Cloud SDKが導入済み
【参考】
Dockerを使ってRuby on Rails環境の構築をしてみる
https://qiita.com/me-654393/items/d11b871ce8d76e153b21Cloud SDK のインストール
https://cloud.google.com/sdk/downloads?hl=jaApp Engineにアプリを作成する
まず最初に、ターミナルからGAEアプリを作成します。
$ gcloud app create You are creating an app for project [project-name]. WARNING: Creating an App Engine application for a project is irreversible and the region cannot be changed. More information about regions is at <https://cloud.google.com/appengine/docs/locations>. Please choose the region where you want your App Engine application located: [1] asia-east2 (supports standard and flexible) [2] asia-northeast1 (supports standard and flexible) [3] asia-northeast2 (supports standard and flexible) [4] asia-south1 (supports standard and flexible) [5] australia-southeast1 (supports standard and flexible) [6] europe-west (supports standard and flexible) [7] europe-west2 (supports standard and flexible) [8] europe-west3 (supports standard and flexible) [9] europe-west6 (supports standard and flexible) [10] northamerica-northeast1 (supports standard and flexible) [11] southamerica-east1 (supports standard and flexible) [12] us-central (supports standard and flexible) [13] us-east1 (supports standard and flexible) [14] us-east4 (supports standard and flexible) [15] us-west2 (supports standard and flexible) [16] cancel Please enter your numeric choice: 2 Creating App Engine application in project [project-name] and region [asia-northeast1]....done. Success! The app is now created. Please use `gcloud app deploy` to deploy your first app.asia-northeast1が東京リージョンですので、選択します。
※[project-name]となっている部分は各々作成したGCPプロジェクト名が入ります。app.yamlを作成する
続いて、Dockerfileと同階層にapp.yamlを作成します。
app.yamlの説明に関してはここでは省略します。
【参考】https://cloud.google.com/appengine/docs/standard/go/config/appref?hl=jaapp.yamlentrypoint: bundle exec rackup --port $PORT env: flex runtime: custom env_variables: SECRET_KEY_BASE: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX(各々のsecret key baseを入れる)SECRET_KEY_BASEの取得方法は、
コンソール上で、$ docker-compose exec web bundle exec rails secret表示される文字列をコピペすればOKです。
Railsサーバの起動ポートを8080に合わせる
GAEでは、8080番に対してアクセスするので、3000番などに設定している方は8080番に変更しましょう。
Dockerfile(例)FROM ruby:2.6.3 RUN apt-get update -qq && \ apt-get install -y build-essential \ libpq-dev \ nodejs RUN mkdir /app_name ENV APP_ROOT /app_name WORKDIR $APP_ROOT ADD ./Gemfile $APP_ROOT/Gemfile ADD ./Gemfile.lock $APP_ROOT/Gemfile.lock RUN bundle install ADD . $APP_ROOT # 8080番でポートを起動する CMD /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 8080 -b '0.0.0.0'"docker-compose.yml(例)version: "3" services: web: environment: TZ: Asia/Tokyo build: . volumes: - .:/app ports: - 8080:8080 tty: true stdin_open: true volumes: db-volume:基本的な準備はここまで。
いざデプロイ!
さて、待ちに待ったデプロイ。この瞬間が一番ドキドキします。
ターミナルを開いて、$ gcloud app deploy descriptor: [/project-name/app.yaml] source: [/projects/project-name] target project: [project-name] target service: [default] target version: [20190000t123456] target url: [https://project-name.appspot.com] Do you want to continue (Y/n)? Y(←上記の内容で問題なければ、Yを入力します。)ビルドが始まり、しばらく待ち、
Updating service [default] (this may take several minutes)...done. Setting traffic split for service [default]...done. Deployed service [default] to [https://project-name.appspot.com] You can stream logs from the command line by running: $ gcloud app logs tail -s default To view your application in the web browser run: $ gcloud app browseと、表示されれば成功。
$ gcloud app browseで確認しましょう。
トラブルシューティング
「Switch to inspect mode.」と怒られる件について
Updating service [default] (this may take several minutes)...failed. ERROR: (gcloud.app.deploy) Error Response: [9] Application startup error: Switch to inspect mode.色々ググったけど今ひとつ情報源に当たれずにめちゃくちゃ困ってた。
8080番でRailsが起動しておらず、GAEがアクセスできていないってことだと思う。原因はdocker-compose側でサーバーを起動していたこと。
docker-compose.yml(例)version: "3" services: web: build: . # ここがアウト command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 8080 -b '0.0.0.0'" volumes: - .:/app_name ports: - "8080:8080" links: - dbこれだとこのエラーが出るみたい。
原因はいまいちよくわかっていないが、もしかしたらdocker-compose読んでいないのかも?8080番ポートの下りで記載したDockerfileのように、
DockerfileCMD /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 8080 -b '0.0.0.0'"で、8080を開いてあげるのがいいのかも。
【参考】
A weekend, a Rails app, a Kubernetes and an Azure.
https://medium.com/@michiels/a-weekend-a-rails-app-a-kubernetes-and-an-azure-d330b003d7c2最後に:Herokuの方がわかりやすいけど、やっぱりGAE早い
今回は実行速度が気になったので、HerokuからGAEに乗り換えることを決意したわけですが、
予想通りGAEの方が速度が出ました。特にRailsの中身をいじること無く、20程度速度が速度が上昇しました。
改善案の部分でサーバー応答時間の短縮(TTFB)が表示されなくなったのがでかい気がします。おまけ:宣伝
今回HerokuからGAEに移行したのはスポチューバーTVという、野球の技術指導メディアです。
スポーツ教育×Techの、主に野球の分野を伸ばしていけたらなと思っているので、興味のある方は是非御覧ください。
https://spotuber-tv.com/参考
- https://medium.com/@michiels/a-weekend-a-rails-app-a-kubernetes-and-an-azure-d330b003d7c2
- https://qiita.com/ClapAndWhistle/items/23e3b4323fd06342b7c4
- https://cloud.google.com/ruby/rails/appengine?hl=ja
- https://qiita.com/takamario/items/33adc033090c31aeb702
- https://qiita.com/kshibata101/items/441de47fcb2d94875e85
- https://qiita.com/shwld/items/e86ee3f642c7857dd56e
- 投稿日:2019-10-12T18:39:35+09:00
自分用メモ(View・部分テンプレート)
Viewあたり
レイアウト
部分テンプレートとも似ているが、レイアウトはページの外枠を定義するのに利用する(ヘッダー・フッター・メニューなど)
パーシャル(_〇〇.html.erb)
Viweの共通化に用いられる
ファイル名の先頭にアンダースコア( _ )をつける呼び出すときはアンダースコアをつけない
ex)
layoutディレクトリの_form.html.erb↓呼び出すときは
render 'layout/form'(app/viewsからの相対パスを用いる)部分テンプレート
複数ページで共通の領域がある場合使用する(毎回同じコードを記載するのは無駄なので)
レイアウトとは違い、ページの外枠ではない、もう少し部分的なページの共通領域を定義するために利用する<% %>と<%= %>の違いがピンと来ていない
<%= %>
与えられた式を出力する<% %>
がブロックの中のコードを実行するだけ
→出力しないでもokな時にこちらを使用する(条件やループ)基本的にテンプレートファイル(コントローラー名/アクション名.html.erb)は画面に大して何らかの出力を行うので、ほとんどの記述は<%= %>で行う
yieldとprovide
<% provide(:tag,xxx) %>で入力しxxxを
<%= yield(:tag) %>で受け取る感じ
- 投稿日:2019-10-12T18:21:13+09:00
Sessionメソッドの使い方、宣言方法
目的
ログイン機能を実装するときにSessionメソッドを使用するが、
機能の流れをおさらいするために備忘録として残しておく。セッションとは?
・主にログイン機能に使用されるもので、ログイン状態を持続させるためにある機能。
・ステートフルな通信を実現するために必要な機能。セッションという仕組みがなけれはページを移動するたびにログインし直さなければならない。
ログイン機能を実装するためRailsではあらかじめセッションを実装するためのメソッドが用意している。
また、セッションの情報はRailsの標準では、ブラウザ側のクッキーに保存される。Sessionメソッドの使い方
まずは、ユーザーを登録するためにユーザーモデルを準備する。
ユーザーモデルには、名前とメールとパスワードが登録できるようにします。gemをGemfileに追加
パスワードを暗号化するための
(コメントアウトされているためコメントインする必要がある)Gemfilegem 'bcrypt', '~> 3.1.7'コメントインが完了したらgemをインストールする必要がある。
bundle installUserモデルを作成
rails g model Users name:string email:string password_digest:stringpassword_digestというカラムにはパスワードが入ります。
こちらはgemであるbcryptの仕様ですが、このカラムにするとパスワードが暗号化されて保存されます。migrationファイルが作成されたので、データベースに反映しましょう。
rails db:migrateこれでユーザーモデルの作成は完成です。
次に作成したユーザモデルにパスワードの暗号化を有効にするための設定を加えます。
app/models/user.rbhas_secure_password
Sessionコントローラーを作成
ログイン機能を作成するためセッションコントローラーを作成する。
rails g controller sessionsapp/controllers/session_sontroller.rbclass SessionsController < ApplicationController def new end def create user = User.find_by(email: params[:session][:email].downcase) if user && user.authenticate(params[:session][:password]) session[:user_id] = user.id redirect_to user_path(user.id) else render 'new' end end endログインボタンを押した後に、セッションに情報が保存されているか判断しています。
user = User.find_by(email: params[:session][:email].downcase)params[:session][:email]で、ユーザのポストでした値を取り出し、メールアドレスには小文字しか入力できないため.downcaseで小文字に変換しています。
その後find_byメソッドで入力したemailをカラムに保存されたemailが一致した場合にユーザーに代入しています。次に、
if user && user.authenticate(params[:session][:password])&&を使って、条件を2つ指定しています。
・user:userの中身があるかどうか
・user.authenticate:userに代入されたレコードのパスワードがポストした値と一致しているかパスワードが登録しているユーザー情報と一致していたらセッションにユーザーIDを登録しています。
session[:user_id] = user.idsession[:名前]は名前をつけて、セッションを登録できます。
また、elseの場合、
render 'new'パスワードが登録しているユーザ情報と一致していなかった場合、入力フォームに再度飛ぶように設定されている。
これでセッションを作成することができました。
まとめ
セッションを作成する際に必要なものは以下である。
・パスワードを暗号化するためのgem:bcrypt
・gem:bcryptで暗号化したパスワードを保存するカラム:password_digest
・パスワードの暗号化を有効にするための設定:has_secure_password
・セッションを作成するためにメソッド:session[:名前] = params[:~]
- 投稿日:2019-10-12T18:01:52+09:00
MacでRailsにgem mysql2をインストールする時のトラブルシューティング
はじめに
2019年10月現在MacでRailsアプリ開発時にDBにMySQLを選択する場合、デフォルトではmysql2というgemをインストールします。
その時にいくつかエラーに出会ったので、まとめておきます。実行環境
- macOS Mojave v10.14.6
- ruby v2.6.4
- Rails v6.0.0
MySQLのクライアントが必要
MacにMySQLクライアントをインストールしていない場合、以下のようなエラーが表示されます。
Fetching mysql2 0.5.2 Installing mysql2 0.5.2 with native extensions Gem::Ext::BuildError: ERROR: Failed to build gem native extension. current directory: /Users/hogehoge/sample-app/vendor/bundle/gems/mysql2-0.5.2/ext/mysql2 /Users/hogehoge/.rbenv/versions/2.6.4/bin/ruby -I /Users/hogehoge/.rbenv/versions/2.6.4/lib/ruby/2.6.0 -r ./siteconf20191012-40688-181m253.rb extconf.rb checking for rb_absint_size()... yes checking for rb_absint_singlebit_p()... yes checking for rb_wait_for_single_fd()... yes checking for -lmysqlclient... no ----- mysql client is missing. You may need to 'brew install mysql' or 'port install mysql', and try again.Homebrewなどでインストールしておきましょう。
なお、2019年10月現在gemが対応しているバージョンは以下のようですので、採用バージョンに応じたものをインストールしましょう。This gem is tested with the following MySQL and MariaDB versions:
MySQL 5.5, 5.6, 5.7, 8.0
MySQL Connector/C 6.0 and 6.1 (primarily on Windows)
MariaDB 5.5, 10.0, 10.1, 10.2, 10.3(https://github.com/brianmario/mysql2 READMEより引用)
# MySQL最新バージョン(8.0) $ brew install mysql # 5.xの場合 $ brew install mysql@5.x5.x系の場合はmysqlコマンドを使えるよう以下のようにPATHを通しておきましょう。
$ export PATH="/usr/local/opt/mysql@5.7/bin:$PATH"bundle install時のlinkerエラー
無事MySQLクライアントをインストールできていても、以下のようなエラーが起こる場合があります。
Fetching mysql2 0.5.2 Installing mysql2 0.5.2 with native extensions Gem::Ext::BuildError: ERROR: Failed to build gem native extension. current directory: /Users/hogehoge/sample-app/vendor/bundle/gems/mysql2-0.5.2/ext/mysql2 /Users/hogehoge/.rbenv/versions/2.6.4/bin/ruby -I /Users/hogehoge/.rbenv/versions/2.6.4/lib/ruby/2.6.0 -r ./siteconf20191012-62886-155hohe.rb extconf.rb checking for rb_absint_size()... yes checking for rb_absint_singlebit_p()... yes checking for rb_wait_for_single_fd()... yes ----- Using mysql_config at /usr/local/bin/mysql_config ----- checking for mysql.h... yes checking for errmsg.h... yes checking for SSL_MODE_DISABLED in mysql.h... yes checking for SSL_MODE_PREFERRED in mysql.h... yes checking for SSL_MODE_REQUIRED in mysql.h... yes checking for SSL_MODE_VERIFY_CA in mysql.h... yes checking for SSL_MODE_VERIFY_IDENTITY in mysql.h... yes checking for MYSQL.net.vio in mysql.h... yes checking for MYSQL.net.pvio in mysql.h... no checking for MYSQL_ENABLE_CLEARTEXT_PLUGIN in mysql.h... yes checking for SERVER_QUERY_NO_GOOD_INDEX_USED in mysql.h... yes checking for SERVER_QUERY_NO_INDEX_USED in mysql.h... yes checking for SERVER_QUERY_WAS_SLOW in mysql.h... yes checking for MYSQL_OPTION_MULTI_STATEMENTS_ON in mysql.h... yes checking for MYSQL_OPTION_MULTI_STATEMENTS_OFF in mysql.h... yes checking for my_bool in mysql.h... no ----- Dont know how to set rpath on your system, if MySQL libraries are not in path mysql2 may not load ----- ----- Setting libpath to /usr/local/Cellar/mysql/8.0.17_1/lib ----- creating Makefile current directory: /Users/hogehoge/sample-app/vendor/bundle/gems/mysql2-0.5.2/ext/mysql2 make "DESTDIR=" clean current directory: /Users/hogehoge/sample-app/vendor/bundle/gems/mysql2-0.5.2/ext/mysql2 make "DESTDIR=" compiling client.c compiling infile.c compiling mysql2_ext.c compiling result.c compiling statement.c linking shared-object mysql2/mysql2.bundle ld: library not found for -lssl clang: error: linker command failed with exit code 1 (use -v to see invocation) make: *** [mysql2.bundle] Error 1 make failed, exit code 2以下がこのエラーの原因で、ざっくり言うとgemのビルド時に、必要なopensslライブラリを見つけられないために発生しています。
ld: library not found for -lssl詳細な原因は以下記事が大変参考になります。
https://qiita.com/HrsUed/items/ca2e0aee6a2402571cf6解決策としては、bundle install時に以下オプションでpathを指定する必要があります。
- --with-cppflags
- --with-ldflags
brew info
でインストールされているopensslを確認すると、自分の環境のLDFLAGSとCPPFLAGSのpathが確認できます。$ brew info openssl@1.1 openssl@1.1: stable 1.1.1d (bottled) [keg-only] ... For compilers to find openssl@1.1 you may need to set: export LDFLAGS="-L/usr/local/opt/openssl@1.1/lib" export CPPFLAGS="-I/usr/local/opt/openssl@1.1/include" ...こちらのpathを
bundle config
で設定してからインストールしましょう。$ bundle config --local build.mysql2 "--with-cppflags=-I/usr/local/opt/openssl@1.1/include" $ bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl@1.1/lib" $ bundle install以上、自分が遭遇したエラー内容でした。
- 投稿日:2019-10-12T17:45:55+09:00
Railsチュートリアル 第10章<復習>
第10章の復習メモです。
個人的に重要と思ったことを書きます。前回と同様、以下3つの視点で書きます。
- 分かったこと
- 分からなかったこと
- 今回はスルーしたこと
分かったこと
PATCHリクエストについて
ユーザの新規作成画面(
app/views/users/new.html.erb
)と、編集画面(app/views/users/edit.html.erb
)は、画面項目が同じなため、フォームを部分テンプレートに共通化した。app/views/users/_form.html.erb<%= form_for(@user) do |f| %> <%= render 'shared/error_messages', object: @user %> <%= f.label :name %> <%= f.text_field :name, class: 'form-control' %> <%= f.label :email %> <%= f.email_field :email, class: 'form-control' %> <%= f.label :password %> <%= f.password_field :password, class: 'form-control' %> <%= f.label :password_confirmation %> <%= f.password_field :password_confirmation, class: 'form-control' %> <%= f.submit yield(:button_text), class: "btn btn-primary" %> <% end %>共通化により懸念されるのが、
- リクエスト先URLの違い
- リクエストのメソッドの違い
これらの違いがあるので、普通に考えたら、分岐の処理を入れる必要がある。しかし、これについてはRailsが上手くやってくれる。
Railsは、form_for(@user)を使ってフォームを構成すると、@user.new_record?がtrueのときにはPOSTを、falseのときにはPATCHを使います。
DBへのデータ一括登録
画面やコンソールから一件ずつ登録せずとも、DBにデータを一括登録する方法がある。
手順は以下の通り。
- Gemfileにgemを追加する
- 登録したいデータを用意する
- DBに反映させる
手順1. Gemfileにgemを追加する
Faker gem
を追加するsource 'https://rubygems.org' gem 'rails', '5.1.6' gem 'bcrypt', '3.1.12' gem 'faker', '1.7.3' # ← これを追加 . . .手順2. 登録したいデータを用意する
db/seeds.rb
ファイルに、登録したいデータを記載するdb/seeds.rbUser.create!(name: "Example User", email: "example@railstutorial.org", password: "foobar", password_confirmation: "foobar") 99.times do |n| name = Faker::Name.name email = "example-#{n+1}@railstutorial.org" password = "password" User.create!(name: name, email: email, password: password, password_confirmation: password) endExample Userという名前とメールアドレスを持つ1人のユーザと、それらしい名前とメールアドレスを持つ99人のユーザーを作成している。
手順3. DBに反映させる
現在登録されているデータを消しておきたい場合、
$ rails db:migrate:resetを実行する。
手順2をDBに反映させるには、
$ rails db:seedを実行する。
ページネーション
一覧画面で、表示件数を区切って出力できる。手順は以下の通り。
- Gemfileにgemを追加する
- ビュー、コントローラを編集する
手順1. Gemfileにgemを追加する
will_paginate gem
、bootstrap-will_paginate gem
を追加するsource 'https://rubygems.org' gem 'rails', '5.1.6' gem 'bcrypt', '3.1.12' gem 'faker', '1.7.3' gem 'will_paginate', '3.1.6' # ← これを追加 gem 'bootstrap-will_paginate', '1.0.0' # ← これを追加 . . .手順2. ビュー、コントローラを編集する
ビューに処理を追記
app/views/users/index.html.erb<% provide(:title, 'All users') %> <h1>All users</h1> <%= will_paginate %> <ul class="users"> # ← これを追加 <% @users.each do |user| %> <li> <%= gravatar_for user, size: 50 %> <%= link_to user.name, user %> </li> <% end %> </ul> <%= will_paginate %> # ← これを追加Railsチュートリアルの説明を引用
このwill_paginateメソッドは少々不思議なことに、usersビューのコードの中から@usersオブジェクトを自動的に見つけ出し、それから他のページにアクセスするためのページネーションリンクを作成しています。
コントローラの処理を変更
app/controllers/users_controller.rbclass UsersController < ApplicationController before_action :logged_in_user, only: [:index, :edit, :update] . . . def index @users = User.paginate(page: params[:page]) # ← ここを変更 end . . . endRailsチュートリアルの説明を引用
paginateでは、キーが:pageで値がページ番号のハッシュを引数に取ります。User.paginateは、:pageパラメーターに基いて、データベースからひとかたまりのデータ (デフォルトでは30) を取り出します。
paginateを使うことで、サンプルアプリケーションのユーザーのページネーションを行えるようになります。具体的には、indexアクション内のallをpaginateメソッドに置き換えます。ここで:pageパラメーターにはparams[:page]が使われていますが、これはwill_paginateによって自動的に生成されます。モデルの論理値属性
モデルの属性に、論理値(boolean)を設定できる。
migrationファイルの作成
$ rails generate migration add_admin_to_users admin:booleanmigrationファイルの編集
default: false
を追加することで、全レコードfalse(0)で登録できる。db/migrate/[timestamp]_add_admin_to_users.rbclass AddAdminToUsers < ActiveRecord::Migration[5.0] def change add_column :users, :admin, :boolean, default: false end end属性の状態を確認
<インスタンス>.<属性>?
メソッドで、属性の状態を確認できる。$ rails console --sandbox >> user = User.first >> user.admin? => false分からなかったこと、今回はスルーしたこと
- Strong Parameters
- テスト全般
- アプリケーションの仕様、ロジックの詳細
- 投稿日:2019-10-12T17:43:10+09:00
【53日目】掲示板にタグを設定しよう!② タグ検索機能の実装、
タグ検索の実装
昨日の続きとなります。
タグの初期データを用意したり、個別の掲示板にタグを設定して保存したり、掲示板詳細画面に関連づけられたタグを表示する機能については【52日目】を参照してください。今日の内容は下記のとおりです。
○ 掲示板一覧でタグによる絞り込み機能の実装
・ セレクトボックスの作成方法
○ ヘッダーメニュー(グローバルメニューの作成)
・ ヘルパーメソッドの自作方法
・ HTMLタグの自作方法
・ ルーティングの自作方法掲示板一覧画面にタグのセレクトボックスを用意し、タグを入力して、該当のタグのある掲示板だけ残すようにしていきます。
掲示板一覧にタグのセレクトボックスを追加する(view)
indexのviewを編集して、掲示板一覧からタグを選び、選んだタグに関連づけられた掲示板のみを表示するようにします。
タグの選択は、プルダウン式のセレクトボックス(select_tagヘルパー使用)によって実装します。
セレクトボックスを選んだ瞬間に掲示板が絞り込まれるのは、「onchange」という属性によってJSを実行します。index.html.erb<%= form_tag boards_path, method: :get, class: 'boards__searchForm' do %> # form_tag, アクションへのパス, HTTPメソッド, HTMLオプション # classはセレクトボックスの位置を調整するためのHTMLオプションで、あとでCSSを編集する。 <%= select_tag :tag_id, # セレクトボックスのname属性がtag_idになる。 options_from_collection_for_select(Tag.all, :id, :name, params[:tag_id]), #ヘルパーによってセレクトボックスの選択肢となるオプション要素を複数作成している #選択肢としたいオブジェクトのリスト, オプションのvalue, オプションの表示名, 何を選択状態とするの指定 # 第四引数の指定によってGET通信でURLに含まれるクエリパラメータのtag_idを選択状態とすることができ、検索後も選択した状態に出来る。 { #ハッシュの中身全部が第三引数 prompt: 'タグで絞り込み', #空白の時に表示する文字 class: 'form-control boards__select', # クラス属性に設定する値 onchange: 'submit(this.form);' #選択されるたびに実行するJSのコードを記載している #onchange属性はセレクトボックスに限らず、値が変わった際に実行されるJSのコードを設定できるイベント属性。 #ここでは、何か選択肢から選んだ時点でフォーム(this.form)を作成するようになっている } %> <% end %>CSSの編集
.boards__searchForm { display: inline-block; } .boards__select { display: inline-block; width: auto; }これによって、掲示板一覧画面の上部にタグのセレクトボックスが表示されます。
ここでタグを選ぶことによって、選んだタグのtag_idをindexアクションに送ることができる。
ただし、現状のコントローラーにはviewから渡ってきたtag_idを使って検索する機能がないので、コントローラーを編集します。tag_idを用いた検索機能の実装(controller)
tag_idに該当するタグの取得 => タグオブジェクトから関連する掲示板を取得する。
boards_controller.rbdef index @boards = params[:tag_id].present? ? Tag.find(params[:tag_id]).boards : Board.all # tag_idがあるかを確認(present? ?) # tag_idがある場合には、tag_idのパラメータを持つタグを検索(.find)し、 # 該当するタグにhas_manyでアソシエーションされている掲示板のリストを取得している(親モデル.<has_manyアソシエーション名>) # tag_idがない場合は(present? ? 存在する場合の処理 : 存在しない場合の処理)全ての掲示板(Board.all)を表示する # @boardsを参照するまではBoard.allを取得することはない。 @boards = @boards.page(params[:page]) # 上記で定義された@boardsに対して、page内に表示する件数の制限をかけてから、取得する。 # 例えば10件とした場合、10件分だけのSQLが発行される。ためBoard.allとしてもパフォーマンスに悪影響しない endヘッダーメニューの追加
ブートストラップのデザインを使用し(もちろんCSSでもいい)viewを作成し、ページを遷移しても常に表示されるメニューを作成する。
touch app/views/application/_header.html.erbを編集していく。
ここではブートストラップのナビゲーションバーのデザインを使用し、部分的に修正している。
修正箇所にコメントを付記する。
独自のヘルパーを用いる部分があるので、この後ヘルパーを定義する。_header.html.erb<nav class="navbar navbar-expand-lg navbar-dark bg-dark"> <a class="navbar-brand" href="#">BoardApp</a> #タイトル名を変更 <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria- controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarSupportedContent"> <ul class="navbar-nav mr-auto"> # リンク部分の修正。header_link_iteというへルパーを作って使用する。 # link_toとしないのは、現在表示中のページのみをアクティブ(リンクが白くなる)にするために設定を加えたいから。 # header_link_item('表示名', リンク先のパス) とすることでリンクを張れる。 <%= header_link_item('Home', root_path) %> #root_pathはrootingを追加しないと存在しないので後で追加します。ホーム画面です。 <%= header_link_item('Boards', boards_path) %> <li class="nav-item dropdown"> <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> Dropdown </a> <div class="dropdown-menu" aria-labelledby="navbarDropdown"> <a class="dropdown-item" href="#">Action</a> <a class="dropdown-item" href="#">Another action</a> <div class="dropdown-divider"></div> <a class="dropdown-item" href="#">Something else here</a> </div> </li> <li class="nav-item"> <a class="nav-link disabled" href="#">Disabled</a> </li> </ul> <form class="form-inline my-2 my-lg-0"> <input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search"> <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button> </form> </div> </nav>ヘルパーメソッドの作成
今回はグローバルメニューに使う=全ページで使うヘルパーになるので
app/helpers/application_helper.rbの中に設定する。
特定のコントローラーでしか使用しない場合は、boards_helper.rbのように区別した方が用途がわかりやすくて間違いにくい。
application_helper.rbmodule ApplicationHelper def header_link_item(name, path) class_name = 'nav-item' # ブートストラップのデザインに合わせるためのクラス class_name << ' active' if current_page?(path) # 表示中のパスと引数のパスが同一であるかを判定する # 表示するパスと引数のパスが同じであれば、クラスの属性に「active」を追加する、というもの。 content_tag :li, class: class_name do # content_tag(HTMLタグ名, HTMLクラス)で任意のHTMLタグを作成できる。 # ここでは上で作成した「class_name」を指定している。 link_to name, path, class: 'nav-link' # content_tagのブロック内に書いたHTMLが作成したタグの中で展開される。 # ここでは仮引数で受け取ったとおりにリンクを貼るアンカータグを埋め込むことになる。 end end endroot_pathの作成
次に、ルーティングを追加する。
ここではまだページは作成していない。routes.rbroot 'home#index' # パス名 'コントローラー名#アクション名'ヘッダーのview(パーシャル)の作成
ヘッダーのパーシャルをrenderで呼び出すだけ。
application.html.erb<%= render 'header' %>この後認証機能の学習に進みますが、かなりジャンルが変わるのでここで一旦投稿します。
- 投稿日:2019-10-12T16:39:21+09:00
【Ruby】=と==、&と&&、|と||の違い
RubySilverの勉強でつまづいたのでメモします。
=と==の違い
・=が左辺に代入
・==が同じ
です。example.html.slim- dinner = @dinner.vegetables? ? "食べたくない" : "食べる" = dinnerexample.rbdef hoge return false if @dinner.vegetables == "きゅうり" return false if @dinner.vegetables == "レタス" return false if @dinner.vegetables == "なす" true end&と&&の違い
・&が積集合(共通する要素を取り出す)
・&&がtrue/falseを返す(全部true(存在する)ならtrue出力)
です。a = [1, 2, 3] b = [2, 3, 4] # 共通する要素を出力 a & b => [2, 3] # 最後に評価されたb(true)を出力 a && b => [1, 2, 3] # aが偽のためnil(右辺を見ない) a = nil a && b => nil|と||の違い
・|が和集合
・||がtrue/falseを返す(true(存在する)の時点でtrue出力)
です。a = [1, 2, 3] b = [2, 3, 4] # いずれかに含まれる要素を出力 a | b => [1, 2, 3, 4] # 最初に評価されたa(true)を出力 a || b => [1, 2, 3] # aが偽のためbを出力(右辺まで見る) a = nil a || b => [2, 3, 4]
- 投稿日:2019-10-12T15:54:04+09:00
carrierwave と fog を使ってasset hostを決める
やりたいこと
取得する画像のURLをホスティングしているサーバーのURL付きで欲しい。
現状、localhost:3000(バックエンド)とlocalhost:4000(フロントエンド)で分けて開発しているが、
画像のURLを取得すると、以下のようになっている。
{ url: "uploads/user/profile_image/1/adcb24fe3b95a9f70fa81f2cf5c6e8ec.jpg" }ので、以下のように変更したい。
{ url: "http://localhost:3000/uploads/user/profile_image/1/adcb24fe3b95a9f70fa81f2cf5c6e8ec.jpg" }tl:dr
config/initializers/carrierwave.rbを作成し、asset_hostを設定する。
Gemのインストール
carrierwaveuploader/carrierwave
※本番環境では、GCPを使うので、あらかじめこのようんな設定にしています。
Using Google Storage for Developers
Fog is used to support Google Storage for Developers. Ensure you have it in your Gemfile:
gem "fog-google"
gem "google-api-client", "> 0.8.5", "< 0.9"
gem "mime-types"設定
Railsプロジェクトにconfig/initializers/carrierwave.rbを作成する。
~/config/initializers/carrierwave.rbCarrierWave.configure do |config| config.fog_provider = "fog/google" if Rails.env.production? config.fog_credentials = { provider: "Google", google_storage_access_key_id: ENV["GCS_ACCESS_KEY_ID"], google_storage_secret_access_key: ENV["GCS_ACCESS_KEY"], path_style: true, } config.fog_directory = ENV["GCS_BUCKET"] end config.asset_host = ENV["ASSET_HOST_IMG"] config.fog_attributes = { "Cache-Control" => "max-age=3600" } endローカルのenv設定
ASSET_HOST_IMG=http://localhost:3000
- 投稿日:2019-10-12T15:51:07+09:00
Rails 爆速で円グラフを実装する[5分]
はじめに
今回は'chartkick'を使って爆速で円グラフを実装します。
Gemの導入
Gemfilegem "chartkick" gem 'chartable'ターミナルbundle installjavascriptライブラリの読み込み
application.js//= require Chart.bundle //= require chartkickapplication.jsに上記を記載。
インスタンスメソッドの定義
tweets_controller.rbdef index 配列の場合 @chart = [['国語', 10], ['算数', 20],['理科',30]['社会',40]] ハッシュの場合 @chart = {"国語" => 10, "算数" => 20, "理科" => 30, "社会" => 40} end配列でもハッシュでも可能です!!
viewページ
tweets/index.html.haml= pie_chart @chartこの一行を追加するだけ!!
こんなかんじですね。
備考
コントローラーの変数を変えればどんなグラフも作れます。
モデルから値を取得することが多いと思うので参考に載せておきます。def index @chart = Post.order('created_at ASC').group(:name) endこんな感じです。
おわりに
めちゃめちゃ簡単です。
ビューページに一行書けば実装できます
では
- 投稿日:2019-10-12T15:39:59+09:00
Mac OS Catalina にアップグレードしたら bundle install でコケる
Mac OS Catalina へアップグレード後に、Gemfile で Rails のみを指定して bundle install したらコケたので備忘です。
エラー内容
$ bundle install --path vendor/bundle Fetching gem metadata from https://rubygems.org/............. Fetching gem metadata from https://rubygems.org/. Resolving dependencies... Fetching rake 13.0.0 Installing rake 13.0.0 Fetching concurrent-ruby 1.1.5 Installing concurrent-ruby 1.1.5 Fetching i18n 1.7.0 Installing i18n 1.7.0 Fetching minitest 5.12.2 Installing minitest 5.12.2 Fetching thread_safe 0.3.6 Installing thread_safe 0.3.6 Fetching tzinfo 1.2.5 Installing tzinfo 1.2.5 Fetching zeitwerk 2.2.0 Installing zeitwerk 2.2.0 Fetching activesupport 6.0.0 Installing activesupport 6.0.0 Fetching builder 3.2.3 Installing builder 3.2.3 Fetching erubi 1.9.0 Installing erubi 1.9.0 Fetching mini_portile2 2.4.0 Installing mini_portile2 2.4.0 Fetching nokogiri 1.10.4 Installing nokogiri 1.10.4 with native extensions Gem::Ext::BuildError: ERROR: Failed to build gem native extension. current directory: ./vendor/bundle/ruby/2.6.0/gems/nokogiri-1.10.4/ext/nokogiri ~/.rbenv/versions/2.6.3/bin/ruby -I ~/.rbenv/versions/2.6.3/lib/ruby/2.6.0 -r ./siteconf20191011-4979-1ke4qzu.rb extconf.rb checking if the C compiler accepts -I /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/libxml2... *** extconf.rb failed *** Could not create Makefile due to some reason, probably lack of necessary libraries and/or headers. Check the mkmf.log file for more details. You may need configuration options. Provided configuration options: --with-opt-dir --without-opt-dir --with-opt-include --without-opt-include=${opt-dir}/include --with-opt-lib --without-opt-lib=${opt-dir}/lib --with-make-prog --without-make-prog --srcdir=. --curdir --ruby=~/.rbenv/versions/2.6.3/bin/$(RUBY_BASE_NAME) --help --clean ~/.rbenv/versions/2.6.3/lib/ruby/2.6.0/mkmf.rb:467:in `try_do': The compiler failed to generate an executable file. (RuntimeError) You have to install development tools first. from ~/.rbenv/versions/2.6.3/lib/ruby/2.6.0/mkmf.rb:585:in `block in try_compile' from ~/.rbenv/versions/2.6.3/lib/ruby/2.6.0/mkmf.rb:532:in `with_werror' from ~/.rbenv/versions/2.6.3/lib/ruby/2.6.0/mkmf.rb:585:in `try_compile' from extconf.rb:138:in `nokogiri_try_compile' from extconf.rb:162:in `block in add_cflags' from ~/.rbenv/versions/2.6.3/lib/ruby/2.6.0/mkmf.rb:643:in `with_cflags' from extconf.rb:161:in `add_cflags' from extconf.rb:416:in `<main>' To see why this extension failed to compile, please check the mkmf.log which can be found here: ./vendor/bundle/ruby/2.6.0/extensions/x86_64-darwin-18/2.6.0-static/nokogiri-1.10.4/mkmf.log extconf failed, exit code 1 Gem files will remain installed in ./vendor/bundle/ruby/2.6.0/gems/nokogiri-1.10.4 for inspection. Results logged to ./vendor/bundle/ruby/2.6.0/extensions/x86_64-darwin-18/2.6.0-static/nokogiri-1.10.4/gem_make.out An error occurred while installing nokogiri (1.10.4), and Bundler cannot continue. Make sure that `gem install nokogiri -v '1.10.4' --source 'https://rubygems.org/'` succeeds before bundling. In Gemfile: rails was resolved to 6.0.0, which depends on actioncable was resolved to 6.0.0, which depends on actionpack was resolved to 6.0.0, which depends on actionview was resolved to 6.0.0, which depends on rails-dom-testing was resolved to 2.0.3, which depends on nokogiri $ gem install nokogiri -v '1.10.4' --source 'https://rubygems.org/' Building native extensions. This could take a while... ERROR: Error installing nokogiri: ERROR: Failed to build gem native extension. current directory: ~/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/nokogiri-1.10.4/ext/nokogiri ~/.rbenv/versions/2.6.3/bin/ruby -I ~/.rbenv/versions/2.6.3/lib/ruby/2.6.0 -r ./siteconf20191011-5067-7lnwuv.rb extconf.rb checking if the C compiler accepts -I /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/libxml2... *** extconf.rb failed *** Could not create Makefile due to some reason, probably lack of necessary libraries and/or headers. Check the mkmf.log file for more details. You may need configuration options. Provided configuration options: --with-opt-dir --without-opt-dir --with-opt-include --without-opt-include=${opt-dir}/include --with-opt-lib --without-opt-lib=${opt-dir}/lib --with-make-prog --without-make-prog --srcdir=. --curdir --ruby=~/.rbenv/versions/2.6.3/bin/$(RUBY_BASE_NAME) --help --clean ~/.rbenv/versions/2.6.3/lib/ruby/2.6.0/mkmf.rb:467:in `try_do': The compiler failed to generate an executable file. (RuntimeError) You have to install development tools first. from ~/.rbenv/versions/2.6.3/lib/ruby/2.6.0/mkmf.rb:585:in `block in try_compile' from ~/.rbenv/versions/2.6.3/lib/ruby/2.6.0/mkmf.rb:532:in `with_werror' from ~/.rbenv/versions/2.6.3/lib/ruby/2.6.0/mkmf.rb:585:in `try_compile' from extconf.rb:138:in `nokogiri_try_compile' from extconf.rb:162:in `block in add_cflags' from ~/.rbenv/versions/2.6.3/lib/ruby/2.6.0/mkmf.rb:643:in `with_cflags' from extconf.rb:161:in `add_cflags' from extconf.rb:416:in `<main>' To see why this extension failed to compile, please check the mkmf.log which can be found here: ~/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/extensions/x86_64-darwin-18/2.6.0-static/nokogiri-1.10.4/mkmf.log extconf failed, exit code 1 Gem files will remain installed in ~/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/nokogiri-1.10.4 for inspection. Results logged to ~/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/extensions/x86_64-darwin-18/2.6.0-static/nokogiri-1.10.4/gem_make.out解決策
$ xcode-select --installでビルドできるようになりました。
- 投稿日:2019-10-12T14:51:07+09:00
文系大学生がアプリ開発よりも機械学習の方が自学自走しやすいと考える理由について
はじめに
最近の風潮として、アプリの開発を一人で自学自走は頑張れば可能と言う考えが蔓延っていて、機械学習はなんか難しそうみたいな考え方があるように見受けられます。確かにアプリの開発を一人で自学自走する人はとてもすごいと思いますが、自分はアプリ開発を一人でやりきるのはとても難しく、また機械学習の自学自走はそれに比べると難しくないと考えています。
自分の感覚で言うと
・アプリ開発自走→天才じゃないと無理ゲー
・機械学習自走→頑張れば可能
という感じです(これは自分の感覚なので、個人差はあると思います)。その理由について述べていきたいと思います。
自分のそれぞれの経験について
まずその前に自分の(お前の経歴なんか興味ねえよって人はすっ飛ばして見て下さい)
アプリ開発
・実際に去年の3月にtechcampさんの方に通って勉強→3ヶ月ほどやるもそこで挫折
・今年の3月にpreogate→railsチュートリアルの流れで勉強をするも、railsチュートリアルで挫折機械学習
・去年の末から初めて今のところ挫折なし
詳しくは以下を参照
https://qiita.com/HayatoYamaguchi/items/1c20595c5e6dac4530dcこんな感じでやっています。確かに機械学習の方が本腰を入れて行なっていたという面だったり実際に一度アプリ開発でプログラミングを学んだ後だからというものもあるかもしれませんが、それを加味しても自分は機械学習の方が自学自走しやすいと考える理由をいかに述べたいと思います。
1、参照するページが多く、さらに自分がどこまで反映させたのかがわかりにくい
プログラミング初心者あるあるとして、まずは写生をしますがこの写生内容は往々にして「,」と「.」のミスなどの文字やスペルミスや、括弧やendの位置などのミスが起こりやすいです。その中でエラーメッセージを見てみると、そのメッセージが起きたサイトに言ってもエラーの根本的な原因はそのページではないなどのことが往々に発生します(例えばビューファイルのエラーなのに実際はコントローラーの中の変数の受け取りに問題があるなど)。そのためエラーの発掘が自分では困難になり、挫折しやすいです。一方機械学習の場合は最初はクラス分けを行わなければjupyter notebookなどの一つのファイルで完結します。そのため、エラーの行を見ればその行や周辺を直せば大体のエラーは解決します。
2、アプリ開発には必要な言語や概念が多すぎる
機械学習においてプログラミング面で必要なのはpythonやそれに付随する各種ライブラリ(numpy,pandas,sklearnなど)のみです。
しかし、アプリ開発を学ぼうとすると、例えばrailsだったらrailsチュートリアルを完遂して自分でポートフォリオを作ろうとすると、・htmlcss
・ruby
・javascript
・SQL
・Gitなどが必要で、データベースとの連携方法やさらにテストの実装についても理解も必要なことがあります。そのため何もやったことがない初心者が始めようとすると、「なんかごちゃごちゃしてるけど今は何をやればいいんだっけ、、、」という状態になりやすいです。
ここまで見ると機械学習の方がはるかに簡単そう、、、って思いそうなので、一応機械学習の方が難しい点も述べたいと思います。
機械学習の方が難しい点について
ある程度の数学や統計が必要である
アプリ開発にはほぼ一切数学の知識は求められません。
一方機械学習ではそうはいかず、ある程度アルゴリズムの中身を理解するとなると、大学基礎レベルの数学は必要になります。そのため数学アレルギーの人には厳しいです。論理的な式がより求められる
機械学習ではモデルを作る前にデータの変形などをする必要があります。そのため、「この条件の時にここを変形する」などの少し論理的なコードを書く力が必要です。例えばこれは自分の昔の記事から引っ張ってきたものですが、条件を指定して削除するなどの少し複雑なものになっています。これは簡単な例ですが、論理的な式を求められることが多いです。」
Xmat = Xmat.drop(Xmat[(Xmat['TotalSF']>5) & (Xmat['SalePrice']<12.5)].index)終わりに
これはあくまでもサンプル数1の考え方ですが、実際にこのような考え方を投稿している人がいなかったので投稿させてもらいました。何をやるかを考えている人には参考にしてもらえると嬉しいです。
- 投稿日:2019-10-12T13:54:05+09:00
Rails on GitHub Actions チュートリアル
Github Actions 使ってますか?
まだβ版ですし本稼働させている人は多くないと思いますが、2019年11月中旬頃にようやくキャッシュ機構が実装されるそうなので、 CircleCI 非課金勢としては非常に楽しみにしています。Rails の CI を Github Actions で動かすにあたって、システムテスト周りで少しハマったので、導入方法をまとめてみました。
Rails プロジェクトの初期化
いつも通り rails new していきます。
今回は Rails 標準の minitest を使っていますが RSpec の場合でもほぼ変わりません。$ mkdir rails_on_github_actions $ bundle initGemfile# frozen_string_literal: true source "https://rubygems.org" git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } gem "rails"$ bundle $ bundle exec rails new . $ bin/rails db:migrateテストをするために user リソースを追加しておきます。
$ bin/rails g scaffold users $ bin/rails db:migrate $ bin/rails testWorkflow の作成
Github Actions でテストを走らせるために、 workflow を作っていきます。
scaffold によってシステムテストも作られていますが、一旦ここではブラウザを使わないテストだけ扱います。.github/workflows/test.ymlname: Test on: [push] jobs: build: runs-on: ubuntu-latest container: image: ruby:2.6.4 steps: - uses: actions/checkout@v1 - name: Set up node and yarn run: | curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list curl -sL https://deb.nodesource.com/setup_12.x | bash - apt install -y nodejs yarn - name: Build and setup run: | bundle -j 4 bin/rails yarn:install db:setup assets:precompile bin/rails testこれを push すると workflow が自動的に走ります。
System Test
Github Actions で system test を実行するため、 Chrome をインストールするスクリプトを workflow に追加しています。
.github/workflows/test.ymlname: Test on: [push] jobs: build: runs-on: ubuntu-latest container: image: ruby:2.6.4 steps: - uses: actions/checkout@v1 - name: Set up YARN and NodeJS run: | curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list curl -sL https://deb.nodesource.com/setup_12.x | bash - apt install -y yarn nodejs - name: Install chrome run: | wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | apt-key add - echo 'deb http://dl.google.com/linux/chrome/deb/ stable main' | tee /etc/apt/sources.list.d/google-chrome.list apt update -y apt install -y google-chrome-stable - name: Build run: | bundle -j 4 bin/rails yarn:install db:setup assets:precompile - name: Run test run: | bin/rails test - name: Run system test run: | bin/rails test:systemローカル環境なら
driven_by :selenium_chrome_headless
だけで Headless Chrome を使ってテストできますが、 Github Actions のような Docker 環境だと/dev/shm
のサイズ割り当てが小さいため、それを使わないようにするためdisable-dev-shm-usage
という起動オプションを追加しています。また、no-sandbox
は Docker 環境のように root 権限で Chrome を立ち上げるのに必要なオプションです。test/application_system_test_case.rbrequire "test_helper" class ApplicationSystemTestCase < ActionDispatch::SystemTestCase driven_by :selenium, using: :headless_chrome, screen_size: [1400, 1400] do |driver_options| driver_options.add_argument('--disable-dev-shm-usage') driver_options.add_argument('--no-sandbox') end endこれを push すると Github Actions で system test も無事に成功します。
MySQL
実際のアプリケーションでは SQLite を使うことはほぼ無いと思うので、 Github Actions でも MySQL を使ってみます。
Gemfile に mysql2 を追加
Gemfilegem 'mysql2'database.yml を MySQL 用に更新します。ほぼデフォルトですが、ホスト名とパスワードを環境変数で設定できるようにしています。
config/database.ymldefault: &default adapter: mysql2 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> username: root charset: utf8mb4 collation: utf8mb4_bin encoding: utf8mb4 password: <%= ENV.fetch('MYSQL_ROOT_PASSWORD', '') %> host: <%= ENV.fetch('MYSQL_HOST', 'localhost') %> development: <<: *default database: rails_on_github_actions_development test: <<: *default database: rails_on_github_actions_test production: <<: *default database: rails_on_github_actions_productionテストが正常に動くかローカルで確認しておきます。
$ bin/rails db:create $ bin/rails test $ bin/rails test:systemworkflow の services に MySQL を追加します。root のパスワードは環境変数で設定します。
services で追加したコンテナのホスト名はサービス名と同じになるようです。.github/workflows/test.ymlname: Test on: [push] jobs: build: runs-on: ubuntu-latest services: mysql: image: mysql:5.7 env: MYSQL_ROOT_PASSWORD: password container: image: ruby:2.6.4 env: MYSQL_HOST: mysql MYSQL_ROOT_PASSWORD: password steps: - uses: actions/checkout@v1 - name: Set up yarn and node run: | curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list curl -sL https://deb.nodesource.com/setup_12.x | bash - apt install -y yarn nodejs - name: Install chrome run: | wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | apt-key add - echo 'deb http://dl.google.com/linux/chrome/deb/ stable main' | tee /etc/apt/sources.list.d/google-chrome.list apt update -y apt install -y google-chrome-stable - name: Build run: | bundle -j 4 bin/rails yarn:install db:setup assets:precompile - name: Run test run: | bin/rails test - name: Run system test run: | bin/rails test:systemこれを push すると Github Actions で MySQL を使ったテストが無事に成功します。
services と環境変数を書き換えれば postgres などの他のデータベースも使用できるかと思います。今回作ったサンプルプロジェクトは Github に置いてますので良かった参考にしてみてください。
https://github.com/d-mato/rails_on_github_actions
- 投稿日:2019-10-12T12:17:22+09:00
order("id ASC") <=> order("id DESC)の切り替え Rails
備忘録及びアウトプットの練習のために、自分が学んだこと・工夫したこと・苦労した事などを書いていきたいと思います。
今回、orderメソッドを使うことにより、テーブルが呼び出したデータのソートができるということで、
画面上のスイッチをクリックするだけで、投稿内容の降順・昇順を切り替えれるようにしてみました。1.ビューの実装
ビューファイルにスイッチ用のコードを書く
= link_to "↕️", "switch", class: "switch", method: :get画面上の↕️をクリックしたら、"switch"に移動するようにしています。
個別にcssを適用できるように、"switch"というクラスもつけています。2.ルーティングの設定
1でswitchというパスを指定したので、対応するルーティングを設定します
get 'switch' => 'tweets/#switch'パス’switch'からtweetsコントローラのswitchアクションを実行するようにしています
3.コントローラの設定
2で指定したswitchアクションを作ります。
@@order = 1 def index if @@order == 1 @tweets = Tweet.order("id ASC") else @tweets = Tweet.order("id DESC") end end def switch @@order *= -1 redirect_to :action => "index" end切り替えに使用するクラス変数@@orderを定義します。
indexアクション内で、@@orderが1かそうでないかで、order("id ASC")かorder("id DESC")かが変わるようなif文を書きます。
次に、@@orderを切り替えるためのswitchアクションを定義します。
switchアクションを実行するたび、
つまりビュー上の↕️をクリックするたびに、クラス変数@@orderに-1をかけるようにします。
redirect_to :action => "index"とすることで、スイッチを押すたびに別画面に遷移することがなくなるようにします。これで、投稿の順番を変えるスイッチの実装が出来ました。
ルーティングの設定やクラス変数の利用など、色んな項目の復習になりました。
記事の内容は少しづつ更新していこうと思います。
- 投稿日:2019-10-12T12:17:22+09:00
ワンクリックでorder("id ASC") <=> order("id DESC)の切り替え
はじめに
備忘録及びアウトプットの練習のために、自分が学んだこと・工夫したこと・苦労した事などを書いていきたいと思います。
今回、orderメソッドを使うことにより、テーブルが呼び出したデータのソートができるということで、
画面上のスイッチをクリックするだけで、投稿内容の降順・昇順を切り替えれるようにしてみました。1.ビューの実装
ビューファイルにスイッチ用のコードを書く
= link_to "↕️", "switch", class: "switch", method: :get画面上の↕️をクリックしたら、"switch"に移動するようにしています。
個別にcssを適用できるように、"switch"というクラスもつけています。2.ルーティングの設定
1でswitchというパスを指定したので、対応するルーティングを設定します
get 'switch' => 'tweets/#switch'パス’switch'からtweetsコントローラのswitchアクションを実行するようにしています
3.コントローラの設定
2で指定したswitchアクションを作ります。
@@order = 1 def index if @@order == 1 @tweets = Tweet.order("id ASC") else @tweets = Tweet.order("id DESC") end end def switch @@order *= -1 redirect_to :action => "index" end切り替えに使用するクラス変数@@orderを定義します。
indexアクション内で、@@orderが1かそうでないかで、order("id ASC")かorder("id DESC")かが変わるようなif文を書きます。
次に、@@orderを切り替えるためのswitchアクションを定義します。
switchアクションを実行するたび、
つまりビュー上の↕️をクリックするたびに、クラス変数@@orderに-1をかけるようにします。
redirect_to :action => "index"とすることで、スイッチを押すたびに別画面に遷移することがなくなるようにします。終わりに
これで、投稿の順番を変えるスイッチの実装が出来ました。
ルーティングの設定やクラス変数の利用など、色んな項目の復習になりました。
記事の内容は少しづつ更新していこうと思います。
- 投稿日:2019-10-12T11:13:20+09:00
webpacker の check_yarn_integrity オプションについて調べてみた
はじめに
Rails アプリで webpacker を利用するケースが増えていると思います。Rails 5.1以上のアプリでは、
rails new myapp --webpack
というオプションをつける形でも webpacker をインストールできるようになっていますよね。しかし個人的に、使い方を理解しきれていないことが多いです。そこで理解するためのとっかかりとして、
config/webpacker.yml
のオプションを調べてみようと思い、その中のcheck_yarn_integrity
というオプションについて手始めに調べてみました。何をするオプションなのか
webpacker の README を抜粋します。
By default, in development, webpacker runs a yarn integrity check to ensure that all local JavaScript packages are up-to-date. This is similar to what bundler does currently in Rails, but for JavaScript packages. If your system is out of date, then Rails will not initialize. You will be asked to upgrade your local JavaScript packages by running yarn install.こちらを意訳してみました。
- development 環境では、ローカルの全ての JavaScript パッケージが最新であるかを yarn integrity check する
- Rails の
bundler
がやっていることと似てるが、これは JavaScript 用- システムが古くなっていると、Rails は初期化されない
yarn install
でローカルの JavaScript パッケージをアップグレードするか尋ねられるようになる実施していること
実際関連しているコード部分を抜粋すると以下になります。
config.webpacker.check_yarn_integrity = true
にしておけば、rails c
やrails s
といった Rails アプリケーションを起動する際の初期化時に、yarn check --integrity
を実行し、エラーが出たら以下のようなエラーメッセージを出力してくれるようです。======================================== Your Yarn packages are out of date! Please run `yarn install` to update. ======================================== To disable this check, please add `config.webpacker.check_yarn_integrity = false` to your Rails development config file (config/environments/development.rb).不要な場合は
config.webpacker.check_yarn_integrity = false
にすれば OK のようです。
パッケージが古くなっていたらエラーで知らせてくれるということなので、パッケージを最新の状態に保つ手助けになりそうですね。おわりに
JavaScript のパッケージ管理は複雑で理解が難しいですね。根気よく学習していきたいと思います。
参考
- 投稿日:2019-10-12T08:27:39+09:00
Railsのトランザクションと例外処理
Railsのトランザクションと例外処理がよく分からなかったので、調べました。
app/controllers/user_controller.rbdef create ActiveRecode::Base.transaction do # createではなく、create!にすると保存できなかったときに例外が発生します。 @user = User.create!(user_params) recue => e # バリデーションエラーだけ拾いたい場合は次の行 # (ActiveRecord:RecodeInvalid => e) # error処理 end endrecueはphpでいうとexceptionみたいな感じでした。
参考サイト
rails save! create! update!のバリデーション例外を捕捉する - Qiita
- 投稿日:2019-10-12T08:14:05+09:00
Railsのhas_oneで関連テーブルの保存
has_oneで関連させて保存させる方法につまったので書いておきます。
他のやり方(createを2回使う)もあったのですが、create!しても例外をキャッチできない?感じだったので、こちらの書き方にしました。app/controllers/users_controller.rbdef create @user = User.create(user_params) # この行のcreate_articleは状況に応じてprofile部分を読みかえて使います。 @profile = @user.create_profile(profile_params) endapp/models/user.rbhas_one :profileapp/models/profile.rbbelongs_to :user