- 投稿日:2019-04-03T23:37:55+09:00
[RUBY] %記法
%記法
「’ ‘」や「” “」に対するエスケープを省略するためのもの。
%w
文字列の配列の("")
などを省略することができる。例:
puts ["test1", "test2", "test3"]%wを使えばスッキリ書くことができる。
puts %w(test1 test2 test3)また、%Wと%wの違いは以下の通り。
%W→変数の式展開あり
%w→変数の式展開なし%と%Q
「” “」(ダブルクォーテーション)の代替をする。
例:
puts "\"テスト\" \"サンプル\""puts %("テスト","サンプル")さいごに
まぁ、%wがめちゃ便利だということがわかりました。
- 投稿日:2019-04-03T22:07:27+09:00
Railsで「投稿お気に入り追加機能」を実装する
プログラミングスクールの発展的な課題で、【Railsで「投稿お気に入り追加機能」」の実装】がありましたが、難易度が高く理解するのに数十時間を要しため、簡単に整理します。
なお、ユーザーUserモデルと投稿Micropostモデルの中間テーブルをFavoriteモデルとして定義し、進めていきます。
説明は、基本的に「投稿お気に入り追加機能」の実装に絞ります。
モデルを作成する
Userモデルの作成
Userモデルはログイン機能を実装することを前提にしています。
rails g model User name:string email:string password_digest:string下記のマイグレーションファイルが作成されます。
class CreateUsers < ActiveRecord::Migration[5.0] def change create_table :users do |t| t.string :name t.string :email t.string :password_digest t.timestamps end end endMicropostモデルの作成
MicropostモデルはUserモデルに関連づけることを前提にしています。
rails g model Micropost content:string user:references下記のマイグレーションファイルが作成されます。
class CreateMicroposts < ActiveRecord::Migration[5.0] def change create_table :microposts do |t| t.string :content t.references :user, foreign_key: true t.timestamps end end endFavoriteモデルの作成
rails g model Favorite user:references micropost:references下記のマイグレーションファイルさ作成されるので、
t.index [:user_id, :micropost_id], unique: true
を追加します。これは、
user_id
とmicropost_id
の組み合わせが重複して保存されないようにするためです。class CreateFavorites < ActiveRecord::Migration[5.0] def change create_table :favorites do |t| t.references :user, foreign_key: true t.references :micropost, foreign_key: true t.timestamps t.index [:user_id, :micropost_id], unique: true #ここを追記 end end end関連モデルを追記する
Favoriteモデルの確認
favorite.rbclass Favorite < ApplicationRecord belongs_to :user belongs_to :micropost endMicropostモデルの追記
has_many :favorites
でMicropostモデルは複数のFavoriteモデルに関連づけられることを定義します。
foreign_key
にはFavariteモデル作成時に追加したt.index [:user_id, :micropost_id], unique: true
におけるmicropost_id
を追加します。
has_many :users, through: :favorites
では、MicropostモデルはFavoriteモデルを介して複数のUserモデルに関連づけられることを定義します。micropost.rbclass Micropost < ApplicationRecord belongs_to :user validates :content, presence: true, length: { maximum:255 } #お気に入り機能追加用中間テーブル追加 has_many :favorites, foreign_key: 'micropost_id', dependent: :destroy has_many :users, through: :favorites endUserモデルの追記
Userモデルの追記は複雑で、この投稿お気に入り追加機能の一番重要な部分です。
Userモデルは
has_many :microposts
複数のMicropostモデルに紐づけられます。次に、Micropostモデル追記時と同様に、
has_many :favorites
でUserモデルは複数のFavoriteモデルに関連づけられることを定義します。ここがかなり重要で、
has_many :favposts, through: :favorites, source: :micropost
は、UserモデルがFavoriteモデルを介して複数のMicropostモデルと関連づけます。しかし、すでにhas_many :microposts
が使用されているため、favposts
と定義し、source: :micropost
によって情報元はmicropostだと補足することで中間モデルで定義されたbelongs_to :micropost
と関連づけます。user.rbclass User < ApplicationRecord before_save { self.email.downcase! } validates :name, presence: true, length: { maximum: 50} validates :email, presence: true, length: { maximum: 50}, format: { with: /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i }, uniqueness: { case_sensitive: false } has_secure_password #Userモデルは複数のMicropostモデルに関連づけられる has_many :microposts #お気に入り機能追加用 has_many :favorites has_many :favposts, through: :favorites, source: :micropost投稿お気に入り追加メソッドを追加
like(micropost)
メソッドでは、favoritesテーブルに保存されているFavoriteモデル作成時に定義したmicropost_id
を投稿一覧のインスタンスmicropostのidであるmicropost.id
と照合(find)し、見つからなければ新規に作成(create)します。
unlike(micropost)
メソッドでは、favoritesテーブルに保存されているFavoriteモデル作成時に定義したmicropost_id
を投稿一覧のインスタンスmicropostのidであるmicropost.id
と照合(find)し、削除します。likeメソッド違いcreate
されない点がポイントです。
favpost?
メソッドでは、お気に入り追加した投稿が、投稿一覧の投稿一覧のインスタンスmicropostを含むかどうかを判定しています。含んでいればtrue
含んでいなければfalse
を返すメソッドです。user.rbclass User < ApplicationRecord #お気に入り追加 def like(micropost) favorites.find_or_create_by(micropost_id: micropost.id) end #お気に入り削除 def unlike(micropost) favorite = favorites.find_by(micropost_id: micropost.id) favorite.destroy if favorite end #お気にり登録判定 def favpost?(micropost) self.favposts.include?(micropost) end endrails console で確認
user = User.find(1) micropost = Micropost.find(1) #favoritesテーブルに保存されるか確認 user.like(1) #trueが返り値となるか確認 user.favpost?(micropost) #favoritesテーブルから削除されるか確認 user.unlike(1)お気に入り追加の確認
お気に入り登録判定の確認
user1.favpost?(micropost1)
で=> true
が表示されたら成功です。user1.favpost?(micropost1)お気に入り削除の確認
Favorite.all
でuser_idとmicropost_idの組み合わせが表示されなくなったら成功です。user1.unlike(micropost1) Favorite.allcontrollerの作成
favoritesコントローラー
このコントローラーは投稿一覧に「お気に入り登録」もしくは「お気に入り削除」機能を追加します。
そのため、元となる投稿一覧のインスタンスが
@micropost.each do |micropost|
で取り出されたmicropost
である点が超重要です。決して@が付く@micropost
では無いのです。
user.rb
で定義したlike
メソッドを用いて、micropostをお気に入り登録します。favorites_controller.rbclass FavoritesController < ApplicationController def create #@micropostとはならないよ micropost = Micropost.find(params[:micropost_id]) current_user.like(micropost) flash[:success] = 'お気に入り登録をしました。' redirect_back(fallback_location: root_path) end def destroy micropost = Micropost.find(params[:micropost_id]) current_user.unlike(micropost) flash[:success] = 'お気に入り登録を解除しました。' redirect_back(fallback_location: root_path) end endusersコントローラー
likesメソッド
でuserがお気に入り登録した投稿の一覧を取得します。user.rbで定義したお気に入り登録した投稿である
favposts
を用いて@favposts
を取得します。users_controller.rbclass UsersController < ApplicationController before_action :require_user_logged_in, only: [:index, :show, :followings, :followers, :likes] def index @users = User.all.page(params[:page]) end def show @user = User.find(params[:id]) @microposts = @user.microposts.order('created_at DESC').page(params[:page]) counts(@user) end def new @user = User.new end def edit end def create @user = User.new(user_params) if @user.save flash[:success] = 'ユーザ登録しました' redirect_to @user else flash[:danger] = 'ユーザの登録に失敗しました' render :new end end def followings @user = User.find(params[:id]) @followings = @user.followings.page(params[:page]) counts(@user) end def followers @user = User.find(params[:id]) @followers = @user.followers.page(params[:page]) counts(@user) end #お気に入り投稿一覧取得 def likes @user = User.find(params[:id]) @favposts = @user.favposts.page(params[:page]) counts(@user) end private def user_params params.require(:user).permit(:name, :email, :password, :password_confirmation) end endmicropostsコントローラー
お気に入り投稿機能と直接の関連性はないため説明は省略します。
microposts_controller.rbclass MicropostsController < ApplicationController before_action :require_user_logged_in before_action :correct_user, only: [:destroy] def create @micropost = current_user.microposts.build(micropost_params) if @micropost.save flash[:success] = 'メッセージの投稿に成功しました' redirect_to root_url else @microposts = current_user.feed_microposts.order('created_at DESC').page(params[:page]) flash.now[:danger] = 'メッセージの投稿に失敗しました' render 'toppages/index' end end def destroy @micropost.destroy flash[:success] = 'メッセージを削除しました。' redirect_back(fallback_location: root_path) end private def micropost_params params.require(:micropost).permit(:content) end def correct_user @micropost = current_user.microposts.find_by(id: params[:id]) unless @micropost redirect_to root_url end end endrouteの作成
下記のURLに対応するようにルートファイルを設定します。
/users/:id/likes お気に入り投稿一覧取得アクション /favorites お気に入り登録アクション /favorites/:id お気に入り登録削除アクションお気に入り投稿一覧取得アクションは、
/users/:id/likes
とするため、member do
を用いてresources
内に定義します。routes.rbRails.application.routes.draw do root to: 'toppages#index' get 'login', to: 'sessions#new' post 'login', to: 'sessions#create' delete 'logout', to: 'sessions#destroy' get 'signup', to: 'users#new' resources :users, only: [:index, :show, :new, :create] do member do get :followings get :followers get :likes end end resources :microposts, only: [:create, :destroy] resources :relationships, only: [:create, :destroy] resources :favorites, only: [:create, :destroy] endviewの作成
作成するアプリケーションによって、ビューファイルの作成はかなり変わると思いますので、あくまで一例ということで。
viewの作成では、renderを用いるなどする中で、ローカル変数やインスタンス変数に何が代入されているのかを注意することがポイントになります。
お気に入りボタンページ
user.rbで定義した
favpost?(micropost)
メソットを用いてお気に入り登録の判定します。favorites/_like_button.html.erb<% if current_user.favpost?(micropost) %> <%= form_for(current_user.favorites.find_by(micropost_id: micropost.id), html: { method: :delete }) do |f| %> <%= hidden_field_tag :micropost_id, micropost.id %> <%= f.submit 'お気に入り登録解除', class: 'btn btn-danger' %> <% end %> <% else %> <%= form_for(current_user.favorites.build) do |f| %> <%= hidden_field_tag :micropost_id, micropost.id %> <%= f.submit 'お気に入り登録', class: 'btn btn-primary' %> <% end %> <% end %>お気に入り投稿一覧取得ページ
render 'microposts/microposts', microposts: @favposts
によってmicropostの一覧取得ページとの共通化を図っています。renderメソッドは<%= render 'パーシャルのパス', パーシャルで使う変数名: 変数に代入する値 %>
なので、変数に代入する値にはusers_controller.rbで定義した@favpost
を指定します。users/show.html.erb<div class="row"> <aside class="col-xs-4"> <div class="panel panel-default"> <div class="panel-heading"> <h3 class="panel-title"><%= @user.name %></h3> </div> <div class="panel-body"> <img class="media-object img-rounded img-responsive" src="<%= gravatar_url(@user, { size: 500 }) %>" alt=""> </div> </div> <%= render 'relationships/follow_button', user: @user %> </aside> <div class="col-xs-8"> <ul class="nav nav-tabs nav-justified"> <li class="<%= 'active' if current_page?(user_path(@user)) %>"><%= link_to user_path(@user) do %>Microposts <span class="badge"><%= @count_microposts %></span><% end %></li> <li class="<%= 'active' if current_page?(followings_user_path(@user)) %>"><%= link_to followings_user_path(@user) do %>Followings <span class="badge"><%= @count_followings %></span><% end %></li> <li class="<%= 'active' if current_page?(followers_user_path(@user)) %>"><%= link_to followers_user_path(@user) do %>Followers <span class="badge"><%= @count_followers %></span><% end %></li> <li class="<%= 'active' if current_page?(likes_user_path(@user)) %>"><%= link_to likes_user_path(@user) do %>Likes<span class="badge"><%= @count_favposts %></span><% end %></li> </ul> <%= render 'microposts/microposts', microposts: @favposts %> # </div> </div>投稿一覧ページ(お気に入りボタン設置)
お気に入りボタンを投稿一覧ページに設定するため、renderメソッドを用いて
<%= render 'favorites/like_button', micropost: micropost %>
とします。
microposts.each do |micropost|
として抽出されたmicropost
に対してお気に入りボタンを1つずつ結びつけるので@不要
でmicropost: micropost
になります。microposts/_microposts.html.erb<ul class="media-list"> <% microposts.each do |micropost| %> <li class="media"> <div class="media-left"> <img class="media-object img-rounded" src="<%= gravatar_url(micropost.user, { size: 50 }) %>" alt=""> </div> <div class="media-body"> <div> <%= link_to micropost.user.name, user_path(micropost.user) %> <span class="text-muted">posted at <%= micropost.created_at %></span> </div> <div> <p><%= micropost.content %></p> </div> <div> <%= link_to "Delete", micropost, method: :delete, data: { confirm: "You sure?" }, class: 'btn btn-danger btn-xs' %> </div> <!--お気に入りボタン登録--> <div> <%= render 'favorites/like_button', micropost: micropost %> </div> </div> </li> <% end %> <%= paginate microposts %> </ul>Railsで「投稿お気に入り追加機能」を実装する方法まとめ
以上が、Railsで「投稿お気に入り追加機能」を実装する方法でした。
まとめることで、改めてわかりきっていないことを調べるきっかけになり良い経験となりました。
- 投稿日:2019-04-03T21:44:14+09:00
Ruby 文字列の中に特定の文字列が含まれるかの確認
はじめに
文字列中に特定の文字が含まれる場合の文字列の特定の仕方
特定の文字列が含まれる場合、それが含まれる文字列全体を返し、含まれない場合Noneを返すプログラムです
標準入力 cat #特定の文字列 catbrue #調べる対象の文字列word = gets.chomp array = readlines(chomp: true).select { |x| x.include?(word) } if array.empty? puts "None" else puts array end出力結果 catbrue上のプログラムは調べる対象の文字が増えることにも対応しています
標準入力 cat #特定の文字列 catbrue #これ以下は調べる対象の文字列 dogred birdgreenword = gets.chomp array = readlines(chomp: true).select { |x| x.include?(word) } if array.empty? puts "None" else puts array end出力結果 catbrueもちろん、一つも存在しない場合はNoneを返すようになっています
標準入力 cat #特定の文字列 rabittpink #これ以下は調べる対象の文字列 dogred birdgreenword = gets.chomp array = readlines(chomp: true).select { |x| x.include?(word) } if array.empty? puts "None" else puts array end出力結果 None
- 投稿日:2019-04-03T21:32:05+09:00
deviseの導入と実装
deviseの導入と実装
Gemfileにgemを追加
Gemfilegem 'devise'bundle installを実行し、サーバーを再起動
$ bundle install $ rails sdeviseの設定ファイルを作成
$ rails g devise:installuserモデルを作成
$ rails g devise user $ bundle exec rake db:migrate #マイグレーションファイルに必要なカラム(name等)を設定した後に実行deviseのビューファイルを作成
$ rails g devise:viewsuserのサインアップ時に名前を登録できるようにする
deviseでは初期状態でサインアップ時にメールアドレスとパスワードのみを受け取るようにストロングパラメーターが設定してあるので、
追加のパラメーターを許可したい場合は、application_controllerでbefore_actionにconfigure_permitted_parametersメソッドを設定する。application_controller.rbbefore_action :configure_permitted_parameters, if: :devise_controller? protected def configure_permitted_parameters devise_parameter_sanitizer.permit(:sign_up, keys: [:name]) enduser編集機能を追加する
①ルーティング
routes.rbresources :users, only: [:edit, :update]②users_controller作成
$ rails g controller users③edit,updateの定義
users_controllerclass UsersController < ApplicationController def edit end def update if current_user.update(user_params) redirect_to root_path else render :edit #更新できない場合は編集画面に戻る end end private def user_params params.require(:user).permit(:name, :email) end end④ビューファイル作成
- 投稿日:2019-04-03T21:23:46+09:00
自動更新機能の実装
自動更新機能とは、例えばあるブラウザで投稿したメッセージを、自分のブラウザで確認した際に再読み込みせずに自動で呼び込んでくれる昨日のこと。
- 投稿日:2019-04-03T21:04:15+09:00
18日目:トランザクションって
授業でやった扱った『トランザクション』について、書く。
参考:「トランザクション」とは何か?を超わかりやすく語ってみた!
解説用の図が分かりやすかった。
あと、ウィキペディアも参照トランザクションとは
コンピュータ内で実行される、分けることのできない一連の情報処理の一単位。
トランザクション処理における永続性記憶資源の管理では、複数のデータ項目の更新操作列をすべて実行するか、まったく実行しないように制御する必要がある。
ACID 標準
また、トランザクション処理システムは4つの属性の機能をサポートしており、頭文字からACID標準という。
- A : Atomic 不可分性
- C : Consistency 一貫性
- I : Isolation 独立性
- D : Durability 永続性実際に動かしてみる
DB内で操作
参照:13.3.1 START TRANSACTION、COMMIT、および ROLLBACK 構文 -MySQLリファレンス
MySQLはデフォルトで、自動コミットモードが有効になった状態で動作し、実行するとすぐに、ディスクに格納されて永続的になります。この変更はロールバックできない。
自動コミットモードを暗黙的に無効にするには、START TRANSACTIONをし、その後、COMMITまたはROLLBACK で終了するまで、自動コミットは無効のままになります。そのあと、自動コミットモードはその以前の状態に戻ります。
実作業
今回はMySQLと、以前に作成した大学生徒データAppのデータを再利用する
terminalmysql -u root -pMySQL#使用するデータベース情報の選択 mysql> USE cebu_college_development; #使用するstudentsテーブルの構造を確認 mysql> DESC students; +------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------+--------------+------+-----+---------+----------------+ | id | bigint(20) | NO | PRI | NULL | auto_increment | | name | varchar(255) | YES | | NULL | | | email | varchar(255) | YES | | NULL | | | gender | int(11) | YES | | NULL | | | age | int(11) | YES | | NULL | | | opinion | text | YES | | NULL | | | created_at | datetime | NO | | NULL | | | updated_at | datetime | NO | | NULL | | +------------+--------------+------+-----+---------+----------------+#id3のtaro-2さんを使ってみる mysql> SELECT name FROM students WHERE id = 3; +--------+ | name | +--------+ | taro-2 | +--------+COMMITするパターン
# mysql> START TRANSACTION; # id=3のnameを"tran-sakuko"に更新 mysql> UPDATE students SET name = "tran-sakuko" WHERE id = 3; Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0 # 確認してみる mysql> SELECT name FROM students WHERE id =3; +-------------+ | name | +-------------+ | tran-sakuko | +-------------+ 1 row in set (0.00 sec) # コミットする mysql> COMMIT; Query OK, 0 rows affected (0.00 sec) # COMMITされてるか確認 mysql> select name from students where id =3; +-------------+ | name | +-------------+ | tran-sakuko | +-------------+ 1 row in set (0.00 sec)ROLLBACKするパターン
mysql> START TRANSACTION; Query OK, 0 rows affected (0.00 sec) # id3のnameを"tran sakutarou"に更新 mysql> UPDATE students SET name = "tran sakutarou" WHERE id =3; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 # id3のnameに新しいデータの"tran sakutarou"がセットされてる mysql> SELECT name FROM students WHERE id = 3; +----------------+ | name | +----------------+ | tran sakutarou | +----------------+ 1 row in set (0.00 sec) # ロールバックしてみる mysql> ROLLBACK; Query OK, 0 rows affected (0.01 sec) #セットした"trans sakutarou"というデータはDBに格納されない。 mysql> SELECT name FROM students WHERE id = 3; +-------------+ | name | +-------------+ | tran-sakuko | +-------------+ 1 row in set (0.00 sec)RubyonRailsで動かしてみる
新しく、アプリを作成する。
今回はDBの操作だけなので、rails g modelコマンドのみ使用
テーブルはUserとReviewの2つ。準備
terminalrails new transact_self -d mysql # database.ymlを編集後 rails db:create # Userモデル作成 rails g model User name:string approved:boolean deleted:boolean # Reviewモデル作成 rails g model Review user:references rate:integer approved:boolean rails db:migrateデータ入力
console(1..5).each do |i| User.create(name: "taro-#{i}", approved: true, deleted: false) endconsole(1..5).each do |i| user = User.first Review.create!(user_id: user.id, rate: i, approved: true) endDB内で確認
mysqlmysql> SELECT * FROM users; +----+--------+----------+---------+---------------------+---------------------+ | id | name | approved | deleted | created_at | updated_at | +----+--------+----------+---------+---------------------+---------------------+ | 1 | taro-1 | 1 | 0 | 2019-04-03 09:01:31 | 2019-04-03 09:01:31 | | 2 | taro-2 | 1 | 0 | 2019-04-03 09:01:31 | 2019-04-03 09:01:31 | | 3 | taro-3 | 1 | 0 | 2019-04-03 09:01:31 | 2019-04-03 09:01:31 | | 4 | taro-4 | 1 | 0 | 2019-04-03 09:01:31 | 2019-04-03 09:01:31 | | 5 | taro-5 | 1 | 0 | 2019-04-03 09:01:31 | 2019-04-03 09:01:31 | +----+--------+----------+---------+---------------------+---------------------+ mysql> SELECT * FROM reviews; +----+---------+------+----------+---------------------+---------------------+ | id | user_id | rate | approved | created_at | updated_at | +----+---------+------+----------+---------------------+---------------------+ | 1 | 1 | 1 | 1 | 2019-04-03 09:01:38 | 2019-04-03 09:01:38 | | 2 | 1 | 2 | 1 | 2019-04-03 09:01:38 | 2019-04-03 09:01:38 | | 3 | 1 | 3 | 1 | 2019-04-03 09:01:38 | 2019-04-03 09:01:38 | | 4 | 1 | 4 | 1 | 2019-04-03 09:01:38 | 2019-04-03 09:01:38 | | 5 | 1 | 5 | 1 | 2019-04-03 09:01:38 | 2019-04-03 09:01:38 | +----+---------+------+----------+---------------------+---------------------+userとreviewとの、関連付け
app/models/user.rbclass User < ApplicationRecord has_many :reviews endreviewモデルにvalidation追加
approvedカラムを空欄不可にしておく。app/models/review.rbclass Review < ApplicationRecord belongs_to :user validates :approved, presence: true endコンソールで、トランザクション処理の挙動を確認
1. トランザクション処理に成功し、commitされるパターン
consoleuser = User.first User.transaction do user.update!(approved: false) user.reviews.each { |review| review.update!(approved: true) } end =>(0.1ms) BEGIN User Update (0.3ms) UPDATE `users` SET `approved` = FALSE, `updated_at` = '2019-04-03 09:10:46' WHERE `users`.`id` = 1 Review Load (0.2ms) SELECT `reviews`.* FROM `reviews` WHERE `reviews`.`user_id` = 1 (6.8ms) COMMIT => [#<Review id: 1, user_id: 1, rate: 1, approved: true, created_at: "2019-04-03 09:01:38", updated_at: "2019-04-03 09:01:38">, #<Review id: 2, user_id: 1, rate: 2,approved: true, created_at: "2019-04-03 09:01:38", updated_at: "2019-04-03 09:01:38">, #<Review id: 3, user_id: 1, rate: 3, approved: true, created_at: "2019-04-03 09:01:38", updated_at: "2019-04-03 09:01:38">, ,,,userテーブルのid1のtaro-1が、更新されてる
mysqlmysql> select * from users; +----+--------+----------+---------+---------------------+---------------------+ | id | name | approved | deleted | created_at | updated_at | +----+--------+----------+---------+---------------------+---------------------+ | 1 | taro-1 | 0 | 0 | 2019-04-03 09:01:31 | 2019-04-03 09:10:46 |
- トランザクション処理に失敗し、rollbackされるパターン
:console user = User.first User.transaction do user.update!(approved: true) user.reviews.each { |review| review.update!(approved: false) } end =>(0.1ms) BEGIN User Update (0.2ms) UPDATE `users` SET `approved` = TRUE, `updated_at` = '2019-04-03 09:14:44' WHERE `users`.`id` = 1 Review Load (0.2ms) SELECT `reviews`.* FROM `reviews` WHERE `reviews`.`user_id` = 1 (6.6ms) ROLLBACK Traceback (most recent call last): 3: from (irb):2 2: from (irb):4:in `block in irb_binding' 1: from (irb):4:in `block (2 levels) in irb_binding' ActiveRecord::RecordInvalid (Validation failed: Approved can't be blank)
トランザクション処理に失敗し、rollbackしたため、DBに変化はない。modelファイルを編集して実装
app/models/user.rbclass User < ApplicationRecord has_many :reviews def suspend! self.class.transaction do disapprove_user! disapprove_reviews! end end private def disapprove_user! self.update!(approved: false) end def disapprove_reviews! reviews.each { |review| review.update!(approved: false) } end endと、ここまでが授業でやった分。
トランザクション処理の概念は理解できた(と思う)。
- 投稿日:2019-04-03T20:56:12+09:00
Ruby 配列の大文字、小文字を変換する
- 投稿日:2019-04-03T19:17:39+09:00
Railsチュートリアル三章あたりから、テストの際にエラーが出る方々へ...
cloud9環境にてRailsチュートリアルを学習中、テスト自体は無事に検証できるものの、毎回下記のようなエラーが出て気になっていました。
今後も同じ経験をされる方がいらっしゃると思い、共有しようと思います!
まずは私自身のコンソールに生じていたエラーです。
ec2-user:~/environment/sample_app (master) $ rails t Running via Spring preloader in process 19388 Run options: --seed 51796 # Running: .................. Finished in 0.564856s, 31.8665 runs/s, 63.7331 assertions/s. 18 runs, 36 assertions, 0 failures, 0 errors, 0 skips Traceback (most recent call last): 33: from -e:1:in `<main>' 32: from /home/ec2-user/.rvm/rubies/ruby-2.6.0/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require' 31: from /home/ec2-user/.rvm/rubies/ruby-2.6.0/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require' 30: from /home/ec2-user/.rvm/gems/ruby-2.6.0/gems/spring-2.0.2/lib/spring/application/boot.rb:19:in `<top (required)>' 29: from /home/ec2-user/.rvm/gems/ruby-2.6.0/gems/spring-2.0.2/lib/spring/application.rb:135:in `run' 28: from /home/ec2-user/.rvm/gems/ruby-2.6.0/gems/spring-2.0.2/lib/spring/application.rb:135:in `loop' 27: from /home/ec2-user/.rvm/gems/ruby-2.6.0/gems/spring-2.0.2/lib/spring/application.rb:141:in `block in run' 26: from /home/ec2-user/.rvm/gems/ruby-2.6.0/gems/spring-2.0.2/lib/spring/application.rb:171:in `serve' 25: from /home/ec2-user/.rvm/gems/ruby-2.6.0/gems/spring-2.0.2/lib/spring/application.rb:171:in `fork' 24: from /home/ec2-user/.rvm/gems/ruby-2.6.0/gems/minitest-5.10.3/lib/minitest.rb:63:in `block in autorun' 23: from /home/ec2-user/.rvm/gems/ruby-2.6.0/gems/minitest-5.10.3/lib/minitest.rb:141:in `run' 22: from /home/ec2-user/.rvm/gems/ruby-2.6.0/gems/minitest-5.10.3/lib/minitest.rb:687:in `report' 21: from /home/ec2-user/.rvm/gems/ruby-2.6.0/gems/minitest-5.10.3/lib/minitest.rb:687:in `each' 20: from /home/ec2-user/.rvm/gems/ruby-2.6.0/gems/guard-minitest-2.4.4/lib/guard/minitest/reporter.rb:10:in `report' 19: from /home/ec2-user/.rvm/gems/ruby-2.6.0/gems/guard-minitest-2.4.4/lib/guard/minitest/notifier.rb:31:in `notify' 18: from /home/ec2-user/.rvm/gems/ruby-2.6.0/gems/guard-compat-1.2.1/lib/guard/compat/plugin.rb:113:in `notify' 17: from /home/ec2-user/.rvm/gems/ruby-2.6.0/gems/guard-2.13.0/lib/guard/notifier.rb:31:in `notify' 16: from /home/ec2-user/.rvm/gems/ruby-2.6.0/gems/guard-2.13.0/lib/guard/notifier.rb:11:in `connect' 15: from /home/ec2-user/.rvm/gems/ruby-2.6.0/gems/notiffany-0.1.1/lib/notiffany/notifier.rb:42:in `connect' 14: from /home/ec2-user/.rvm/gems/ruby-2.6.0/gems/notiffany-0.1.1/lib/notiffany/notifier.rb:42:in `new' 13: from /home/ec2-user/.rvm/gems/ruby-2.6.0/gems/notiffany-0.1.1/lib/notiffany/notifier.rb:87:in `initialize' 12: from /home/ec2-user/.rvm/gems/ruby-2.6.0/gems/notiffany-0.1.1/lib/notiffany/notifier.rb:198:in `_activate' 11: from /home/ec2-user/.rvm/gems/ruby-2.6.0/gems/notiffany-0.1.1/lib/notiffany/notifier.rb:180:in `_detect_or_add_notifiers' 10: from /home/ec2-user/.rvm/gems/ruby-2.6.0/gems/notiffany-0.1.1/lib/notiffany/notifier/detected.rb:59:in `detect' 9: from /home/ec2-user/.rvm/gems/ruby-2.6.0/gems/notiffany-0.1.1/lib/notiffany/notifier/detected.rb:59:in `each' 8: from /home/ec2-user/.rvm/gems/ruby-2.6.0/gems/notiffany-0.1.1/lib/notiffany/notifier/detected.rb:60:in `block in detect' 7: from /home/ec2-user/.rvm/gems/ruby-2.6.0/gems/notiffany-0.1.1/lib/notiffany/notifier/detected.rb:60:in `detect' 6: from /home/ec2-user/.rvm/gems/ruby-2.6.0/gems/notiffany-0.1.1/lib/notiffany/notifier/detected.rb:60:in `each' 5: from /home/ec2-user/.rvm/gems/ruby-2.6.0/gems/notiffany-0.1.1/lib/notiffany/notifier/detected.rb:62:in `block (2 levels) in detect' 4: from /home/ec2-user/.rvm/gems/ruby-2.6.0/gems/notiffany-0.1.1/lib/notiffany/notifier/detected.rb:100:in `_add' 3: from /home/ec2-user/.rvm/gems/ruby-2.6.0/gems/notiffany-0.1.1/lib/notiffany/notifier/detected.rb:100:in `new' 2: from /home/ec2-user/.rvm/gems/ruby-2.6.0/gems/notiffany-0.1.1/lib/notiffany/notifier/base.rb:59:in `initialize' 1: from /home/ec2-user/.rvm/gems/ruby-2.6.0/gems/notiffany-0.1.1/lib/notiffany/notifier/tmux.rb:69:in `_check_available' /home/ec2-user/.rvm/gems/ruby-2.6.0/gems/notiffany-0.1.1/lib/notiffany/notifier/tmux/client.rb:12:in `version': undefined method `[]' for nil:NilClass (NoMethodError)長くなってしまいましたが、、、
_check_available' /home/ec2-user/.rvm/gems/ruby-2.6.0/gems/notiffany-0.1.1/lib/notiffany/notifier/tmux/client.rb:12:in `version': undefined method `[]' for nil:NilClass (NoMethodError)一番下のこの辺り↑が怪しそう。。。
結論から述べると、「tmux」の部分が原因です。
まずtmux(てぃーまっくす)とは何者なのか・・・
Answer.
tmuxは端末多重化ソフトウェアつまり、1つのターミナルで複数の擬似ターミナルを起動することが可能になります。
複数のターミナルを立ち上げずとも、tmux上のターミナルを切り替えてオペレーションすることを可能とするソフトウェアです。cloud9は一つのターミナルで複数のターミナルに切り替えることが出来ますよね。。。
そこで、とりあえずtmuxをインストールすることに。。。
$ sudo yum install -y tmuxLoaded plugins: priorities, update-motd, upgrade-helper amzn-main | 2.1 kB 00:00:00 amzn-updates | 2.5 kB 00:00:00 epel/x86_64/metalink | 13 kB 00:00:00 epel | 4.7 kB 00:00:00 1060 packages excluded due to repository priority protections Resolving Dependencies --> Running transaction check ---> Package tmux.x86_64 0:1.8-4.12.amzn1 will be installed --> Finished Dependency Resolution Dependencies Resolved ============================================================================================================ Package Arch Version Repository Size ============================================================================================================ Installing: tmux x86_64 1.8-4.12.amzn1 amzn-main 254 k Transaction Summary ============================================================================================================ Install 1 Package Total download size: 254 k Installed size: 543 k Downloading packages: tmux-1.8-4.12.amzn1.x86_64.rpm | 254 kB 00:00:00 Running transaction check Running transaction test Transaction test succeeded Running transaction Installing : tmux-1.8-4.12.amzn1.x86_64 1/1 Verifying : tmux-1.8-4.12.amzn1.x86_64 1/1 Installed: tmux.x86_64 0:1.8-4.12.amzn1 Complete!どうやらインストール出来ました!
再度、テストを実行してみると。。。??
ec2-user:~/environment/sample_app (master) $ rails t Running via Spring preloader in process 19512 Run options: --seed 63909 # Running: .................. Finished in 0.582820s, 30.8843 runs/s, 61.7686 assertions/s. 18 runs, 36 assertions, 0 failures, 0 errors, 0 skipsエラー文が消え、スッキリとテストを実行できるようになりました!!
- 投稿日:2019-04-03T17:46:28+09:00
railsチュートリアル1章 herokuへのデプロイに七転八倒。
railsチュートリアル1章後半のherokuへのデプロイにつまづきまくったので、2度とここでつまづかないようにまとめておきます。
railsチュートリアル1.5で
git push heroku master
を実行した後に生成されたアドレスをブラウザで開こうとしたら、
Application Errorの文字が、、、下に書いてある
heroku logs --tail
を実行しても、2019-04-02T08:45:11.178789+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" host=cherry-pudding-18708.herokuapp.com request_id=418c602d-6211-4552-9488-abbfd39fae16 fwd="115.69.237.151" dyno= connect= service= status=503 bytes= protocol=https 2019-04-02T08:45:11.634170+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/favicon.ico" host=cherry-pudding-18708.herokuapp.com request_id=7d395db1-345a-40ad-833c-8e770f0b8b7b fwd="115.69.237.151" dyno= connect= service= status=503 bytes= protocol=https ^C何言ってるか分かりません。笑
ここで
heroku run rails console
を実行。`Add `gem 'sqlite3'`to your Gemfile (and ensure its version is at the minimum required by ActiveRecord). (Gem::LoadError)の文字が。
railsチュートリアルのいうことを正確に聞いてきた人には分かりますが、
sqlite3
はGemfileで実行してますよ!?!?ここで、またググる。
すると、ここの記事に答えに繋がりそうなことが、、、!
Rails Tutorial原因
.bundle/config の中身が
BUNDLE_WITHOUT: "production"
になっていることが原因らしい。あと、
database.yml
も変更する必要があるっぽい。
対策
.bundle/configってどこにあるんだと思って探したけど、どこにも見つからなかったので、c9コマンドでそこまで移動。
BUNDLE_WITHOUT: "production"
を
#BUNDLE_WITHOUT: "production"
に変更。それでもうまくいかない。
そこで、datebase.ytmlproduction: <<: *default adapter: postgresql database: db/production.pgに変更。
それでもうまくいかない、、、。
一旦、もう一度
heroku run rails console
をしてみると、Add `gem 'pg'` to your Gemfile (and ensure its version is at the minimum required by ActiveRecord). (Gem::LoadError)あれ?
Add gem 'pg'
に変わってる!!
これを解決すれば、デプロイできるぞ、、、と思い、ググるが、答えが見つからない。
そこで、色々いじった後にgit push heroku master
を実行してないことに気づき、実行。これでデプロイが完了した。2日間格闘した甲斐があった。(おそらく、ここまで分からなかったら飛ばして次に行くほうが効率がいい)
まとめ
おそらく、
database.yml
の変更が解決法に繋がったと考える。
それと、heroku run rails console
で確認をすると丁寧にどこが間違っていたのかを教えてくれるので、有効活用していきたい。
- 投稿日:2019-04-03T17:00:05+09:00
Qiita初投稿。プログラミングに本腰を入れて1か月でわかってきたこと。
就活を終え、とあるweb系企業に就職することになりました。
webアプリを作ろうと1か月ほどの出来事を初心忘るべからず精神で書き留めることにしました。
この先のアウトプットの第一歩として。
来年の今頃にはしっかりとしたエンジニアの知識を持っていたいなぁ。就活を終えてまずやったこと
就職までに出来るだけ技術力を身に付けないといけないと思い、Udemyで適当なコースを何個か購入。
Udemy(https://www.udemy.com/)これできっと自分もかっこいいホームページとか、webアプリケーションとかバンバン作れるぞ!!!と思った
だけど・・・
webページを作る。と言っても色んな事を決めないといけない事に気が付く
- webページを作るにはそもそも何の言語で作るのかを決めないといけない。
- なんのwebページを作るかも決まってない
- なにをしたいかも決まってない
何していいのか、何がベストなのかぜんっぜんわからない!!!
わからない事がわからない問題
そもそもプログラミングと言っても、研究のデータ分析のためにpythonをいじくり回してた程度で、プログラミングが何のために存在しているかわかってない。
恐らく体系的に勉強することが第一歩なのだろうけど...
とりあえずudemyで購入したコースを1個やり遂げよう
出来ない事はとにかく一回やってみようの精神で、こちらのコースをやってみた。
よくわかるRuby on Rails入門-RubyとRailsを基礎から学びWebアプリケーションをネットに公開しよう(https://www.udemy.com/the-ultimate-ruby-on-rails-bootcamp/)
こちらのコースはAWSを使って、RubyとRuby on railsを使って簡単なQアンドAサイトをリリースしてみましょう。という内容。
このコースで学んだことを今度また記事にしてみよう。このコースを選んだのは、webアプリケーションと調べた時にRubyが便利だよ!みたいな記事を見たから。あとAWSが入社予定の会社で使われているから。今のうちから触ってたら後々重宝するかもしれないと思った。
結果どうなったか
自分で書いたコード(厳密にいえば写経だけど)が実際に動いて、ボタンだとか、質問機能だとかが実装されていくのはとても面白かった。
すげぇええええええ!!これ見たことあるうううううぅぅぅぅ!!ってなった最終的に実際に誰でもアクセスできるようにして、友達に書き込んでみてもらったりした。
自分以外の人が自分で作ったサイトを使ってくれるのってなんだか不思議な感覚だった。多分webエンジニアのやりがいってこういうところにあるのかなぁと思ったし、これで喜べるならエンジニアの素養あるんじゃ?ってなった。
今のところわかったこと
- 簡単なwebアプリケーションの制作
- webアプリのリリース、デプロイ?(本当はそう呼べないだろうけど、カッコつけのために)
- Rubyの記法とかもろもろ(まだ全然使いこなせてない)
- railsを使ってのwebアプリの作り方(MVCアーキテクチャがどう作用するのか)
- アプリ作りの楽しさ
- 自分で作ることの大変さ
まとめてみると大事なことを結構得られた気がする
一番わかったのはやることが決まってないとやる気が出ない事
今回はwebアプリを作ることが目的だったけど、何の目標もなしにただ言語だけ学習するのは本当に退屈だと思った。
まだわからないこと
- サーバー、データベース関連 → SQLとかその辺り。こいつらが何のためにあるのかわかってない
- AWSの機能について → 今回言われるがままに使ったけど、ローカル環境にわざわざlinux環境を作らなくていいって事くらいしかわかってない
- linux関連 → 操作方法全然わかんねぇ。そもそも何がわかってないのかがわかってない。優先度どれくらいなんだ
- railsについて → なんかgemを使うと機能が拡張できるってことは分かった。どんなものがあるかは自分で調べる事っぽい
- git・Githubについて → コードの編集履歴を残せるってことは知ってる。どう使うかは勉強しないと
最後に。これからやりたいこと
- 新しいwebアプリケーションの制作 → 就活のための補助アプリとかできないかな
- HTML5、CSSを使いこなして見栄えがいいものを作れるようになる → まだ色とかリンクとかもわからないから、ハンズオンで身に付けていきたい
- セキュリティについての勉強 → もしこの先アカウント情報とかを管理するようになった時のために。転ばぬ先の杖
- 自分のポートフォリオの制作 → ぶっちゃけこれが最優先事項なんじゃないだろうか。
Qiitaでやっていきたいこと
定期的な更新!!!!
せっかく初投稿したんだから定期的に投稿したいし、色んな人に読んでもらいたいし、コメント貰ったり、コメント送りたい
見やすいページとか、いろいろ研究していこうと思います。
- 投稿日:2019-04-03T16:25:24+09:00
【Ruby】型変換 "to_?" メソッドのおさらい
Rubyのクラスには、型変換を行うメソッド "to_?"がいくつか存在するので、
どんな物があるのか、どんな使い方なのかを今一度おさらいしたいと思いました。※下記ソースコードはオンライン実行環境にて実行しておりますが、
エスケープ等見にくい表現部分は切り取っておりますので実際の結果とは異なる場合がございます。① to_i 整数変換
p a = 2019.to_i >> 2019 p a = "2020".to_i >> 2020 p a = "4/1".to_i >> 4 # 先頭から数値解釈できる場所まで p a = "令和元年".to_i >> 0 # 数値がないためto_iメソッドは、文字列に限り引数にレシーバの進数の指定ができ(デフォルト10進数)、10進数に変換した整数値を返します。
p a = "ff".to_i(16) >> 255 # 16進数"ff" -> 10進数255② to_s 文字列変換
p a = 2019.to_s >> "2019" p a = "2020".to_s >> "2020" p a = "4/1".to_s >> "4/1" p a = "令和元年".to_s >> "令和元年" # シンボル p a = :hello.to_s >> "hello" p a = :"hello world".to_s >> "hello world"to_sメソッドは、整数に限り、引数に指定した進数に変換した文字列を返すことができます(デフォルト10進数)。
※ to_iとは考え方が逆p a = 8217.to_s(16) >> "2019" # 10進数8217 -> 16進数"2019"③ to_f 浮動小数点数変換
p a = 2019.to_f >> 2019.0 p a = "3.14".to_f >> 3.14 p a = "4/1".to_f >> 4.0 # 先頭から数値解釈できる場所まで p a = "令和元年".to_f >> 0.0 # 数値が無いため④ to_a 配列変換
# 配列 p a = [1,2,3].to_a >> [1, 2, 3] # ハッシュ p a = {"k1"=>"v1", "k2"=>"v2"}.to_a >> [["k1", "v1"], ["k2", "v2"]]⑤ to_h ハッシュ変換
# 配列 p a = [[1,2], [3,4]].to_h >> {1=>2, 3=>4} # ハッシュ p a = {"k1"=>"v1", "k2"=>"v2"}.to_h >> {"k1"=>"v1", "k2"=>"v2"}⑥ to_sym シンボル変換
p a = "hello".to_sym >> :hello p a = :hello.to_sym >> :hello p a = "hello world".to_sym >> :"hello world" # スペースが存在する場合はダブルクォートに囲まれる #ハッシュ p a = {:k1=>"v1"}.to_sym >> NoMethodError # ハッシュに対してなにかできるわけではない⑦ to_json JSON変換
require "json" # 配列 p a = [[1,2], [3,4]].to_json >> [[1,2],[3,4]] # ハッシュ p a = {"k1"=>"v1", "k2"=>"v2"}.to_json >> {"k1":"v1","k2":"v2"}? 明示的・暗黙的な型変換
???なにそれ???
to_i
とto_int
to_s
とto_str
to_a
とto_ary
to_h
とto_hash
- (その他)
to_io
、to_proc
、to_regexp
リファレンスマニュアルにて、長い方(右側)のメソッドを見ると
暗黙の変換が必要なときに内部で呼ばれます。 デフォルトでは定義されていません。
説明のためここに記載してありますが、 このメソッドは実際には Object クラスには定義されていません。
必要に応じてサブクラスで定義すべきものです。このメソッドを定義する条件は、
・"対象の型"が使われるすべての場面で代置可能であるような、
・"対象の型"そのものとみなせるようなものという厳しいものになっています。
class Foo def to_int 1 end end ary = [:a, :b, :c] p(ary[Foo.new]) # => :bとなにやら難しいことが書いてありますが、例文を見てもわかるように非常にシンプルで、
その型(to_intならint)を”暗黙的に”解釈できる際に使えるよと言っています。
(あまり使い道が思いつかない・・・)短い方(左側)は暗黙的の対義語として明示的と呼ばれ、使い方は上に書いたとおりです。
- 投稿日:2019-04-03T16:02:07+09:00
【sass変換サイト】cssからsassにコンパイルできるサイト
Vue+Webpack+Sass使った開発があるんだがsassが全然わからん(PG歴半年)
sassを使うメリット
・コードがシンプルらしい
・変数の使用が可能らしい
・コードを使い回しができるらしい
・if文・while文が使えるらしい
・四則演算ができるらしい参考にしたサイト
https://qiita.com/m0nch1/items/b01c966dd2273e3f6abe↓↓↓↓↓こんなん↓↓↓↓↓↓
※他にいいのあったら教えてください
- 投稿日:2019-04-03T15:29:57+09:00
Ruby InvalidURIError 〜単純な落とし穴〜
はじめに
Qiitaに初めて投稿します。日々研究室で過ごす中で体験したトラブル等、ちょっとしたことを備忘録的に書いて投稿していけたらと思います。
まだまだ勉強を始めたばかりなので、間違いなどがありましたら、ご指摘いただけると幸いです。
それでは本題に入ります。背景
Web上にあるデータを取得するRubyスクリプトをCrontabにより毎日実行している。
これまではUbuntu14.04LTSを使っていたが、間も無くサーポートが切れるということで、新たにUbuntu18.04をクリーンインストールし、環境構築を行なった。ちゃんと動かない...
OSのバージョンは大幅に変化したが、今まで通りにスクリプトを実行できる環境に戻した...つもりだった。
が、ここで問題が発生。順調にデータ取得のログが表示されていたが、スクリプトが途中で止まる...なぜ...??
エラーの内容はこんな感じ。(URI省略)
/usr/lib/ruby/2.5.0/uri/rfc3986_parser.rb:67:in `split': bad URI(is not URI?): https://〜〜 (URI::InvalidURIError)
InvalidURIError...え!!?? URI間違ってる???
OS変えるまでちゃんと動いてたのに?なんで?プログラム内容
そもそもこのプログラムでは、
取得したい情報のあるURIをCSVファイルにまとめて保存されており、URIの日時部分をスクリプトで変更することにより毎日データを取得している。取得するデータ数が少しなら手作業でもいいが(よくない)、数百(もっと?)あるので手作業なんてやってられない。
バグ出し
まず...
Ubuntuのバージョンを上げるまではきちんと動いていた。
それに新しい環境下でデータの取得が1つもできないわけではなく、途中でエラーが起きる。まず考えたのが、突然サイトがなくなった、もしくはURIが違うという可能性。
そこで、エラーで表示されているURIをブラウザにコピペ...
ちゃんとページ表示されるやん...!!
つぎに...
そこで次に考えたのが、Rubyのバージョンが今と前のOSで違う可能性。
しかし、アホな自分は前の環境で使っていたRubyのバージョンを確認していない。Rubyのバージョンが違うことが影響しているなら、最初からエラーが出てもいい気がするが...
なんて考えながら、URI情報が保存されているCSVファイルを開き、エラーをはいているURIを確認。
ぱっと見何もおかしくない...
空白が入っているようにも見えへんし〜...ん?URIの末尾に半角スペースがあるぞ...
もしかしてこれのせいか...?
他のURIの行には空白は無く、該当のURIにのみ空白が入っていた。
この空白を削除し、スクリプトを実行。
結果
ちゃんと動いた〜〜(^^)/
やはり、エラーの理由はURI末尾の空白だったようだ。
OSのバージョン変更に伴いRubyのバージョンが変わったことで、Rubyの空白処理が変わったのでしょうか??
何はともあれ、これでまた毎日データを取得できそうでよかった。
反省
今回のトラブルはおそらくRubyのバージョン変更によるものだと考える。
自分の環境管理はしっかりしないといけないと感じた。
バージョンなんてどれでも大概一緒や〜なんて考えないようにしよう...
- 投稿日:2019-04-03T15:05:48+09:00
もそ、プログラミングを学ぶ【Ruby & Rails復習編】〜どんどんエラーを解いてみよう!〜
エラーを克服せよ
エラー解決の数をこなしていくうちに、プログラミングスキルが徐々に覚醒しつつある もそ。
前はあまりにエラーが解決できず奇声を発しそうになっていたのですが、だんだんと考え方のコツをつかんで落ち着きを取り戻した今、波紋の呼吸を修得しつつあります。
プログラミングだし、スタンド名はOKコンピューターとかがいいかな〜...さっそく話がそれてしまいました。
今回も引き続き、エラーを解決していこうと思います。エラー発生!名探偵もそ、出動!
まずはエラー画面を見てみましょう。
精神を乱さず、まずは冷静に英文を読みます。
1行目を読んでみると「NoMethodError in Tweets#index」と表示されていますよね。
これは、「tweetsコントローラのindexアクションを読み込んだ時に、メソッドがなかったよ〜」
という内容です。
さらに2行目を見てみると、「部分テンプレートファイルの6行目に記述しているtweet__path
の部分でメソッドが定義されていない」と出ています。仮説を立ててみる
これまでの経験と勘から、”NoMethodError”と出ているのでメソッドの名前とコントローラのアクションが一致していないのでは?と考えました。
そこで改めて部分テンプレートファイルの記述を確認してみます。
でも、詳細ページを表示するためのHTTPメソッドはgetで合っているはず。う〜〜む、これは難題な予感です。
名探偵もそ、ターミナルを捜査(操作)
ここでエラーの原因箇所がビューファイルにない可能性も考え、ターミナルにrake routesコマンドを実行しました。
rake routesすることでルーティング名やルートパス、コントローラとアクションに対応するHTTPメソッドを確認することができます。表示されている内容についてカンタンに説明します。
薄きみどり色(もそカラーをイメージして設定してみました)の1列目の表記ですが、・Prefix...ルーティング名
・Verb...HTTPメソッド
・URI Pattern...ルートパス名
・Controller#Action...コントローラ名#アクション名を表しています。
画像内の下の方、ブルーボックスで中途半端に選択してしまっている
tweets GET /tweets(.:format) tweets#index
この部分が今回エラーを起こした処理になります。
思ったとおり、HTTPメソッドはやはり間違っていないようです。
原因はどこにあるのか...ターミナルの実行画面を見ていると、もそはハッと気がつきました。「あれ?ほかのtweetsコントローラ全然表示されてなくない??」
本来であれば、tweetsコントローラのファイルで定義した各アクションが並ぶはずです。
でも実行結果をよく見ると、tweetsコントローラのindexアクションしか表示されていません。エラー解決編
この結果を踏まえて、原因はルーティングにあると断定しました。
コントローラファイルの記述がごっそり抜けている可能性もなくはないのですが、この部分は30弱の記述があります。
この部分がまるっと無くなっていたらさすがに気がつくだろうと考え、今回は先にルーティングを検証することにしました。さっそくルーティングファイルを開き、記述を確認してみます。
error_routing.rbRails.application.routes.draw do devise_for :users root "tweets#index" do resources :tweets resources :comments, only: [:create] end resources :users, only: [:show] endよ〜〜く見てみましょう。
...
...!!!
3行目のdoの記述位置、間違ってるやん!!resourcesメソッドはコントローラとアクションの設定をかんたんに行ってくれる便利なメソッドで、基本となるコントローラの7つのアクション名に対して、ルーティングを自動で生成してくれます。
詳しくはこちらの記事へ。記述の仕方はこんな感じです。↓
resources :コントローラ名 doさらにここでは、resourcesメソッドをネストという入れ子構造にしています。
そんなわけで、正しい記述はこちら↓routing.rbRails.application.routes.draw do devise_for :users root "tweets#index" resources :tweets do resources :comments, only: [:create] end resources :users, only: [:show] endなかなかの難題でしたが、名探偵もそ、見事に解決しました!
--
エラー解決は難しいですが、解けるとなるほど面白い!もっと頑張ろう!と前向きな気持になれます。
次の目標も決まってきたので(※スタンド発動ではありません)、復習をしつつエラーに挑戦していこうと思います。
...続く。
- 投稿日:2019-04-03T13:40:57+09:00
docker-composeで起動しているRubyアプリケーションをデバッグする方法
自分はRubyのデバッグにはpry-byebugを利用しています。
pry-byebugは、デバッグしたいポイントにbinding.pry
を仕込むことでその時点でアプリが停止し、デバッグをすることができます。問題点
フォアグラウンドで
docker-compose up
すると、binding.pryを仕込むことで以下のようなログが表示されます。
アプリの実行は中断されますが、あくまでログが表示されているだけなのでこのコンソール上でデバッグはできません。web_1 | 9: def index web_1 | 10: binding.pry web_1 | => 11: end web_1 |解決方法
docker attachでRubyアプリケーションのコンテナに入るとデバッグできます。
$ docker attach ${container_id} ### エンターキーを押すとデバッグができる [1] pry(#<HomeController>)>
- 投稿日:2019-04-03T11:44:44+09:00
RailsでSQLite3を複数Thread/Processから同時WriteするときにBusyExceptionを回避
TL;DR
Rails
のDBにSQLite3
を使ってしまうと,Redis
等々で同時WriteするとSQLite3::BusyException
が発生する.
database.yml
のtimeout
も効かぬらしい.
仕方がないので自分でプロセス横断の排他Lockを実装する.やったこと
ActiveRecord.save/.save!
でfalseが返ったり例外発生したりするので,成功するまでRetryするとかしても良かったかもしれませんが,あまり格好良くないので,排他Lock制御します.
Ruby
の排他Lockの実装自体はぐぐるといっぱい出てくるので,それらを参考に↓のようなblockを排他実行させるClassを用意しました.LockBlock.rbrequire 'tmpdir' class LockBlock class << self def locked(lock_file_name) File::open(File::join(Dir::tmpdir, lock_file_name), 'w') { |file| begin file.flock(File::LOCK_EX) yield ensure file.flock(File::LOCK_UN) end } end end endこの排他Lockで守った状態で
ActiveRecord.save/.save!
するためのMethodをApplicationRecord
に用意します.app/models/application_record.rbdef safe_save! LockBlock::locked(`db_lock`) { self.save! } endあとは各Modelの
.save/.save!
やってるところをsafe_save!
に置き換えれば完了.これでいいのか疑問
ひとまず ↑ の対応を入れて
Redis
使って平行動作させて様子見してますが,FileのLock/Unlockのアトミック性とかよくわかっておらず,これで100%保証されてるのかどうかが不明...# そもそも`SQLite3やめいとかは言わないように...
# 最初はシンプル機能のお手軽Appになるはずやったんや...---///
- 投稿日:2019-04-03T10:04:08+09:00
「Long Life RailsApps」というテーマで登壇した話 (前編)
少し前ですが、Reproさんのイベントで登壇させていただきました。
その際に使用したスライドの共有と、深掘りをしたいと思います。スライド
まずは耳障りの良いKeepからいきます。
Keep
リリースしたり、効果が良かったりすると事業側のメンバーから感謝される
素晴らしく良い雰囲気で仕事できます。何気ない一言で救われる場面が多々あります。
(自分は特にちょろい気がする)Githubフローをちゃんと回せている
当然の話ではありますが、事実良い習慣なのでKeepしたいです。
開発環境をDockerで構築できるようにした
新しいメンバーが参画する時にめちゃくちゃ楽になりました。特定のバージョンのミドルウェアを使用していたりするとセットアップ手順のアップデートが大変なのですがコマンド数回でセットアップできるようになりました。
効率的にレビューをするために色々ルールを設けた
2名以上のレビュアーに見てもらうというローカルルールがあるのですが、一日10プルリクエストほどレビューしないといけないので気を抜くとすぐ溢れてしまいます。
レビューをする時間を決めたり、レビュアー毎に権限を設けこの人のレビューを貰わないとリリースできない
というルールを設けました。
権限のあるレビュアーはしっかりと見ますし、通常のメンバーはレビューに対して重い責任を負わずに済みます。
良かったのはメンバーが軽い気持ちでレビューができ、レビュアーはメンバーのレビューを参考にできる
という点です。Jenkinsを使ってデプロイやタスクの実行をできるようにした
DevOps的な。ここはSlackに移行するなどTryが挙げられそうなKeepです。
RspecとSeleniumが主要な機能をカバーした
テストのカバレッジが極端に低かったので、サービス(ビジネス)として障害になってはいけないところのテストを厚くしました。ユーザーの基本フローを網羅することで実装者、事業者が安心して過ごすことができるようになりました。
Reviewdogで自動的にコードの書き方を指摘されるのでロジックに対して議論することができる
導入はぐぐっていただけると助かります。
ドキュメント管理システムを導入して非エンジニアも巻き込んだ
色々なツールを試しましたが、カスタマイズが可能なオープンソースに落ち着きました。
API連携も見据えた動きができています。
ここからは直近のプロジェクトを振り返ってみた結果
プロジェクトのキックオフをすることでコアメンバーの意識を統一できた
なんだかんだキックオフは大事。ゆるゆると始まるプロジェクトはだいたい炎上する気がします。
プロジェクト進行においてシンプルなルールだけ決めて守るようにした
blameしない、前を向く、などプロジェクトマネジメントの基本を守りました。
当然ながら良い習慣だと思います。何のためのプロジェクトなのかを明確にした
めちゃくちゃKeepです。意思決定のスピードが格段に向上し、方向性が明確なので決定事項について背景を説明することができるので、
メンバーが納得感を持って業務に当たることができます。ガントチャートをすぐ更新できるように専用のツールを導入した
Backlogを普段使っているのですがガントチャートの更新が非常に多かったのでxPlanというツールを導入しました。
クリティカルパスの設定も簡単にできるのでおすすめです。(有料)Backlogは基本的にFIXした内容とスケジュールのみ記載するようにした
ガントチャートと分業したので相応の使い方にまとめました。
情報が散らばらないのは良いことです。Try
KeepからTryに挙げられるのは以下です。
- Jenkinsで運用しているものはSlackやクラウドサービスへ移行できそう
- Rspec, Seleniumのカバレッジを増やしたい
- とは言えテストリソースの上限はあるのでバランスを取るべき
- 開発用DockerImageを配布できるようにしたい
- Reviewdogはタイミングによって邪魔な場合があるので任意での実行も視野に入れる
- ドキュメント管理者が不在なので責任者を据えたい
- 進行管理の雑務に時間を割くことに対する心理的ハードルを下げたい
- ガントチャート、Github、Backlog、スプレッドシートを使って進行管理すると情報が分散して効率が下がるポイントがある
- プロジェクト管理及びドキュメント管理のベストプラクティスを探る
重い話になるProblemは後編で綴っていきたいと思います。
- 投稿日:2019-04-03T09:38:12+09:00
Ruby 標準入力から値を受け取る方法
はじめに
Paizaのプログラミング問題で標準入力を使い、値を持ってくる方法がいくつかあったのでメモ
前提
使用する言語はRubyです
一行に一要素だけしか存在しない場合
標準入力 Tokyoline = gets p line出力結果 "Tokyo"一行に複数要素存在する場合
標準入力 Tokyo Osaka Kyotoline = gets.split(' ') p line出力結果 ["Tokyo", "Osaka", "Kyoto"]splitを使用することで3つの要素をそれぞれ別のものとして配列に格納しています
※splitの使い方
splitはsplit('')のシングルクォート内の文字で文字列を分解する
例えば、Tokyoという文字をそれぞれ一文字ずつ取得したければ、シングルクォートの中に何も入れずにすると下記のように取得できる標準入力 Tokyoline = gets.split('') p line出力結果 ["T", "o", "k", "y", "o"]複数行に一つずつ要素が存在する場合
標準入力 Tokyo Osaka Kyotoline = readlines len = line.length i = 0 while i < len line[i] = line[i].chomp i += 1 end p line出力結果 ["Tokyo", "Osaka", "Kyoto"]上記のものの簡潔な書き方として、mapを使用したものがあります
標準入力 Tokyo Osaka Kyotoline = readlines.map(&:chomp) p line出力結果 ["Tokyo", "Osaka", "Kyoto"]複数行に複数要素が存在する場合
標準入力 Tokyo Osaka Kyoto Japan USA Chinaline = readlines len = line.length i = 0 while i < len line[i] = line[i].chomp.split(' ') i += 1 end p line出力結果 [["Tokyo", "Osaka", "Kyoto"], ["Japan", "USA", "China"]]上記のものの簡潔な書き方として以下のものもあります
標準入力 Tokyo Osaka Kyoto Japan USA Chinalines = [] while line = gets lines << line.chomp.split(' ') end p lines出力結果 [["Tokyo", "Osaka", "Kyoto"], ["Japan", "USA", "China"]]while line = getsとすることで、標準入力の値を全て取得するまで繰り返されます
出力結果を見ると、受け取った値は文字列なので数値を受け取りたい場合は次のようにします
数値として受け取りたい場合
一行に一要素だけしか存在しない
標準入力 123line = gets.to_i p line出力結果 123一行に複数要素存在する場合
標準入力 1 2 3line = gets.split(' ') p line出力結果 ["1", "2", "3"]このままだと文字列として扱われるので、mapを使用して数値型の配列に変換します
標準入力 1 2 3line = gets.split(' ').map(&:to_i) p line出力結果 [1, 2, 3]複数行に一つずつ要素が存在する場合
標準入力 1 2 3line = readlines.map(&:to_i) p line出力結果 [1, 2, 3]複数行に複数要素が存在する場合
標準入力 1 2 3 4 5 6lines = [] while line = gets lines << line.chomp.split(' ').map(&:to_i) end p lines出力結果 [[1, 2, 3], [4, 5, 6]]
- 投稿日:2019-04-03T01:59:40+09:00
compass使用時にパスに日本語が含まれてるとエラーが出る
ディレクトリ(フォルダ)名をアルファベットにすれば動く
/Users/hoge/Documents/HTML/アーカイブ/html/src
↓
/Users/hoge/Documents/HTML/arcv/html/srczip圧縮した時にファイル名こうなった模様
以下自分が検索しやすいようにエラー貼り付け
DEPRECATION WARNING on line 87 of /Users/username/.rbenv/versions/2.x.x/lib/ruby/gems/2.x.x/gems/compass-core-1.0.3/stylesheets/compass/css3/_deprecated-support.scss:
#{} interpolation near operators will be simplified in a future version of Sass.
To preserve the current behavior, use quotes:unquote('"\$moz-"#{\$experimental-support-for-mozilla} "\$webkit-"#{\$experimental-support-for-webkit} "\$opera-"#{$experimental-support-for-opera} "\$microsoft-"#{\$experimental-support-for-microsoft} "\$khtml-"#{\$experimental-support-for-khtml}')
You can use the sass-convert command to automatically fix most cases.
DEPRECATION WARNING on line 92 of /Users/username/.rbenv/versions/2.x.x/lib/ruby/gems/2.x.x/gems/compass-core-1.0.3/stylesheets/compass/css3/_deprecated-support.scss:
#{} interpolation near operators will be simplified in a future version of Sass.
To preserve the current behavior, use quotes:unquote('"\$ie6-"#{\$legacy-support-for-ie6} "\$ie7-"#{\$legacy-support-for-ie7} "\$ie8-"#{$legacy-support-for-ie8}')
You can use the sass-convert command to automatically fix most cases.
- 投稿日:2019-04-03T01:04:07+09:00
Rails初学者が次に覚えるべきルーティング
ルーティングを制するものはRailsを制す!
目次
・rootとなるURLを指定する
・パスごとに個々のルーティングを設定する
・resources
・id以外のパスを指定するparamオプション
・単数 resource
・resourcesのネスト
・アクションの絞り込み
・onlyオプション
・exceprオプション
・アクションの追加
・member
・collection
・ルーティングをまとめる
・namespace
・scope
・module
・おわりにrootとなるURLを指定する
routes.rbroot to: "toppages#index"生成されるパスPrefix Verb URI Pattern Controller#Action root GET / toppages#indexパスごとに個々のルーティングを設定する
routes.rbget 'users/:id', to: 'users#show', as: 'users'生成されるパスPrefix Verb URI Pattern Controller#Action users GET /users/:id(.:format) users#show
asオプション
を使うことでルート名(Prefix)を指定することができます。resources
RESTfulなURLを生成できる
resources
はルーティングの基本です。routes.rbresources :users生成されるパスPrefix Verb URI Pattern Controller#Action users GET /users(.:format) users#index POST /users(.:format) users#create new_user GET /users/new(.:format) users#new edit_user GET /users/:id/edit(.:format) users#edit user GET /users/:id(.:format) users#show PATCH /users/:id(.:format) users#update PUT /users/:id(.:format) users#update DELETE /users/:id(.:format) users#destroy複数のリソースを同時に定義することもできます。
resources :users, :tweets, :photosid以外のパスを指定するparamオプション
showやeditなどのidを指定するアクションでは
paramオプション
を使ってid以外の値をパスに指定することもできます。
例えば、idの代わりにuser_nameを使う場合は以下のようになります。routes.rbresources :users, param: :user_name生成されるパスPrefix Verb URI Pattern Controller#Action users GET /users(.:format) users#index POST /users(.:format) users#create new_user GET /users/new(.:format) users#new edit_user GET /users/:user_name/edit(.:format) users#edit user GET /users/:user_name(.:format) users#show PATCH /users/:user_name(.:format) users#update PUT /users/:user_name(.:format) users#update DELETE /users/:user_name(.:format) users#destroy単数 resource
idの振り分けが不要なページでは単数形のresourceでRESTfulなURLを生成できます。
routes.rbresource :users生成されるパスPrefix Verb URI Pattern Controller#Action new_users GET /users/new(.:format) users#new edit_users GET /users/edit(.:format) users#edit users GET /users(.:format) users#show PATCH /users(.:format) users#update PUT /users(.:format) users#update DELETE /users(.:format) users#destroy POST /users(.:format) users#createresourcesのネスト
resources
ブロックの中に別のresources
をネストさせた場合のルーティングは以下のようになります。usersのRESTfulなURLが生成される他にネストされたtweetsのRESTfulなURLも生成されます。ネストさせる場合も必要に応じて単数resourceを使いましょう。routes.rbresources :users do resources :tweets end生成されるパスPrefix Verb URI Pattern Controller#Action user_tweets GET /users/:user_id/tweets(.:format) tweets#index POST /users/:user_id/tweets(.:format) tweets#create new_user_tweet GET /users/:user_id/tweets/new(.:format) tweets#new edit_user_tweet GET /users/:user_id/tweets/:id/edit(.:format) tweets#edit user_tweet GET /users/:user_id/tweets/:id(.:format) tweets#show PATCH /users/:user_id/tweets/:id(.:format) tweets#update PUT /users/:user_id/tweets/:id(.:format) tweets#update DELETE /users/:user_id/tweets/:id(.:format) tweets#destroy users GET /users(.:format) users#index POST /users(.:format) users#create new_user GET /users/new(.:format) users#new edit_user GET /users/:id/edit(.:format) users#edit user GET /users/:id(.:format) users#show PATCH /users/:id(.:format) users#update PUT /users/:id(.:format) users#update DELETE /users/:id(.:format) users#destroyアクションの絞り込み
resources
を使うとRESTfulなURLを簡単に生成できますが、必ずしも全てのアクションが必要とは限りません。不要なデフォルトアクションはオプションで絞り込みましょう。only オプション
使用するデフォルトアクションが少ない場合はonly オプションが便利です。
routes.rbresources :users, only: [:index, :show]生成されるパスPrefix Verb URI Pattern Controller#Action users GET /users(.:format) users#index user GET /users/:id(.:format) users#showexcept オプション
使用するデフォルトアクションが多い場合はexcept オプションが便利です。
routes.rbresources :users, except: [:show, :destroy]生成されるパスPrefix Verb URI Pattern Controller#Action users GET /users(.:format) users#index POST /users(.:format) users#create new_user GET /users/new(.:format) users#new edit_user GET /users/:id/edit(.:format) users#edit user PATCH /users/:id(.:format) users#update PUT /users/:id(.:format) users#updateアクションの追加
Rails標準のindex, show, new, edit, create, update, destroy 以外のアクションを追加する場合には
member
またはcollection
を使います。
両者にはmember
ではidを伴うパスが生成され、collection
ではidのないパスが生成されるという違いがあります。member
member
はidを伴うパスの生成に使います。routes.rbresources :users do member do get :search end end追加で生成されるパスPrefix Verb URI Pattern Controller#Action search_user GET /users/:id/search(.:format) users#search ~省略~collection
idの指定をしないパスの生成には
collection
を使います。routes.rbresources :users do collection do get :search end end追加で生成されるパスPrefix Verb URI Pattern Controller#Action search_users GET /users/search(.:format) users#search ~省略~ルーティングをまとめる
続いてルーティングをまとめていきます。ルーティングをまとめることでアプリケーション全体の構成も整理されます。
namespace
ルーティングを名前空間
namespace
のブロックで囲むとパスとコントローラーを指定のディレクトリ配下におくことができます。routes.rbnamespace :admin do resources :users end生成されるパスPrefix Verb URI Pattern Controller#Action admin_users GET /admin/users(.:format) admin/users#index POST /admin/users(.:format) admin/users#create new_admin_user GET /admin/users/new(.:format) admin/users#new edit_admin_user GET /admin/users/:id/edit(.:format) admin/users#edit admin_user GET /admin/users/:id(.:format) admin/users#show PATCH /admin/users/:id(.:format) admin/users#update PUT /admin/users/:id(.:format) admin/users#update DELETE /admin/users/:id(.:format) admin/users#destroyscope
パスのみを指定のディレクトリ配下におく場合は
scope
を使います。routes.rbscope '/admin' do resources :users end生成されるパスPrefix Verb URI Pattern Controller#Action users GET /admin/users(.:format) users#index POST /admin/users(.:format) users#create new_user GET /admin/users/new(.:format) users#new edit_user GET /admin/users/:id/edit(.:format) users#edit user GET /admin/users/:id(.:format) users#show PATCH /admin/users/:id(.:format) users#update PUT /admin/users/:id(.:format) users#update DELETE /admin/users/:id(.:format) users#destroymodule
コントローラーのみを指定のディレクトリ配下におく場合は
module
を使います。routes.rbscope module: :admin do resources :users end生成されるパスPrefix Verb URI Pattern Controller#Action users GET /users(.:format) admin/users#index POST /users(.:format) admin/users#create new_user GET /users/new(.:format) admin/users#new edit_user GET /users/:id/edit(.:format) admin/users#edit user GET /users/:id(.:format) admin/users#show PATCH /users/:id(.:format) admin/users#update PUT /users/:id(.:format) admin/users#update DELETE /users/:id(.:format) admin/users#destroyおわりに
細かいルーティングのオプションは他にもありますが、まずはここで紹介したものが組み合わせて使えると良いと思います。ありがとうございました。
- 投稿日:2019-04-03T01:04:07+09:00
Rails ルーティングのすべて
※ルーティングのすべてと言っておきながら「すべて」ではありません。ごめんなさい。
ルーティングを制するものはRailsを制す!
目次
・rootとなるURLを指定する
・パスごとに個々のルーティングを設定する
・resources
・id以外のパスを指定するparamオプション
・単数 resource
・resourcesのネスト
・アクションの絞り込み
・onlyオプション
・exceprオプション
・アクションの追加
・member
・collection
・ルーティングをまとめる
・namespace
・scope
・module
・おわりにrootとなるURLを指定する
routes.rbroot to: "toppages#index"生成されるパスPrefix Verb URI Pattern Controller#Action root GET / toppages#indexパスごとに個々のルーティングを設定する
routes.rbget 'users/:id', to: 'users#show', as: 'users'生成されるパスPrefix Verb URI Pattern Controller#Action users GET /users/:id(.:format) users#show
asオプション
を使うことでルート名(Prefix)を指定することができます。resources
RESTfulなURLを生成できる
resources
はルーティングの基本です。routes.rbresources :users生成されるパスPrefix Verb URI Pattern Controller#Action users GET /users(.:format) users#index POST /users(.:format) users#create new_user GET /users/new(.:format) users#new edit_user GET /users/:id/edit(.:format) users#edit user GET /users/:id(.:format) users#show PATCH /users/:id(.:format) users#update PUT /users/:id(.:format) users#update DELETE /users/:id(.:format) users#destroy複数のリソースを同時に定義することもできます。
resources :users, :tweets, :photosid以外のパスを指定するparamオプション
showやeditなどのidを指定するアクションでは
paramオプション
を使ってid以外の値をパスに指定することもできます。
例えば、idの代わりにuser_nameを使う場合は以下のようになります。routes.rbresources :users, param: :user_name生成されるパスPrefix Verb URI Pattern Controller#Action users GET /users(.:format) users#index POST /users(.:format) users#create new_user GET /users/new(.:format) users#new edit_user GET /users/:user_name/edit(.:format) users#edit user GET /users/:user_name(.:format) users#show PATCH /users/:user_name(.:format) users#update PUT /users/:user_name(.:format) users#update DELETE /users/:user_name(.:format) users#destroy単数 resource
idの振り分けが不要なページでは単数形のresourceでRESTfulなURLを生成できます。
routes.rbresource :users生成されるパスPrefix Verb URI Pattern Controller#Action new_users GET /users/new(.:format) users#new edit_users GET /users/edit(.:format) users#edit users GET /users(.:format) users#show PATCH /users(.:format) users#update PUT /users(.:format) users#update DELETE /users(.:format) users#destroy POST /users(.:format) users#createresourcesのネスト
resources
ブロックの中に別のresources
をネストさせた場合のルーティングは以下のようになります。usersのRESTfulなURLが生成される他にネストされたtweetsのRESTfulなURLも生成されます。ネストさせる場合も必要に応じて単数resourceを使いましょう。routes.rbresources :users do resources :tweets end生成されるパスPrefix Verb URI Pattern Controller#Action user_tweets GET /users/:user_id/tweets(.:format) tweets#index POST /users/:user_id/tweets(.:format) tweets#create new_user_tweet GET /users/:user_id/tweets/new(.:format) tweets#new edit_user_tweet GET /users/:user_id/tweets/:id/edit(.:format) tweets#edit user_tweet GET /users/:user_id/tweets/:id(.:format) tweets#show PATCH /users/:user_id/tweets/:id(.:format) tweets#update PUT /users/:user_id/tweets/:id(.:format) tweets#update DELETE /users/:user_id/tweets/:id(.:format) tweets#destroy users GET /users(.:format) users#index POST /users(.:format) users#create new_user GET /users/new(.:format) users#new edit_user GET /users/:id/edit(.:format) users#edit user GET /users/:id(.:format) users#show PATCH /users/:id(.:format) users#update PUT /users/:id(.:format) users#update DELETE /users/:id(.:format) users#destroyアクションの絞り込み
resources
を使うとRESTfulなURLを簡単に生成できますが、必ずしも全てのアクションが必要とは限りません。不要なデフォルトアクションはオプションで絞り込みましょう。only オプション
使用するデフォルトアクションが少ない場合はonly オプションが便利です。
routes.rbresources :users, only: [:index, :show]生成されるパスPrefix Verb URI Pattern Controller#Action users GET /users(.:format) users#index user GET /users/:id(.:format) users#showexcept オプション
使用するデフォルトアクションが多い場合はexcept オプションが便利です。
routes.rbresources :users, except: [:show, :destroy]生成されるパスPrefix Verb URI Pattern Controller#Action users GET /users(.:format) users#index POST /users(.:format) users#create new_user GET /users/new(.:format) users#new edit_user GET /users/:id/edit(.:format) users#edit user PATCH /users/:id(.:format) users#update PUT /users/:id(.:format) users#updateアクションの追加
Rails標準のindex, show, new, edit, create, update, destroy 以外のアクションを追加する場合には
member
またはcollection
を使います。
両者にはmember
ではidを伴うパスが生成され、collection
ではidのないパスが生成されるという違いがあります。member
member
はidを伴うパスの生成に使います。routes.rbresources :users do member do get :search end end追加で生成されるパスPrefix Verb URI Pattern Controller#Action search_user GET /users/:id/search(.:format) users#search ~省略~collection
idの指定をしないパスの生成には
collection
を使います。routes.rbresources :users do collection do get :search end end追加で生成されるパスPrefix Verb URI Pattern Controller#Action search_users GET /users/search(.:format) users#search ~省略~ルーティングをまとめる
続いてルーティングをまとめていきます。ルーティングをまとめることでアプリケーション全体の構成も整理されます。
namespace
ルーティングを名前空間
namespace
のブロックで囲むとパスとコントローラーを指定のディレクトリ配下におくことができます。routes.rbnamespace :admin do resources :users end生成されるパスPrefix Verb URI Pattern Controller#Action admin_users GET /admin/users(.:format) admin/users#index POST /admin/users(.:format) admin/users#create new_admin_user GET /admin/users/new(.:format) admin/users#new edit_admin_user GET /admin/users/:id/edit(.:format) admin/users#edit admin_user GET /admin/users/:id(.:format) admin/users#show PATCH /admin/users/:id(.:format) admin/users#update PUT /admin/users/:id(.:format) admin/users#update DELETE /admin/users/:id(.:format) admin/users#destroyscope
パスのみを指定のディレクトリ配下におく場合は
scope
を使います。routes.rbscope '/admin' do resources :users end生成されるパスPrefix Verb URI Pattern Controller#Action users GET /admin/users(.:format) users#index POST /admin/users(.:format) users#create new_user GET /admin/users/new(.:format) users#new edit_user GET /admin/users/:id/edit(.:format) users#edit user GET /admin/users/:id(.:format) users#show PATCH /admin/users/:id(.:format) users#update PUT /admin/users/:id(.:format) users#update DELETE /admin/users/:id(.:format) users#destroymodule
コントローラーのみを指定のディレクトリ配下におく場合は
module
を使います。routes.rbscope module: :admin do resources :users end生成されるパスPrefix Verb URI Pattern Controller#Action users GET /users(.:format) admin/users#index POST /users(.:format) admin/users#create new_user GET /users/new(.:format) admin/users#new edit_user GET /users/:id/edit(.:format) admin/users#edit user GET /users/:id(.:format) admin/users#show PATCH /users/:id(.:format) admin/users#update PUT /users/:id(.:format) admin/users#update DELETE /users/:id(.:format) admin/users#destroyおわりに
細かいルーティングのオプションは他にもありますが、まずはここで紹介したものが組み合わせて使えると良いと思います。ありがとうございました。
- 投稿日:2019-04-03T00:29:16+09:00
[Ruby] 真偽値を返すメソッドの実装について
Ruby で true / false を返すメソッドの実装について、いくつか書き方があると思ったのでまとめてみた。
前提
こんな感じの仕様のメソッドを実装するときのことを考える
下記条件を全て満たす場合 "true" を返し、それ以外の場合は "false" を返す、ポイント付与可能かどうかを判定するメソッド - ログインユーザーであること - ユーザーのステータスコードが "1" であること<条件を整理する>
logged_in? user.status_code 結果 true 1 true true 0 false false 1 false false 0 false 1. 真面目実装
超真面目に実装するとこうなる。こんな書き方をしたのは久しぶりなので、なんだか気持ち悪い。こういう書き方は Ruby だとあまり見ないかも?
def pointable? if logged_in? if user.status_code == '1' true else false end else false end end2. 比較演算子
比較演算子を使って実装する。
def pointable? logged_in? && user.status_code == '1' end※ Ruby 触り始めは、こんな風に書いていたなー。
def pointable? (logged_in? && user.status_code == '1') ? true : false end3. ガード節
- 全て満たす場合に "true" なので、ひとつでも "false" になる条件があったらその時点で return する
- 結構よく見る
- ネストが浅くなるので読みやすい
- 正常系とエラー系の処理が別れていて読みやすい
- 最後の "true" を書き忘れることがあるが(実際この前書き忘れた)、テストをちゃんと書いていれば気付けるはず
def pointable? return false unless logged_in? return false if user.status_code != '1' true end※ if 使うか unless 使うかは好みの問題だと思うけど結構迷う。個人的には下記の2択だったら、前者の方が分かりやすくて好き。
# false を返す、もし user.status_code が '1' でないならば return false if user.status_code != '1' # false を返す、そうじゃないなら user.status_code が '1' である return false unless user.status_code == '1'4. all? メソッドを使う
こんなのも思いついたけど、どうなんでしょう。
def pointable? [logged_in?, user.status_code == '1'].all? endまとめ
同じ仕様のメソッドでも、実装の仕方がいくつもあるので考えてみると楽しいです。
個人的には、2. 比較演算子
か3. ガード節
の書き方をよく見るし読みやすくて好きなのですが、どうなんでしょう。
- 投稿日:2019-04-03T00:09:25+09:00
railsでtwitter api ログイン認証を使おうとしたらエラー400でたのでメモっとく
はじめに開発環境は
mac os x
ruby '2.5.2'
'rails', '~> 5.2.3'を使っています。
何をしたいか
railsでtwitterログイン認証をしたい
どのgemを使ったか?
gem 'omniauth'
gem 'omniauth-twitter'作業したこと
/.envAPI_KEY = "xxxxxxxxxxxxxxxxxxxxxxxxxxx" API_SECRET = "xxxxxxxxxxxxxxxxxxxxxxxxx"config/initializers/omniauth.rbRails.application.config.middleware.use OmniAuth::Builder do provider :twitter, ENV["API_KEY"], ENV["API_SECRET"] endを書いて rails s でrails サーバー起動したら 400が出た
どうやって直したか
400のエラーはそもそもENVで
ENV["API_KEY"], ENV["API_SECRET"]
が取れていないことが問題らしいなのでこれを書いた。
/Gemfile.gem 'omniauth' gem 'omniauth-twitter'でbundle installしたらenvが正常に動作して、エラーが消えた
終わり