20190330のRailsに関する記事は12件です。

Materializeとsimple_formでシンプルでいい感じのフォームを作りたい!

マテリアルデザイン「Materialize」とフォームの記述がシンプルな「simple_form」の実装をしたので、メモ。
今回はシンプルなinputボックスのみとなります。selectボックスも使いたい方は下記もご参照ください。
enumを使ったselectボックスの実装

GemfileにGemを記載からのbundle install

Gemfile.
gem 'simple_form' #simple_formのGem
gem 'materialize-sass' #MaterializeのGem
gem 'jquery-rails' #記載あるか確認
ターミナル.
bundle install

「jquery-rails」の記載があるか要確認です。
無いとMaterializeが正しく表示されません場合は記載しましょう。

simple_formのインストール

ターミナル.
rails g simple_form:install

上記コマンドにより、関連ファイルの作成が作成されます。
simple_formの導入はこれでOKです。

simple_formの記述方法(例)

<%= simple_form_for @user do |f| %>
  <%= f.input :username %>
  <%= f.input :password %>
  <%= f.button :submit %>
<% end %>

上記のようにシンプルに記述することができます。
詳しくは、[Github] simple_formを参考に。

Materializeの続き

「application.css」のファイル名を「application.scss」に変更。
「materialize」を読み込みます。

application.scss
@import "materialize";

結果確認

Materialize画面.png
正常に表示されました!!

おまけ

1.画像アップロード Carrierwaveの導入方法

2.今回作成したフォームのコード

new.html.haml
.row
  = simple_form_for(@product) do |f|
    .row
      .input-field.col.s6
        = f.input :name
        = f.input :description
        = f.input :price
        = f.input :unit
        = f.input :image
        = f.button :submit

参考

[参考]Railsのform_for内のコードをすっきりさせるsimple_formの使い方
[参考]Github simple_form
[参考]Github materialize-sass
[参考]【Rails】【ソースコードあり】簡単にMaterializecssを導入する方法

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

画像アップロードCarrierwaveを導入する

画像アップロードのGem Carrierwaveの導入方法を忘れちゃうので、手順をメモ。
今回は画像リサイズのためmini_magickも導入します

Gemfileを設定

それでは早速、下記Gemをインストールします。

Gemfile.
gem 'carrierwave'
gem 'mini_magick'

そして、「bundle install」。また「rails g uploader image」でアップローダーも作成します。

ターミナル.
bundle install
rails g uploader image //アップローダーを作成

app/uploaders/image_uploader.rb //ファイルが作成されます

画像をカラムがない場合は作成しましょう。今回はproductモデルに作成します。

ターミナル.
rails g migration add_image_to_product image:string
rake db:migrate

カラムができました。追加したモデルの「product.rb」を編集し
「image_uploader」をマウントする記述をします。

product.rb
class Product < ApplicationRecord
  mount_uploader :image, ImageUploader #記述を追加
end

先ほど作成した「image_uploader.rb」を編集して、MiniMagick経由で画像のリサイズを行えるようにします

app/uploaders/image_uploader.rb
include CarrierWave::MiniMagick
process resize_to_fit: [800, 800]
#上記追記。コメントアウトされてるところもあるので、それを解除でも可。

以上で導入はOKです。

参考

[参考]carrierwaveの使い方
[参考]CarrierWaveの使い方

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

「.gitignore」をコピーし損ねてGithub desktopに膨大な変更履歴があがった話

初投稿です。
初学者の私がハマった不具合の内容と原因を共有します。

[内容]

Gitでリポジトリを作成しRailsファイルを編集していたところ、viewファイルを2~3ついじっただけでキャッシュやログのデータが1,000件以上Github desktop上にあがってしまった。

[経緯]

  • 使用するRailsアプリケーション(仮にAとする)をrails new Aコマンドで作成した。

  • そのディレクトリとは別に空のディレクトリを作成(仮にA'とする)、そのディレクトリにgit initをしてローカルリポジトリとした。

  • Railsファイル(A)をカットアンドペーストしA’に貼り付けてA’内で作業した。
    image.png上の画像の様にfinderで切り取りしてAからA'にそのままRailsファイルを貼り付けた。

[原因]image.png

実際は隠しファイルの.gitnoreは選択されていませんでした...。
.gitignore内にログやキャッシュを追跡対象から外す記述がされているので、このファイルがないとGitは全ての変更を記録してしまい、私の様に1,000件以上の変更履歴を残すことになってしまいます...。
(※因みに隠しファイルは「⌘ + shift + .(ドット)」で表示できます)

[対応]

とりあえず、Railsディレクトリ内に「.gitignore」を作成。何を追跡対象から外すのが良いかは全く見当が付かなかったので、下記リンクからRails.gitignoreのテンプレートを使用しました。

以下、色々な.gitignoreのテンプレートが載っているリポジトリです。
https://github.com/github/gitignore

また、.gitignoreを編集しても、既にGitが記録してしまっているものに対しては反映されません。ファイルを指定して追跡対象から外すこともできますが、私の場合キャッシュデータが膨大だった為、以下のコードでまとめて追跡対象から除外しました。

git rm --cached `git ls-files -i --full-name --exclude-from=.gitignore`

以下、参照させて頂いた記事です。

[参考記事]

https://qiita.com/yuuAn/items/b1d1df2e810fd6b92574
https://qiita.com/koppayashi/items/fa971b641770266af9a7

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

【まつもとゆきひろ氏 特別講演】20代エンジニアのためのプログラマー勉強法のまとめ 2019/3/30

【まつもとゆきひろ氏 特別講演】20代エンジニアのためのプログラマー勉強法のまとめ

予想していた技術的な勉強法というより、エンジニア、ビジネスマンとしての生き方や、成功するための方法論を20代に向けてMatzさんが伝えてくれたのでまとめます。(自分なりの解釈も少し入ってます)
とてもためになる講演でした。個人的には特に前談2、3、4、5、6がためになりました!!
Matzさんありがとうございました!

講演内容

前談1. テクノロジーとは人を幸せにするためのもの
前談2. 若いうちから頑張ろう
1.学生と社会人の"勉強"の違い
2.なぜ勉強するのか?
3.勉強についてのTips(what, where, when, how)
4.とにかくアウトプット
5.成功するためのTips
6.最後に3つのアドバイス

前談1. テクノロジーとは人を幸せにするためのもの

本来人を幸せにするためのテクノロジーが人を不幸にしてしまっていることがある。
もっと幸せになるために使われるべき。
EX)エントリーシート
・人事担当はチェックするのめんどい
・就活生は競争力のある就活生しか”人”をみてもらえない

前談2. 若いうちから頑張ろう

30代は遅すぎる訳ではないが、身体的にも無理がきく20代で頑張った方がいい。
20代をモラトリアムにしてしまうのはもったいない。
→故に特に若い時は戦略が必要だし、若いうちが頑張りが効くし成果も出やすい。
Ex)アインシュタインがノーベル賞をとったのは比較的若いうち
Ex)Matzは27歳でRuby開発

確かに前みたTEDで35歳までの出来事で人生の80%が決まると聞いて頑張ろうと思ったのを思い出した。
20代の人は絶対見た方がいい。

そして社会人の勉強法としてこの前談以降を参考にしてほしいとのこと

1. 学生と社会人の"勉強"の違い

まず、勉強というと学生時代にやった勉強をイメージしがちであるが学生と社会人の勉強は異なる。
こういった"勉強"という言葉の抽象化は時に便利だが、誤解や二元論に繋がったりもするので抽象的な言葉を使うときは注意が必要。

共通点

  • 知識と技術の獲得

違い

  • 満点 VS 満点なし:学校では満点あるが社会にでてから会社では満点はない。
  • 苦手克服 VS 得意を伸ばす:学生では苦手教科を克服した方が、いい成績を取る上で効率がいいが社会では得意なことを伸ばした方が効果的。
  • 暗記 VS 把握:学生のテストでは覚えてなければいけないが、会社ではわからなければではググればいい。
  • 知識 VS インデックス:同上。
  • 試験 VS 常在戦場:学校では基本テストの時の結果が大事、会社では常に仕事での成果が見られる。
  • メイン VS サブ:学ぶことは学生にとってはメイン、社会人は学ぶうこと自体はサブ、学びを使って成果を出す必要がある。

2.なぜ勉強するのか?

※以降、勉強の定義は”お勉強”ではなく”成長するための方法”
正直Matzも勉強したくない、
でも成功したい、高収入が欲しい、良好な人間関係が欲しい、嫌なことはしたくない、好きなことでいきていきたいから勉強する。
そのために必要なのは「高評価」を得ること。
→つまり勉強の目的は「尊敬」または「尊重」を得ることと言える。

3.勉強についてのTips(what, where, when, how)

what

好きなことを学ぼう。すきそこものの上手なれ。

好きなものを見つけるためには、インベントリ(棚卸し)、つまり自己分析をするべき。
得意、趣味、興味、思考、背景といった自分の特性について理解を深めることが大切。

そういえば最近読んだメモの魔力に書いてあったなー
あの本についてた自己分析の質問をやるのがいいかもしれない。

where

上でも書いたが、
成功=高評価、尊敬、尊重されること。

いい環境で学ぶ→成長する→尊敬される→モチベーションUP→もっと勉強する
といった好循環ループが入ることができる環境に自分を置くべき。
ループになることを妨げる環境からは離れていい。
win-winの好循環ループか No Dealであるべきで、そうならないのなら逃げていい。

when

まとまった時間をつくるのは意外に難しい。
だからこそ優先順位をつけるべき。
だから無意識の優先順位と意識(理想の)の優先順位を一致させる必要がある。
Ex)twitterのフォローワーをしぼるとか、情報収拾のフォーカスをしぼるとか、ただ音楽を聴いている時間をAudibleで本を聞くとか。

あとは生産性を高める。
Ex)早く仕事を終わらせて、終わったと上司にあえて伝えず、自分が得たい技術を身につけるための時間にするとか。

how

好きなことをやって稼げるのがベストだが、お金にならない可能性もある。
だから妥協と打算が大事。
どこまで妥協して、どこまでは譲れないのかを決めるということ。

Ex) Matzが就職するタイミングで言語を開発したかったけど、そんなことをしている会社はなかったので、とりあえずUnixでソフトウェア開発で食えるというところまで、妥協した。

ただ一回決めた自分の判断を永遠に信用したらいけない。
上の例の10年後、言語を開発して食っていけるようになったみたいなことが起こるから、一回妥協しても、常に可能性を模索すべき。

4.とにかくアウトプット

知識を得ることはググればいいので比較的楽である昨今、アウトプットに価値がある。
一見簡単だが、アウトプットすることで失敗したらどうしようとか、めんどくさかったりと意外にできなかったり心理的障壁がある。
Ex)Youtuberとか。「スライム風呂はいるとかだれでもできるでしょ。」的なことを思うけど、意外にみんなやらない。

でもアウトプットは人を成長させる。
ハードルを下げるためにアウトプットの質はとりあえず棚上げしても良い。
→アウトプットしていくと、アウトプットを習慣にしていくうちに楽になっていく。
→繰り返すことによって心理的障壁を下げる。

繰り返すことで変われるという人間の可塑性にかけるべき。

Ex)マークザッカーバーグは彼女に振られて大学のデータベースから女子の写真を盗み、美人コンテストしてた悪ガキ。でも今は大企業で社長を立派にやっていけてる。

5.成功するためのTips

成功するためには知名度を上げる。
→基本的にみんなミーハー、有名人を見るとそんな好きでなくても写真を撮りたくなる、サイン欲しいとかなる。

ということで知名度はそれだけで価値がある。

そのためには認知され、知られる必要がある。
故にアウトプットして、自分の価値を示す必要がある。
俺はここにいるぞ!、こんな人だぞって。

でもマタイによる福音書第13章
「おおよそ、持っている人は与えられて、いよいよ豊かになるが、持っていない人は、持っているものまでも取り上げられるであろう。」
とあるように

成功するためには成功していなければならない。

じゃあはじめに成功するには?

会社でのマーケティングなら金つかってCM打てばいいかもが、個人の場合はキャズム理論が役に立つ。

キャズム理論

5つの顧客群
イノベーター
アーリーアダプター
------------------ここにキャズム(溝)がある
アーリーマジョリティ
レートマジョリティ
ラガード

キャズム理論とは簡単にいうと、このキャズムを超えるのがむずいからターゲットを絞り、まずニッチを攻めなさいというもの。

個人でやるなら、ユニークさ、埋没しないのが大切。
ターゲットを絞り、まずニッチを攻め認知度を広げその後、横展開するのがいい戦略なのではないか。

Ex)Matzの例
言語開発者という局所的なところで認知度を高める。
→他にも講演や執筆等の横展開。

6.最後に3つのアドバイス

コンピューターサイエンス・アーキテクチャの基礎を押さえる

CSの基礎知識それ自体が差別化になりうる。
いいプログラムを書く人はコンピューターアーキテクチャをしっかり理解してる。

英語を学ぶ

まず英語があれば18億人と繋がれる。
プログラミングに限らず、最新の技術や発見は英語で発信される。
英語があればそこで一時情報を取れるが、できないと日本語に訳されるのを待つしかない。

ぺらぺらでなくても、最低、英語で情報を取る能力は身につけるべき。

またタイムマシン経営とかできる。
欧米の流行りが5年の時差で日本に来るやつ。

日本というガラパゴス諸島に囚われているのは得策ではない。

コンフォートゾーンから出る

とりあえずやってみよう!以上!

個人的な感想

まず、若いうちから頑張ろうというテーマで、35までで人生80%決まるという恐ろしい事実思い出したので、とりあえずそれまでは自分のリソースほぼ投資に使おうと改めて思った。
アウトプットの重要性についても最近認識してたので、ちょうど今日から情報発信前提のtwitterも始めた。この記事でもQiitaで初めてアウトプットしてるし継続する。
自己分析についてはもっと深掘りする必要があると最近感じて、前田さんのメモの魔力を買ったが、全然やってないので、やるべき。
環境については今のところ、問題なしかなーと思う。
時間の使い方は改善する必要ある。人生は自分の時間をどう使ったかの結果だと思うので、ここはすごい大事。
キャズム理論は勉強になった。これももっと考えるべき。
英語とコンフォートゾーンでるについては今のとこそこまで問題なしだが、CSの基礎はやはり、今のうちに固めとくべきと痛感した。

とりあえず、Matzさんの講演いってよかった!写真撮れたし!サインもらえたし!
3/30にtwitterを始めたので、よかったら!
@mokkey19930617

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

プログラミング学習記録42〜ハンバーガーメニューが究極にダサくなってしまったが、見やすくなったのでオーケー?〜

今日やったこと

  • Progate Railsのレッスンで作ったアプリをCSSでざっくりレスポンシブ化する
  • 前田裕二さんの「メモの魔力」に書かれているメモを共有できるWebアプリ作りに取り組む

今日はだいぶ進みました。

ユーザーの退会機能以外はほぼ終わりました。

Progateのアプリでは投稿内容を入力するフォームが1つだけなのですが、3つにしたものを作ってみました。

「メモの魔力」ではただファクトをメモするだけでなく、「ファクト→抽象化→転用」というフレームワークに従ってメモしていきます。

なので、「ファクト」「抽象化」「転用」の3つを分けて投稿できるようにするために、入力フォームを3つ作りました。

最初はめんどくさそうだな〜と思ったのですが、3つにするのは意外と簡単でした。

いじったところはビュー、コントローラ、データベースの3つだけです。

ルーティングはいじらずにできました。

コントローラで設定する処理の種類(アクション)もedit、show、new、index、、、などある程度使われるものが決まっているのもあって、そんなに難しくなかったんだと思います。

Herokuにデプロイして終わろうかなと思ったのですが、疲れたので今日はここで終わります。

明日、デプロイしてみてちゃんと動くかどうか確かめます。

ということで明日からも引き続きプログラミング学習頑張ります。

おわり

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

Railsチュートリアルのサンプルアプリにlike(いいね)機能を拡張する

Railsチュートリアルで作成したサンプルアプリに、like(いいね)機能を拡張します。

環境

・Rails 5.1.6
・Railsチュートリアル第4版(Rails5.1) 14章まで実装済み

仕様

・プロフィールにユーザーのlike数が表示される
・like数をクリックすると、likeしたマイクロポスト一覧が表示される
・マイクロポストにlikeボタンとlikeされた回数が表示される
・likeボタンをクリックすると、like数とボタンのlike/unlikeが非同期で更新される

完成版の動作は以下の通りです。
動作イメージ(軽量).gif

FavoriteRelationshipModel

テーブルの作成

ユーザーは複数のマイクロポストをlikeでき、また、マイクロポストは複数のユーザーからlikeされます。そのため、フォロー機能のときと同じように、中間テーブルを作成して多対多の関係を作っていきます。モデル名は、チュートリアルにならってFavoriteRelationshipとします。このFavoriteRelationshipモデルは、ユーザとマイクロポストを結びつけるため、user_idとmicropost_idを属性として持たせます。まずは以下のコマンドを実行して、マイグレーションを生成します。
rails generate model FavoriteRelationship user_id:integer micropost_id:integer

次に、インデックスを追加します。さらに、user_idとmicropost_idの組み合わせがユニークであるという制約も追加します。

/sample_app/db/migrate/[timestamp]_create_favorite_relationships.rb
class CreateFavoriteRelationships < ActiveRecord::Migration[5.1]
  def change
    create_table :favorite_relationships do |t|
      t.integer :user_id
      t.integer :micropost_id

      t.timestamps
    end
    #indexを追加
    add_index :favorite_relationships, :user_id
    add_index :favorite_relationships, :micropost_id
    add_index :favorite_relationships, [:user_id, :micropost_id], unique: true
  end
end

最後に以下のコマンドを実行して、FavoriteRelationshipテーブルを作成します。
rails db:migrate

User/Micropostの関連付け

ユーザーは複数のマイクロポストをlikeでき、マイクロポストは複数のユーザーからlikeされるという多対多の関係を、FavoriteRelationshipモデルを用いて定義します。
まず、ユーザーが、likeしたマイクロポストを複数持つことを、FavoriteRelationshipモデルを用いて以下のように定義します。これにより、user.likesでそのユーザーがlikeしたマイクロポスト一覧を取得可能になります。

/sample_app/app/models/user.rb
class User < ApplicationRecord
  :
  :
  has_many :favorite_relationships, dependent: :destroy
  has_many :likes, through: :favorite_relationships, source: :micropost
  :
  :
end

同様にして、マイクロポストが、likeしたユーザーを複数持つことを以下のように定義します。これにより、micropost.liked_byで、そのマイクロポストをlikeしたユーザー一覧が取得できるようになります。

/sample_app/app/models/micropost.rb
class Micropost < ApplicationRecord
  :
  :
  has_many :favorite_relationships, dependent: :destroy
  has_many :liked_by, through: :favorite_relationships, source: :user
  :
  :  
end

最後に、FavoriteRelationshipをユーザーとマイクロポストの両方に属するように定義します。

/sample_app/app/models/favorite_relationship.rb
class FavoriteRelationship < ApplicationRecord
  belongs_to :user
  belongs_to :micropost
  validates :user_id, presence: true
  validates :micropost_id, presence: true
end

likes関連のメソッドの追加

マイクロポストのlikeやlike解除を簡単に行えるようにするために、便利なメソッドを追加します。

/sample_app/app/models/user.rb
class User < ApplicationRecord

class UserTest < ActiveSupport::TestCase
  :
  :
  # マイクロポストをライクする
  def like(micropost)
    likes << micropost
  end

  # マイクロポストをライク解除する
  def unlike(micropost)
    favorite_relationships.find_by(micropost_id: micropost.id).destroy
  end

  # 現在のユーザーがライクしていたらtrueを返す
  def likes?(micropost)
    likes.include?(micropost)
  end

  private
  :
  :
end

これにより、user.like(micropost)でマイクロポストをlikeし、user.unlike(micropost)でマイクロポストのlikeを解除することができるようになりました。

likeページの作成

ユーザーのステータス部分にlike数を表示し、そこをクリックするとlikeしたマイクロポスト一覧を表示できるようにします。完成イメージは以下の通りです。
likeページ.png

like数の表示

ユーザーのステータス部分に、そのユーザーがlikeしたマイクロポストの総数を表示します。
まずは、以下のようにルーティングを追加します。

/sample_app/config/routes.rb
:
:
resources :users do
  member do
    get :following, :followers , :likes
  end
end
:
:

これにより、以下のようなルーティングテーブルが生成されます。

HTTPリクエスト URL アクション 名前付きルート
GET /users/1/likes likes likes_user_path(1)

次に、統計情報パーシャルに以下を追記することによって、プロフィールページとHomeページのステータス部分にlike数を表示します。

/sample_app/app/views/shared/_stats.html.erb
.
.
<a href="<%= likes_user_path(@user) %>">
    <strong id="likes" class="stat">
      <%= @user.likes.count %>
    </strong>
    likes
</a>
</div>

これで、ユーザーのステータスにlike数が追加されました。

likeしたマイクロポスト一覧の表示

ユーザーのプロフィール内のlike数をクリックすると、そのユーザーがこれまでにlikeしたマイクロポスト一覧が表示されるようにします。
まず、users_controller.rbにlikesアクションを追加します。

/sample_app/app/controllers/users_controller.rb
class UsersController < ApplicationController
  before_action :logged_in_user, only: [:index, :edit, :update, :destroy,
                                        :following, :followers, :likes]
:
:
def likes
    @title = "Likes"
    @user  = User.find(params[:id])
    @microposts = @user.likes.paginate(page: params[:page])
    render 'show_like'
end

  private
:
:

likesアクションでは、@micropostsにユーザーがlikeしているマイクロポストを代入し、show_likeビューを描画しています。このビューは以下の通り作成します。

/sample_app/app/views/users/show_like.html.erb
<% provide(:title, @user.name) %>
<div class="row">
  <aside class="col-md-4">
    <section class="user_info">
      <%= gravatar_for @user %>
      <h1><%= @user.name %></h1>
      <span><%= link_to "view my profile", @user %></span>
      <span><b>Microposts:</b> <%= @user.microposts.count %></span>
    </section>
    <section class="stats">
      <%= render 'shared/stats' %>
    </section>
  </aside>
  <div class="col-md-8">
    <h3><%= @title %></h3>
    <% if @user.likes.any? %>
      <ol class="microposts">
        <%= render @microposts %>
      </ol>
      <%= will_paginate @microposts %>
    <% end %>
  </div>
</div>

以上で、likeしたマイクロポスト一覧を表示できるようになりました。

likeボタンの作成

マイクロポストにlikeボタンを表示し、クリックでlike/unlikeの切り替えができるようにします。

likeボタンの表示

likeページのときと同様に、まずはルーティングの追加から始めます。以下のように、FavoriteRelationshipリソース用のルーティングを追加します。

/sample_app/config/routes.rb
:
:
resources :favorite_relationships, only: [:create, :destroy]
end

次に、micropostパーシャルに、like/unlikeボタンの表示を追加します。以下では、current_userがそのマイクロポストをlikeしているかどうかで、表示するボタンを切り替えています。また、後でAjaxを実装して非同期でボタンを切り替えるために、ユニークなidをspanタグに割り振っています。

/sample_app/app/views/microposts/_micropost.html.erb
:
:
  <span class="like" id="like_form_<%= micropost.id %>">
    <% if micropost.liked_by.include?(current_user) %>
      <%= render "microposts/unlike", micropost: micropost %>
    <% else %>
      <%= render "microposts/like", micropost: micropost %>
    <% end %>
  </span>
</li>

likeボタンとunlikeボタンのパーシャルは、それぞれ以下の通りです。ボタンには、Bootstrap3に用意されているglyphiconと呼ばれるアイコン集の中のハートアイコンを用いています。また、likeされた数をmicropost.liked_by.countで取得し、ハートアイコンの隣に表示しています。

/sample_app/app/views/microposts/_like.html.erb
<%= form_for(current_user.favorite_relationships.build) do |f| %>
  <div><%= hidden_field_tag :micropost_id, micropost.id %></div>
  <%= button_tag(class: "btn btn-default" ) do %>
    <%= content_tag :span, micropost.liked_by.count, class: "glyphicon glyphicon-heart-empty" %>
  <% end %>
<% end %>
/sample_app/app/views/microposts/_unlike.html.erb
<%= form_for(current_user.favorite_relationships.find_by(micropost_id: micropost.id),
             html: { method: :delete }) do |f| %>
  <%= button_tag( class: "btn btn-default") do %>
    <%= content_tag :span, micropost.liked_by.count, class: "glyphicon glyphicon-heart" %>
  <% end %>
<% end %>

最後に、ボタンの配置や色を変更するために、custom.scssに以下を追記します。

/sample_app/app/assets/stylesheets/custom.scss
:
:
/* likes */

.glyphicon-heart {
  color: red;
}
.btn-default:hover > .glyphicon-heart-empty {
  color: red;
}
.btn-default {
  position: relative;
  left: 60px;
}

ここまでで、マイクロポストにlike/unlikeボタンが表示されました。次は、これを動作させてlike機能を完成させます。

likeボタンの動作

rails generate controller FavoriteRelationshipsでFavoriteRelationshipsコントローラーを作成し、コントローラー内にcreateアクションとdestroyアクションを記述します。

/sample_app/app/controllers/favorite_relationships_controller.rb
class FavoriteRelationshipsController < ApplicationController
  before_action :logged_in_user

  def create
    micropost = Micropost.find(params[:micropost_id])
    current_user.like(micropost)
    redirect_back(fallback_location: root_url)
  end

  def destroy
    micropost = FavoriteRelationship.find(params[:id]).micropost
    current_user.unlike(micropost)
    redirect_back(fallback_location: root_url)
  end
end

ここまででlike機能が完成しました。次は、これを非同期で動作するように拡張します。

Ajaxによる非同期化

Ajaxを用いて、like/unlikeボタンをクリックした際に、ページを更新せずにlike数の更新とlike/unlikeボタンの切り替えを行うようにします。
まずは、like_formunlike_formに、remote:trueを追加します。

/sample_app/app/views/microposts/_like_form.html.erb
<%= form_for(current_user.favorite_relationships.build, remote: true) do |f| %>
:
:
/sample_app/app/views/microposts/_unlike_form.html.erb
<%= form_for(current_user.favorite_relationships.find_by(micropost_id: micropost.id),
             html: { method: :delete }, remote: true) do |f| %>
:
:

次に、FavoriteRelationshipsコントローラでAjaxリクエストに対応します。

/sample_app/app/controllers/favorite_relationships_controller.rb
class FavoriteRelationshipsController < ApplicationController
  before_action :logged_in_user

  def create
    @user = current_user
    @micropost = Micropost.find(params[:micropost_id])
    current_user.like(@micropost)
    respond_to do |format|
      format.html { redirect_back(fallback_location: root_url) }
      format.js
    end
  end

  def destroy
    @user = current_user
    @micropost = FavoriteRelationship.find(params[:id]).micropost
    current_user.unlike(@micropost)
    respond_to do |format|
      format.html { redirect_back(fallback_location: root_url) }
      format.js
    end
  end
end

最後に、Ajaxリクエストを受信時に呼び出されるJS-ERbファイルを作成します。以下では、likes数の更新と、like/unlikeボタンの切り替えを行なっています。

/sample_app/app/views/favorite_relationships/create.js.erb
$("#likes").html('<%= @user.likes.count %>');
$("#like_form_<%= @micropost.id %>").html("<%= escape_javascript(render('microposts/unlike',
                micropost: @micropost)) %>");
/sample_app/app/views/favorite_relationships/destroy.js.erb
$("#likes").html('<%= @user.likes.count %>');
$("#like_form_<%= @micropost.id %>").html("<%= escape_javascript(render('microposts/like',
                micropost: @micropost)) %>");

以上で完成です。
内容に不備がございましたら、コメントにてお知らせいただければ幸いです。

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

配列から繰り返し処理する場合にindexが欲しい場合【each.with_index】

はじめに

本項ではeach.with_indexについて解説

概要

要素にインデックスを添えて繰り返すメソッド。
要素自体に順番を示すインデックスを属性として設定していないが、処理として要素の順番を示したい場合に使用する。

使用方法

参考例.rb
Objs.each.with_index(offset){|obj,index| 〜繰り返す処理〜 }

# Objs => 繰り返す対象の配列。
# offset => 開始するインデックス番号。
# obj => 繰り返し処理中の要素の変数名。
# index => 繰り返し処理中のインデックスの変数名。

備考
- offsetを与えない場合、indexは0から始まります。

使用例(offsetなし)

使用例(offsetなし).rb
animals = ["cat","dog","mouse"]

animals.each.with_index {|animal,i|
  puts "#{i}番目は#{animal}です。"
}

出力結果は以下

0番目はcatです
1番目はdogです
2番目はmouseです

使用例(offsetあり)

人間の感覚で0から始まると気持ちが悪いのでoffsetに1を与えると良いと思います。

使用例(offsetあり).rb
animals = ["cat","dog","mouse"]

animals.each.with_index(1) {|animal,i|
  puts "#{i}番目は#{animal}です。"
}

出力結果は以下

1番目はcatです
2番目はdogです
3番目はmouseです

参考記事

each_with_index (Enumerable) - Rubyリファレンス

内容のみならず、レイアウトや書き方にアドバイスがある方はお気軽に(優しく)コメントを頂けると助かります。

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

配列から繰り返し処理する際にindexが欲しい場合【each.with_index】

はじめに

本項ではeach.with_indexについて解説

概要

要素にインデックスを添えて繰り返すメソッド。
要素自体に順番を示すインデックスを属性として設定していないが、処理として要素の順番を示したい場合に使用する。

使用方法

参考例.rb
Objs.each.with_index(offset){|obj,index| 〜繰り返す処理〜 }

# Objs => 繰り返す対象の配列。
# offset => 開始するインデックス番号。
# obj => 繰り返し処理中の要素の変数名。
# index => 繰り返し処理中のインデックスの変数名。

備考
- offsetを与えない場合、indexは0から始まります。

使用例(offsetなし)

使用例(offsetなし).rb
animals = ["cat","dog","mouse"]

animals.each.with_index {|animal,i|
  puts "#{i}番目は#{animal}です。"
}

出力結果は以下

0番目はcatです
1番目はdogです
2番目はmouseです

使用例(offsetあり)

人間の感覚で0から始まると気持ちが悪いのでoffsetに1を与えると良いと思います。

使用例(offsetあり).rb
animals = ["cat","dog","mouse"]

animals.each.with_index(1) {|animal,i|
  puts "#{i}番目は#{animal}です。"
}

出力結果は以下

1番目はcatです
2番目はdogです
3番目はmouseです

参考記事

each_with_index (Enumerable) - Rubyリファレンス

内容のみならず、レイアウトや書き方にアドバイスがある方はお気軽に(優しく)コメントを頂けると助かります。

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

rails モーダル表示サンプル

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

Ruby on Rails スタートライン〜アプリ立ち上げ〜

開発の道具

  • ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-darwin17]
  • Rails 5.2.2

アプリ立ち上げ

ターミナルでコマンド入力

$ rails new tweet-app

これでtweet-appというフォルダが作成され、フォルダの中にappやらbinやら色んなフォルダが生成されました。

早速、ブラウザで見てみたいと思います。

まずはtweet-appに移動します。(最初の頃はこれがわからずに苦労した)
次にサーバーを立ち上げます。

コマンドは以下の通りです。

$ cd tweet-app
$ rails server

ブラウザで、http://0.0.0.0:3000/ を開いてください。
image.png

あれ、、、

原因について調べてみると、どうやらsqlite3のloadにエラーが出ているみたい。
image.png

先ほど生成したtweet-appフォルダの中身(tweet-app/bin)を確認したら、sqlite3が入っておりません。
image.png
そこでsplite3は手動で導入します。

sqlite3の導入

以下コマンドでsqlite3がインストールしましょう。

$ gem install sqlite3

spotliteでsqlite3を検索 。
デベロッパとしてsqlite3がありますので、ドラッグ&ドロップでtweet-appのbinフォルダに移動させます。
image.png
こんな感じでtweet-app/binフォルダの中にsqlite3が導入されました。
image.png

もう一回ブラウザチャレンジ

さあ、これでブラウザで開けるはずです。
http:/0.0.0.0.3000で更新しましょう。
image.png
あれ、、、
まだどこかおかしいようです。

原因について

このエラーの原因をめっちゃ調べました。

teratailの記事にも同じようなトラブルに見舞われた人がいたようで・・・
https://teratail.com/questions/174121

結論から言うと、
image.png
らしいです。

そこで、tweet-appのGemfileを開き、修正することにします。
これを・・・
image.png

こう修正
image.png

で、ターミナルでbundle installします。

ひとつ注意なのが、rails serverを実行しているターミナルではなく、新しくターミナルのウィンドウを開いて、そこから実行してください。

コマンドは以下の通りです。

$ cd tweet-app #tweet-appに移動
$ bundle install

こうすると、インストールが完了します。

3度目の正直

できているでしょうか。
Chromeで、http:0.0.0.0:3000にアクセスします。

image.png

無事にできていることが確認できました。

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

Ruby on Railsを触ってみる

はじめに

RoRがどんなものか試してみたかった。
雑ですが、また同じことを調べなくて済むようにメモ。
ちなみにsqliteもお初。

前提

Ubuntu 16.04
Ruby 2.4.1p111
Rails 5.2.3
Sqlite 2.4.1p111

プロジェクト作成

プロジェクト作成からscaffoldingまで。

## プロジェクト作成
$ rails new cafe
$ cd cafe/
## サーバ起動→http://localhost:3000でYay!が出ることを確認。
$ rails s
## 日記機能を生成
$ rails g scaffold diary title:string body:text 
## scaffoldingした機能がURLマッピングされていることを確認
$ rails routes
## scaffoldingの結果を元にDBにテーブルを追加する
$ rails db:migrate

ちなみにscaffoldするときのstringは省略可能。デフォルトの型はstringのため。

DBにアクセスしてみる

"rails db"でDBコンソールにログインする。

### DBコンソール(sqlite)にログインする
$ rails db
### テーブル一覧を見てみる
sqlite> .tables
### テーブル定義を確認する
sqlite> .schema diaries
CREATE TABLE "diaries" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar, "body" text, "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL);
### select結果にカラム名も出す
sqlite> .headers on
sqlite> .mode column
### SELECTしてみる
sqlite> SELECT * FROM diaries;
### sqliteコンソールを抜ける
sqlite> .quit

Viewをいじってみる

更新日時を追加してみる。ヘッダとかも日本語にする。

app/views/diaries/index.html.erb
<p id="notice"><%= notice %></p>

<h1>日記一覧</h1>

<table>
  <thead>
    <tr>
      <th>タイトル</th>
      <th>本文</th>
      <th>更新日時</th> <!-- 追加 -->
      <th colspan="3"></th>
    </tr>
  </thead>

  <tbody>
    <% @diaries.each do |diary| %>
      <tr>
        <td><%= diary.title %></td>
        <td><%= diary.body %></td>
        <td><%= diary.updated_at %></td> <!-- 追加 -->
        <td><%= link_to '見る', diary %></td>
        <td><%= link_to '編集', edit_diary_path(diary) %></td>
        <td><%= link_to '削除', diary, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
    <% end %>
  </tbody>
</table>

<br>

<%= link_to '日記を新規作成する', new_diary_path %>

updated_atはscaffoldingの際に指定してないが、Railsが勝手に追加してくれる。

日付形式を変更する

最初はUTCになっているので、JSTに変更&表示形式も変更する。

JSTへ変更

config/application.rb へ
config.time_zone = 'Tokyo' を追加。

config/application.rb
require_relative 'boot'

require 'rails/all'

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module Cafe
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 5.2
    config.time_zone = 'Tokyo'
    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration can go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded after loading
    # the framework and any gems in your application.
  end
end

time_formats.rb の作成

以下を記入したconfig/initializers/time_formats.rbを作成する。

time_formats.rb
Time::DATE_FORMATS[:default] = "%Y/%m/%d %H:%M"

確認

再起動して更新日時が"%Y/%m/%d %H:%M"で表示されていることを確認。

scaffoldとは

参照・登録・編集・削除の機能を持つアプリの雛形を作成するジェネレータコマンド。
コマンド1つで必要なファイルを一括して作成してくれるのでとても便利だが、
これしか使わないとRailsがいつまでたっても理解できないので乱用はよろしくないってよく言われるらしい。他の言語でプログラミングとかMVCの基礎を学んでいる人は別にいいと思う。もちろんscaffoldを使わない方法も知る必要がある。
以下でコントローラから機能を作成する手順も載せる。

コントローラ生成からスタートして機能を作成する

コントローラの生成

usersコントローラとそれが持つindexアクションを生成。
コントローラだけでなくビューなどいろいろ生成されていることがわかる。

$ rails g controller users index
Running via Spring preloader in process 9407
      create  app/controllers/users_controller.rb
       route  get 'users/index'
      invoke  erb
      create    app/views/users
      create    app/views/users/index.html.erb
      invoke  test_unit
      create    test/controllers/users_controller_test.rb
      invoke  helper
      create    app/helpers/users_helper.rb
      invoke    test_unit
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/users.coffee
      invoke    scss
      create      app/assets/stylesheets/users.scss

生成されたコントローラ

app/controllers/users_controller.rb
class UsersController < ApplicationController
  def index
  end
end

以下の通り、処理がない場合は紐づくビューが呼ばれる。
Action Controller の概要 - 3 メソッドとアクション

ここでご注目いただきたいのは、newメソッドの内容が空であるにもかかわらず正常に動作するという点です。これは、Railsではnewアクションで特に指定のない場合にはnew.html.erbビューを描画するようになっているからです。

よって空のusers/indexアクションはapp/views/users/index.html.erbを返す。
※ちなみにerbは(embedded ruby)の略。

ルーティング追加

config/routes.rbにgetの2行を追加。usersとusers/indexにアクセスがあった場合はusersコントローラのindexアクションを実行するという意味。

config/routes.rb
Rails.application.routes.draw do
  get 'users', to: 'users#index'
  get 'users/index', to: 'users#index'
  resources :diaries
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end

modelの生成

タイヤ、エンジン、ハンドルを属性に持つ車モデルを定義。
モデルクラスとマイグレーションファイルが生成されている。

$ rails g model car tire:string engine:string handle:string
Running via Spring preloader in process 12514
      invoke  active_record
      create    db/migrate/20190329170956_create_cars.rb
      create    app/models/car.rb
      invoke    test_unit
      create      test/models/car_test.rb
      create      test/fixtures/cars.yml

作成されたモデルクラスcar.rbを見ると処理は記載されていないがこのクラスがあるだけでcarsテーブルにアクセスできるようになる。

マイグレーションの実行

Rails4まではrakeコマンドで行う必要があったが5からはrailsコマンドに吸収されたため以下のようにマイグレーションやroutesもrailsコマンドで実施できる。

$ rails db:migrate
== 20190329170956 CreateCars: migrating =======================================
-- create_table(:cars)
   -> 0.0024s
== 20190329170956 CreateCars: migrated (0.0025s) ==============================

このあとrails dbコマンドでDBコンソールを開いてcarsテーブルが作成されていることを確認。

ERBの記述のルール

記号 動作 サンプル
<% %> コードとして実行 <% if @test.present? %>Test<% end %>
<%= %> 変数の中身を出力 <%= @test %>

コントローラからビューへ変数を渡す

app/controllers/users_controller.rb
class UsersController < ApplicationController
  def index
    @test='テストだよ!!'
    render template: 'users/index'
  end
end
app/views/users/index.html.erb
<h1>Users#index</h1>
<p><%= @test %></p>
<p><% if @test.present? %>test test test<% end %></p>

結果

Users#index
テストだよ!!
test test test

が画面に表示される。

デザインの変更

共通のレイアウトは以下のファイルで定義されている。
app/views/layouts/application.html.erb
ここに共通で適用したいcssとかjavascriptを設定してあげればOK。

ページごとにデザインを変えたい場合

assetを追加する

app/assets/javascripts/users.coffee
.users-index {
  font-size: 20px;
}
app/assets/stylesheets/users.scss
alert('Hi user!');

のように、coffeeまたはscssを配置する。(ファイル名はassets.rbに指定する)

assets.rbのprecompileのコメントアウトを外す

指定するのはSprocketsによって変換された後のjs、css。

config/initializers/assets.rb
Rails.application.config.assets.precompile += %w( users.js users.css )

サーバを再起動してポップアップが出ることと、文字がおっきくなっていることを確認。

Sprocketsとは

coffeescriptやscssからJavascriptやcssを生成する仕組みを管理する。

ActiveRecordとは

Railsが採用するO/Rマッパー。
SQLを使用せずにDBにアクセスする。
rails g modelコマンドでActiveRecordによるモデルクラスを生成する。
このコマンドを使用するとテーブル作成SQLを実行するためのマイグレーションファイルも作成してくれる。

マイグレーションとは

テーブルの新規作成や変更を簡単に行うための仕組み。
DBMSによる違いを吸収して記述することができる。
以下はdiaryをg scaffoldした時のマイグレーションファイル。
timestampsはupdated_atなどのメタ情報。

db/migrate/20190328140515_create_diaries.rb
class CreateDiaries < ActiveRecord::Migration[5.2]
  def change
    create_table :diaries do |t|
      t.string :title
      t.text :body

      t.timestamps
    end
  end
end

あとがき

ほんとはWindows+VSCodeで試したかったけど8年選手の低スペックマシンでは耐え切れなかったのでUbuntu16+Atomで試しました。
次は簡単なWEBページを作成してみようと思います。

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

はじめてのCircleCI。Railsプロジェクトで試してみる。

CIツールを入れて生産性バク上げしたい。今回はよく聞くCIツール、CircleCIを使ってみた。

この記事のゴール

RSpecで書いたRuby on RailsのアプリをCircleCI上でテストする

動作環境

ruby 2.5.1
rails 5.2.2
CircleCI 2

アプリケーションのセットアップ

まず、Railsアプリのセットアップ。無心でセットアップしていく。

$ rails new circle-ci-test -d mysql
$ cd circle-ci-test
$ rails db:create
$ rails g rspec:install
$ rails g scaffold product title:string content:text
$ rails db:migrate
$ rails s

以上でproductリソースをCRUD処理する機能が出来上がった。下記みたいなカンジ。

Image from Gyazo

テストをCIで試してみたいので、RSpecを書いていく。

specを書く

コントローラのspecが自動で生成されているが、モデルのほうがテストを書くのが簡単なので、コントローラのspecはぶち消す。productモデルにバリデーションを実装して、そのテストを書いていく。

product.rb

class Product < ApplicationRecord
  validates :title, :content, presence: true
  validates :title, length: { in: 5..20 }
end

product_spec.rb

require 'rails_helper'

RSpec.describe Product, type: :model do
  it 'title, contentが存在するので、バリデーションが通る' do
    product = Product.new(title: 'こんにちは!', content: 'うあはうあ!')
    expect(product).to be_valid
  end
  it 'titleが存在しないので、バリデーションが弾かれる' do
    product = Product.new(content: 'しょーもない人生')
    expect(product).not_to be_valid
  end
  it 'contentが存在しないので、バリデーションが弾かれる' do
    product = Product.new(title: 'スマブラ強くなりてえ!!!!')
    expect(product).not_to be_valid
  end
  it 'titleが5文字未満なので、バリデーションが弾かれる' do
    product = Product.new(title: 'パクチー')
    expect(product).not_to be_valid
  end
end

テストを実行

$ bundle exec rspec
...

Finished in 0.01224 seconds (files took 0.81481 seconds to load)
4 examples, 0 failures

OK、テストアプリはできた。以上をコミットしてGithubリポジトリを作ってpushする。

CircleCIのセットアップ

CircleCIにサインアップして、GirHub連携をするとダッシュボードが表示されて、以下のカードが表示される。
Image from Gyazo
この画像通りに設定をしてみる。

circle-ci-testレポジトリ発見。Set Up Projectボタンを押す。
Image from Gyazo

ボタンを押すとこんな画面に。
Image from Gyazo

下の方に優しく設定方法が書いてある。これに従えば基本的なセットアップができる親切設計。最高
Image from Gyazo

この順に設定していく。

$ mkdir .circleci && cd .circleci && touch config.yml && cd ..

config.ymlを以下の設定にする。
ちょっと試行錯誤した。

# Ruby CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/language-ruby/ for more details
#
version: 2
jobs:
  build:
    docker:
      # specify the version you desire here
      - image: circleci/ruby:2.5.1-node-browsers
        environment:
          RAILS_ENV: test
          MYSQL_HOST: 127.0.0.1
          MYSQL_USERNAME: 'root'
          MYSQL_PASSWORD: ''
          MYSQL_PORT: 3306
      - image: circleci/mysql:5.7.18
        environment:
          MYSQL_ALLOW_EMPTY_PASSWORD: true
          MYSQL_ROOT_PASSWORD: ''
          MYSQL_DATABASE: circle_ci_test-test

      # Specify service dependencies here if necessary
      # CircleCI maintains a library of pre-built images
      # documented at https://circleci.com/docs/2.0/circleci-images/
      # - image: circleci/postgres:9.4

    working_directory: ~/circle-ci-test

    steps:
      - checkout

      # Download and cache dependencies
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "Gemfile.lock" }}
            # fallback to using the latest cache if no exact match is found
            - v1-dependencies-

      - run:
          name: install dependencies
          command: |
            bundle install --jobs=4 --retry=3 --path vendor/bundle

      - save_cache:
          paths:
            - ./vendor/bundle
          key: v1-dependencies-{{ checksum "Gemfile.lock" }}

      # Database setup
      - run:
          name: waiting for stating database
          command: dockerize -wait tcp://127.0.0.1:3306 -timeout 1m
      - run: bundle exec rake db:create
      - run: bundle exec rake db:schema:load

      # run tests!
      - run:
          name: Run rspec in parallel
          command: |
            bundle exec rspec --profile 10 \
                              --format RspecJunitFormatter \
                              --out test_results/rspec.xml \
                              --format progress \
                              $(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings)

      # collect reports
      - store_test_results:
          path: /tmp/test-results
      - store_artifacts:
          path: /tmp/test-results
          destination: test-results

また、Gemfileに以下を追加する

gem 'rspec_junit_formatter'

bundle installしてpushすると、自動でGithubでビルド&テスト実行される!
Image from Gyazo

雑感

めっちゃ簡単!チーム開発する場合はどんどん入れていきたいところ!

また、上のプロジェクトをGithubのパブリックなリポジトリに登録していたらCircleCIからフィードバックアンケートのお願いのメールが来た。ユーザーと共に良いプロダクトを作っていて最高でございます。

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