20190710のRailsに関する記事は26件です。

RSpecの導入

ユーザー認証の単体テスト

ユーザーモデルクラスが単体で正常に動作するかテストを行う

RSpecを導入する

Gemfileに gem 'rspec-rails' を追記する

Gemfile
group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug', platform: :mri

  gem 'capistrano'
  gem 'capistrano-rbenv'
  gem 'capistrano-bundler'
  gem 'capistrano-rails'
  gem 'capistrano3-unicorn'
  gem 'rspec-rails'

end

追記したらbundle intallを行う

RSpec用の設定ファイルを作成する

$ rails g rspec:install

ターミナルで実行すると、以下のようにファイルが作成される

   create  .rspec
   create  spec
   create  spec/spec_helper.rb
   create  spec/rails_helper.rb

.rspecに追記する

.rspec
--format documentation

これで設定ファイルの準備は完了♩

RSpecが正常に利用できるかの確認

$ bundle exec rspec

ターミナルで上記を実行して、次の通り表示されれば利用できます。

No examples found.


Finished in 0.00058 seconds (files took 0.20912 seconds to load)
0 examples, 0 failures
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

今日学んだ事

7/10(水)

●groupメソッド

・テーブルのレコードを指定したカラムでまとめた状態で取得する。

コード

モデル.group(カラム名)

・idが一番小さいコードの1件が表示されるが、裏側ではまとめられた状態で取得されている。
・具体的に何個まとまっているか個数は分からない。

●countメソッド

・配列などの要素数を返すメソッド。
・groupメソッドに続けて使うと、まとめられたそれぞれのレコードの数が取得できる。
コード

モデル.group(カラム名).count

・返り値はハッシュとなる

●keysメソッド

・ハッシュはkeysメソッドを持っている
・ハッシュのキーだけを取り出し、配列として返すメソッド

●mapメソッド

・配列の中身を1つずつ取り出してブロックという構文を繰り返し実行する。
・ブロックの返り値を集めた新しい配列を作成する。
コード

配列オブジェクト.map{|ele| ブロックの処理}

●order('count_カラム名').count(カラム名)

・指定したカラムをグルーピングし、それぞれのレコード数でソートできる

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

【Rails】ユーザ作成

Railsのユーザ作成について

Railsでログイン機能を実装する場合に、ユーザ作成を行うと思います。
今回は、その、ユーザ作成機能について説明していきます。

使用するコントローラ

toppagesコントローラ(サインアップページへ移行するurlがある)
-index

usersコントローラ
-index,show,new,create

の二つです。toppages,usersのように、語尾に「s」を付けているのは、あとあと便利になってくるからです。

使用するモデル

Userモデル
-name:string email:string password_digest:string

ユーザ名、メールアドレス、パスワードを入力とします。

Gemファイルに

gem 'bcrypt', '~>   '

のような記述がありますが、railsに提供されている認証機能です。
この行のコメントアウトを消し、

$ bundle install

を実行し、railsのサーバを再起動させましょう。

また、railsで「bcrypt」を使用する際は、モデル作成時に、

password_digest:string

の記述が必須となります。この記述が無ければ認証ができなくなるので注意しましょう。

コントローラ

topppagesコントローラは、ページの表示だけなので、usersコントローラのみを記述します。

users.rb
class UsersController < ApplicationController
  def index
    @users = User.all.page(params[:page])
  end

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

  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    if @user.save
      flash[:success] = 'ユーザを登録しました。'
      redirect_to @user
    else
      flash.now[:danger] = 'ユーザの登録に失敗しました'
      render :new
    end

  end

  private

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

特筆すべきなのはcreateアクションのuser_paramsのところです。
ストロングパラメータの、password_confirmationは、確認用のパスワードのことです。
password_confirmationが記述されることで、パスワードの確認をプログラムがいい感じにやってのけてくれます。

モデル

ユーザモデルに、has_secure_passwordと記述することでbcryptの認証機能を呼び出すことが出来ます。

user.rb
class User < ApplicationRecord
    has_secure_password
end

ユーザ作成画面

CSSも適用してない最低限の画面です。

new.html.erb
<h1>Sign up</h1>
<p>
<%= form_for(@user) do |f| %>
<p>
<div class="form-group">
    <%= f.label :name, 'Name' %>
    <%= f.text_field :name, class: 'form-control' %>
</div>
<div class="form-group">
    <%= f.label :email, 'Email' %>
    <%= f.email_field :email, class: 'form-control' %>
</div>
<div class="form-group">
    <%= f.label :password, 'Password' %>
    <%= f.password_field :password, class: 'form-control' %>
</div>
<div class="form-group">
    <%= f.label :password_confirmation, 'Confirmation' %>
    <%= f.password_field :password_confirmation, class: 'form-control' %>
</div>
<P>
<%= f.submit 'Sign up', class: 'btn btn-primary btn-block' %>

<% end %>
show.html.erb
<h3 class="panel-title"><%= @user.name %></h3>

これでユーザ作成に必要な主要な部分は完成しました!

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

RailsのログからRubyGemsによるwarningを非表示にする方法

現象

Ruby v2.6とRails5.1系でRubyがRails側のGemに対してものすごい数のwarningを出すようになりました。
具体的には、ActiveRecordの内部で BigDecimal.new を呼んでいるようで、それに対してwarningが出ています。

こんな感じのエラーが出る
.../vendor/bundle/ruby/2.6.0/gems/activerecord-5.1.7/lib/active_record/connection_adapters/mysql/database_statements.rb:32: warning: BigDecimal.new is deprecated; use BigDecimal() method instead.

Ruby v2.6では明示的にwarningを出すようになったからだそうです。
ref: Ruby 2.6 の変更点 - Numeric, BigDecimal BigDecmial.new が非推奨

対処法

対処法としてはJeremy Evans氏作のruby-warning gemを使うと良さげです。
具体的には下記のような処理をconfig/initializers配下に置いておくと、Railsが起動される前に読み込まれて、Gemに起因するwarningがログに出なくなります。

*開発環境ではログに出るようにしておくと、「あ、このGemアップデートしなきゃ」などが分かっていいかなと思います。

initializer配下にこんな感じのを置いておく
unless Rails.env.development?
  Gem.path.each do |path|
    Warning.ignore(//, path)
  end
end

他にもっとスマートな方法をご存知の方がいらっしゃいましたら、ご指摘お願いします。 :pray:

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

ほとんどアクセスのない個人開発サービスがAWSに月額いくら払っているか全て公開します

はじめに

「AWSって結局いくらかかるの?」
これが結構見積もりが難しい問題で、ざっくりAWSのようにざっくり見積もれるサービスが登場したのはその見積もりの難しさから来ていると思う。

個人的に開発しているwebサービスをAWSで公開してからしばらくたって、月の料金が安定しているので、ここで公開してみる。

しょっぼいwebサービスを公開したいけど、AWSだといくら掛かるのかなー?という方に向けて書いているので、「herokuなら無料だぜ!もしくは7ドルだぜ!」とかいう話ではないです。

サービス概要

公開したサービスはこちら。
https://uwaoe.net

html5のcanvas機能を利用してブラウザ上でお絵かきすることができて、他の人が描いた絵にうわがき(というか落書き)することができる。
サーバはRuby on Rails、フロントはVue.jsで作った。

利用ユーザは2人。
たった2人!!
これはストレージ的にもアクセス数的にも安上がり!!!

料金内訳

AWSコンソールのコストエクスプローラから、半年間の支払い金額を取得した。

EC2 ELB EC2 インスタンス EC2 その他 税金 Route 53 S3 CloudFront 合計
2019-01-01 18.08 11.31 3.60 2.68 0.50 0.02 0.01 36.20
2019-02-01 16.33 10.21 3.60 2.46 0.50 0.02 0.02 33.14
2019-03-01 18.08 11.31 3.60 2.68 0.50 0.02 0.01 36.20
2019-04-01 17.50 10.92 3.60 2.60 0.50 0.02 0.01 35.15
2019-05-01 18.08 11.31 3.60 2.68 0.50 0.02 0.01 36.20
2019-06-01 17.50 10.94 3.60 2.61 0.50 0.02 0.01 35.18

※ 単位は$
※ 見易さのために少数第3位を四捨五入しています

EC2 ELB

平均 $17.595(ドル円108円として約1900円

EC2インスタンスは1台しか使ってないのだけど、ELBで簡単にhttpsを使いたかったので導入。
結構する。httpsにしたいだけなので、Let's Encryptとか使ってEC2に直接証明書をインストールしたほうが安上がりだったかな。
初回12ヶ月間は1台分無料だけど、無料期間は切れているため課金。

EC2 インスタンス

平均 $11.000(ドル円108円として約1188円

インスタンスはt2.microが1台。t3ではない。
microインスタンスには、初回12ヶ月は1台分が無料というキャンペーンがあるんだけど、12ヶ月間の無料期間は過ぎているためお金がかかっている。

EC2 その他

平均 $3.600(ドル円108円として約389円

EBSの料金ぽい。
SSD30Gを使っているので計算は$0.12 * 30
空きがめっちゃあるのでもっと少なくてもいけそう。

Route 53

平均 $0.500(ドル円108円として約54円

uwaoe.netのドメインを登録している。
リクエスト数で料金が上がるらしいが、現状やっすいので、金額的には気にならないレベル。

S3

平均 $0.020(ドル円108円として約2円

おえかきされた絵やアップロードされたユーザのアバターを保存している。
put系の書き込みリクエストが1000件、get系の取得リクエストが45000件、データ送料が 50MB程度なので大したことがない。
rails側で画像のサムネイルを何種類か作成してS3に上げたり、画像アップロード用のgemのshrineがキャッシュをS3に作りまくったりしているけど、軽い。
現状やっすいので、誤差レベル。

関係ないけど、gem shrineはBase64エンコードされた画像を簡単に扱えるので、canvasの画像を扱いたい場合におすすめ。

Coundfront

平均 $0.012(ドル円108円として約1円

t2.microサーバから画像配信するのは不安があったので、画像の配信にはCloudfrontを使用するようにした。
現状やっすいね。

RDS

使ってない。
節約のためにEC2インスタンスにmysql-serverを入れちゃったのだけど、メモリが足りなくて辛い。
t2.microってメモリ0.5Gじゃん? mysqldがメモリを160MB使っていて、railsを動かしているpumaサーバが180MB使っている。その他サービスで使われているメモリもありで、デプロイを実行するメモリが足りない。デプロイする時、assets:precompileのたびにメモリが足りなくてアプリケーションサーバが死ぬというカッコいい状態になっている。

CloudWatch

使ってない。
別にサービスが何時間止まろうが困らないし・・。

SES

使ってるけど0円。
月62,000件までは0円らしい。

合計

平均 $35.345(ドル円108円として約3817円

おわりに

月3800円。上で書いたようにALBが無駄っぽいので月2000円ぐらいまで節約できると思う。
今の所、広告や課金要素は全く無いので完全赤字になっているが、趣味として見たら安い。

AWSには初回12ヶ月無料なことがいっぱいあって、1年間であれば次の構成が無料にできそう。
* EC2 microインスタンス1つ
* ALB 1つ
* RDS microインスタンス1つ

新規に個人開発のサービス公開を目論んでいる方は、AWSもインフラの候補にしてみてはどうだろうか。

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

BootstrapVueをRailsに導入してみる

初投稿です

RailsでBootstrapとVue.jsを使う方法を調べると、
Vue.jsをrails new project --webpack=vueで入れてきて、
BootstrapはGemfileにgem 'bootstrap'を書いてbundle installしてjsやscssをいじって、、、
というのがオーソドックスなやり方のよう

ちょっと面倒なのと、なぜかvueファイルのtemplateに書いたtooltipがちゃんと効いてくれなかったので、Bootstrapをgemで入れないようにして、yarnでBootstrapVueを入れるようにしてみた

BootstrapVue

おなじみBootstrapとVue.jsが合体したもの
公式サイト

やったこと

プロジェクト作成(webpackでvueもインストール)

$ rails new bootstrapvue_rails --webpack=vue

yarnでBootstrapVueをインストール

$ cd bootstrapvue_rails
$ yarn add bootstrap-vue

画面を用意して、ルーティングしてあげる

$ rails g controller Home index
config/routes.rb
Rails.application.routes.draw do
  root to: 'home#index'
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end

画面のjsファイルを作る

app/javascript/packs/home.js
import Vue from 'vue/dist/vue.esm'
import BootstrapVue from 'bootstrap-vue'
import App from '../app.vue'

import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'

Vue.use(BootstrapVue)

document.addEventListener('DOMContentLoaded', () => {
  const app = new Vue({
    el: '#hello',
     data: {
      message: "Can you say hello?"
    },
    components: { App }
  })
})

vueファイルを作る

app/javascript/app.vue
<template>
  <div id="app">
    <p>{{ message }}</p>
    <div class="text-center my-3">
      <b-button v-b-tooltip.hover title="Tooltip content">Hover Me</b-button>
    </div>
  </div>
</template>

<script>
export default {
  data: function () {
    return {
      message: "Hello Vue!"
    }
  }
}
</script>

<style scoped>
p {
  font-size: 2em;
  text-align: center;
}
</style>

viewで読み込む

app/views/home/index.html.erb
<h1>Home#index</h1>
<p>Find me in app/views/home/index.html.erb</p>

<div id='hello'>
  {{message}}
  <app></app>
</div>

<%= javascript_pack_tag 'home' %>

サーバーを立ち上げたらtooltipが効いてくれてる

$ ./bin/webpack-dev-server
$ rails s

スクリーンショット 2019-07-10 21.05.55.png

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

TECH ~Day15~

中間試験

これまで2週間学習をしてきた知識を活かしてこの日は中間試験を行いました。
現時点で自分がどれだけ知識を覚えられているのかというのがよくわかりました。

ちなみに結果としては百点満点中の7点でした。。。。。
正直この点数も実際かなり個人的に甘くつけた点数なので正直かなりショックは大きかったです。
しかし後からメンターの方から聞いた話だと、この中間試験の今までの平均点は0〜14点という話でした。これを聞いた時は最初のショックも少しは無くなりました。

現時点ではまだまだ社会で通用する力はかけらも備わっていないということがわかりました。
これからもさらに気を緩めずに学習に力を入れていかなければいけないというように改めて思いました。

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

あなたはRailsチュートリアルで一体なにを学んだというのか【5章】

  • 注意:プログラミング歴29日の初心者が書いています

  • 注意:間違っていたら優しく教えてください(喜びます)

「Ruby on Rails チュートリアル実例を使ってRailsを学ぼう」
https://railstutorial.jp/

素晴らしいチュートリアルに感謝します。

5.1.1 ナビゲーション

link_toについて

link_toはRailsのヘルパー(viewsで使える関数)です。
最終的には<a>タグが生成されます。
第1引数はリンクテキスト、第2引数はURLです。

 link_to "sample app", '#', id:"logo" 

カッコが省略されています。関数です。

 link_to("sample app", '#', id:"logo" )

image_tagについて

image_tagもRailsのヘルパー(viewsで使える関数)です。
最終的には<img>タグが生成されます。
第1引数は画像のsrc、第2引数はここではalt属性です。

image_tag("rails.png", alt: "Rails logo")

第一引数として、単に画像ファイル名のみを指定した場合は、assetディレクトリ内のimagesディレクトリから自動で画像を引っ張ってきてくれます。

5.1.2 BootstrapとカスタムCSS

アセットパイプラインについて

↓がわかりやすい
「railsのアセットパイプラインについて解説する」@hogehoge1234
https://qiita.com/hogehoge1234/items/9a94ebc93c5f937502cd

アセットパイプラインとは、htmlファイルと、css,javascript, imgファイルを自動で統合できるようにする仕組みです。

そもそも、webサイトの表示は、主に以下の3つをブラウザが読み込むことで実現される。

  • htmlファイル

  • cssファイル

  • JavaScriptファイル

*imgファイル

これらを一つのファイルで実現することは可能だが、わかりやすいように通常は別々のファイルで作って、最後にそれぞれをhtmlファイルにリンクさせる。

Railsにおいては、

  • htmlファイルに相当するhtml.erbファイルはviewsディレクトリに保存します。

  • cssとJavascriptとimgファイルはassetディレクトリ内部にある、それぞれのディレクトリに保存します。

さらに言うと、cssファイルではなくsassというcssの便利バージョンになっています。sassファイルからcssファイルに変換(コンパイル)しないとブラウザが読み込めないのですが、アセットパイプラインにはコンパイラも含まれています。

つまり、assetディレクトリに入っているファイルたちが、あたかもパイプの中を通りながら1つのファイルに統合されて出てくるようなイメージです。

Railsサーバーの再起動が必要なタイミング

  • Rubyのバージョンを変更したり、

  • Gemfileを変更したり、

  • Railsの内部クラスから何かを変更した場合は、

再起動する必要があります。

5.1.3 パーシャル (partial)

renderについて

renderはヘルパー(viewsに使える関数)の呼び出しをします。
テンプレートを呼び出して表示させるためによく使われます。

テンプレート(要は繰り返し使うhtml部分など)は、partial(パーシャル)という仕組みを使って、コードを一つのファイルにまとめておきます。

その際、パーシャルのファイル名は、_(アンダースコア)で始まるファイル名にします。

render 'layouts/shim'

これは、/_shim.html.erbというファイルを探してその内容をレンダリング(表示)します。
先頭の_(アンダースコア)html.erbなどの余分な内容は省略して記述します。

もちろん、パーシャルにするコードは別ディレクトリに用意しておく必要があります。

5.2.1 アセットパイプライン

アセットディレクトリについて

assetsディレクトリは、その内容によって、以下3つのディレクトリに含まれています。

  • app/assets: 現在のアプリケーション固有のアセット

  • lib/assets: あなたの開発チームによって作成されたライブラリ用のアセット

  • vendor/assets: サードパーティのアセット

それぞれのassetsディレクトリの内部には、CSS、JavaScript、Imagesのディレクトリが存在します。

マニフェストファイルについて

統合させたり読み込ませるCSSやJavaScriptを指定したり設定したりするファイルです。

プリプロセッサエンジンについて

.erb.scssなど、拡張子を読み取って、.html.cssにコンパイルできるように加工してくれます。

その他の加工について

ファイルすべてに対して 不要な空白やインデントを取り除く処理を行い、ファイルサイズを最小化してくれます。結果として、読み込みが早くなります。

5.3 レイアウトのリンク

名前付きルート

root_path -> '/'
root_url  -> 'http://www.example.com/'

例えば、ルートに関してはすでにrootという名前付きルートが定義されています。
ここに_pathメソッドや_urlメソッドを使用することで、名前付きルートの中身を見てみることができます。

get 'static_pages/help'

上記を、以下の名前付きルートに変換します。

get  '/help', to: 'static_pages#help'

読み方は、
『GETリクエスト(ページを取得しろ)が /help に送信されたとき、
StaticPagesコントローラーのhelpアクションを呼び出してくれ』です。

  test "should get help" do
    get help_path #これ
    assert_response :success
    assert_select "title", "Help | Ruby on Rails Tutorial Sample App"
  end

テストコードの修正をします。
これは、helpという名前付きルートに対して、_pathメソッドを使用し、
/static_pages/helpというパスを取得しています。

5.3.4 リンクのテスト

統合テスト

統合テストは、複数のコントローラの動きをチェックするテストのことです。

assert_select "a[href=?]", about_path

?の中身は、第2引数のabout_pathになります。
つまり、<a href="/about">...</a>というaboutページへのパスを含む<a>タグがあるかどうかのチェックです。

$ rails test:integration

上記コマンドで動かします。

5.4.1 Usersコントローラ

Usersコントローラの生成 (newアクションを追加)

「newアクション」とは、Railsの7アクションの1つです。何かを新規作成する際のアクションです。

get  '/signup',  to: 'users#new'

ルーティングに/signupを追加したことによって、signup_pathでページへのパスを表現できるようになりました。

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

わたしがRailsチュートリアルで学んだこと【5章】

  • 注意:プログラミング歴29日の初心者が書いています

  • 注意:間違っていたら優しく教えてください(喜びます)

「Ruby on Rails チュートリアル実例を使ってRailsを学ぼう」
https://railstutorial.jp/

素晴らしいチュートリアルに感謝します。

5.1.1 ナビゲーション

link_toについて

link_toはRailsのヘルパー(viewsで使える関数)です。
最終的には<a>タグが生成されます。
第1引数はリンクテキスト、第2引数はURLです。

 link_to "sample app", '#', id:"logo" 

カッコが省略されています。関数です。

 link_to("sample app", '#', id:"logo" )

image_tagについて

image_tagもRailsのヘルパー(viewsで使える関数)です。
最終的には<img>タグが生成されます。
第1引数は画像のsrc、第2引数はここではalt属性です。

image_tag("rails.png", alt: "Rails logo")

第一引数として、単に画像ファイル名のみを指定した場合は、assetディレクトリ内のimagesディレクトリから自動で画像を引っ張ってきてくれます。

5.1.2 BootstrapとカスタムCSS

アセットパイプラインについて

↓がわかりやすい
「railsのアセットパイプラインについて解説する」@hogehoge1234
https://qiita.com/hogehoge1234/items/9a94ebc93c5f937502cd

アセットパイプラインとは、htmlファイルと、css,javascript, imgファイルを自動で統合できるようにする仕組みです。

そもそも、webサイトの表示は、主に以下の3つをブラウザが読み込むことで実現される。

  • htmlファイル

  • cssファイル

  • JavaScriptファイル

*imgファイル

これらを一つのファイルで実現することは可能だが、わかりやすいように通常は別々のファイルで作って、最後にそれぞれをhtmlファイルにリンクさせる。

Railsにおいては、

  • htmlファイルに相当するhtml.erbファイルはviewsディレクトリに保存します。

  • cssとJavascriptとimgファイルはassetディレクトリ内部にある、それぞれのディレクトリに保存します。

さらに言うと、cssファイルではなくsassというcssの便利バージョンになっています。sassファイルからcssファイルに変換(コンパイル)しないとブラウザが読み込めないのですが、アセットパイプラインにはコンパイラも含まれています。

つまり、assetディレクトリに入っているファイルたちが、あたかもパイプの中を通りながら1つのファイルに統合されて出てくるようなイメージです。

Railsサーバーの再起動が必要なタイミング

  • Rubyのバージョンを変更したり、

  • Gemfileを変更したり、

  • Railsの内部クラスから何かを変更した場合は、

再起動する必要があります。

5.1.3 パーシャル (partial)

renderについて

renderはヘルパー(viewsに使える関数)の呼び出しをします。
テンプレートを呼び出して表示させるためによく使われます。

テンプレート(要は繰り返し使うhtml部分など)は、partial(パーシャル)という仕組みを使って、コードを一つのファイルにまとめておきます。

その際、パーシャルのファイル名は、_(アンダースコア)で始まるファイル名にします。

render 'layouts/shim'

これは、/_shim.html.erbというファイルを探してその内容をレンダリング(表示)します。
先頭の_(アンダースコア)html.erbなどの余分な内容は省略して記述します。

もちろん、パーシャルにするコードは別ディレクトリに用意しておく必要があります。

5.2.1 アセットパイプライン

アセットディレクトリについて

assetsディレクトリは、その内容によって、以下3つのディレクトリに含まれています。

  • app/assets: 現在のアプリケーション固有のアセット

  • lib/assets: あなたの開発チームによって作成されたライブラリ用のアセット

  • vendor/assets: サードパーティのアセット

それぞれのassetsディレクトリの内部には、CSS、JavaScript、Imagesのディレクトリが存在します。

マニフェストファイルについて

統合させたり読み込ませるCSSやJavaScriptを指定したり設定したりするファイルです。

プリプロセッサエンジンについて

.erb.scssなど、拡張子を読み取って、.html.cssにコンパイルできるように加工してくれます。

その他の加工について

ファイルすべてに対して 不要な空白やインデントを取り除く処理を行い、ファイルサイズを最小化してくれます。結果として、読み込みが早くなります。

5.3 レイアウトのリンク

名前付きルート

root_path -> '/'
root_url  -> 'http://www.example.com/'

例えば、ルートに関してはすでにrootという名前付きルートが定義されています。
ここに_pathメソッドや_urlメソッドを使用することで、名前付きルートの中身を見てみることができます。

get 'static_pages/help'

上記を、以下の名前付きルートに変換します。

get  '/help', to: 'static_pages#help'

読み方は、
『GETリクエスト(ページを取得しろ)が /help に送信されたとき、
StaticPagesコントローラーのhelpアクションを呼び出してくれ』です。

  test "should get help" do
    get help_path #これ
    assert_response :success
    assert_select "title", "Help | Ruby on Rails Tutorial Sample App"
  end

テストコードの修正をします。
これは、helpという名前付きルートに対して、_pathメソッドを使用し、
/static_pages/helpというパスを取得しています。

5.3.4 リンクのテスト

統合テスト

統合テストは、複数のコントローラの動きをチェックするテストのことです。

assert_select "a[href=?]", about_path

?の中身は、第2引数のabout_pathになります。
つまり、<a href="/about">...</a>というaboutページへのパスを含む<a>タグがあるかどうかのチェックです。

$ rails test:integration

上記コマンドで動かします。

5.4.1 Usersコントローラ

Usersコントローラの生成 (newアクションを追加)

「newアクション」とは、Railsの7アクションの1つです。何かを新規作成する際のアクションです。

get  '/signup',  to: 'users#new'

ルーティングに/signupを追加したことによって、signup_pathでページへのパスを表現できるようになりました。

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

[メモ]Windows上のVagrantでRails環境構築する際の共有フォルダの注意点

gemを共有フォルダ以下に置くとエラーになる

解決策:gemを共有フォルダ以外にインストールする。

> bundle install --path 共有フォルダ以外へのpath

sqlite3のデータベースファイルを共有フォルダ以下に置くとエラーになる

解決策1:マイグレーションについては以下のように対処できる。

config/database.yml
...

test:
  <<: *default
  database: db/test.sqlite3 # ←pathを共有フォルダ以外に変更

production:
  <<: *default
  database: db/production.sqlite3 # ←pathを共有フォルダ以外に変更

解決策2:PostgreSQL, MySQLなどの他のDBを使う。

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

Windows上のVagrantでRails環境構築する際の共有フォルダの注意点【メモ】

gemを共有フォルダ以下にインストールするとエラーになる

解決策:gemを共有フォルダ以外にインストールする。

> bundle install --path 共有フォルダ以外へのpath

sqlite3のデータベースファイルを共有フォルダ以下に置くとエラーになる

解決策1:マイグレーションについては以下のように対処できる。

config/database.yml
...

test:
  <<: *default
  database: db/test.sqlite3 # ←pathを共有フォルダ以外に変更

production:
  <<: *default
  database: db/production.sqlite3 # ←pathを共有フォルダ以外に変更

解決策2:PostgreSQL, MySQLなどの他のDBを使う。

筆者の環境

Host OS: Windows 10 Home (バージョン 1809(OSビルド 17763.557))
Vagrant 2.2.4
Virtual Box 6.0.8
Vagrant Box(Guest OS): CentOS/7

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

rails runner で Please specify a valid ruby command or the path of a script to run.

問題:lib以下のディレクトリを読み込んでくれない

スクリプトはこんな感じ

#lib/batch/push.rb
class Test
  def self.push
    require 'json'
    result = TalkHistory.where(call_status: 'skyway_ringing').where(call_duration: nil).where('talked_at>?',Time.zone.now - 1.days).count("id")
    result_hash = {"count"=> result}

    File.open("test.json","w") do |file|    
      JSON.dump(result_hash,file)
    end
    #jsonファイルのアップロード
    require 'aws-sdk'
    s3 = Aws::S3::Resource.new(
      :region => 'ap-northeast-1',
      :access_key_id => ENV['ACCESS_KEY_ID'],
      :secret_access_key => ENV['SECRET_ACCESS_KEY']
    )
    bucket = s3.bucket('testbucket0709')
    bucket.object('test').upload_file("test.json")
    puts bucket.object('test').exists?
    puts bucket.object('test').get.body.read
  end
end

実行すると...

rails ruuner 'Test.push'
=>
Please specify a valid ruby command or the path of a script to run.
Run 'bin/rails runner -h' for help.

uninitialized constant Test

autoload_pathsを確認

$ bin/rails r 'puts ActiveSupport::Dependencies.autoload_paths'
/Users/satou/projects/koetomosql/lib
/Users/satou/projects/koetomosql/lib/
/Users/satou/projects/koetomosql/lib/tasks/
/Users/satou/projects/koetomosql/lib/batch/
/Users/satou/projects/koetomosql/lib/assets/
/Users/satou/projects/koetomosql/app/assets
/Users/satou/projects/koetomosql/app/channels
/Users/satou/projects/koetomosql/app/controllers
/Users/satou/projects/koetomosql/app/controllers/concerns
/Users/satou/projects/koetomosql/app/helpers
/Users/satou/projects/koetomosql/app/jobs
/Users/satou/projects/koetomosql/app/mailers
/Users/satou/projects/koetomosql/app/models
/Users/satou/projects/koetomosql/app/models/concerns
/Users/satou/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activestorage-5.2.3/app/assets
/Users/satou/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activestorage-5.2.3/app/controllers
/Users/satou/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activestorage-5.2.3/app/controllers/concerns
/Users/satou/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activestorage-5.2.3/app/javascript
/Users/satou/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activestorage-5.2.3/app/jobs
/Users/satou/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/activestorage-5.2.3/app/models
/Users/satou/projects/koetomosql/test/mailers/previews

問題なさそう
でもコンソールで確認するとクラスを読み込めてない...

Loading development environment (Rails 5.2.3)
irb(main):001:0> Test
Traceback (most recent call last):
        1: from (irb):1
NameError (uninitialized constant Test)

解決

ディレクトリ名とファイル名をクラス名と合わせる必要があるらしい!!
以下の記事の最後のほう!!
あーむかついた!
Rails Runnerを使ってみる

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

【Rails】sendを使ってメタプロっぽい書き方をしたので記しておく

タイトル通り、sendメソッドを使ってメタプロっぽい書き方をやってみたので書き残しておく。

説明

deviseで clientcreatorという2つのモデルを用意している。
それぞれ、nameが登録されているか/されていないかによって、ログイン後の繊維ページが異なるが、
clientとcreator間での法則性は同一である。
↓こんな感じ

name登録済み name未登録
client client_mypage_path edit_client_path(current_client)
creator creator_mypage_path edit_creator_path(current_creator)

send使ってafter_sign_in_path_for

application_controller.rb
class ApplicationController < ActionController::Base
  helper_method :current_resource, :current_resource_model, :other_side_model, :registered_name?

  def current_resource
    if client_signed_in?
      current_client
    elsif creator_signed_in?
      current_creator
    end
  end

  def current_resource_model
    return unless current_resource
    current_resource.class.to_s.downcase
  end

  # ログイン後に遷移するpathを設定
  def after_sign_in_path_for(resource)
    return unless current_resource
    resource_mypage_path = send(current_resource_model + "_mypage_path")
    edit_resource_path = send("edit_" + current_resource_model + "_path", current_resource)

    registered_name? ? resource_mypage_path : edit_resource_path
  end

  def registered_name?
    current_resource&.name.present?
  end

このように、複数のdeviseモデルでの法則的なコードを1つにまとめて記述する時に役に立ちそう。

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

あなたはRailsチュートリアルで一体なにを学んだというのか【4章】

  • 注意:プログラミング歴29日の初心者が書いています

  • 注意:間違っていたら優しく教えてください(喜びます)

「Ruby on Rails チュートリアル実例を使ってRailsを学ぼう」
https://railstutorial.jp/

素晴らしいチュートリアルに感謝します。

4.1.1 組み込みヘルパー

組み込み関数ってなんですか

組み込み関数とは、プログラミング言語がもともと用意してくれている関数のことです。
ビルトイン関数とも言います。

ヘルパーってなんですか

viewで使える関数のことをrailsではヘルパーと呼んでいます。

つまり、
「組み込みヘルパー」とは

  • 「railsがもともと用意してくれている」

  • 「viewで使える関数」

のことです。

4.1.2 カスタムヘルパー

カスタムヘルパーってなんですか

  • 「自分でカスタムした(自分で作る)」

  • 「viewで使える関数」

ということになります。

リスト 4.2: full_titleヘルパーを定義する

「Home」ページにアクセスした際に、Home | Ruby on Rails Tutorial Sample App ではなく、Ruby on Rails Tutorial Sample Appのみを表示させたい。
しかし、現状のコードのまま実装を進めると、|(縦棒)が残ってしまいます。

「full_title」関数(ヘルパー)を作って、|(縦棒)が残らないようにしましょう。

viewで使いたい関数はhelperディレクトリ内のファイルに記述する

これです。ここで言いたいのは多分これです。
「viewで使いたい関数はhelperディレクトリ内のファイルに記述すること」

ヘルパーの中身

module ApplicationHelper
    # ページごとの完全なタイトルを返します。
  def full_title(page_title = '') #1
    base_title = "Ruby on Rails Tutorial Sample App" #2
    if page_title.empty? #3
      base_title #4
    else
      page_title + " | " + base_title #5
    end
  end
end

#1: full_title関数の定義・引数page_title = ''は、『引数としてpage_titleをとる。引数の指定がない場合は' 'を引数とする』という意味です。

#2: 変数base_title"Ruby on Rails Tutorial Sample App"を代入。

#3: page_titleに対して.empty?メソッドを用いて、変数内に値が存在するかどうかで条件分岐させます。

#4: .empty?メソッドは、変数が空ならTrueを返します。 page_titleが空のとき、base_titileのみを返します。
(ちなみに、Rubyではメソッドがtrueまたはfalseを返す場合、メソッド名に?がついています。)

#5: 変数内に値が存在する場合、page_title|(縦棒)base_titleを返します。


application_helper.rbに書き込まれた上記の内容は、railsの力によって、自動的にapplication.html.erbで使用可能になります。

apprication.html.erbの中身

<title><%= full_title(yield(:title)) %></title>

タイトルタグのコードです。
ヘルパーで定義した、「full_title」関数を呼び出しています。

引数には、yieldメソッドでページごとにprovideで設定してあるタイトルを呼び出しています。

Homeページから「Home | 」を取り除く

まずはテストから作り初めて、それからテストを通す実装をします。

  test "should get home" do
    get static_pages_home_url
    assert_response :success
    assert_select "title", "Ruby on Rails Tutorial Sample App"#←ココ
  end

home_urlのgetリクエストに対して、
titleは"Ruby on Rails Tutorial Sample App"を表示
というテストです。

rails testすると当然失敗します。
なぜなら、home.html.erbprovideメソッドがタイトルとして"Home"を指定しているからです。

テストを通すためには、
home.html.erbから、provideメソッドの行を取り除きます。

4.3.2 ブロック

ブロックは、メソッドの引数として渡すことのできる処理のかたまりです。
{}波括弧do ... endの部分がブロックです。

test "should get home" do
  get static_pages_home_url
  assert_response :success
  assert_select "title", "Ruby on Rails Tutorial Sample App"
end

テスト文も、じつはtestメソッドが、引数としてブロックをとっています。
do ... endで挟まれた処理がtestメソッドの引数になっています。

4.4.5 ユーザークラス

class User
  attr_accessor :name, :email #アクセサメソッド

  def initialize(attributes = {}) #initializeメソッド
    @name  = attributes[:name]
    @email = attributes[:email]
  end

  def formatted_email #インスタンスメソッドの定義
    "#{@name} <#{@email}>"
  end
end

#アクセサメソッド
インスタンス変数に、クラス外からアクセスできるようになります。

#initializeメソッド
User.newを実行すると自動的に呼び出されるメソッドです。
.newと同時に実行されます。

#インスタンスメソッドの定義
メソッドを呼び出すことで、
"ユーザー名 <メールアドレス>"という文字列を返すメソッドです。
特に意味はないです。

 user = User.new(name: "Michael Hartl", email: "mhartl@example.com")

上記のように使えます。

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

[Rails]既存のデータベースにRailsで接続してActiveRecordでレコードを抽出する方法

やりたいこと

[Rails]gem"whenever"を使って定期的にタスクを実行するの続きです
今回は その2:既存のデータベースにRailsで接続してActiveRecordでレコードを抽出する をやります

config/database.ymlの中身を変更

development:
  adapter: mysql2
  database: データベース名
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: ユーザ名
  password: パスワード
  host: ホスト
  port: ポート番号

既存のデータベースのスキーマ情報を新規Railsプロジェクトにコピーする

参考記事
Rails - schema.rb(既存DBを使ったアプリ作成)
既存DBを使ってRails

以下のコマンドでスキーマ情報がdb/schema.rbに書き込まれる

rake environment -t RAILS_ENV=development db:schema:dump

空のマイグレーションファイルを生成して中身を先ほどコピーしてきたschema.rbに置き換えてマイグレートする

rails g migration create_table
中身を書き換えてから
rails db:migrate

モデルを生成する

テーブルの数だけ作るらしいです(正直まだ理解できてません)
でも作らないとエラー吐かれるので作りました...
オプション指定するとマイグレーションファイル生成するのを防ぐことができます

rails g model モデル名 --migration false

ここまで設定したらActiveRecord使えるようになりました!

lib/tasks/testsql.rb

namespace :testsql do
  desc "sqlの定期送信"
  task sql: :environment do

    require 'json'
    result = TalkHistory.where(call_status: 'skyway_ringing').where(call_duration: nil).where('talked_at>?',Time.zone.now - 1.days).count("id")
    result_hash = {"count"=> result}
    result_json = JSON.generate(result_hash)

    File.open("test2.json","w") do |file|    
      file.puts result_json
    end

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

Rails6 のちょい足しな新機能を試す50(scaffold 編)

はじめに

Rails 6 に追加されそうな新機能を試す第50段。 今回は、 scaffold 編です。
Rails 6 では、 belongs_to な関係のあるモデルがあるアプリを scaffold で作った場合に、 belongs_to で指定される親モデルの表示のされ方が変わりました。
...ってなんだか良くわかりませんね。

実際にやってみた方がわかりやすいです。

Ruby 2.6.3, Rails 6.0.0.rc1, Rails 5.2.3 で確認しました。Rails 6.0.0.rc1 は gem install rails --prerelease でインストールできます。

$ rails --version
Rails 6.0.0.rc1

rails プロジェクトを作る

$ rails new rails6_0_0rc1
$ cd rails6_0_0rc1

scaffold を使う

scaffold で Author と Book の CRUD を作成します。Book は、 Author に属します。

$ bin/rails g scaffold Author name
$ bin/rails g scaffold Book title author:references

seed データを作る

Author と Book のデータを1つずつ作成します。

db/seeds.rb
author = Author.create(name: 'Dave Thomas')
Book.create(title: 'Programming Ruby', author: author)

データベースを作る

データベースを作って seed データを登録します。

$ bin/rails db:create db:migrate db:seed

rails server を実行して Book のデータを表示する

rails server を実行します。

$ bin/rails s

http://localhost:3000/bookshttp://localhost:3000/books/1 で一覧画面と詳細画面を表示します。

Rails 5 では

一覧画面でも詳細画面でも、Author はAuthorオブジェクト( Author#to_s )を表示します。

一覧画面

rails5index.png

詳細画面

rails5show.png

Rails 6 では

一覧画面でも詳細画面でも、Author は ID ( Author#id ) の 1 を表示します。

一覧画面

rails6index.png

詳細画面

rails6show.png

試したソース

試したソースは以下にあります。
https://github.com/suketa/rails6_0_0rc1/tree/try050_scaffold

参考情報

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

[Rails]gem"whenever"を使って定期的にタスクを実行する

やりたいこと

その1:定期的にSQLを発行して返ってきたデータをjson形式でファイル出力する
その2:既存のDBにRailsで接続してActiveRecordでレコードを抽出する
その3:AWSのS3ストレージにjsonファイルをアップロードする
この記事ではその1だけ

gem"whenever"を利用した定刻処理の実装

この記事の通りにやりました。記事書いてくれた人ありがとうございます。

参考記事
[初学者]whenever を使って定期的にバッチ処理を行う(公開設定編)

コードの全体像

namespace :testsql do
  desc "sqlの定期送信"
  task sql: :environment do

    #SQLの接続
    require "mysql2"
    require 'json'

    client = Mysql2::Client.new(host: '******', username: ENV["DB_USERNAME"], 
      password: '******', database: ENV["DATABASE"])
    result = client.query("select count(id) from talk_histories 
      where call_status = 'skyway_ringing' and call_duration is NULL and talked_at > (now() - interval 1 day)")

      puts result #=> <Mysql::Result>オブジェクトが返ってくる
    result.each do |r|
      puts r  #=> {"count(id)"=>85} 
      puts r["count(id)"] #=> 85
      $count = {count: r["count(id)"]} #グローバル変数$countにハッシュ形式で格納
    end

    #ファイル作成
    File.open("test.json","w") do |text|
      text.puts $count
    end

    #jsonファイルのアップロード
    require 'aws-sdk'
    s3 = Aws::S3::Resource.new( #S3リソースの作成
      :region => 'ap-northeast-1',
      :access_key_id => '******',
      :secret_access_key => '******',
    )

    bucket = s3.bucket('testbucket0709') #バケットの作成
    bucket.object('test2').upload_file("test2.json") #.objectの引数がキーになる
    puts bucket.object('test2').exists? #"test2"のキーを持つオブジェクトがバケットにあるか確認
    puts bucket.object('test2').get.body.read #オブジェクトの読み込み

  end
end

問題:出力したファイルがJSON形式になっていなかった

json形式になっているかどうかの確認はこちらでやりました
JSONLint

参考記事
RubyでのJSONの書き込み
RubyでJSONを扱うときに便利な関数まとめ

僕はハッシュなら全部JSONなんじゃないのとか思ってましたがよく見ると全然違いますね

ハッシュ

{"json"=>"12345"}

JSON

'{"rails": {"json": "12345"}}'

どうやらRubyのライブラリを使うそうです
JSON.generate(配列)とするとjson形式のファイルができるっぽい

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

Rails console でも FactoryBot のメソッド呼び出しを簡単にする

Ruby on Rails + FactoryBot で開発をおこなっていると、Rails console を使ってサクッとデータを作成して REPL で検証したくなることがあります。この時 FactoryBot.create()FactoryBot.build() と書かなければならず、普段テストで書いている create()build() に比べると若干の面倒さが目立ってしまいます。

僕は怠惰なので以下のような hook を .pryrc に書いてこの問題を解決してみました。

# -*- mode: ruby -*-
Pry.hooks.add_hook(:before_session, "use FactoryBot shorthand") do |output, binding, pry|
  Object.include FactoryBot::Syntax::Methods
end

これでいつでも create(:user)build(:user) でユーザーを作成することができます。

なお、みなさんご想像の通りトップレベルに世界の開発者が想像もしないようなメソッドを生やすので世界が壊れるかもしれません :innocent:

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

form_tagをform_forに書き換える

初めまして!
Rails初学者が初めてQiitaで書きます!

form_forってどうやって書いたらいいの?


アプリを作成する際に苦戦したので備忘録として記事を残しておきます。

form_for基本形
<%= form_for (modelobject, option) do |f| %>
 フォームコントロールの設定
<% end %>

これ書いたらformが作成されると思っていましたが、うまくいきません。

まずはビューの部分を記述する


new.html.erb
<div class="contents row">
 <%= form_for @post do |form| %>
//@postにフォームコントロール内で入力する値を入れる//
  <h5>タイトル</h5>
   <%= form.text_field :content, placeholder: 'content' %>
  //ブログのタイトルを入力する為のtext_field
  <h5>本文</h5>
   <%= form.text_field :content, placeholder: 'content' %>
  //ブログの本文を入力する為のtext_filed
  <%= form.submit "SENT" %>
 //送信ボタン
 <% end %>
</div>

次にcontrollerを編集する


posts_controller.rb
class PostsController < ApplicationController

  before_action :move_to_index, except: [:index, :show]
  def new
    @post = Post.new
    //新規作成された値は@postに入れる
  end
  //~省略~

これでform_for内で入力した値は@postに渡されます!
新規作成のフォームは完成したので次は編集する時のフォームの書き方。

編集のビュー部分の作成


edit.html.erb
<div class="contents row">
  <%=form_for @post, url => {action: 'update'} do |form|%>
  //form_forのupdateアクションを明示する為にaction:を指定
  <h5>タイトル</h5>
     <%= form.text_field :title, placeholder: 'title:最大文字数20文字まで' %>
   <h5>本文</H5>
     <%= form_text_field :content. placeholder 'content'%>
   <%= form.submit "SENT" %>
 <% end %>
</div>

次にcontrollerを編集する


posts_controller.rb
class PostsController < ApplicationController
  before_action :set_post, only: [:edit, :show]
  //共通のアクションはcallbackする為、before_action内に設定
〜省略〜
  def show
  end

  def edit
  end

  private

  def set_post
    @post = Post.find(params[:id])
  end

  def post_params
    params.require(:post).permit(:content, :title)
  end
end

以上でform_forでフォームの新規作成と編集ができるようになりました!

最後に


筆者について

TEXH::EXPERT渋谷校の夜間クラスで4月からRuby・Railsの学習をしています。
記載内容に不備・不足があればご指摘いただけると幸いです。
至らぬ点ばかりですので、改善点がありましたらどんどんご指摘下さい!

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

rails投稿機能の追加方法 ※自分メモ用

2019/7/10

自動生成されるカラム確認

◎idカラムについて

idカラムには、データベースに保存される時に数字が自動で入る。
idは1から順に入っていき、データ毎に重複しないようになっている。

スクリーンショット 2019-07-10 10.19.39.png

◎created_atカラムとupdated_atカラムについて

created_atカラムとupdated_atカラムには、
データベースに保存された時刻が自動で入るようになっている。
updated_atはデータ更新時にも時刻が更新される。

スクリーンショット 2019-07-10 10.23.14.png

find_byメソッドで投稿を取得する

特定のidの投稿を取得するためには、find_byメソッドを用いる。
find_byメソッドは、ある条件に合致するデータを取得することができます。
図のように、「モデル名.find_by(カラム名: 値)」とすることで、その値を持ったデータをデータベースから取得することができる。

スクリーンショット 2019-07-10 10.35.13.png

今回は↓↓↓

post = Post.find_by(id:3)

投稿詳細ページを作成

ルーティング・アクション・ビューの思考が必要。
投稿詳細ページのURLに表示したい投稿のidを入れる必要がある。
そしてそのidを持つ投稿データを表示する。

スクリーンショット 2019-07-10 10.43.00.png

①投稿詳細ページのルーティング

・showアクションを作る
・URLにidを含める
→ルーティングのURLの部分に「:」を用いて"posts/:id"と指定して
 「posts/1」「posts/2」でもshowアクションにいくようになる。

②URLからidの取得

変数params

Controllerの場所で..↓↓↓

@id = params[:id]

③投稿詳細ページ完成

〜Controllerタブ〜

showアクションで変数@postを定義してidカラムの値が
params[:id]と等しい投稿をデータベースから取得して代入します。
@postをshow.html.erbで表示することで、
各URLに対応した投稿のデータが表示されるようにしましょう!

スクリーンショット 2019-07-11 9.13.54.png

④仕上げ

詳細画面へのリンクを作成する。

投稿一覧ページに、各投稿の詳細ページへのリンクを作成しましょう。
各投稿の内容の部分をクリックすると詳細ページに移動できるように、
link_to(post.content, "/posts/#{post.id}")とします。

スクリーンショット 2019-07-11 9.16.23.png

新規投稿ページの作成

・新規投稿ページ準備

新規投稿ページは、「localhost:3000/posts/new」というURLでアクセスできるようにしましょう。
そのためにルーティング、アクション、ビューを追加しましょう。
アクションは、newアクションとしましょう。

スクリーンショット 2019-07-11 10.00.58.png

・入力フォームの作成

HTML & CSSのレッスンで学習した<textarea>タグや<input>タグを用いることで入力フォームを作成することができます。
送信ボタンにはtype="submit"と、value="投稿"を指定することに気をつけましょう。

スクリーンショット 2019-07-11 10.04.15.png

・投稿を保存する準備

・投稿を保存するまでの流れ
 フォームの投稿ボタンを押すと、Rails側に投稿データが送信されます。
 今回はcreateアクションを用意して、受け取った投稿データをデータベースに保存するようにします。
 createアクションのURLは「/posts/create」としましょう。

スクリーンショット 2019-07-11 10.07.37.png

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

#Ruby / #Rails - FactoryBot でエイリアスを呼び出すみたいに、元の定義をコピー・継承して別名を作る

Ruby / # Rails-Copy and inherit the original definition to create an alias, just like calling an alias in FactoryBot

Factoryの中にFactoryを書くだけで良いらしい。こいつは使える!

factory :user do
  name { 'SomeName' }

  factory :alice do
      name { 'Alice' }
  end

  factory :bob do
      name { 'Bob' } 
  end
end
FactoryBot.create :user
FactoryBot.create :alice
FactoryBot.create :bob

FactoryGirlチートシート - Qiita

Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/2259

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

nested attributes 使用時に毎回新規登録が行われてしまう

概要

accepts_nested_attributes_for を使って、とあるレコードの編集時に、関連レコードの新規作成/更新 を行うようにしたつもりだったのですが、なぜか常に新規登録扱いになってしまい、SQL発行時に Duplicate entry でエラーになる、という事象がおこっていました。

原因は大したことなかったのですが、これにハマったのが2度目だったので自戒のため記事に残しておくことにした次第です。よろしければお付き合いください。

環境

  • Ruby 2.5.1
  • Rails 5.2.2.1

結論

先に結論を書いておきます。
id を permit メソッド内で許可していなかったから。 です。

ハマるときに限って、意外と原因は大したことなかったりします。

舞台設定

順に説明していきます。まず今回の Model と Controller について記載します。

Model

Parent が親で、Child が関連モデルです。名前がいまいちですがご容赦ください:sweat_smile:

parent.rb
class Parent < ApplicationRecord
  has_one :child
  accepts_nested_attributes_for :child, allow_destroy: true
end
child.rb
class Child < ApplicationRecord
  belongs_to :parent
  self.primary_key = :parent_id
end

Controller

問題の原因はここにあります。ここではあえて問題が再現する状態のままにしています。

child_controller.rb
class ChildController
  def update
    if @parent.update(child_params)
      # リダイレクト先は適当に書いたただの例なので気にしないでください
      redirect_to detail_page_path(@parent)
    else
      render :edit
    end
  end

  def child_params
    params.require(:parent).permit(
      # parent側もいろいろ指定がありますがここでは省略してます
      child_attributes: %i[title _destroy]
    )
  end
end

問題の解消方法

前述コントローラの child_params メソッド内を下記のように変更すると解消します。結論で書いたとおりですが、id を permit メソッド内で許可するキーに追加しています。

- child_attributes: %i[title _destroy]
+ child_attributes: %i[id title _destroy]

そもそもこの id って?

まずはこちらをご覧ください。これは child_controller に対応したビューの一部です。このようなフォームを作成しています。

child.html.erb
<%= form_with(model: @parent, local: true) do |form_parent| %>
  <!-- parent のフォームは省略 -->
  <%= form_parent.fields_for :child, @parent.child.build do |form_child|%>
    <%= form_child.text_field :title, placeholder: 'なんか入力してくれ' %>
  <%end%>
<%end%>

そして、実際に生成される child 分のフォームは以下のような html になります。

item.html
<input placeholder="なんか入力してくれ" type="text" value="" name="parent[child_attributes][title]" id="parent_child_attributes_title">
<input type="hidden" value="2" name="parent[child_attributes][id]" id="parent_child_attributes_id">

おや?
parent[child_attributes][id] という、自分では作成した覚えのない input hidden のフォームが生成されています。これが id パラメータの正体のようです。value 属性に入っているのは childs の主キーである parent_id の値でした。

どうやらこの値を見て、新規登録か、既存レコードの更新かを区別しているようです。新規登録の際は value に何も入っていません。そのため、コントローラ側の処理で id を permit メソッド内で許可しておかないと、常に新規登録として扱われてしまう、ということです。

ここで注意が必要なのが、主キーのカラム名は parent_id であるにも関わらず、input タグの name 属性には必ず id という名前が使用される という点です。DBのカラム名でそのまま考えると permit には parent_id を書いてしまいがちなんですが、主キーが送信されているパラメータの名前は常に id という名前であるため間違えないように気をつけましょう。でないと僕の二の舞になります。こんなミスする人は僕だけかもしれませんが

参考

余談

とはいえ、Rails はほんとにDB保存系の処理を書くのが楽ですね。そもそも最近の ORM ってみんなこんなかんじなんでしょうか?Laravel の ORM とかどうなんだろう、ということをふと考えました。

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

railsの基礎知識② ※自分メモ用

共通のレイアウトをまとめる

2019/7/9

このコードにより各ビューファイルが<%= yield %>に代入される

<%= yield %>

リンクにできるコマンド

引数がここで登場

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

shields.ioを使って技術系アイコンを量産した

概要

shields.ioを用いて技術系アイコンを量産しました。

とりあえず完成したのがこちらです。
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
skills.png

これでスキルマップを作ってみたらいい感じになりました。

shields.ioについて

https://shields.io/

GitHubのREADMEでよく見かけるアレです。
shields.ioはSVG形式のバッジサービスです。

カスタムバッジを作る

特徴的な機能の1つとして
URLのパターンでカスタムバッジを作ることができます。

https://img.shields.io/badge/${subject}-${status}-${color}.svg

subject : バッジの左側に入る文言
status : バッジの右側に入る文言
color : 色

Color

以下のようなものが用意されています。

color.png

16進数形式で指定することも可能です。

カスタムスタイル

いくつかのスタイルが用意されています。

?style=plastic&logo=appveyor

?style=flat&logo=appveyor

?style=flat-square&logo=appveyor

?style=for-the-badge&logo=appveyor

?style=popout&logo=appveyor

?style=popout-square&logo=appveyor

?style=social&logo=appveyor

simpleicons

バッジではいくつかのアイコンが使えます。
これについてはsimpleiconsを参考になります。

https://simpleicons.org/

そして一例がこれです。

 2019-07-08 1.41.11.png

全部で数えたら648ありました。

おすすめアイコンを作った

おすすめしたいアイコンを作りました。

言語系

 2019-07-08 23.38.15.png

ライブラリ・フレームワーク

 2019-07-08 23.38.46.png

OS

 2019-07-08 23.39.28.png

ミドルウェア

 2019-07-08 23.39.50.png

エディタ・IDE

 2019-07-08 23.40.09.png

クラウド・他

 2019-07-08 23.40.25.png

参考

shields.ioで技術系のアイコンをたくさん作ってみる

付録 : アイコンのURL

各アイコンのURLです。1

### 言語系

<img src="https://img.shields.io/badge/PHP-ccc.svg?logo=php&style=flat">
<img src="https://img.shields.io/badge/Javascript-276DC3.svg?logo=javascript&style=flat">
<img src="https://img.shields.io/badge/-TypeScript-007ACC.svg?logo=typescript&style=flat">
<img src="https://img.shields.io/badge/-Python-F9DC3E.svg?logo=python&style=flat">
<img src="https://img.shields.io/badge/-CSS3-1572B6.svg?logo=css3&style=flat">
<img src="https://img.shields.io/badge/-HTML5-333.svg?logo=html5&style=flat">

### ライブラリ・フレームワーク

<img src="https://img.shields.io/badge/-CakePHP-D3DC43.svg?logo=cakephp&style=flat">
<img src="https://img.shields.io/badge/-Rails-CC0000.svg?logo=rails&style=flat">
<img src="https://img.shields.io/badge/-Django-092E20.svg?logo=django&style=flat">
<img src="https://img.shields.io/badge/-Flask-000000.svg?logo=flask&style=flat">
<img src="https://img.shields.io/badge/-Bootstrap-563D7C.svg?logo=bootstrap&style=flat">
<img src="https://img.shields.io/badge/-React-555.svg?logo=react&style=flat">
<img src="https://img.shields.io/badge/-jQuery-0769AD.svg?logo=jquery&style=flat">

### OS

<img src="https://img.shields.io/badge/-Linux-6C6694.svg?logo=linux&style=flat">
<img src="https://img.shields.io/badge/-Ubuntu-6F52B5.svg?logo=ubuntu&style=flat">
<img src="https://img.shields.io/badge/-Windows-0078D6.svg?logo=windows&style=flat">
<img src="https://img.shields.io/badge/-RedHat-EE0000.svg?logo=red-hat&style=flat">
<img src="https://img.shields.io/badge/-Debian-A81D33.svg?logo=debian&style=flat">
<img src="https://img.shields.io/badge/-Raspberry%20Pi-C51A4A.svg?logo=raspberry-pi&style=flat">
<img src="https://img.shields.io/badge/-Arch%20Linux-EEE.svg?logo=arch-linux&style=flat">

### ミドルウェア

<img src="https://img.shields.io/badge/-Apache-D22128.svg?logo=apache&style=flat">
<img src="https://img.shields.io/badge/-Nginx-bfcfcf.svg?logo=nginx&style=flat">
<img src="https://img.shields.io/badge/-Oracle-f80000.svg?logo=oracle&style=flat">
<img src="https://img.shields.io/badge/-Redis-D82C20.svg?logo=redis&style=flat">
<img src="https://img.shields.io/badge/-Elasticsearch-005571.svg?logo=elasticsearch&style=flat">
<img src="https://img.shields.io/badge/-PostgreSQL-336791.svg?logo=postgresql&style=flat">


### エディタ・IDE

<img src="https://img.shields.io/badge/-Visual%20Studio%20Code-007ACC.svg?logo=visual-studio-code&style=flat">
<img src="https://img.shields.io/badge/-Vim-019733.svg?logo=vim&style=flat">
<img src="https://img.shields.io/badge/-Emacs-EEE.svg?logo=spacemacs&style=flat">
<img src="https://img.shields.io/badge/-Atom-66595C.svg?logo=atom&style=flat">
<img src="https://img.shields.io/badge/-Xcode-EEE.svg?logo=xcode&style=flat">
<img src="https://img.shields.io/badge/-intellij%20IDEA-000.svg?logo=intellij-idea&style=flat">

### クラウド・他

<img src="https://img.shields.io/badge/-Amazon%20AWS-232F3E.svg?logo=amazon-aws&style=flat">
<img src="https://img.shields.io/badge/-Google%20Cloud-EEE.svg?logo=google-cloud&style=flat">
<img src="https://img.shields.io/badge/-Ansible-EE0000.svg?logo=ansible&style=flat">
<img src="https://img.shields.io/badge/-GitHub-181717.svg?logo=github&style=flat">
<img src="https://img.shields.io/badge/-Docker-EEE.svg?logo=docker&style=flat">
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Rails】Slimで入れ子になっている要素の親タグのみを分岐させる

Slimで、入れ子になっている子タグはそのままで、親タグのみ切り替えたいケースの書き方でハマったのでメモ。

具体的にはこんな感じのHTMLを出力したいときです。

求めるHTML
<div class="User__list">

  <!-- 選択中ユーザの場合、親タグをaタグではなくdivタグにしたい -->
  <div class="User__listSection--selected">
    <div>[ユーザ名]</div>
    <div>[メールアドレス]</div>
  </div>

  <a class="User__listSection"> <!-- hrefは割愛 -->
    <div>[ユーザ名]</div>
    <div>[メールアドレス]</div>
  </a>

  <a class="User__listSection">
    <div>[ユーザ名]</div>
    <div>[メールアドレス]</div>
  </a>

  ...

</div>

ダメな例

直感的にはこう書きたいところですが、slimには end が無いのでこれだとエラーになってしまいます。

slim
.User__list
  - users.each do |user|
    - if current_user == user
      .User__listSection--selected
    - else
      a.User__listSection
    - end / slimに end は無いのでエラー!
        div #{user.name}
        div #{user.email}

実現できるけど微妙な例

一番素朴にやるとこうなると思います。

slim
.User__list
  - users.each do |user|
    - if current_user == user
      / 選択中ユーザの場合、親タグをaタグではなくdivタグにする
      .User__listSection--selected
        div #{user.name}
        div #{user.email}
    - else
      a.User__listSection
        div #{user.name}
        div #{user.email}

これは入れ子のタグを2回書いていて冗長なのであまり好ましくないですね。メンテナンス性も極めて悪いです。

動的タグを使ってちょっぴりスマートに書いた例

動的タグを使うと入れ子のタグは一度だけ書けば済むようになります。

slim
ruby:
  def user_list_section_tag(current_user, user)
    if current_user == user
      # 選択中ユーザの場合、親タグをaタグではなくdivタグにする
      { tag: 'div', class: 'User__listSection--selected' }
    else
      { tag: 'a', class: 'User__listSection' }
    end
  end

.User__list
  - users.each do |user|
    *user_list_section_tag(current_user, user)
      div #{user.name}
      div #{user.email}

複雑な分岐がある場合は動的タグを使うと良さそうですが、slimの中に急にrubyが出てくるのはちょっと気持ち悪い気がします。

content_tagを使って書いた例

content_tagでタグを生成するようにすれば、slim内にrubyを書かずに済みます。

slim
.User__list
  - users.each do |user|
    - user_list_section_attrs = current_user == user \
      ? { class: "User__listSection--selected" } \
      : { class: "User__listSection" }

    / 選択中ユーザの場合、親タグをaタグではなくdivタグにする
    = content_tag(current_user == user ? :div : :a, '', user_list_section_attrs)
      div #{user.name}
      div #{user.email}

content_tag を使えば確かにRubyを書かずに済みますが、current_user == user が2回出てきたりして、むしろこっちの方が分かりづらいのでは?という気もします。
が、純粋にslimだけで書けるのでこちらの方が僕は良いと感じています。

もっとスマートな方法があればどなたか教えて欲しいです! :bow:

追記:tagを使ってもっとスマートに書いた例

@eRy-sk さんに コメント でより良い書き方を教えていただきました!ありがとうございます!

tagsend で生成したいタグ名を分岐して渡します。

slim
.User__list
  - users.each do |user|
    - selected = current_user == user

    / 選択中ユーザの場合、親タグをaタグではなくdivタグにする
    = tag.send(selected ? 'div' : 'a', class: "User__listSection#{'--selected' if selected}")
      div = user.name
      div = user.email

content_tag だと第二引数が悲しいことになりますし、この tag を使う書き方が良さそうですね!

さらに追記: content_tagでもっとスマートに書いた例

@scivola さんに コメント でもっとスマートな書き方を教えていただきました!ありがとうございます!!!

content_tag に渡す引数として、タグ名も含めた配列を分岐して定義しておいて、それを渡すようにします。

slim
.User__list
  - users.each do |user|
    / 選択中ユーザの場合、親タグをaタグではなくdivタグにする
    - if current_user == user
      - args = [:div, class: "User__listSection--selected"]
    - else
      - args = [:a, class: "User__listSection"]
    = content_tag(*args)
      div = user.name
      div = user.email

send を使わなくてよくなりますし、これが現状一番スマートな書き方、というところでしょうか。

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

railsのcontrollerからjavascriptに対して変数を渡す

About

railsからjavascriptに対して変数を渡す方法の一つについて記載しています。
html.erbファイル内にscriptタグでjavascriptを書いた場合に変数を渡せる方法です。

Environment

この記事ではmacbook(unix)にインストールしたruby 2.5.1p57, Rails 5.2.3を使用しています。

変数の渡し方

controller内での変数の定義

まずは変数をcontroller内で定義します。
今回は配列を渡してみます。

sleeps_controller.rb
class UsersController < ApplicationController

  def show
    @user = User.find(params[:id])
    @sleeps = @user.sleeps.order('date DESC').includes(:user).limit(14).reverse
  end
end

html.erbで変数を受け取る

ここからは力技です。参考までにamchartsのスクリプトを拝借しています。
他に良い方法があると思いますので、最終手段くらいに思っていただければと思います。
また、良い方法がある方、コメントいただけると幸いです。

show.html.erb
<!-- Chart code -->
<script>
    //略
    // Add data
    var sleepings = '<%= @sleeps %>'
    // 以下略
</script>

この様にすることで、javascriptの変数として、文字列を渡すことができます。
ただし、ここで注意しなくてはいけないのが、あくまで javascript側には文字列が渡されるだけ、ということです。

そのため、以下の様に文字列を分解して、配列に変換しています。
文字列の[]をそれぞれ置換の要領で削除し、カンマでsplitし、配列化します。

show.html.erb
<!-- Chart code -->
<script>
    //略
    // Add data
    var sleepings = '<%= @sleeps %>'.replace(/\[/g, "").replace(/\]/g, "").split(',');
    // 以下略
</script>

これでjavascriptにrailsのcontrollerから値を渡す事ができます。
...ゴリ押し感が否めないですが。

最後に

ここまでゴリ押し感が強いものを共有するべきか悩みましたが、同じ様な悩みを抱えている方が少しでもいらっしゃれば、その方の助けになるかもと思い書きました。
さらに良い方法がありましたら、是非教えてください!

筆者について

TECH::EXPERTにて4月よりruby, railsを学習している未経験エンジニアです。
記載内容に不備・不足があればご指摘いただけると幸いです。
至らぬ点ばかりですので、改善点がありましたらどんどんご指摘下さい!

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