20210429のRubyに関する記事は22件です。

form_withで指定するurl:とmodel:の違いについて

はじめに プログラミング初学者のため、自分の理解できている範囲内で言語化しています。 何か間違っている情報や改善点などありましたら、コメントいただけますと幸いです。?‍♂️ これについて書こうと思ったきっかけ 簡単なお問い合わせ機能を作成しようとしたときに、 form_withのmodel:でモデルのインスタンスを指定したら、 pathが違うというエラーが出たので、url:で指定したら、成功した。 が、、、データベースに情報を保存したかったため、model:でどうしてもやりたかったが エラーがなかなか倒せなかったので、form_withをまとめてみようと思った? 最終的な解決策 今回は、url:も指定してみました html.erb <%= form_with model: @information, url: informations_path, class: 'form' do |f| %> model:を使うと、作ってもいないpathを使おうとしていたので、url:も指定して解決することができた。 モデルだけ指定して、変なpathや、うまくいかない人はこれを試すと良い ちなみにモデルの名前を複数形にしたりすると、このようなエラーになるみたい、、、 私はいろんなとこを確認しても、原因がわからなかったので力技みたいですがこれで解決 url: model: の違い 大まかな違いは、データベースに情報を保存するかしないかである 保存する → model: 保存しない → url: を使う。 これによってコントローラーのストロングパラメーターの記述も変わる url: → params.permit(:name, :email) model: → params.require(:user).permit(:name, :email) まとめ 今回は、エラーの原因がわからなかったが、とりあえず完成を優先したかったので解決してよしとしたが、原因を知らないのは悔しい、、、 また、仮にurl:のままでお問い合わせ機能を作ったとして、うまく投稿できなかったときのバリデーションのエラーメッセージの表示はどうするのか気になった。 本来であれば、if model.errors.any? を使うから、modelの部分はどうなる? 疑問がさらに疑問を産んだため、いったんここで打ち切り? また次の機会で投稿してみようと思う腕
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

form_with使用の際model:を使ったときにエラーになった話

はじめに プログラミング初学者のため、自分の理解できている範囲内で言語化しています。 何か間違っている情報や改善点などありましたら、コメントいただけますと幸いです。?‍♂️ 何が起きたのか html.erb <%= form_with model: @information, class: 'form' do |f| %> 簡単なお問い合わせ機能を作成しようとしたときに、 form_withのmodel:でモデルのインスタンスを指定したら、 pathが違うというエラーが出たので、url:で指定したら、成功した。 が、、、データベースに情報を保存したかったため、model:でどうしてもやりたかったが エラーがなかなか倒せなかったので、調べようと思った? このエラーのよくある原因 1.『@モデル名』 の部分が記述ミス 2. コントローラーでインスタンス変数がうまく設定できていない 3. モデル自体を複数形で作ってしまっている まずはそこをチェック。** それ以外の人はこの方法で行けるかも?‍♂️ 最終的な解決策 url:も指定して、正しいpathを記述する html.erb <%= form_with model: @information, url: informations_path, class: 'form' do |f| %> model:を使うと、作ってもいないpathを使おうとしていたので、url:も指定して解決することができた。 モデルだけ指定して、変なpathや、うまくいかない人はこれを試すと良い ちなみにモデルの名前を複数形にしたりすると、このようなエラーになるみたい、、、 私はいろんなとこを確認しても、原因がわからなかったので力技みたいですがこれで解決 url: model: の違い 大まかな違いは、データベースに情報を保存するかしないかである 保存する → model: 保存しない → url: を使う。 これによってコントローラーのストロングパラメーターの記述も変わる url: → params.permit(:name, :email) model: → params.require(:user).permit(:name, :email) まとめ 今回は、エラーの原因がわからなかったが、とりあえず完成を優先したかったので解決してよしとしたが、原因を知らないのは悔しい、、、 また、仮にurl:のままでお問い合わせ機能を作ったとして、うまく投稿できなかったときのバリデーションのエラーメッセージの表示はどうするのか気になった。 本来であれば、if model.errors.any? を使うから、modelの部分はどうなる? 疑問がさらに疑問を産んだため、いったんここで打ち切り? また次の機会で投稿してみようと思う腕
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails]deviseを使ったビューファイルの作成

はじめに RailsでWebアプリケーションを作る時にdeviseを使ったので備忘録として残しておきます。 今回はdeviseで作成できるビューファイルの作成をしていきたいと思います。 ビューの作成方法 deviseでは認証周りが実装されたビューファイルを一行のコマンドで作成することができます。 作成する場合はターミナルで下記のコマンドを実行します。 $ rails g devise:views するとapp/viewの下にdeviseフォルダが作成されます。 さらにdeviseフォルダ下に7つのフォルダが作成されています。 これらの各フォルダがどのビューに対応しているかは以下になります。 フォルダ名 フォルダの内容 confirmations パスワード再発行のフォーム mailer メール認証のフォーム passwords パスワード関連のフォーム registrations ユーザー登録やユーザー編集のフォーム sessions ログインフォーム shared 各フォームに表示されている、リンクのパーシャル(部分テンプレート)が入っている unlocks アカウントロック通知を行うフォーム これらのビューは簡素なデザインなので自分でアレンジすると良いです。 以上です。 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS EC2 の CPU 使用率を API で取得する方法(Ruby)

Gemfile gem 'aws-sdk-cloudwatch' 特定インスタンスの CPU 使用率(最大値)を1日分取得する例 metric = Aws::CloudWatch::Metric.new( 'AWS/EC2', 'CPUUtilization', region: region, # 例: 'ap-northeast-1' credentials: Aws::Credentials.new( access_key_id, secret_access_key ) ) result = metric.get_statistics( start_time: Time.now.beginning_of_day, end_time: Time.now, statistics: ['Maximum'], # SampleCount, Average, Sum, Minimum, Maximum を指定可能です period: 60 * 60 * 24, # 1 day dimensions: [{ name: "InstanceId", value: instance_id }] ) result => #<struct Aws::CloudWatch::Types::GetMetricStatisticsOutput label="CPUUtilization", datapoints=[ #<struct Aws::CloudWatch::Types::Datapoint timestamp=2021-04-28 15:00:00 UTC, sample_count=nil, average=nil, sum=nil, minimum=nil, maximum=24.0, unit="Percent", extended_statistics={} > ] > 参照 Class: Aws::CloudWatch::Metric | 公式ドキュメント Rubyからaws-sdkを使ってCloudWatchのメトリックスを取得する | ぺけみさお
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS EC2 の CPU 使用率を取得する方法(Ruby)

Gemfile gem 'aws-sdk-cloudwatch' 特定インスタンスの CPU 使用率(最大値)を1日分取得する例 metric = Aws::CloudWatch::Metric.new( 'AWS/EC2', 'CPUUtilization', region: region, # 例: 'ap-northeast-1' credentials: Aws::Credentials.new( access_key_id, secret_access_key ) ) result = metric.get_statistics( start_time: Time.now.beginning_of_day, end_time: Time.now, statistics: ['Maximum'], # SampleCount, Average, Sum, Minimum, Maximum を指定可能です period: 60 * 60 * 24, # 1 day dimensions: [{ name: "InstanceId", value: instance_id }] ) result => #<struct Aws::CloudWatch::Types::GetMetricStatisticsOutput label="CPUUtilization", datapoints=[ #<struct Aws::CloudWatch::Types::Datapoint timestamp=2021-04-28 15:00:00 UTC, sample_count=nil, average=nil, sum=nil, minimum=nil, maximum=24.0, unit="Percent", extended_statistics={} > ] > 参照 Class: Aws::CloudWatch::Metric | 公式ドキュメント Rubyからaws-sdkを使ってCloudWatchのメトリックスを取得する | ぺけみさお
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JupyterLab(Jupyter-notebook)でRubyの実行環境構築

概要 JupyterLabでRubyの実行環境を構築した際に、すんなりいかなかったので解決方法を残そうと思います。 ネットで調べた方法で構築した後に、実際にJupyterLabを起動すると以下のようなメッセージが表示されました。 JupyterLab上でRubyを選択できますが、Rubyのコードを実行しようとすると実行できない状態でした。 どうもlibzmq.dllというdllが読み込めていないようでした。 W, [2021-04-29T21:21:26.640618 #12140] WARN -- : Could not load bundler: Could not locate Gemfile or .bundle/ directoryW, [2021-04-29T21:21:26.709311 #15356] WARN -- : Could not load bundler: Could not locate Gemfile or .bundle/ directoryUnable to load this gem. The libzmq library exists, but cannot be loaded. libzmq library was found at: ["C:\\anaconda3\\Library\\bin/libzmq.dll"] On Windows: - Check that you have MSVC runtime installed or statically linked - Check that your DLL is compiled for 64 bit WARNING: ::CZMQ::FFI is not available without libczmq. F, [2021-04-29T21:21:27.062988 #12140] FATAL -- : Kernel died: No session adapter is available C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/iruby-0.5.0/lib/iruby/session_adapter.rb:63:in `select_adapter_class' C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/iruby-0.5.0/lib/iruby/session.rb:112:in `create_session_adapter' C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/iruby-0.5.0/lib/iruby/session.rb:12:in `initialize' C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/iruby-0.5.0/lib/iruby/kernel.rb:17:in `new' C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/iruby-0.5.0/lib/iruby/kernel.rb:17:in `initialize' C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/iruby-0.5.0/lib/iruby/command.rb:110:in `new' C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/iruby-0.5.0/lib/iruby/command.rb:110:in `run_kernel' C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/iruby-0.5.0/lib/iruby/command.rb:40:in `run' C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/iruby-0.5.0/bin/iruby:5:in `<top (required)>' C:/Ruby30-x64/bin/iruby:23:in `load' C:/Ruby30-x64/bin/iruby:23:in `<main>' C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/iruby-0.5.0/lib/iruby/session_adapter.rb:63:in `select_adapter_class': No session adapter is available (IRuby::SessionAdapterNotFound) from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/iruby-0.5.0/lib/iruby/session.rb:112:in `create_session_adapter' from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/iruby-0.5.0/lib/iruby/session.rb:12:in `initialize' from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/iruby-0.5.0/lib/iruby/kernel.rb:17:in `new' from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/iruby-0.5.0/lib/iruby/kernel.rb:17:in `initialize' from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/iruby-0.5.0/lib/iruby/command.rb:110:in `new' from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/iruby-0.5.0/lib/iruby/command.rb:110:in `run_kernel' from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/iruby-0.5.0/lib/iruby/command.rb:40:in `run' from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/iruby-0.5.0/bin/iruby:5:in `<top (required)>' from C:/Ruby30-x64/bin/iruby:23:in `load' from C:/Ruby30-x64/bin/iruby:23:in `<main>' Unable to load this gem. The libzmq library exists, but cannot be loaded. libzmq library was found at: ["C:\\anaconda3\\Library\\bin/libzmq.dll"] On Windows: - Check that you have MSVC runtime installed or statically linked - Check that your DLL is compiled for 64 bit 実行環境 環境 バージョン OS Windows 10 JupyterLab 3.0.14 Ruby 3.0.1 x64 ZeroMQ 4.3.2 Rubyのディレクトリ C:\Ruby30-x64 手順 まず前提として、JupyterLab(もしくはJupyter Notebook)とRubyはインストール済みとして説明します。 手順をまとめると以下になります。 1. ZeroMQのダウンロード 2. ZeroMQのdllをRubyのディレクトリにコピー 3. ffi-rzmqのインストール 4. iRubyのインストール 5. iRubyの登録 1. ZeroMQのダウンロード ZeroMQからライブラリをダウンロードして、zipファイルを展開します。 私の環境では「Visual Studio 15 2017 x64」を選択しました。 2. ZeroMQのdllをRubyのディレクトリにコピー 1.展開したディレクトリ内のlibzmq-v141-mt-4_3_2.dllの名前をlibzmq.dllに変更します。 libzmq-v141-mt-4_3_2.dll -> libzmq.dll ダウンロード時のファイル名はバージョンによって変わります。 2.libzmq.dll、libsodium.dllをRubyのインストールディレクトリのbinへコピーします。 私の環境の場合は「C:\Ruby30-x64\bin」にコピーします。 3. ffi-rzmqのインストール 1.ZeroMQをRubyで使用するためのGemをインストールします。 コマンドプロンプトで以下のコマンドを実行します。 console gem install ffi-rzmq 2.動作確認 下記コマンドを実行してtrueとなれば、インストール完了です。 console > irb irb(main):001:0> require "ffi-rzmq" => true 4. iRubyのインストール 以下のコマンドを実行します。 console gem install iruby 5. iRubyの登録 以下のコマンドを実行します。 console iruby register --force JupyterLab起動 コマンドプロンプトで以下のコマンドを実行してJupyterLabを起動します。 console jupyter lab JupyterLabでRubyのコードが実行できれば完了です。 以上で設定完了です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

authenticate_user!メソッド

authenticate_user!メソッドはログイン状態によって表示するページを切り替えるメソッドでdeviseをインストールをすることで使用できます。 通常はbefore_actiontiと一緒に利用しアクションを実行する前にログインしていなければログイン画面に遷移させられます。 ただindexページ、詳細ページ、検索機能などはログインしていなくても見れる状態にしたいというのがあるので before_action :authenticate_user!, except: [:index, :show, :search] のようにexcept: [:index, :show, :search]をつけてあげればindex,show,searchアクションは除かれるのでログインしていなくても遷移させられることはありません。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Graphql-Rubyの認可についてまとめる

はじめに 最近、GraphQL-Rubyを使って認可実装する機会があったのでまとめてみます。 用語的には認証と認可がありますが、今回は認可を扱います。(GraphQLは一般的には認証を扱ってません) REST APIと違ってコントローラごとに認可を実装できないので、GraphQLの場合はひと工夫必要になります。 resolverやmutationに認可をつける まずは、resolverやmutationに対しての認可に利用できるメソッドについてまとめます。 https://graphql-ruby.org/mutations/mutation_authorization.html ready? ready?メソッドは、以下のようにresolverやmutationで使用できます。ready?メソッドはmutation実行前に自動的に実行されます。戻り値がfalseの場合はnullが返されますが、例のようにGraphQL Errorを発生させた方がベターでしょう。 mutation.rb class Mutations::PromoteEmployee < Mutations::BaseMutation def ready?(**args) # argsはmutationの引数 if !context[:current_user].admin? raise GraphQL::ExecutionError, "Only admins can run this mutation" else true end end def resolver(**args) # mutation実行 end end authorized? GraphGL-Rubyのmutationにはauthorized?メソッドも用意されています。実はこのメソッドはready?メソッドとほとんど同じ動きをします。 上のready?をauthorized?に書き換えても同様に動作します。唯一の違いはargumentsをロードするかどうかです。 argumentsをロードするとは、以下のようにargumentを定義した場合にargumentのemployee_idからloadsで定義されているEmployeeオブジェクトを自動的にDBから取得してくれることを指します。 mutation.rb argument :employee_id, ID, required: true, loads: Types::Employee 上記の場合だと、引数で指定したidのemployeeオブジェクトが取得されます。故にauthorized?メソッドを利用すると、以下のようにも書くことができます。 mutation.rb argument :employee_id, ID, required: true, loads: Types::Employee def authorized?(employee:) context[:current_user].manager_of?(employee) end オブジェクトタイプに認可をつける GraphQL-Rubyでは、スキーマとしてオブジェクトタイプを定義します。関連を持つオブジェクト同士は、クライアント側で自由に取得できてしまいます。すると、本来は権限が必要なリソースにもアクセスできてしまいます。 それを防ぐためにオブジェクトタイプごとに認可を設定する方法をまとめます。 visible?を使う https://graphql-ruby.org/authorization/visibility.html visible?メソッドはその名の通り、スキーマ自体がユーザから見えなくなります。例えば、実験的な機能を特定のユーザのみに開放するみたいなユースケースが考えられます。 以下の例では、visible?メソッドの戻り値がfalseなら、graphqlエラーが返ることになります secret_type.rb class secretType < BaseObject def self.visible?(context) context[:current_user].admin? end field :hoge, Hoge, null: true end authorized?を使う https://graphql-ruby.org/authorization/authorization.html 1番、認可っぽいのはこのauthorized?メソッドでしょうか。名前からしてそうですね。 以下の例では、current_userがobject.userと等しい場合は、Objectが返され、等しくない場合は、nullが返ります。 secret_type.rb class secretType < BaseObject def self.authorized?(object, context) context[:current_user] === object.user end field :hoge, Hoge, null: true end また、authorized?メソッドがfalseの場合にエラーを返したい場合は、schemaのトップレベルにエラーを定義することができます。 my_schema.rb class MySchema < GraphQL::Schema def self.unauthorized_object(error) raise GraphQL::ExecutionError, "An object of type #{error.type.graphql_name} was hidden due to permissions" end end scopeを使う https://graphql-ruby.org/authorization/scoping.html authorized?メソッドは、そのオブジェクトを返すか、返さないかの二択でしたが、ユーザによって返すオブジェクトを制限したい場合もあると思います。その場合はscopeメソッドが便利です。 以下の場合は、adminユーザならば、オブジェクトを全て返し、それ以外はpublishedなproductを返します。 product_type.rb class prodcutType < BaseObject def self.scope_items(items, context) context[:current_user].admin? items : items.published end end このscopeを適用するかどうかは、以下のようにfieldの引数で定義できます。 field :products, [Types::Product] scope: true 戻り値が配列の場合は、デフォルトでtrueになっており、値の場合はfalseになっています。 まとめ 以上、GraphQL-Rubyの認可についてまとめました。Graphqlの認可は結構ややこしいので、しっかり整理していきたいです!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GraphQL-Rubyの認可についてまとめる

はじめに 最近、GraphQL-Rubyを使って認可を実装する機会があったのでまとめてみます。 用語的には認証と認可がありますが、今回は認可を扱います。(GraphQLは一般的には認証を扱ってません) resolverやmutationに認可をつける まずは、resolverやmutationに対しての認可に利用できるメソッドについてまとめます。 https://graphql-ruby.org/mutations/mutation_authorization.html ready? ready?メソッドは、以下のようにresolverやmutationで使用できます。ready?はmutation実行前に自動的に実行されます。戻り値がfalseの場合はnullが返されますが、例のようにGraphQL Errorを発生させた方がベターでしょう。 mutation.rb class Mutations::PromoteEmployee < Mutations::BaseMutation def ready?(**args) # argsはmutationの引数 if !context[:current_user].admin? raise GraphQL::ExecutionError, "Only admins can run this mutation" else true end end def resolver(**args) # mutation実行 end end authorized? mutationにはauthorized?メソッドも用意されています。実はこのメソッドはready?メソッドとほとんど同じ動きをします。上のready?をauthorized?に書き換えても同様に動作します。唯一の違いはargumentsをロードするかどうかです。 argumentsをロードするとは、以下のようにargumentを定義した場合にargumentのemployee_idからloadsで定義されているEmployeeオブジェクトを自動的にDBから取得してくれることを指します(多分)。 mutation.rb argument :employee_id, ID, required: true, loads: Types::Employee 上記の場合だと、引数で指定したidのemployeeオブジェクトが取得されます。故にauthorized?メソッドを利用すると、以下のようにも書くことができます。 mutation.rb argument :employee_id, ID, required: true, loads: Types::Employee def authorized?(employee:) context[:current_user].manager_of?(employee) end オブジェクトタイプに認可をつける GraphQL-Rubyでは、関連を持つオブジェクト同士は、クライアント側で自由に取得できます。すると、本来は権限が必要なリソースにもアクセスできてしまうことがあります。それを防ぐためにオブジェクトタイプごとに認可を設定する方法をまとめます。 visible?を使う https://graphql-ruby.org/authorization/visibility.html visible?メソッドはその名の通り、スキーマ自体がユーザから見えなくなります。例えば、実験的な機能を特定のユーザのみに開放するみたいなユースケースが考えられます。 以下の例では、visible?メソッドの戻り値がfalseなら、graphqlエラーが返ることになります secret_type.rb class secretType < BaseObject def self.visible?(context) context[:current_user].admin? end field :hoge, Hoge, null: true end authorized?を使う https://graphql-ruby.org/authorization/authorization.html 1番、認可っぽいのはこのauthorized?メソッドでしょうか。名前からしてそうですね。 以下の例では、current_userがobject.userと等しい場合は、Objectが返され、等しくない場合は、nullが返ります。 secret_type.rb class secretType < BaseObject def self.authorized?(object, context) context[:current_user] === object.user end field :hoge, Hoge, null: true end また、authorized?メソッドがfalseの場合にエラーを返したい場合は、schemaのトップレベルにエラーを定義することができます。 my_schema.rb class MySchema < GraphQL::Schema def self.unauthorized_object(error) raise GraphQL::ExecutionError, "An object of type #{error.type.graphql_name} was hidden due to permissions" end end scopeを使う https://graphql-ruby.org/authorization/scoping.html authorized?メソッドは、そのオブジェクトを返すか、返さないかの二択でしたが、ユーザによって返すオブジェクトを制限したい場合もあると思います。その場合はscopeメソッドが便利です。 以下の場合は、adminユーザならば、オブジェクトを全て返し、それ以外はpublishedなproductを返します。 product_type.rb class prodcutType < BaseObject def self.scope_items(items, context) context[:current_user].admin? items : items.published end end このscopeを適用するかどうかは、以下のようにfieldの引数で定義できます。 field :products, [Types::Product] scope: true 戻り値が配列の場合は、デフォルトでtrueになっており、値の場合はfalseになっています。 まとめ 以上、GraphQL-Rubyの認可についてまとめました。Graphqlの認可は結構ややこしいので、しっかり整理していきたいです!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails]ウィザード形式のフォームの実装

はじめに 先日あるサイトにて新規会員登録の項目が大量あると登録する気が失せるなと感じました。そのことをきっかけに、ユーザへの興味を削がないように登録フォームを進めさせる方法はないかなあと考えていたらウィザード形式なるものに出会いましたのでアウトプットします。 ウィザード形式とは ウィザード形式とは、対話の如く順番に操作画面が進んでいく方式のことです。身の回りでいえば、新幹線の切符購入画面とかそうですよね(出発駅選択→到着駅選択→時間選択→座席指定みたいな)。ユーザからすると、1ページで項目を一気に登録しないといけないフォームよりも、ウィザード形式の方が、今何をしているのかシンプルにわかりやすくてみやすいと言う特徴があります。 実装(ユーザ登録編) ユーザ登録の後、住所情報を登録するウィザード形式を作ることとします。 registrations_controller.rb def new @user = User.new end def create @user = User.new(sign_up_params) unless @user.valid? render :new and return end session["devise.regist_data"] = {user: @user.attributes} session["devise.regist_data"][:user]["password"] = params[:user][:password] @address = @user.build_address #1対1の場合は、buildメソッド_関連づけられたモデル名 render :new_address end このコントローラで行うことは次の3つです。 ユーザ情報入力画面から受け取った情報の ①バリデーションチェックを行い、 ②sessionに登録情報を持たせて、 ③次の住所情報登録で使用するインスタンスを生成しておく。 三行目でreturnしている理由は、バリデーションチェックが通らない場合は、その後の処理もいったん止めたいからです。もし、この記述を怠ると、その後出てくるrenderが実行されて「、DoubleRenderErrorというエラーが発生します。 unless @user.valid? render :new and return end 次に、sessionを使用することで登録した情報を保持します。 session["devise.regist_data"] = {user: @user.attributes} session["devise.regist_data"][:user]["password"] = params[:user][:password] attributesメソッド ここでattributesメソッドについて軽く触れておきます。 attributesメソッドはインスタンスメソッドから取得できる値をオブジェクト型からハッシュ型に変換してくれます。 実際に見てみるとよくわかります。 # 例:Userインスタンスがもつオブジェクト型の値 #=><user:12345678921> # 例:Userインスタンスがもつハッシュ型の値 #=> {name=>"yamada", :sex=>"man"} これを踏まえ、今回の記述を再度見てみると、sessionにはハッシュ型で渡していることがわかります。 実装(住所登録編) 住所登録では以下のようなアクションを追加します。 registrations_controller.rb #省略 def create_address @user = User.new(session["devise.regist_data"]["user"]) @address = Address.new(address_params) unless @address.valid? render :new_address and return end @user.build_address(@address.attributes)#住所情報付け足し @user.save session["devise.regist_data"]["user"].clear sign_in(:user, @user) end private def address_params params.require(:address).permit(:postal_code, :address) end おそらくuserモデルとさほど変わりはありませんが、、、 sessionはclearメソッドを使用して明示的に削除するようにしましょう。 そして、最後にsign_inでサインインします。 終わりに ただ開発するのではなく、どうしたらユーザ(お客様)にとって、快適で便利になるのか、実装した結果どうなるのかを意識して開発に取り組んでいきます!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】カラム名の変更方法

はじめに Railsでサービス開発中、カラム名を間違えてしまったので カラムの変更方法を備忘録としてまとめておきます。 Rails:5.2.5 モデル名 変更前のカラム名 変更後のカラム名 user profile_image profile_image_id 1.migrationファイルを作成する カラム名を変更するために、migrationファイルを作成する。 $ rails g migrate rename_[変更前のカラム名]_column_to_[モデル名(複数形)] 今回の場合だと、以下のようになる。 $ rails g migrate rename_profile_image_column_to_users 2.migrationファイルを編集する 生成されたファイルにchangeメソッドを追加し、変更したいカラム名を記述する。 rename_column :テーブル名, :変更前のカラム名, :変更後のカラム名 db/migrate/20210425060907_rename_profile_image_column_to_users def change rename_column :users, :profile_image, :profile_image_id end 3.DBに反映する 下記コマンドを実行。 $ rails db:migrate 4.カラム名が変更されているか確認 rails cでカラム名を確認する。 モデル名.column_names $ rails c $ User.column_names
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsコードリーデイング① validatesメソッドを深掘りしてみた 【備忘録】

はじめに プログラミング学習を開始して1年。自己流でアプリ開発を続けることによる成長幅に限界を感じ、次のステップとしてコードリーディングをすることにしました。 こちらの記事では、コードリーディングで得た知識の備忘録を記していきます。 なお今回はこちらの記事を参考にし、コードリーディングの環境を整えることができました。 またvalidatesの解説も載っていましたのでそちらもかなり参考にしていますが、今回は私のような初学者に価値があるような内容を共有させて戴きます。 https://qiita.com/jabba/items/8a9ac664eb2a0e61e621 今回はmodelのvalidatesメソッドをリーディング ターミナルで以下を実行。 rails c [1] pry(main)> u = User.new(name: 'sample name') nameの長さの最大が30というvalidatesの場合の処理を見ていきます。 user.rb class User < ApplicationRecord #binding.pryで処理を止める binding.pry validates :name, length: { maximum: 30 } end validatesメソッドがどのように宣言されているのか。 UserクラスはApplicationRecordを継承していますが、さらに元をたどるとActiveRecord::Baseを継承しています。 以下Railsのreadmeで以下のようにmodel層に関して解説がありました。 Model layer models can also be ordinary Ruby classes, or Ruby classes that implement a set of interfaces as provided by the Active Model module. モデルは、通常のRubyクラス、またはActiveModelモジュールによって提供される一連のインターフェースを実装するRubyクラスにすることもできます。 https://github.com/rails/rails いつも利用している便利なメソッドは、ActiveModelモジュールによって提供されたものということがわかりました。 本題のvalidates.rbを読んでみた。 確かにActiveModelモジュールの中に宣言されていました。 rails/activemodel/lib/active_model/validations/validates.rb module ActiveModel module Validations module ClassMethods def validates(*attributes) (省略) end end end end 処理①引数の調整 rails/activemodel/lib/active_model/validations/validates.rb def validates(*attributes) defaults = attributes.extract_options!.dup validations = defaults.slice!(*_validates_default_keys) extract_options!の継承元は以下の通り。 rails/activesupport/lib/active_support/core_ext/array/extract_options.rb # frozen_string_literal: true class Hash # By default, only instances of Hash itself are extractable. # Subclasses of Hash may implement this method and return # true to declare themselves as extractable. If a Hash # is extractable, Array#extract_options! pops it from # the Array when it is the last element of the Array. def extractable_options? instance_of?(Hash) end end class Array # Extracts options from a set of arguments. Removes and returns the last # element in the array if it's a hash, otherwise returns a blank hash. # # def options(*args) # args.extract_options! # end # # options(1, 2) # => {} # options(1, 2, a: :b) # => {:a=>:b} def extract_options! if last.is_a?(Hash) && last.extractable_options? pop else {} end end end defaultに代入する値では、 渡された引数の最後がハッシュクラスの直接のインスタンスで書かれている場合は、pop それ以外は、{} を代入しています。 学び① is_a?(mod) is_a?(mod)メソッドを使用すれば、オブジェクトが指定されたクラス mod かそのサブクラスのインスタンスであるとき真を返します。 したがって、ここではattributes(validatesの引数)がハッシュクラスかどうか判定しています。 学び② instance_of?(klass) オブジェクトがクラス klass の直接のインスタンスである時真を返します。 https://docs.ruby-lang.org/ja/latest/method/Object/i/instance_of=3f.html 学び③ popとpush 基本情報処理の試験勉強で学んでいたものでした。 popは配列の末尾から指定個数取り出し、取り出した要素を返す。 pushは末尾に新たな要素を加える。 https://docs.ruby-lang.org/ja/latest/method/Array/i/pop.html https://docs.ruby-lang.org/ja/1.8.7/method/Array/i/push.html 学び④ dup オブジェクトを複製することができます。 そのもの自体を変更したくない時に便利そうです。 https://docs.ruby-lang.org/ja/latest/method/Object/i/clone.html 疑問点 instance_of?(Hash)のみで条件式として十分なのではないのか? どのような意図があって、AND条件なのだろうか。 終わりに 本日はここまでにします。 たった1行読み込むだけで相当な勉強になりました。(コードリーディング恐るべし) 疑問点が残ってしまいましたが、わかり次第追記して修正します。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Ruby】数値の任意の位での切り捨て・切り上げ

解決したかったこと 数値を扱う時に、 1234 → 1200 のように十の位以下を切り捨てたい。 解決方法 floorメソッドで負の整数を指定する。 # 切り捨て 1234.floor(-2) # => 1200 #切り上げ 1234.ceil(-2) # => 1300 (-2)なら十の位以下、(-3)なら百の位以下という風に任意の桁で処理ができます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【GitHub】リモートブランチにプッシュしてしまったコミットメッセージを修正する

1.今回の状況 作業ブランチ上で、GitHubのリモートリポジトリへプッシュした後に、コミットメッセージの誤りに気づきました。 デフォルトのブランチへはまだマージを行っていない状況です。 2.使用環境 mac.os バージョン10.15.6 Ruby 2.6.6 Rails 6.1.3.1 psql (PostgreSQL) 12.6 3.早速やってみる 今回はこちらのサイトを参考にやってみました。 参考:Gitのコミットメッセージを後から修正変更する方法! ①修正するコミットメッセージを確認 まず修正したいコミットが何番目なのか確認します。 GitHub上では下が古く、上に向かって新しいコミットメッセージが並びます。 今回は上から2つ目の「挨拶を英語おに変更う」を修正します。 # git rebase -i コマンドを実行して修正するコミットを選択 # HEAD~nをつけることで該当コマンドが最上位に来る(今回はn=2) test_commit_mistake % git rebase -i HEAD~2 参考1: 【Git】rebaseコマンドの理解 参考2: 6. rebase -i でコミットを修正する ②該当のコミットメッセージのeditに変更 テキストエディタが起動するのでpickをeditに変更して、保存してテキストエディタを閉じます。 すると、ターミナル上で Stopped at b16ad30... 挨拶を英語おに変更う You can amend the commit now, with git commit --amend Once you are satisfied with your changes, run git rebase --continue と表示されます。この順に従って進めていきます。 ③コミットメッセージを修正 今回は「挨拶を英語おに変更う」を「挨拶を英語に変更」に修正します。 # git commit --amend -m コマンドを実行して修正する # -mをつけることでテキストエディタを開かずに修正できる test_commit_mistake % git commit --amend -m "挨拶を英語に変更" [detached HEAD 95cfc4b] 挨拶を英語に変更 Date: Thu Apr 29 08:51:45 2021 +0900 1 file changed, 2 insertions(+), 2 deletions(-) 参考:7.6 Git のさまざまなツール - 歴史の書き換え ④修正を完了させる git rebase --continueで完了です。 # rebaseを続行し、完了させる test_commit_mistake % git rebase --continue Successfully rebased and updated refs/heads/feature/introduce. 参考:git rebase についてまとめてみた 再度コミットメッセージを確認すると、修正ができていることが分かります。 test_commit_mistake % git log --oneline 02f1d4a (HEAD -> feature/introduce) やり取りを追加 95cfc4b 挨拶を英語に変更 #今回修正箇所 7712b62 挨拶を追加 7ae483a init ⑤GitHubに再プッシュ ローカルブランチでの修正が終わったので、リモートブランチに修正を反映させます。 今回は既にプッシュを行っているため、 git push --originのコマンドを使用するとプッシュに失敗します。 # 作業ブランチにいることを確認後 test_commit_mistake % git push origin HEAD To https://github.com/hogehoge/test_commit_mistake.git ! [rejected] HEAD -> feature/introduce (non-fast-forward) error: failed to push some refs to 'https://github.com/hogehoge/test_commit_mistake.git' hint: Updates were rejected because the tip of your current branch is behind hint: its remote counterpart. Integrate the remote changes (e.g. hint: 'git pull ...') before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details. 今回は競合箇所がないか確認した後に --forceオプションをつけて強制的にプッシュを行います。 ※リモートブランチが強制的にローカルブランチの内容で上書きされてしまうので共同開発等、複数人で使用する際は要注意 test_commit_mistake % git push --force origin HEAD Enumerating objects: 8, done. Counting objects: 100% (8/8), done. Delta compression using up to 8 threads Compressing objects: 100% (3/3), done. Writing objects: 100% (6/6), 633 bytes | 633.00 KiB/s, done. Total 6 (delta 0), reused 0 (delta 0), pack-reused 0 To https://github.com/hogehoge/test_commit_mistake.git + 6f5ca4a...02f1d4a HEAD -> feature/introduce (forced update) GitHub上でもコミットメッセージが修正できていることが確認できました。 4.まとめ コミットメッセージを含め、不具合がないか等確認してから行う。 --forceは強制的にプッシュできるためなるべく使用しないよう気をつける。 5.最後に 記事の感想や意見、ご指摘等あれば伝えていただけるとありがたいです。 読んでいただき、ありがとうございました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【GithHub】リモートブランチにプッシュしてしまったコミットメッセージを修正する

1.今回の状況 作業ブランチ上でリモートリポジトリへプッシュした後に、コミットメッセージの誤りに気づきました。 デフォルトのブランチへはまだマージを行っていない状況です。 2.使用環境 mac.os バージョン10.15.6 Ruby 2.6.6 Rails 6.1.3.1 psql (PostgreSQL) 12.6 3.早速やってみる 今回はこちらのサイトを参考にやってみました。 参考:Gitのコミットメッセージを後から修正変更する方法! ①修正するコミットメッセージを確認 まず修正したいコミットが何番目なのか確認します。 GitHub上では下が古く、上に向かって新しいコミットメッセージが並びます。 今回は上から2つ目の「挨拶を英語おに変更う」を修正します。 # git rebase -i コマンドを実行して修正するコミットを選択 # HEAD~nをつけることで該当コマンドが最上位に来る(今回はn=2) test_commit_mistake % git rebase -i HEAD~2 参考1: 【Git】rebaseコマンドの理解 参考2: 6. rebase -i でコミットを修正する ②該当のコミットメッセージのeditに変更 テキストエディタが起動するのでpickをeditに変更して、保存してテキストエディタを閉じます。 すると、ターミナル上で Stopped at b16ad30... 挨拶を英語おに変更う You can amend the commit now, with git commit --amend Once you are satisfied with your changes, run git rebase --continue と表示されます。この順に従って進めていきます。 ③コミットメッセージを修正 今回は「挨拶を英語おに変更う」を「挨拶を英語に変更」に修正します。 # git commit --amend -m コマンドを実行して修正する # -mをつけることでテキストエディタを開かずに修正できる test_commit_mistake % git commit --amend -m "挨拶を英語に変更" [detached HEAD 95cfc4b] 挨拶を英語に変更 Date: Thu Apr 29 08:51:45 2021 +0900 1 file changed, 2 insertions(+), 2 deletions(-) 参考:7.6 Git のさまざまなツール - 歴史の書き換え ④修正を完了させる git rebase --continueで完了です。 # rebaseを続行し、完了させる test_commit_mistake % git rebase --continue Successfully rebased and updated refs/heads/feature/introduce. 参考:git rebase についてまとめてみた 再度コミットメッセージを確認すると、修正ができていることが分かります。 test_commit_mistake % git log --oneline 02f1d4a (HEAD -> feature/introduce) やり取りを追加 95cfc4b 挨拶を英語に変更 #今回修正箇所 7712b62 挨拶を追加 7ae483a init ⑤GitHubに再プッシュ ローカルブランチでの修正が終わったので、リモートブランチに修正を反映させます。 今回は既にプッシュを行っているため、 git push --originのコマンドを使用するとプッシュに失敗します。 # 作業ブランチにいることを確認後 test_commit_mistake % git push origin HEAD To https://github.com/hogehoge/test_commit_mistake.git ! [rejected] HEAD -> feature/introduce (non-fast-forward) error: failed to push some refs to 'https://github.com/hogehoge/test_commit_mistake.git' hint: Updates were rejected because the tip of your current branch is behind hint: its remote counterpart. Integrate the remote changes (e.g. hint: 'git pull ...') before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details. 今回は競合箇所がないか確認した後に --forceオプションをつけて強制的にプッシュを行います。 ※リモートブランチが強制的にローカルブランチの内容で上書きされてしまうので共同開発等、複数人で使用する際は要注意 test_commit_mistake % git push --force origin HEAD Enumerating objects: 8, done. Counting objects: 100% (8/8), done. Delta compression using up to 8 threads Compressing objects: 100% (3/3), done. Writing objects: 100% (6/6), 633 bytes | 633.00 KiB/s, done. Total 6 (delta 0), reused 0 (delta 0), pack-reused 0 To https://github.com/hogehoge/test_commit_mistake.git + 6f5ca4a...02f1d4a HEAD -> feature/introduce (forced update) GitHub上でもコミットメッセージが修正できていることが確認できました。 4.まとめ コミットメッセージを含め、不具合がないか等確認してから行う。 --forceは強制的にプッシュできるためなるべく使用しないよう気をつける。 5.最後に 記事の感想や意見、ご指摘等あれば伝えていただけるとありがたいです。 読んでいただき、ありがとうございました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

rails でJavaScriptを使う

商品出品機能をつくる際に、販売手数料や利益を計算させるためにJavaScriptを使ったので まとめておこうと思います。 手順 -手順1 必要なJSファイルを作成する -手順2 必要な要素を取得する -手順3 入力するたびにイベントを発火できるようにする -手順4 必要なvalue属性を取得できるようにする -手順5 HTMLをJavaScriptで作成し、ブラウザ上に描画できるようにする ファイルを作成して読み込もう まずは、app/javascriptディレクトリにファイル名.jsを作成しましょう。 そして、application.jsにrequire("作成したJSファイルのパス");を記述して、作成したJSファイルを読み込めるようにしましょう。このとき、作成したJSファイルが存在するディレクトリに注意して記述してください。 【例】application.js require("../item_price"); 作成したJSファイルがブラウザで読み込まれるか確認するため、JSファイルにconsole.logを記述します。 【例】item_price.js window.addEventListener('load', () => { console.log("OK"); }); loadというイベントは、ページが全て読み込まれた後に発火します。JSファイルの読み込みが正しく出来ていればコンソール上に"OK"という文字列が表示されるはずです。 記述ができたら、ブラウザをリロードし、コンソールを開いて確認しましょう。 ブラウザのコンソールは、command + option + Jで開くことができます。 もし"OK"という文字列がコンソール上で確認できない場合は、以下の項目を確認しましょう。 -application.jsファイルで、作成したJSファイルを読み込むための記述が誤っていないか(ファイル名やディレクトリ構造に注意する) -application.html.erbファイルで、application.jsを読み込むためのscriptタグの挿入を忘れていないか 手順2 必要な要素を取得する 次に、取得すべき要素を確認します。 手順2で実装したいことは、「金額を入力したら、その金額の販売手数料と販売利益を表示すること」です。 金額を入力したときに画面上に動きがあった要素を示すセレクタは以下の3つです。 -金額を入力する場所のidセレクタ -販売手数料を表示する場所のidセレクタ -販売利益を表示する場所のidセレクタ idセレクタを確認するときは、検証ツールで探すと分かりやすい。 idセレクタを取得する場合はdocument.getElementById("id名")を使用します。 document.getElementById("id名")は、id名を指定してHTMLの要素を取得するメソッドです。 【例】item_price.js // 金額を入力した数値をpriceInputという変数に格納する const priceInput = document.getElementById("金額を入力する場所のid"); console.logを記述して、定義した変数にinput要素が格納されているか確認をします。 【例】item_price.js const priceInput = document.getElementById("金額を入力する場所のid"); console.log(priceInput); もしコンソール上に何も表示されないもしくはエラーが出る場合は、以下の項目を確認しましょう。 -取得すべきidセレクタの場所に間違いがないか 手順3 入力するたびにイベントを発火できるようにする 金額を入力するたびに、イベント発火するようにaddEventListenerを使用します。 addEventListenerは、イベント発火の際に実行する関数を定義するためのメソッドです。 今回は、入力があるたびにイベント発火を起こしたいため、以下のようにinputというイベントを使用します。そして console.logを記述して、入力するたびにイベント発火されるか確認をします。 【例】item_price.js const priceInput = document.getElementById("金額を入力する場所のid"); priceInput.addEventListener("input", () => { console.log("イベント発火"); }) 商品出品ページで金額を入力し、コンソール上に"イベント発火"と表示されるか確認をします。 もし"イベント発火"という文字列がコンソール上に表示されない場合は、以下の項目を確認しましょう。 -そもそもJSファイルが読み込めているか -turbolinksの記述が残っていないか -JSファイルのコードの記述に間違いがないか 手順4 必要なvalue属性を取得できるようにする 入力した金額の値を取得したい場合は、以下のようにvalue属性を指定する必要があります。 console.logを記述して、入力した金額の取得ができるか確認します。 【例】item_price.js const priceInput = document.getElementById("金額を入力する場所のid"); priceInput.addEventListener("input", () => { const inputValue = priceInput.value; console.log(inputValue); }) 続いて、商品出品ページで金額を入力し、コンソール上に金額が表示されるか確認をします。 もし金額の値がコンソール上に表示されない、もしくはエラーが出る場合は、以下の項目を確認しましょう。 -取得すべきidセレクタの場所に間違いがないか 手順5 HTMLをJavaScriptで作成し、ブラウザ上に描画できるようにする innerHTMLを使用して、販売手数料や利益計算結果を表示できる ようにしましょう。 innerHTMLは、HTML要素の書き換えを行うことができます。 【例】item_price.js const addTaxDom = document.getElementById("販売手数料を表示する場所のid"); addTaxDom.innerHTML = "入力した金額をもとに販売手数料を計算する処理" innerHTMLを実装することで、計算した販売手数料の金額に書き換え、表示することができます。 販売手数料や利益計算の処理は、Math.floorメソッドを用いて実装してみましょう。 もし、表示されているHTMLが崩れたり表示できない場合は、以下の項目を確認しましょう。 -console.logを使用して取得すべきidの場所に間違いがないか 今回はこんな感じ const priceInput = document.getElementById("item-price"); priceInput.addEventListener("input", () => { const inputValue = priceInput.value; const addTaxDom = document.getElementById("add-tax-price"); addTaxDom.innerHTML = (Math.floor(inputValue * 0.1)); const profitNumber = document.getElementById("profit") const value_result = inputValue * 0.1 profitNumber.innerHTML = (Math.floor(inputValue - value_result)); }) 以上です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ruby2.4.3のインストールでBUILD FAILEDエラー

ruby2.4.3のインストールでBUILD FAILEDエラー MacOS BigSur 11.2.2でruby2.4.3をインストールした時にエラー発生 % rbenv install 2.4.3 Downloading openssl-1.1.1k.tar.gz... -> https://dqw8nmjcqpjn7.cloudfront.net/892a0875b9872acd04a9fde79b1f943075d5ea162415de3047c327df33fbaee5 Installing openssl-1.1.1k... Installed openssl-1.1.1k to /Users/satou/.rbenv/versions/2.4.3 Downloading ruby-2.4.3.tar.bz2... -> https://cache.ruby-lang.org/pub/ruby/2.4/ruby-2.4.3.tar.bz2 Installing ruby-2.4.3... WARNING: ruby-2.4.3 is past its end of life and is now unsupported. It no longer receives bug fixes or critical security updates. ruby-build: using readline from homebrew BUILD FAILED (macOS 11.2.2 using ruby-build 20210423) Inspect or clean up the working tree at /var/folders/h3/4830l_xd6hj1msdhp0v_s3j40000gn/T/ruby-build.20210429133129.9166.uvvuHD Results logged to /var/folders/h3/4830l_xd6hj1msdhp0v_s3j40000gn/T/ruby-build.20210429133129.9166.log Last 10 log lines: compiling fiber.c linking shared-object fiber.bundle compiling closure.c closure.c:263:14: error: implicit declaration of function 'ffi_prep_closure' is invalid in C99 [-Werror,-Wimplicit-function-declaration] result = ffi_prep_closure(pcl, cif, callback, (void *)self); ^ 1 error generated. make[2]: *** [closure.o] Error 1 make[1]: *** [ext/fiddle/all] Error 2 make: *** [build-ext] Error 2 解決 以下コマンドで解決 % RUBY_CFLAGS=-DUSE_FFI_CLOSURE_ALLOC rbenv install 2.4.3 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

rails 画像投稿をテストする時

フリマアプリを作っています。画像をつけて投稿するのでその時の、単体テストの方法をまとめておこうと思います。 初心者なので、勉強用で間違えている箇所もあると思います。 もし、違っておりましたらコメントなどで教えて下さい https://qiita.com/on97-nakamatsu-mayumi/items/810a2cd2fdefeb7c3485 単体テストの方は↑こちらの方です 画像投稿のテストのしかた テスト用のダミー画像を用意しましょう テストコードは自動で実行されるものです。自動で画像をアップロードさせることはできないため、画像投稿の挙動をチェックするための画像ファイルを、あらかじめ用意しておく必要があります。 画像をダウンロードや作成したら、publicディレクトリの中に「images」というディレクトリを作成します。 そして、先ほどダウンロードした画像を、imagesディレクトリの中に配置しましょう。 続いてコードを記述しますが、画像は生成したインスタンスに紐付ける必要があります。そのため、afterというメソッドを用いて、インスタンス生成後に画像が保存されるようにしましょう。 afterメソッド afterメソッドは任意の処理の後に指定の処理を実行することができます。例えば、after(:build) とすることで、インスタンスがbuildされた後に指定の処理を実行できます FactoryBotを編集しましょう afterメソッドを用いて、生成するダミーデータに画像を添付します。 例えば FactoryBot.define do factory :message do content {Faker::Lorem.sentence} association :user association :room after(:build) do |message| message.image.attach(io: File.open('public/images/test_image.png'), filename: 'test_image.png') end end end 上の場合は8行目の記述では、io: File.openで設定したパスのファイル(public/images/test_image.png)を、test_image.pngというファイル名で保存をしています。 ちゃんとインスタンスが生成されているか確認するときはコンソール使用できることを確認しましょう。 rails c 例えば FactoryBot.create(:message) ()の中にはテストしたいモデル名 もしKeyErrorというエラーが発生した場合は、下記コマンドを実行した後、もう一度コンソールでFactoryBotの確認を行ってください。 # コンソールを終了する pry(main)> exit # Springを停止 % spring stop Railsに標準で導入されている「Spring」というGemがバックグラウンドで作動していて、稀にロードエラーを起こす為、一度作動を停止します。Springは、railsコマンドと同じタイミングで再起動されます。 画像の保存を確認する場合は、以下のように変数に入れてます。画像が保存できているか確認するにはimage.attached?で確認をしましょう。 実行結果として、trueが返ってきていれば保存されています。 【例】ターミナル(コンソール) pry(main)> message = FactoryBot.create(:message) # 省略 pry(main)> message.image.attached? # 省略 => true 以上です
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby、Railsでの日付・時間の操作系メソッドまとめ

はじめに アプリケーション開発において、日付や時間の情報というのは必ずといっていいほど絡んできます。 毎回日付・時間操作のメソッドを忘れてしまい、ググる時間が勿体ないので、まとめました。 今回だけでは網羅できていない部分とあると思うため、順次更新予定です。 XX日前・後 Dateクラス -1、+1をするだけです。 require 'date' today = Date.today yesterday = today - 1 tomorrow = today + 1 p today #<Date: 2021-04-28 ((2459333j,0s,0n),+0s,2299161j)> p yesterday #<Date: 2021-04-27 ((2459332j,0s,0n),+0s,2299161j)> p tomorrow #<Date: 2021-04-29 ((2459334j,0s,0n),+0s,2299161j)> DateTimeクラス Dateクラスと同様に-1、+1で対応出来ます。 require 'date' today = DateTime.now yesterday = today - 1 tomorrow = today + 1 p today #<DateTime: 2021-04-28T18:46:07+09:00 ((2459333j,35167s,22091000n),+32400s,2299161j)> p yesterday #<DateTime: 2021-04-27T18:46:07+09:00 ((2459332j,35167s,22091000n),+32400s,2299161j)> p tomorrow #<DateTime: 2021-04-29T19:00:30+09:00 ((2459334j,36030s,963561000n),+32400s,2299161j)> Time Timeクラスの場合-1、+1を指定すると単純に1秒の加算・減算になります。 Timeクラスで日付操作をする場面は少ないと思いますが、もし±1日を求めたい場合 86400秒で1日となリます。 p now = Time.now # 2021-04-28 18:48:54.976575 +0900 p now -1 # 2021-04-28 18:48:53.976575 +0900 p now +1 # 2021-04-28 18:48:55.976575 +0900 p now = Time.now # 2021-04-28 18:50:22.141586 +0900 p now -1 * 60 * 60 * 24 # 2021-04-27 18:50:22.141586 +0900 TimeWithZone 主にRailsで使用されるクラス。あまり意識せずに使っている人も多いかもしれないが、Railsでアプリケーションを開発する場合、TimeWithZoneを使っているケースが多いと思います。 activesupportを使えるようにgemをインストールします。 gem install activesupport require 'active_support/all' p Time.current # 2021-04-28 19:27:49.093581 +0900 # 昨日 p TIme.current.yesterday # 2021-04-27 19:27:49.093649 +0900 # 翌日 p Time.current.tomorrow # 2021-04-29 19:27:49.093752 +0900 # 3日前 p Time.current.ago(3.days) # 2021-04-25 19:27:49.093787 +0900 # 3日後 p Time.current.since(3.days) # 2021-05-01 19:27:49.093837 +0900 # 1日前 current = Time.current p current - 1.day # 2021-04-27 19:30:54.945456 +0900 TimeWithZoneは日付関連のメソッドが豊富なため、色々な求め方が出来ます。 Xヶ月 Dateクラス require 'date' today = Date.today p today #<Date: 2021-04-28 ((2459333j,0s,0n),+0s,2299161j)> # 1ヶ月前 p today << 1 #<Date: 2021-03-28 ((2459302j,0s,0n),+0s,2299161j)> # 2ヶ月前 p today.prev_month(2) #<Date: 2021-02-28 ((2459274j,0s,0n),+0s,2299161j)> # 1ヶ月後 p today >> 1 #<Date: 2021-05-28 ((2459363j,0s,0n),+0s,2299161j)> # 3ヶ月後 p today.next_month(3) #<Date: 2021-07-28 ((2459424j,0s,0n),+0s,2299161j)> prev_month、next_monthは引数を指定しない場合それぞれ、レシーバの1ヶ月前、1ヶ月後を返します。 DateTimeクラス DateTimeは日付のときと同様に、Dateクラスと同じメソッドで対応出来ます。 require 'date' today = DateTime.now p today #<DateTime: 2021-04-28T19:39:15+09:00 ((2459333j,38355s,430222000n),+32400s,2299161j)> # 1ヶ月前 p today << 1 #<DateTime: 2021-03-28T19:39:15+09:00 ((2459302j,38355s,430222000n),+32400s,2299161j)> # 2ヶ月前 p today.prev_month(2) #<DateTime: 2021-02-28T19:39:15+09:00 ((2459274j,38355s,430222000n),+32400s,2299161j)> # 1ヶ月後 p today >> 1 #<DateTime: 2021-05-28T19:43:19+09:00 ((2459363j,38599s,727644000n),+32400s,2299161j)> # 3ヶ月後 p today.next_month(3) #<DateTime: 2021-07-28T19:43:19+09:00 ((2459424j,38599s,727644000n),+32400s,2299161j)> TimeWithZone require 'active_support/all' # 1ヶ月前 p Time.current.prev_month # 2021-03-28 19:52:16.958094 +0900 # 1ヶ月後 p Time.current.next_month # 2021-05-28 19:50:22.450258 +0900 # 3ヶ月前 p Time.current.ago(3.month) # 2021-01-28 19:50:22.450291 +0900 # 3ヶ月後 p Time.current.since(3.month) # 2021-07-28 19:50:22.450393 +0900 current = Time.current # 1ヶ月前 p current -1.month # 2021-03-28 19:50:22.450436 +0900 # 1ヶ月後 p current +1.month # 2021-05-28 19:50:22.450436 +0900 X時間・X分・X秒 DateTime require 'date' today = DateTime.new(2021,4,29,0,0,0) # 1時間後 p today + Rational(1,24) #<DateTime: 2021-04-29T01:00:00+00:00 ((2459334j,3600s,0n),+0s,2299161j)> # 1分後 p today + Rational(1,24*60) #<DateTime: 2021-04-29T00:01:00+00:00 ((2459334j,60s,0n),+0s,2299161j)> # 1秒後 p today + Rational(1,24*60*60) #<DateTime: 2021-04-29T00:00:01+00:00 ((2459334j,1s,0n),+0s,2299161j)> 年月日や曜日など日時に関する情報を取得する require 'date' today = Date.today p today #<Date: 2021-04-29 ((2459334j,0s,0n),+0s,2299161j)> # 年 p today.year #2021 # 月 p today.month # 4 # 日 p today.day # 29 # 曜日 week = ['日曜日','月曜日','火曜日','水曜日','木曜日','金曜日','土曜日' ] p week[today.wday] # "木曜日" 曜日を取得するwdayメソッドに関しては、曜日の文字列が返り値になるのではなく、対応する数値が返って来ます。 (0-6、日曜日は0) DateTimeクラスでも同様のメソッドで年月日と曜日を取得出来ます。 差分 Dateクラス Date型の場合純粋に引き算をするだけで、日にちの差分が取得出来ます。 1点気をつける部分としては、Date型同士で引き算した際の戻り値がRational型(分数などを扱えるクラス)で返って来るので、分子のみを取得するnumeratorメソッドを使用することで純粋な日付の差分のみを取得出来ます。 require 'date' d1 = Date.new(2021, 4, 30) d2 = Date.new(2021, 5, 5) p (d2 - d1).numerator # 5 フォーマット・パース 日付 ⇛ 文字列 strftime おそらく年月日操作で一番使用頻度が高いメソッド require 'date' day = Date.new(2021, 5, 1) p day.strftime('%Y年%m月%d日') # "2021年05月01日" # 0サプレス p day.strftime('%Y年%-m月%-d日') # "2021年5月1日" p day.strftime('%Y/%m/%d') # "2021/05/01" # 0サプレス p day.strftime('%Y/%-m/%-d') # "2021/5/1" 文字列 ⇛ 日付 strptime require 'date' p Date.strptime("2021年4月30日", '%Y年%m月%d日') parse require 'date' p Date.parse('20210430') #<Date: 2021-04-30 ((2459335j,0s,0n),+0s,2299161j)> p Date.parse('2021/4/30') #<Date: 2021-04-30 ((2459335j,0s,0n),+0s,2299161j)> p Date.parse('2021-4-30') #<Date: 2021-04-30 ((2459335j,0s,0n),+0s,2299161j)>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

attribute, read_attribute, _read_attribute の違い

環境 / Environment Rails 6.1.3.1 Ruby 3.0.1 OS: macOS attribute とは attribute は Rails での ActiveRecord モデルオブジェクト のメソッドで、 属性名を引数として渡すとその値を返してくれます。 ただしこれは モデルの内部でのみ使えるプライベートメソッドとなっています。 そして実態は _read_attribute へのエイリアスで、 _read_attribute はパブリックメソッドになっています。 Rails Console での実行例 >> u = User.new => #<User:0x00007fb142bdd288 ... >> u.name = 'a' => "a" >> u.name => "a" >> u._read_attribute('name') => "a" >> u._read_attribute(:name) => nil 文字列を渡すと値が返りますが、シンボルでは値が nil となります。 u.name のように、 カラム名をメソッドとして実行した場合にも この _read_attribute が実行されます。 read_attribute とは read_attribute は、 _read_attribute と同様に属性値を返すメソッドですが、 _read_attribute よりも複雑な処理を行います。 引数を文字列に変換する処理を行っているため、シンボルを引数とした場合でも正しく属性値を返します。 Rails Console での実行例 >> u = User.new => #<User:0x00007fb142bdd288 ... >> u.name = 'a' => "a" >> u.read_attribute('name') => "a" >> u.read_attribute(:name) => "a" 文字列を渡した場合でも、シンボルを渡した場合でも、同じ結果となっています。 定義 紹介した3つのメソッドは、 ActiveRecord で定義されています。 read.rb module ActiveRecord module AttributeMethods module Read def read_attribute(attr_name, &block) name = attr_name.to_s name = self.class.attribute_aliases[name] || name name = @primary_key if name == "id" && @primary_key @attributes.fetch_value(name, &block) end # This method exists to avoid the expensive primary_key check internally, without # breaking compatibility with the read_attribute API def _read_attribute(attr_name, &block) # :nodoc @attributes.fetch_value(attr_name, &block) end alias :attribute :_read_attribute private :attribute 実はその昔... 昔の Rails (たとえば version 3.0.1) では このような違いはありませんでした。 attribute も read_attribute も ActiveRecord 6.1.3.1 と同じように read.rb で定義されていましたが、 シンボルを渡した場合でも文字列を渡した場合でも、 同じ結果を返していました。 そのとき _read_attribute は存在しませんでした。 read.rb def read_attribute(attr_name) attr_name = attr_name.to_s attr_name = self.class.primary_key if attr_name == 'id' if !(value = @attributes[attr_name]).nil? if column = column_for_attribute(attr_name) if unserializable_attribute?(attr_name, column) unserialize_attribute(attr_name) else column.type_cast(value) end else value end else nil end end def attribute(attribute_name) read_attribute(attribute_name) end
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

The Ruby zlib extension was not compiled

rbenv で特定のバージョンがインストールできない場合 % rbenv uninstall 2.7.1 BUILD FAILED (macOS 11.2.3 using ruby-build 20200520-14-g1642176) 略 The Ruby zlib extension was not compiled. ERROR: Ruby install aborted due to missing extensions Configure options used: --prefix=/Users/XXXX/.rbenv/versions/2.7.1 --with-openssl-dir=/Users/cano/.rbenv/versions/2.7.1/openssl --enable-shared --with-readline-dir=/usr/local/opt/readline CC=clang LDFLAGS=-L/Users/cano/.rbenv/versions/2.7.1/lib CPPFLAGS=-I/Users/cano/.rbenv/versions/2.7.1/include オプションをつけてインストール % RUBY_CONFIGURE_OPTS="--with-zlib-dir=$(brew --prefix zlib)" rbenv install 2.7.1 ダメな場合は % RUBY_CONFIGURE_OPTS="--with-openssl-dir=/usr/local/opt/openssl" rbenv install 2.7.1
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Rails]deviseで使えるヘルパーメソッド一覧

はじめに 個人でRailsアプリケーションを作った際にdeviseを使ったので備忘録として残しておきます。 deviseのヘルパーメソッドの種類 ※下記のuserの部分はモデル名なので例えばpostがモデル名の場合はpostに置き換えてください ヘルパーメソッド 説明 current_user 現在ログインしているユーザのレコードを取得する user_signed_in? ユーザーがサインインしていればtrue、サインアウトしていればfalseが返ってくる user_session ユーザーのsession情報にアクセスする configure_permitted_parameters モデルにストロングパラメーターを追加します。デフォルトはメールアドレスとパスワードのみ適応されています。 authenticate_user! ログインしていないユーザーをログインページにリダイレクトさせます。before_action :authenticate_user! のように使います。  補足 authenticate_user! onlyやexceptionでアクションを設定することが多い、例を以下に示す。 before_action :authenticate_user! , only: [:show, :edit, :update, :destroy] or before_action :authenticate_user! , except: [:show, :edit, :update, :destroy] configure_permitted_parameters 第一引数は下記のように指定できる ・sign_up: 新規登録時 ・sign_in: ログイン時 ・account_update: 更新時 下記に使用例を示します。 before_action :configure_permitted_parameters, if: :devise_controller? def configure_permitted_parameters # サインアップ時にusernameのストロングパラメータを追加 devise_parameter_sanitizer.permit(:sign_up, keys: [:username, :image]) # アカウント編集の時にnameとprofileのストロングパラメータを追加 devise_parameter_sanitizer.permit(:account_update, keys:[:username,:image,:profile]) end
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む