20210321のRubyに関する記事は21件です。

【Rails】現在使用しているgemの中身を見る方法

gemの中身を見たい意図

  • Rubyの勉強のため、gemの中身を見てみたい。
  • でも中の見方がわからない。GitHub上で見ても、個別のファイルごとになっているので見辛い。エディタで表示されるように見たい。

バージョンの状況

  • ruby 3.0.0
  • rails 6.1.3
  • homebrewをインストール済

今回勉強するために見たかったgem

結論

 % bundle open gem名

見るまでにエラーが出た?解消までの経緯(参考)

まずは準備(Railsアプリ上で、見たいgemをインストール)

Gemfile
gem 'gimei'
terminal
% bundle install

カレントディレクトリにて、実行したところエラー発生

⚠️開きたいなら、エディターをセットしてね!

terminal
% bundle open gimei
To open a bundled gem, set $EDITOR or $BUNDLER_EDITOR

解決策

  • Homebrew-caskと呼ばれるmacのGUIをコマンドでインストール出来る拡張機能を使った。
  • Homebrew-cask内にあるsublime-textというエディターをインストールし、環境変数に設定したところopenコマンドで見られるようになった!
terminal
# (ホームディレクトリに移動して)tapコマンドで、caskを追加
% brew tap homebrew/cask

# brew内に、sublime-textがあるか探す・・
% brew search subl 
=> Casks
subler  sublercli  sublime-merge  sublime-text

# sublime-textをインストール
% brew install sublime-text

# 環境変数に設定
% export EDITOR='subl -w'

# (gimeiをインストールしていたアプリに移動して)
% bundle open gimei

すごくコードが綺麗?
また複数のクラスがあるRubyコードを見たのが初めてだった。
(やっと見れるようになったので、勉強のため詳細はこれから見ようと思います!!)
gimei.png

見るまでに戸惑ったので、誰かの役に立てば幸いです。
誤っている部分などありましたら教えてください?‍♀️

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsのコントローラー上で.envを使った環境変数を読み込めなかった時の対応

実現したいこと:
Railsのコントローラー上で、
.envのファイルに設定した環境変数を読み込んでAPIを取得したい。

環境:
Ruby 2.6.6
Rails 6.0.3.4
gemのdotenv-railsをインストール済

状況:
Ruby-on-RailsでSNSのアプリケーションを作成中にNewsApiを使用し、
Newsの情報を取得し表示する機能を実装していた。
APIKEYを.envファイルにて環境変数に置き換えて使用したかったが、
エラーが発生して読み込めなかった。

ニュース機能の実装で参考にした記事:
https://qiita.com/UTOG/items/f6438420e81b6488a508
上記執筆者様の実装方法を参考にNewsApiへ登録し、
APIKEYを取得し環境変数として設定後、記載されている実装コードを活用しファイル作成。(ニュースカテゴリー等の設定は変更)

対象ファイル:

app/controller/news_Controller.rb
class NewsController < ApplicationController
  def index
  end

  def data
    uri = URI.parse('http://newsapi.org/v2/top-headlines?country=jp&category=business&pageSize=15&apiKey=<%="#{ENV['API_KEY']}"%>')
    json = Net::HTTP.get(uri)
    moments = JSON.parse(json)
    @data = moments['articles'].to_json
  end
end
.env
API_KEY='この中に取得したAPI_KEYを入力'

上記コードでは下記のようなエラーが発生。

エラー文:
syntax error, unexpected tCONSTANT, expecting ')'
...ze=15&apiKey=<%="#{ENV['API_KEY']}"%>')
... ^~~~~~~
/app/controllers/news_controller.rb:6: syntax error, unexpected ')', expecting end
...iKey=<%="#{ENV['API_KEY']}"%>')

調べたところ閉じタグがないと警告が出ており、
どうやら環境変数が読み込めていないため、
そこでコードの読み込みが止まってしまっているようあった。

試したこと:
1.環境変数を挿入していた該当のURLに取得したAPIKEYをベタ打ちで挿入
→ニュースが問題なく表示される。

2.コンソール上で環境変数を実行( 実行コード:$ ENV['API_KEY'] )
→.env内に記載していたAPIKEYが問題なく表示される。

→この時点で、
①ニュースを表示すること
②.env内での環境変数の設定はできていると予想。
コントローラーへの環境変数の組み込み方に問題があるのではと仮定。

2.環境変数の挿入方法を変更
(news.controller.rb 6行目を下記のパターンで変更 ※対象箇所周辺コードのみ抜粋)

country=jp&category=business&pageSize=15&apiKey=<%="#{ENV['API_KEY']}"%>')
country=jp&category=business&pageSize=15&apiKey=<%=ENV['API_KEY']%>')
country=jp&category=business&pageSize=15&apiKey=<"#{ENV['API_KEY']}"')
country=jp&category=business&pageSize=15&apiKey=ENV['API_KEY']')

→検索しながら上記色々なパターンを実行したものの、エラー等で読み込めない状況は変わらず。。

原因:
<% %>や<%= %>の記述はerbファイル内で使える記述であり、
erb上でRubyコードを実行したり、Rubyで定義した変数などをHTMLとして出力したりする際に利用するとのことであり、コントローラー内では記述方法は異なるとのこと。

解決策:
下記、コードを修正。
ダブルクォーテーション(")とシングルクォーテーション(')の使い方にも間違いがあった模様。

app/controller/news_Controller.rb
class NewsController < ApplicationController
  def index
  end

  def data
    uri = URI.parse("http://newsapi.org/v2/top-headlines?country=jp&category=business&pageSize=15&apiKey=#{ENV['API_KEY']}")
    json = Net::HTTP.get(uri)
    moments = JSON.parse(json)
    @data = moments['articles'].to_json
  end
end

今回、エラーにハマっていたところを質問サイトにて回答を頂いたため、
同じ状況の方のご参考になればと思い、共有させて頂きます。

まだまだ未熟なため説明不足な点もございますが、
今後修正等加えて参りますので気になる点がございましたらぜひ、
ご指導、ご鞭撻のほどよろしくお願いいたします。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Tips: Rubyでresponse bodyをstreamで受け取ってNoMemoryErrorを回避する

RubyやRailsなどでHTTPリクエストを行う場合に、response bodyをstreamで受け取る方法を紹介します。
単純にリクエストをするとレスポンスの結果を全てメモリに載せてしまうので、メモリの節約や巨大なデータを取得するとNoMemoryErrorが発生してしまいます。
今回の手法はこのエラーになってしまう状態を回避する方法として有効です。

Net::HTTPの場合

にある通り、read_bodyというメソッドを用いることでstreamでデータの受け取りを行うことができます。ファイルに書き出すことでメモリを圧迫せずにデータを取得できます。

require 'net/http'

uri = URI.parse('http://example.com/')
Net::HTTP.start(uri.host, uri.port) do |http|
  http.request_get(uri.path) do |response|
    File.open("file_path", "w") do |file|
      response.read_body do |chunk|
        file.write(chunk)
      end
    end
  end
end

また、streamで取得したデータの累計サイズを記録しておくことで、特定のサイズでデータの取得を打ち切るようなこともできます。

require 'net/http'

uri = URI.parse('http://example.com/')
response_body = ''
total_size = 0
Net::HTTP.start(uri.host, uri.port) do |http|
  http.request_get(uri.path) do |response|
    response.read_body do |chunk|
      response_body += chunk if total_size <= 1000000 # 1Mバイトまでのデータまで受け取る
      total_size += chunk.bytesize
    end
  end
end

Faradayの場合

にある通り、on_dataというオプションにprocを渡すことでread_bodyと同じようなことができます(このオプションが使えるのはNet::HTTPをアダプタにしている場合のみです)

require 'faraday'

connection = Faraday.new(url: 'http://example.com/')
response_body = ''
connection.get('/') do |request|
  request.options.on_data = proc do |chunk, overall_received_bytes|
    puts "Received #{overall_received_bytes} characters"
    response_body += chunk
  end
end

また、Net::HTTPと同じようにファイルに書き出すこともできますし、切り捨ても行えます。

require 'faraday'

connection = Faraday.new(url: 'http://example.com/')
connection.get('/') do |request|
  request.options.on_data = proc do |chunk, overall_received_bytes|
    puts "Received #{overall_received_bytes} characters"
    File.open("file_path", "w") do |file|
      file.write(chunk)
    end
  end
end
require 'faraday'

connection = Faraday.new(url: 'http://example.com/')
response_body = ''

connection.get('/') do |request|
  request.options.on_data = proc do |chunk, overall_received_bytes|
    puts "Received #{overall_received_bytes} characters"
    response_body += chunk if overall_received_bytes <= 1000000 # 1Mバイトまでのデータまで受け取る
  end
end
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RSpecデータリクエストを削減してテスト実行時間を削減した話

はじめに

私はエンジニアインターンで主にサーバーサイドの開発を担当させていただいています。

機能実装の際はRSpecでテストケースを書いてから実装していて、コミットする前に全体のテストを通してバグを見つけているのですが

実行時間が長い!

ということで、RSpecのリファクタリングを行いテストの実行時間を削減して見ましたので、一部紹介したいと思います。

1. 従来のRSpecでのデータリクエスト状況

現状、RSpecでは以下のように、letを使用してデータの作成を行っています。

require 'spec_helper'

describe User do
  let!(:user) { FactoryBot.create(:user) }

  it 'anything' do
    # userのテスト
  end

  it 'anything' do
    # userのテスト
  end

  it 'anything' do
    # userのテスト
  end
end

これではexampleが3回行われる度にUserモデルが作成されてしまう。
これをどうにか1回のレコード作成に留められないか...

2. gem "test-prof"の導入

そこでtest-profを導入します。

Gemfile
gem "test-prof"
bundle install

変更後テストケース

require 'spec_helper'

describe User do
  let_it_be(:user) { FactoryBot.create(:user) }

  it 'anything' do
    # userのテスト
  end

  it 'anything' do
    # userのテスト
  end

  it 'anything' do
    # userのテスト
  end
end

このようにtest-profはlet_it_beというヘルパーメソッドを提供してくれるgemになります。

そうするとRailsのトランザクションテスト機能を利用してレコードを最初に1回だけ作成して、テストが終了したら該当データを削除してくれるようになります。

3. ベンチマーク

変更したテストファイル数は全体の3割ほどですが、約1分のテスト実行時間の削減に繋がりました。

let_it_be使用前

スクリーンショット 2021-03-12 18.12.38.png

let_it_be使用後

スクリーンショット 2021-03-12 18.46.49.png

おわりに

画期的にテストの実行時間を削減できた訳ではありませんが、長期的に見て効果のある対処法なのではないかと思います。

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Railsチュートリアル10章まとめ

10.1 ユーザーを更新する

ユーザーを更新する行為は、新規ユーザーの作成に似ている。

アクション リクエストに応答
新規作成 new POSTに対してcreate
更新 edit PATCHに対してupdate

10.1.1編集フォーム

まずやるべきは、Usersコントローラーにeditアクションを追加し、それに対応するeditビューを実装。
ルーティングはresources :usersのおかげで有効になっている。

Railsチュートリアル 表7.1を確認すると、ユーザー編集ページのURLは/users/1/editとなっている。
ここで、ユーザーidを取得するために用いるのが、params[:id]
paramとは、Railsで送られてきた値を取得するメソッド

app/controllers/users_controller.rb
  def edit
    @user = User.find(params[:id])
  end

ユーザーのeditアクション

app/views/users/edit.html.erb
<% provide(:title, "Edit user") %>
<h1>Update your profile</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= form_with(model: @user, local: true) do |f| %>
      <%= render 'shared/error_messages' %>

      <%= 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, "Confirmation" %>
      <%= f.password_field :password_confirmation, class: 'form-control' %>

      <%= f.submit "Save changes", class: "btn btn-primary" %>
    <% end %>

    <div class="gravatar_edit">
      <%= gravatar_for @user %>
      <a href="https://gravatar.com/emails" target="_blank">change</a>
    </div>
  </div>
</div>

ユーザーのeditビュー
ここでは、formの部分で、大部分がユーザー作成画面とかぶっているので、パーシャルでまとめるのが良い。

また、@userインスタンス変数を使って、idを取得し編集ページを表示している。

HTML
<form accept-charset="UTF-8" action="/users/1" class="edit_user"
      id="edit_user_1" method="post">
  <input name="_method" type="hidden" value="patch" />
  .
  .
  .
</form>

WebブラウザではそのままではPATCHリクエストを送信できない。
そこで以下のコードで「偽装」している。

<input name="_method" type="hidden" value="patch" />

リスト 10.2のform_with(@user)のコードは、リスト 7.15のコードと完全に同じである。
ここでは、Active Recordnew_record論理値メソッドでPOSTリクエストとPATCHリクエストを区別している。

$ rails console
>> User.new.new_record?
=> true
>> User.first.new_record?
=> false

true→POST
false→PATCH

最後に、ナビゲーションのリンクを実装

<%= link_to "Settings", edit_user_path(current_user) %>

edit_user_pathもUsersリソースのおかげで使用可能。
current_userはヘルパーメソッド(9章で実装)

10.1.2 編集の失敗

ゴールはupdateメソッドの実装。

app/controllers/users_controller.rb
  def update
    @user = User.find(params[:id])
    if @user.update(user_params)
      # 更新に成功した場合を扱う。
    else
      render 'edit'
    end
  end

抑えておきたいのは、updateの呼び出しにuser_paramsを使っている点。
これはStrong Parametersというテクニック

user_paramsメソッドはx Usersコントローラー内部でのみ実行され、Web経由で外部ユーザーに晒される心配はなし。属性の許可を制限することで管理者権限を乗っ取られることを防ぐ。
(詳しくは7.3.2参照)

  private

    def user_params
      params.require(:user).permit(:name, :email, :password,
                                   :password_confirmation)
    end
end

10.1.3 編集失敗時のテスト

統合テストを行う

$ rails generate integration_test users_edit
      invoke  test_unit
      create    test/integration/users_edit_test.rb

コマンドで統合テストを生成

まずは、編集失敗時のテストから。
流れとしては、編集ページにアクセス→editビューが描画されるか確認→無効な情報を送信→再度editビューが描画される

test/integration/users_edit_test.rb
require 'test_helper'

class UsersEditTest < ActionDispatch::IntegrationTest

  def setup
    @user = users(:michael)
  end

  test "unsuccessful edit" do
    get edit_user_path(@user)
    assert_template 'users/edit'
    patch user_path(@user), params: { user: { name:  "",
                                              email: "foo@invalid",
                                              password:              "foo",
                                              password_confirmation: "bar" } }

    assert_template 'users/edit'
  end
end

ここでPATCHリクエストを送るためにpatchメソッドを使用している。
これはget,postメソッド等と同様に、HTTPリクエストを送るためのもの。
(HTTPリクエストとは、クライアント側からWebサーバーにリクエストする際送信するもの)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ActiveModelに対してエラーメッセージ日本語化 ja.yml書き方

投稿記事にタグ付けをするため、1つのフォーム送信で複数のモデルを更新できるというFormオブジェクトを使用しました。

app/models/posts_tag.rb
class PostsTag
  include ActiveModel::Model
  attr_accessor :title,:text,:answer,:user_id,:image, :name

  with_options presence: true do
    validates :title
    validates :text
    validates :name
  end

  def save
    post = Post.create(title: title,text: text,answer: answer,user_id: user_id,image: image)
    tag = Tag.where(name: name).first_or_initialize
    tag.save

    PostTagRelation.create(post_id: post.id, tag_id: tag.id)
  end
end

そして投稿時にエラーが発生した際に日本語でエラーメッセージが表示されるようにja.ymlを作成したのですが、英語から日本語に変換してくれませんでした。><
↓はダメだった書き方です。

config/locales/ja.yml
ja:
 activerecord:
   attributes:
     user:
       nickname: ニックネーム
     post:
       title: 投稿タイトル
       text: 投稿内容
       image: 画像
       name: タグ名

そこから下記のように修正したところ日本語に変換してくれました!

config/locales/ja.yml
ja:
 activerecord:
   attributes:
     user:
       nickname: ニックネーム
 activemodel:
  attributes:
   posts_tag:
       title: 投稿タイトル
       text: 投稿内容
       image: 画像
       name: タグ名

activerecordとactivemodelの違いも分かっていないプログラミング初学者ですが、
とても良い経験となりました。

おわり

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RubyをMacにインストールするときのエラー

はじめに

Rubyの勉強がしたいと思い、MacbookAirにRubyをインストールしようとしたときの試行錯誤の備忘録です。
Macには標準でRubyがインストールされているのですが、Rubyの参考書を進めていくうちに権限の問題で追加したいライブラリを追加できない。
自身の手でMacにRubyをインストールすれば、権限問題は解消するそうです。

rbenvのインストール

Rubyをインストールするまでの道のりはざっくり4段階あります。
1. Xcodeインストール
2. Homebrewインストール
3. rbenvインストール
4. Rubyインストール

1と2はなんとかできた。
しかし3でエラーが出始める。

Permission denied @ dir_s_mkdir - /private/tmp/homebrew...

brew install rbenvを実行するとエラー出現。
なにこれ?と思いコピーしてGoogle検索するとprivate/tmpフォルダの権限不足でrootユーザしか書き込みできない。ls -lコマンドで確認すると確かにそうなっている。
こちらのサイトによると
sudo chown -R 'username'/private/tmp/
で解決できるとのこと。Thank you.

Interrupted system call @ dir_initialize - /usr/local/Cellar/rbenv/1.1.2

つぎに出たエラー。グーグルで検索してもよくわからない。
とりあえずターミナルを再起動して再度brew install rbenvを実行するとエラーはなくrbenvのインストールに成功した。

BUILD FAILED

rbenv install 3.0.0を実行するとエラーが出る。
Installing ruby-3.0.0...
ruby-build: using readline from homebrew
BUILD FAILED (macOS 11.0.1 using ruby-build 20210309)
こちらのページによるとcurlとopensslが古いバージョンのため。らしいとのことなので対策する。
対策でやったこと。
・opensslとcurlがinstallされていなかったので再インストール
・opensslとcurlがanaconda3のPATHだったので.bash_profileからPATHを削除して/usr/bin/配下のopensslとcurlに通す。

インストール成功

rbenv install 3.0.0を再度実行するもまたしてもBUILD FAILEDが出る。

ならばRubyのバージョンを変えてみたらどうか、と思いrbenv install 2.7.2を実行するとなんと成功。

Windowsばかり使ってきていたので今回PATHやシェルの勉強を予期せずできてよかった。Rubyがんばるぞー。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】 dependent: :destroy とは

どんな機能なの?

結論から言うと、dependent: :destroyを使いことによって
親モデルのレコードを削除する際に、それに紐づく子モデルのレコードも同時に削除されます。

具体的な使い方

dependent: :destroyはモデルのアソシエーションで使います。
例えば下記のようにユーザーとマイクロポストのアソシエーションを定義します。

user.rb
has_many :mictroposts

これだけではユーザーが退会した時、そのユーザーのマイクロポストは残ってしまいます。
そのような場合に下記のようにdependent: :destroyを追加します。

user.rb
has_many :mictroposts, dependent: :destroy

こうすることでユーザー退会時には、そのユーザーのマイクロポストも同時に削除されます。

最後に

この機能は他に、いいね機能(いいねした投稿、された投稿が削除された場合、LikeModelのレコードも削除する。)やフォロー機能(フォローしたユーザー、されたユーザーが削除された場合、RelationshipModelのレコードも削除する。)など、アソシエーションをいじる場面でよく出てくるので必ず覚えておきたいですね!

また基本、応用関係なくなるほどと思ったことについて日記感覚で投稿していきます!
ありがとうございました!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RubyとRailsの個人的によく使うメソッドをまとめてみた

今回はタイトルにもある通り、個人的によく使うメソッドをまとめてみました。
初学者なので間違いがあれば指摘していただけると嬉しいです。

そもそもメソッドとは?

メソッド = 処理。

  • 自分で作るメソッド
  • Rubyがあらかじめ用意してくれているメソッド

のふたつがある。
今回はRubyがあらかじめ用意してくれている便利メソッドを紹介します。

putsメソッド

ターミナルに値を出力するメソッド。putsの後に値を記述することで出力できる。

puts "Helloworld"

=> Helloworld

getsメソッド

ターミナルに値の入力機能を起動するメソッド。入力された値は文字列としてプログラムに渡される。
また文字列として扱う際、getsで取得した値の後は、出力の際に改行され、gets.to_iで数値として扱う場合は改行されない。

name = gets
puts "こんにちわ、" + name + "さん!"

=> 好きな文字列を入力する(今回は太郎)

=> こんにちわ、太郎
  さん!

上記の通り、このままだと改行がされてしまうのでそんな時はchompメソッドを合わせて使うと良い。

chompメソッド

文字列の末尾に存在する改行を取り除くメソッド。

name = gets.chomp
puts "こんにちわ、" + name + "さん!"

=> 好きな文字列を入力する(今回も太郎)

=> こんにちは、太郎さん!

となって改行されるのを防いでくれる。

lengthメソッド(文字列)

文字列の文字数を数えるメソッド。その際、半角スペースも文字数として数えられる。

出力する際は数値として出力される。

a = "Helloworld".length

puts a

=> 10

ちなみにこんな感じで配列にくっつければ要素数を数えてくれる。

a = ["Hello","World"].length

puts a

=> 2

to_sメソッド

整数 → 文字列に変換するメソッド。
通常、整数(Integer)型と文字列(String)型による足し算はできないが、こうして型を換えることで可能になる。

puts 20.to_s + "歳"

=> 20歳

ただ、下記のように文字列に対して掛け算をすることは整数(Integer)型に変換しなくても可能。

puts "歳" * 10

=> 歳歳歳歳歳歳歳歳歳歳歳

to_iメソッド

文字列(String) → 整数(Integer)に変換するメソッド。

a = "10".to_i

puts 20 + a

=> 30 

ちなみに文字列をto_iで変換し、整数型と四則演算すると、全て0として変換されるらしい。
冷静に考えたら当たり前なのだが、最近まで知らなかった。

理想↓↓

a = "歳".to_i

puts 20 + a

=> 20歳

現実↓↓

a = "歳".to_i

puts 20 + a

=> 20

getsメソッドと合わせて使うと応用が効いて便利。
ちなみにgetsのsはstring(文字列)型のsらしいです。
(複数形だと思ってたなんて口が裂けても言えない....)

input = gets.to_i

puts 100 + input

=> 好きな数値を入力(今回は100を入力する)
   200

その他類似の変換系メソッド

個人的にはまだ活用できていないが、使い方を理解できると便利であろう変換系のメソッド。

メソッド   効果
to_f Floatクラス(浮動小数点数)に変換
to_sym シンボルに変換
to_h ハッシュオブジェクトに変換
to_a 配列オブジェクトに変換

requireメソッド

外部ファイルを読み込むためのメソッド。require "外部ファイル名"で読み込める。
ただしカレントディレクトリから読み込む場合はrequire "./外部ファイル名"で読み込む。

日付や時間を取得する際に便利なメソッド

Dateクラス

Rubyの標準ライブラリの機能で日付を扱うためのクラスのこと。
require "date"という一文をコード内に記述することで使用できる。

todayメソッド

本日の日付を取得するメソッド。
例)Date.today 今日の日付を取得する

wdayメソッド

0~6の数値で曜日を取得するメソッド。
0:日曜日、1:月曜日、2:火曜日、3:水曜日、4:木曜日、5:金曜日、6:土曜日を表す。

例)Date.today.wday 今日の曜日を数値で取得する

strftimeメソッド

日時データを指定したフォーマットで文字列に変換するメソッド。

例)message.created_at.strftime("%Y年%m月%d日 %H時%M分") 保存された日時を文字列で取得する

eachメソッド

配列や範囲オブジェクトなどで用意されているメソッドであり、オブジェクトに含まれている要素を順に取り出し、変数に格納します。

オブジェクト.each do |変数|
  実行する処理1
  実行する処理2
end

↓↓↓↓

@posts = Post.all だとここでは認識しておいてください。

 <% @posts.each do |post| %>
   タイトル:<% post.title %>
   投稿者:<% post.user %>
   投稿内容:<% post.product %>
<% end %>

each_with_indexメソッド

each(要素の繰り返し処理)と同時に、その要素が何番目に処理されたかを表すメソッド。デフォルトだと処理番号は0から割り当てられる。
僕はランキング機能を作成するさいに用いました。

オブジェクト.each.with_index do |変数1,変数2|
  実行する処理1
  実行する処理2
end

↓↓↓↓

 <% @posts.each.with_index(1) do |post, i| %>
   第<%= i %>位
   <% post.title %>
<% end %>

@postsの中身と指定した数字(1)が |post, i|にそれぞれ格納され、「第◯位」と「投稿のタイトル」に割り振られる。

include?メソッド

指定した要素が配列や文字列内に含まれているかを判定するメソッド。

number = [100, 200, 300 , 400 , 500]

puts number.include?(200)

=> true

splitメソッド

指定した区切り文字で対象となる文字列を分割して配列にする。

fruit = "apple,strawberry,grape,banana"

puts fruit.split(',')

=> ["apple", "strawberry", "grape", "banana"]

sliceメソッド

配列や文字列から指定した要素を取り出すことができるメソッド。
文字列の要素を指定する際は数字を用い、先頭の文字列は0から指定する。また第二引数として、取り出す要素の数も指定したい場合は指定することもできる。

number = [100, 200, 300 , 400 , 500]

puts number.slice(3,2)

=> [400 , 500]

エクスクラメーションマーク(!)

末尾につけることにより破壊的メソッドになり、もとの配列や文字列を変化させるメソッド。

scanメソッド

対象の要素から引数で指定した文字列を数え、配列として返すメソッド。

puts "ワン!ワンッ!ワンワンッ!".scan("ワ")

=> [ワ, ワ, ワ, ワ]

lengthと組み合わせると含まれている"ワ"の数で返ってくる。

puts "ワン!ワンッ!ワンワン!".scan("ワ").length

=> 4

ただ、下記にcountというメソッドもあるのでそっちの方が使いやすい。

countメソッド

特定の文字列の中に指定した文字列がいくつ含まれているかを数えたり、配列の要素数を数えるメソッド。

puts "ワン!ワンッ!ワンワン!".count("ワ")

=> 4

firstメソッド

配列から最初の要素を取得するメソッド。
引数がある場合は配列の最初の要素からその引数分の要素を配列で取得する

name = ["太朗", "花子", "二郎"]

puts name.first(2)

=> ["太朗", "花子"]

lastメソッド

配列から最後の要素を取得するメソッド。
引数がある場合は配列の最後の要素からその引数分の要素を配列で取得する

name = ["太朗", "花子", "二郎"]

puts name.last(2)

=> ["花子", "二郎"]

sortメソッド

配列の要素を一定の規則(アルファベット、数値の降順、昇順など)で並び替えるメソッド。

fruit = ["apple", "strawberry", "grape", "banana"]

puts fruit.sort

=>  ["apple", "banana", "grape", "strawberry"]

joinメソッド

配列内の要素と要素を連結させるメソッド。
引数を渡すことで区切ることもできる。

fruit = ["apple", "strawberry", "grape", "banana"]

puts fruit.join(",")

=>  apple,strawberry,grape,banana

pushメソッド

配列の末尾に要素を連結する

fruit = ["apple", "strawberry", "grape", "banana"]

puts fruit.push("orange")

=> ["apple", "strawberry", "grape", "banana","orange"]

unshiftメソッド

配列の先頭に要素を追加する。

fruit = ["apple", "strawberry", "grape", "banana"]

puts fruit.unshift("orange")

=> ["orange", "apple", "strawberry", "grape", "banana"]

shiftメソッド

配列の先頭の要素を削除する。または配列の先頭の要素を取り出す。

fruit = ["apple", "strawberry", "grape", "banana"]

puts fruit.shift

=> ["Apple"]

pluckメソッド

引数に指定したカラムの配列を返す(Railsのメソッド)

#Fruitモデルのnameカラムに "Apple" "grape" "banana" が入っている場合
=> Fruit.pluck(:name)
=> ["Apple","grape","banana"]

最後に

まだまだ足りないメソッドだらけで、適切に使えているかどうかも定かではありませんが、使える技が増えればそれだけ自分の中のアイデアを形にすることができると思います。
また、思い付いたらこれから追加していく予定です。
誰かの手助けになれればいいなと思います。
間違いや指摘があればコメントに残していただけると幸いです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

/dev/loopに容量が圧迫されてrails testができない問題...

cloud9のterminalでrails testを実行しようとしたら何と12ものエラーが...

備忘録として、またその他どなたかのお役に立てればと思い、記事を書いていきます。

キャプチャを失念しており、ほとんど文章での説明になりわかりにくいかと思いますが、ご容赦のほどお願いいたします。
では、書いていきます!

【1.状況】
AWSでrails testの実行時に12ものエラーが発生し、以下のメッセージが登場。
⇒ Error:「No spacd left on device」
 
【2.状況分析】
→ 上記1.について色々調べていくと、どうにも容量不足のようです。

  容量不足とは、主に以下2つのいずれかを指します。
  ① ディスク容量の不足
  ② 「inode」の容量不足

  ここで、「inode」とは要するに、ファイル情報(誰が、いつetc...などのプロパティ的な
  情報)を管理するためのデータであるとのこと。

   従って、この2つの内、どちらが原因であるのかを見極めることが必要です。
  
  それぞれ、以下に示すコマンドをterminalで実行すれば、容量が確認できます。
 
  ・ ①の場合 
    2-1) $ df 
  
  ・ ②の場合
    2-2) $ df -i
  
  その結果、私の場合、②のパターンであることが分かりました。

   内容を見ていくと、以下5つのディレクトリが使用率100%と判明。。。
    ・/dev/xvda1
   ・/dev/loop1
   ・/dev/loop2
   ・/dev/loop3
   ・/dev/loop4

  と分かれば、これらディレクトリを消去すればよいことになります。

【3.対策】
 
  ターミナルで以下コマンドを実行すれば、ディレクトリを消去できます。

  $ sudo rm -d ディレクトリ名
  
  今回の場合、/dev以下の階層を消去すれば良いので、
  3-1) $ sudo rm -d /dev
   を実行。 ※ rmはremove、dは(おそらく)ディレクトリの略

  これで、完了…と思いきや/devに格納されている全部のファイルに
  以下のエラー発生。
   Error:Operation not Permitted

  この事象について調べていくと、どうにも上記2.の/devディレクトリに
  ファイルを実行する権限が与えられていないことが原因であるとのこと。

  そこで、/devディレクトリにファイルの実行権限を与える操作を行います。

  そのためのコマンドを以下示します。
  $ sudo chmod モード ファイル名(ディレクトリ名)

  ここでいう、モードとは3桁の数字abcであるとのこと。

   a:「所有者」の権限
   b:「所有グループ」の権限
   c:「その他」

   ここで、abcの各桁には以下数字の合計値が入ります。
  
  モード(数字)   モード(アルファベット)    権限
    4           r          読み取り
    2           w          書き込み
    1           x           実行

  つまり、実行だけが必要なら1、読み取りと実行が必要なら4+1=5、
  何も必要なければ、0が入ります。

  今回は、「所有者」と「その他」に全機能を付与したかったので、707としました。

  従って、以下3-2)のコマンドをターミナルで実行しました。
  3-2) $ sudo chmod 707 /dev

  そして、再び3-1)を実行した後に2-1)を実行し、
  フォルダ内を確認します。

  以下の画像のように/devが消去され、容量が開放されたと思われます。
  スクリーンショット 2021-03-21 16.54.39.png

  確認のため、rails testを実行します。
  スクリーンショット 2021-03-21 16.54.50.png

  エラーがなくなり、晴れて問題が解消されました。

以上となります、イメージがつきにくかったかもしれませんが、ご参考になりますと幸いです。
それでは、また!

参照先
https://qiita.com/shisama/items/5f4c4fa768642aad9e06
https://mem-archive.com/2019/07/28/post-1976/
https://itojisan.xyz/trouble/15772/#2_inode
https://www.souichi.club/aws/out-of-disk-space/
  

 
  

   

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】古いデータベースが影響してエラーが出た話

概要

以前作成したRailsアプリを削除して、再び同じ名前で同様のアプリ作成しました。
そしてrails db:migrate実行後、ActiveRecord::PendingMigrationErrorが発生した。

結論から言うと、過去アプリのデータベースが残っており
作成したアプリ上のdb/migrateディレクトリ内のファイルをコマンドdb:migrateにて反映させようとした際、ファイルのバージョンが異なるためエラーが発生しました。
2021-03-17 13.20.47.png

開発環境

・データベース:PostgreSQL
・railsのバージョン:6.1.3
・PC:macbook pro

エラー発生から解決までの流れ

  1. 元々あったrailsアプリを削除する。(rails db:create,rails db migrate実行済み)
  2. 元々あったrailsアプリと同じ名前のrailsアプリを再び作成する。(rails db:create実行済み)
  3. rails db:migrateを実行後、rails sにてサーバを立ち上げてブラウザを見ると、ActiveRecord::PendingMigrationErrorが発生する。
  4. rails db:versionを実行すると、terminal上のファイルとアプリmigrationファイル(db/migrate)のバージョンが異なる。
  5. rails db:resetを実行してrails db:migrateを行うと、問題なくアプリケーションを実行できる。
    また、rails db:versionにてファイルを確認すると、terminal上とrailsアプリのmigrationファイルが一致していることが確認できた。
  6. rails db:migrateを行ってアプリを起動してみると、問題なく動作した。 スクリーンショット 2021-03-17 12.22.31.png

エラーが発生した原因

原因は私の理解不足によるもので、アプリファイルを削除すると一緒にデータベースも消すことができると思っていたためです。
(アプリファイルとデータベースは、同一の場所にあると思っていた)
実際は、下記ディレクトリにデータベースが保存されています。
また、データベース削除とversion確認コマンドは、下記になります。

PostgreSQL:… /usr/local/var/postgres 内
MySQL:… /usr/local/var/mysql 内

データベース削除:rails db:reset (データベース内の情報は消えるので注意!)
データベースversion確認:rails db:version

最後に

正直なところ、データベースについてまだまだわかっていない点がたくさんあります。
もし間違っている点等がある場合、ご指摘頂けると大変ありがたいです。
最後まで読んで頂きありがとうございました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

投稿機能 統合テストの実装

今回ポートフォリオ作成中にでたエラーの解決策を備忘録も含め、同じところでつまづかれている方などいましたら、ご参考にして頂けましたら幸いです。

投稿機能では画像つきの機能を取り入れてまして、
でたエラーに関してが、

Capybara::ElementNotFound: Unable to find field "post[images][]" that is not disabled
from /Users/takuya/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/capybara-3.35.3/lib/capybara/node/finders.rb:303:in `block in synced_resolve'

上記のエラーでした。

アウトプットの前に、
rspec
factory.bot
上記は導入済みで、進めさせていただきます。

ちなみにかなり時間を取られました?

投稿機能統合テスト記述

RSpec.describe '写真テキスト投稿', type: :system do
  before do
    @user = FactoryBot.create(:user)
    @post_name = Faker::Lorem.sentence
  end
  context '写真テキスト投稿ができるとき'do
    it 'ログインしたユーザーは新規投稿できる' do
      # トップページに移動する
      visit root_path
      # トップページにログインページへ遷移するボタンがあることを確認する
      expect(page).to have_content('LOGIN')
      # ログインページへ遷移する
      visit new_user_session_path
      # 正しいユーザー情報を入力する
      fill_in 'Eメール', with: @user.email
      fill_in 'パスワード', with: @user.password
      # ログインボタンを押す
      find('input[name="commit"]').click
      # トップページへ遷移することを確認する
      expect(current_path).to eq(root_path)
      # 写真投稿一覧ページに移動する
      visit posts_path
      # 新規投稿ページへのリンクがあることを確認する
      expect(page).to have_content('PUSH 投稿')
      # 投稿ページに移動する
      visit new_post_path
      # フォームに情報を入力する
      fill_in 'post[images][]', with: "public/images/test_image.jpg"
      fill_in 'post[name]', with: @post_name
      # 送信するとPostモデルのカウントが1上がることを確認する
      expect{
        find('input[name="commit"]').click
      }.to change { Post.count }.by(1)
      # 写真投稿一覧ページに移動する
      visit posts_path
      # 写真投稿一覧ページには先ほど投稿した内容の写真テキストが存在することを確認する(画像)
      expect(page).to have_selector("img[src$='test_image.png']")
      # 写真投稿一覧ぺージには先ほど投稿した内容の写真テキストが存在することを確認する(テキスト)
      expect(page).to have_content(@post_name)
    end
  end
  context '写真投稿ができないとき'do
    it 'ログインしていないと新規投稿ページに遷移できない' do
      # 写真投稿一覧ページに移動する
      visit posts_path
      # 新規投稿ページへのリンクがない
      expect(page).to have_no_content('nPUSH 投稿')
    end
  end
end

fill_in 'post[images][]', with: "public/images/test_image.jpg"
の上にbinding.pryを入れて、上記コードを入力すると画像が挿入できない状態でした。

要素中にinputタグのname要素を入れ込んでいるのになぜエラーが出るのかと四苦八苦していました。

一度頭を整理して、fill_in意外にも画像挿入する方法はないかと調べたところ、

attach_file

というメソットが引っかかりました。

そこでfill_inを削除してattach_fileメソットの記述を行いました。

変更前

# フォームに情報を入力する
      fill_in 'post[images][]', with: "public/images/test_image.jpg"
      fill_in 'post[name]', with: @post_name

変更後

# フォームに情報を入力する
      attach_file('post[images][]', image_path, make_visible: true)
      fill_in 'post[name]', with: @post_name

上記を記述変更を行い、今すぐにでも実装を行いたかったのですが、焦ってはいけませんでした

変更後の記述の中にimage_pathを代入していることから、
フォームに情報を入力する
の統合テストを行う前に、添付する画像を定義する記述を行いました。
そうしないとなんの画像を指定しているのかわからないためです

そして、

# 添付する画像を定義する
      image_path = Rails.root.join('public/test_image.png')
      # フォームに情報を入力する
      attach_file('post[images][]', image_path, make_visible: true)
      fill_in 'post[name]', with: @post_name

フォーム情報を入力するの前に、画像を定義する記述を行い、無事テストが行える状況になりました。

実装を行うと、問題なく統合テストを行うことができました

完成コード

RSpec.describe '写真テキスト投稿', type: :system do
  before do
    @user = FactoryBot.create(:user)
    @post_name = Faker::Lorem.sentence
  end
  context '写真テキスト投稿ができるとき'do
    it 'ログインしたユーザーは新規投稿できる' do
      # トップページに移動する
      visit root_path
      # トップページにログインページへ遷移するボタンがあることを確認する
      expect(page).to have_content('LOGIN')
      # ログインページへ遷移する
      visit new_user_session_path
      # 正しいユーザー情報を入力する
      fill_in 'Eメール', with: @user.email
      fill_in 'パスワード', with: @user.password
      # ログインボタンを押す
      find('input[name="commit"]').click
      # トップページへ遷移することを確認する
      expect(current_path).to eq(root_path)
      # 写真投稿一覧ページに移動する
      visit posts_path
      # 新規投稿ページへのリンクがあることを確認する
      expect(page).to have_content('PUSH 投稿')
      # 投稿ページに移動する
      visit new_post_path
      # 添付する画像を定義する
      image_path = Rails.root.join('public/test_image.png')
      # フォームに情報を入力する
      attach_file('post[images][]', image_path, make_visible: true)
      fill_in 'post[name]', with: @post_name
      # 送信するとPostモデルのカウントが1上がることを確認する
      expect{
        find('input[name="commit"]').click
      }.to change { Post.count }.by(1)
      # 写真投稿一覧ページに移動する
      visit posts_path
      # 写真投稿一覧ページには先ほど投稿した内容の写真テキストが存在することを確認する(画像)
      expect(page).to have_selector("img[src$='test_image.png']")
      # 写真投稿一覧ぺージには先ほど投稿した内容の写真テキストが存在することを確認する(テキスト)
      expect(page).to have_content(@post_name)
    end
  end
  context '写真投稿ができないとき'do
    it 'ログインしていないと新規投稿ページに遷移できない' do
      # 写真投稿一覧ページに移動する
      visit posts_path
      # 新規投稿ページへのリンクがない
      expect(page).to have_no_content('nPUSH 投稿')
    end
  end
end

画像挿入するだけのことでしたがかなり時間を使ってしまいました。

冷静に頭を整理して、根本のところから他に定義するメソットはないのという発想で成功することができました。

もし似たような内容で詰まっている方などいましたら、ご参考にして頂けましたら幸いです。

宜しくお願いします!!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

リンク先のを別タブで表示させる方法

はじめに

外部リンクを貼り付ける際
リンクから飛ぶと戻るのがめんどくさい!
他のサイトを見ると、別タブに表示してくれる
そっちの方が都合が良いと言うことで、
今回はそのことに付いて書いて行きます?

参考サイト

実装

target: :_blankと言うのをaタグなりlink_toに記載します

<%= link_to "SNS", "#",target: :_blank ,class: "burger-nav-link" %>

こちらでも別タブで表示してはくれます。
ですが、いくつかサイトを見ると 悪用 フィッシング詐欺などと
強めのワードが目につきます。

そこでrel: "noopener noreferrer"
をつけると大丈夫みたいで。

<%= link_to "SNS", "#",target: :_blank, rel: "noopener noreferrer",class: "burger-nav-link" %>   

これで対策できました! 笑

終わりに

些細なことでも疑問に思った点
解決した点など更新して行きます?

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

rails urlパス変更

コントローラー名とは違う命名でルーティングを指定したい!
そんなことが起きた時に使えるコマンドを紹介します。

resourcesとネスト

Railsのルーティング記法の基本は、複数形のresourcesメソッドと単数形のresourceメソッドです。また、Railsのルーティングにはネストを含む多くのオプションがあり、自由度が飛躍的に高まっています。

始めに

スクリーンショット 2021-03-21 15.00.37.png

resources :notifications, only: [:show]

notificationコントローラーのshowアクションにと、ごく普通の記述です。

/notifications/:idの部分を違う名前に変更したいと思い。

pathオプションを使用する。

resources :notifications, only: [:show], :path => "articles" 

スクリーンショット 2021-03-21 15.06.23.png

おわりに

些細なことでも疑問に思った点
解決した点など更新して行きます?

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

実はJrubyはgradleだけで管理できる

はじめに

Jruby覚えてますか?JRubyはまだ現役です。こういう言語を扱うと必ずと言っていいほど、「javaでいいじゃん」と言われます。確かにJRubyでできることはJVMでできることです。
現状ではRubyが好きな人がたまに使うといった感覚でしょうか。

ですが、私はJrubyでJava開発のテストを書いてます。理由は生産性が高いからです。

この記事では普段Java使いのみなさんがJrubyで楽できるtipsを紹介します。

依存環境

ですが、全て意識なくていいです。管理はすべてgradleで行います。ここでは一旦、jrubyのコマンドも忘れてしまいましょう。

初期プロジェクトを立ち上げる

必要なのは2つのファイルだけです。

terminal
mkdir sample
cd sample
nvim build.gradle #neovimはいいぞ
nvim main.rb
build.gradle
/*
 * This is sample programs under the jruby.
 *@ak.f
 */

buildscript {
  repositories {
    jcenter()
  }
  dependencies {
    classpath 'com.github.jruby-gradle:jruby-gradle-plugin:2.0.0'
    classpath 'com.github.jruby-gradle:jruby-gradle-jar-plugin:2.0.0'
    classpath 'com.github.jengelman.gradle.plugins:shadow:5.0.0'
  }
}

apply plugin: 'com.github.jruby-gradle.jar'

repositories {
  jcenter()
  ruby.gems()
}

dependencies {
  jrubyJar  'org.slf4j:slf4j-simple:1.7.12'
  jrubyJar "rubygems:colorize:0.7.7+"
}

jrubyJar {
  initScript "./main.rb"
}

task jrubyRun(type: Exec){
  dependsOn jrubyJar
  workingDir "./build/libs"
  commandLine 'java', '-jar', jrubyJar.outputs.files.singleFile.absolutePath
}

main.rb
require 'colorize'

java_import 'org.slf4j.Logger'
java_import 'org.slf4j.LoggerFactory'

logger = LoggerFactory.getLogger('demo')

puts "-" * 20
logger.info "Ruby version: #{RUBY_VERSION}"
logger.info "Ruby platform: #{RUBY_PLATFORM}"
logger.info "Current file: #{__FILE__}"
puts "-" * 20

puts "Roses are red".red
puts "Violets are blue".blue
puts "I can use JRuby/Gradle".green
puts "And now you can too!".yellow

以上がサンプルプロジェクトになります。
自分の管理するJavaライブラリを呼び出す場合は、

repositories {
jcenter()
ruby.gems()
maven {url 'mavenリポジトリのURL'}}
dependencies {
jrubyJar 'xxx.org:name:version'
}

として参照してやればgradleが全部やってくれます。

コマンドチートシート

  • とりあえず実行する gradle jrubyRun
  • jarファイルにビルドする gradle jrubyJar
  • ビルドファイルを削除する gradle clean
  • ビルドしたものを実行する java -jar build/libs/sample-jruby.jar

最後に

今どきのJRubyでした。
最近は日本語に記事であまり話題に上がらないですが、実務ではjavaライブラリのテストケースや、使い捨てのメインクラスを作成するぐらいなら私はJrubyで書くようになりました。
gradleで管理できるのが最高です。

ほとんど、http://jruby-gradle.org/ で紹介されているとおりですが、
build.gradleにはjrubyRunのタスクを定義してあります。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

attr_accessor

①エラーが起きるパターン

user.rb

class User
def initialize(name, age)
@name = name
@age = age
end
end

tanaka = User.new('田中太郎', 18)
tanaka.name

=> undefined method `name' for # (NoMethodError)

tanaka.age = 33

=> undefined method `age=' for # (NoMethodError)

②attr_accessorメソッド を使ったパターン

user.rb

class User
# 以下の記述でクラス外部から@name,@ageにアクセスが可能になる
attr_accessor :name, :age

def initialize(name, age)
@name = name
@age = age
end
end

tanaka = User.new('田中太郎', 18)
p tanaka.age #=> 18

tanaka.age = 33
p tanaka.age # => 33

このように、attr_accessorメソッドはインスタンス変数にアクセスするためのメソッドを裏側で定義してくれる。attr_accessorメソッドに指定されたインスタンス変数は、クラス外部から参照と変更の両方を行う事が出来るようになる。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

inquiry

TL;DR

文字列等価のチェックで'hoge' == 'hoge'という書き方以外の方法があります。
Rails AcctiveSupportにはStringオブジェクトの拡張でinquiryというメソッドが定義されています。

word = 'hoge'.inquiry
word       # => 'hoge'
word.hoge? # => true
word.fuga? # => false

どう定義されてる?

active_support/core_ext/string/inquiry.rb で定義されてます。

lib/active_support/core_ext/string/inquiry.rb
require "active_support/string_inquirer"

class String
  def inquiry
    ActiveSupport::StringInquirer.new(self)
  end
end

ではActiveSupport::StringInquirerは何者?

次で定義されてます。

lib/active_support/string_inquirer.rb
module ActiveSupport
  class StringInquirer < String
    ...
    def method_missing(method_name, *arguments)
      if method_name.end_with?("?")
        self == method_name[0..-2]
      else
        super
      end
    end

    def respond_to_missing?(method_name, include_private = false)
      method_name.end_with?("?") || super
    end
  end
end

method_missingの部分がinquiryメソッドの核になってます。
メソッド名の最後に?がついている場合、そのメソッド名の?を除いた部分がインスタンス名と一致するかの真偽値を返します。

ちなみに...

method_missingは呼び出したメソッドが定義されていなかった時に呼び出されるRuby組み込みのメソッドです。一つ目の引数に呼び出しに失敗したメソッド名、その引数が第二引数に渡されます。
つまりこんな感じ

class String
  def method_missing(method_name, *args)
    puts "method named #{method_name} is not defined!"
  end
end

'hoge'.fuga # => method named fuga is not defined!

またrespond_to_missing?も同じくRuby組み込みのメソッドです。method_missingを呼び出すに該当するメソッドがrespond_to?で呼び出された際に応答します。

class String
  def method_missing(method_name, *args)
    puts "method named #{method_name} is not defined!"
  end

  def respond_to_missing?(method_name, include_private)
    method_name.end_with?("?") || super
  end
end

'hoge'.respond_to?(:fuga?) # => true 
'hoge'.respond_to?(:piyo) # => false

終わり

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

scope使い方(Rails)

modelの中にscopeを書く

複数使う場合はスコープで書いた方がコードが読みやすくなりますし、
単体テスト書くことが可能になるため積極的に使った方がいいです。

item.rb
 scope :published, -> { where(private: true) }
users_controller.rb
 def show
    if !@user.me?(current_user)
      @items = @user.items.published
    else
      @items = @user.items
    end
  end

モデルで{ where(private: true) }定義することで
コントローラの記述が少なくなります。

おまけ

user.rb
def me?(user_id)
  id == user_id
end

current_user@userが一致しているか
モデルに書くことで可能になります。

users_controll.rb
if !@user.me?(current_user)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

画像がアップデートされない。。

refile(Gem)を使って画像投稿をしていて、
マイページでプロフィール画像の編集できるようにしたが、
なぜか画像が更新されない。

editアクション、updateアクションもやっている。

def edit
    @user = User.find(params[:id])
end

def update
  @user = User.find(params[:id])
  @user.update(user_params)
  redirect_to user_path(@user.id)
end

viewもこんな感じ

<%= attachment_image_tag @user, :profile_image, :fill, 60, 60, class: "img-circle pull-left profile-thumb", fallback: "no_image.jpg"%>

環境

・docker
・Rails

試したこと

・ブラウザにキャッシュされているのかな?と思いキャッシュを削除。
・fillの部分をsizeに変更してみましたが出来ない。

解決

docker-compose runをしてみたら、なぜか出来た。

⇨新しいコンテナが作られたからかな?
⇨最初、docker-copose up -d で放置していて、それから新しいコンテナを作っていなかったから?
⇨まだ頭のモヤモヤが。。。

とりあえず、解決したので、進みます。もやもやがありますが、、、

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

アソシエーションしてbuildするときの1対多と1対1の記述の仕方の違いについて

buildの使い方

アソシエーションによって記述の仕方に違いがあるが、まとっているサイトがなかったので書きました。

1対多

# User.rb
class User < ApplicationRecord
  has_many :posts
end

# Post.rb
class Post < ApplicationRecord
  belongs_to :user
end

# Posts_controller.rb
def new
  @post = @user.posts.build
end

1対1

# User.rb
class User < ApplicationRecord
  has_one :account
end

# Account.rb
class Account 
  belongs_to :user
end

# Accounts_controller.rb
def new
  @account = @user.build_account
end

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】deviseでのユーザ名ログイン機能の実装

目標

deviseのユーザー登録/ログイン方法は、デフォルトでメールアドレスとパスワード。
これをユーザ名で登録/ログインできるように変更する。

準備

  1. deviseをインストール
    Gemfileにgem 'devise'追記 + $ bundle install

  2. 初期設定
    rails g devise:install

  3. モデル作成 *モデル名は任意(今回はUser)
    rails g devise User

  4. View作成
    rails g devise:views users

実装

ユーザ登録(Sign Up)

  1. ユーザ名カラムを追加 + rails db:migrate
  2. ユーザ登録画面にユーザ名入力フォームを追加(views/devise/registrations/new.html.erb)
  3. ストロングパラメータを設定し、ユーザ名データの操作を許可
application_controller.rb
  before_action :configure_permitted_parameters, if: :devise_controller?
    # deviseの機能が使われる前に、configure_permitted_parametersを実行

  protected
  def configure_permitted_parameter
    devise_parameter_sanitizer.permit(:sign_up, keys: [:name]) # sign_up時にユーザ名の操作を許可
  end

ログイン(Sign In)

  1. ログイン画面にフォームを追加(views/devise/sessions/new.html.erb)
  2. 認証キーをemail→nameに変更 *コメントアウトは外す
config/initializers/devise.rb
config.authentication_keys = [:name]
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む