Rails5でローカルではsqlite3で動かしてHerokuではPostgresを使う手順
group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] # Adds support for Capybara system testing and selenium driver gem 'capybara', '~> 2.13' gem 'selenium-webdriver' # Use sqlite3 as the database for Active Record gem 'sqlite3' end group :production do gem 'pg' gem 'rails_12factor' end
default: &default adapter: sqlite3 pool: 5 timeout: 5000 development: <<: *default database: db/development.sqlite3 test: <<: *default database: db/test.sqlite3 production: <<: *default adapter: postgresql database: myapp_production username: myapp password: <%= ENV['MYAPP_DATABASE_PASSWORD'] %>
ローカル
bundle install rake db:create rails s
- RailsをHerokuにpushするときにsqlite3でエラーが起こる https://tex2e.github.io/blog/rails/rails-on-heroku
Heroku
heroku run rails db:migrate git push heroku master
package.jsonのdevDependenciesとdependenciesの使い分け
devDependencies
- ライブラリをdev(開発)する時に必要なライブラリを書く
- 開発時のみに必要で実行時には入らないもの
- テストツール - ビルドツール - タスクランナー等
- dependenciesに含まれていても動作はする。ただバンドルファイルの容量が増えたり用途がわからなくなったりするので分けた方がいい
dependencies
- ユーザーとしてライブラリを使う時に必要なライブラリを書く
npm install
- dependenciesとdevDependencies両方がインストールされる
本番環境でnpm installする時
- dependenciesさえインストールされればいいはず
NODE_ENV=production npm install
NODE_ENVにproductionを指定すればdependenciesだけ入る
ちなみにHeorokuはデフォルトdependenciesだけインストールされる設定になっている
VSCodeにES6+ReactのESLint設定を行う
1. eslintをプロジェクトのローカルにインストール
yarn add --dev eslint
手軽さからグローバルにインストールする例もありますが、 チームで開発する場合は以下の理由からローカルにインストールした方がいいです
2. eslint-config-airbnbをインストール
$ yarn add --dev eslint-config-airbnb eslint-plugin-import eslint-plugin-react eslint-plugin-jsx-a11y babel-eslint
3. VSCodeのESLint連携用のプラグインをインストール
4. 設定ファイルを用意
- eslintrcの拡張子にはJavaScript,JSON,YAMLがある
- 拡張子無しの
.eslintrc
はJSON,YAMLで記述可能ですが現在は非推奨
です
{ "extends": ["airbnb"], //ESlint標準のパーサーだとES6の一部記法が認識できずパースエラーになるのでbabel-eslintを使う "parser": "babel-eslint", "plugins": [ //Reactのチェックに必要 "react" ], "rules": { } }
上記の設定だとかなりキツめの設定なので使ってみて気に入らない所はrules
に追記して行くのがいいでしょう
5. AutoFixを有効にする
{ "eslint.autoFixOnSave": true }
ESLintが何か動かないぞ?という時
Parsing errorになっている
- 必要なプラグインがインストールされていなかったり、パーサーがES6に対応していなかったりしてパースエラーになっている可能性があります
- ESlintはパースエラーになると、そこから後のチェックはしてくれないです
Rubyの&とRailsの#tryの違い
Rubyの&.
- ruby2.3から追加された新しい演算子
- Safe Navigation Operator(
&.
)
10&.to_s # => "10" nil&.to_s # nil
- レシーバが
nil
でない場合にメソッドを呼び出す - レシーバが
nil
の場合はnil
を返す
Railsの#try
- ActiveSupportで提供されるメソッド
10.try(:to_s) # => "10" nil.try(:to_s) # => nil 10.try(:to_hoge) # => nil
- レシーバがメソッドを呼び出せる場合にそのメソッドを呼び出す
- 呼び出せない場合は
nil
を返す
&.
と#try
の違い
&.
はレシーバがnilじゃないけど呼び出せないメソッドを呼びだそうとした時にNoMethodErrorになります
10.try(:to_hoge) # => nil 10&.to_hoge # => NoMethodError: undefined method `to_hoge' for 10:Integer
hoge = { fuga: 'fuga' } hoge.try(:hogee) # => nil hoge&.(:hogee) # => NoMethodError: undefined method
結論
Railsでレシーバがnilではない時にメソッドを呼び出したいという時はtryを使うのが無難
ちなみにそもそも存在しない変数に対してアクセスしようとした時はtryを使ってもNameErrorになります。
aaaaaaaaa.try(:to_s) NameError: undefined local variable or method `aaaaaaaaa' for main:Object
HerokuにRails5のアプリをデプロイする
Herokuにログインする
$ heroku login
Postgresを使ったアプリを作成
$ rails new myapp --database=postgresql
動作確認用にコントローラーを作っておく
$ rails generate controller welcome
<h2>Hello World</h2> <p> The time is now: <%= Time.now %> </p>
- app/views/welcome/index.html.erb
root 'welcome#index'
- config/routes.rb
rubyのバージョンファイルを作る
rbenv local 2.4.0
ruby "2.4.0"
- ローカルで使っているrubyと同じバージョン番号をGemfileの最後に書く
Herokuにプッシュする
git remote add heroku https://git.heroku.com/myapp.git git push heroku master
CarrierwaveでUUIDを使ったファイル名にする方法
UUIDとは
- Universally (普遍的に) Unique (一意な) IDentifier (識別子) の略
- 誰でも作れるが世界中で重複しないようになっているID
- RFC4122という共通の規格が決められている
UUIDの種類
- UUIDの作成方法には5種類存在する。
1: 時刻とMACアドレスを元にするバージョン 2: DCEセキュリティバージョン 3: バイト列を元にするバージョン。MD5ハッシュを利用 4: ランダム生成するバージョン 5: バイト列を元にするバージョン。SHA-1ハッシュを利用
- RubyのSecureRandom.uuidはバージョン4
- 16進数を32桁で乱数生成したもの
- 340澗(かん)通り。重複はしないと考えていい。
www.slideshare.net
なぜUUIDを使うのか?
- ファイル名にIDを使っている場合、推測ができてしまい他のユーザーが閲覧できてしまう
- IDからサービスのユーザー数がバレてしまう
上記のようなニーズからUUIDは使われる
UUIDにする方法
- xxx_uploader.rbのfilenameメソッドを上書きすればいい
def filename "#{SecureRandom.uuid}.#{file.extension}" if original_filename end
公式では以下のような書き方がサンプルにあるが、uuidだけでも十分だし読みやすいのでいいのではと思っている。
def filename "#{secure_token}.#{file.extension}" if original_filename.present? end protected def secure_token var = :"@#{mounted_as}_secure_token" model.instance_variable_get(var) or model.instance_variable_set(var, SecureRandom.uuid) end
Rails5でajaxを使っていいね機能を実装する
ルーティングを用意する
resources :diaries do resources :diary_comments, only: [:create] resources :diary_likes, only: [:create, :destroy] end
- diaryが重複するので後でスッキリさせる
モデルを用意する
class Diary < ApplicationRecord belongs_to :user has_many :diary_likes, dependent: :destroy # ユーザーのいいねを取得 def like(user_id) diary_likes.find_by(user_id: user_id) end end
部分テンプレートを用意する
<% if diary.like(user.id) %> <button class="btn btn-default btn-xs disabled" type="button"> <i class="fa fa-thumbs-o-up">いいね済み</i> </button> <% else %> <button class="btn btn-default btn-xs" type="button"> <i class="fa fa-thumbs-o-up">いいね</i> </button> <% end %> <% else %>
button_toに書き換える
<%= button_to diary_likes_path(diary), remote: true, class: "btn btn-default btn-xs" do %> <i class="fa fa-thumbs-o-up">いいね</i> <% end %>
- button_toは実際にはformとbuttonタグとして出力される。こんな感じ
<form class="button_to" method="post" action="/diaries/1/likes" data-remote="true" <button class="btn btn-default btn-xs" type="submit"> <i class="fa fa-thumbs-o-up">いいね</i> </button> <input type="hidden" name="authenticity_token" value="xx"> </form>
<% if diary.like(user_id) %> <%= button_to diary_diary_like_path(diary, diary.like(user_id)), remote: true, method: :delete, class: "btn btn-default btn-xs" do %> <i class="fa fa-thumbs-o-up">いいね済み</i> <% end %> <% else %> <%= button_to diary_diary_likes_path(diary), remote: true, class: "btn btn-default btn-xs" do %> <i class="fa fa-thumbs-o-up">いいね</i> <% end %> <% end %> <% else %>
いいねボタンを用意
.like-button{:class => "like-button-#{diary.id}"} = render "diary_likes/like", diary: diary, user_id: diary.user_id
- 日記ごとに部分テンプレート化したいいね!ボタンをrenderする
いいね機能を実装する
def create @like = DiaryLike.new(user_id: current_user.id, diary_id: params[:diary_id]) @like.save end def destroy @like = DiaryLike.find_by(user_id: current_user.id, diary_id: params[:diary_id]) @like.destroy end
- diary_idしか送られてこない & そのまま保存するわけでもないのでストロングパラメータは不要
- remote: trueで送っているので、xxx.js.erbが呼ばれる
create.js.erbを作成
$(".like-button-<%= @like.diary_id %>").html("<%= j(render partial: 'like', locals: { diary: @like.diary, user_id: @like.user_id }) %>")
destroy.js.erbを作成
$(".like-button-<%= @like.diary_id %>").html("<%= j(render partial: 'like', locals: { diary: @like.diary, user_id: @like.user_id }) %>")