20190310のRailsに関する記事は11件です。

http://localhost:3000/に特定のページを表示させたい(ルートへのルーティング設定)

専門的には、ルートへのルーティング設定をするというらしいです。
本当の初心者にとっては、そのワードすら知らないのでggrksと言われてもなかなか辛いところありますよね。。。

ルートへのルーティング設定とは

Cloud9環境では、
https://〜.amazonaws.com/

Vagrant環境では、
http://localhost:3000/
にアクセスした時に、デフォルトで表示される「Welcome aboard」のページではなく、
自分で作ったページなり、アクションなりを表示させたい時にする設定のことです。

ルートへのルーティング設定を行う

早速やっていきましょう!

コントローラーとアクションを作る

ターミナルに下記のコードをうちます。
$ rails g controller コントローラー名 アクション名

ルートファイルを編集する

「config/routes.rb」ファイルに下記のコードを書き込みます。
root :to => 'コントローラ名#アクション名'

例えば、http://localhost:3000/にアクセスした時に、
indexページを表示させたい場合は、
root :to => 'コントローラ名#index'
と書きます。

これだけです。
もう少し理解が進んだら、ルートとは、ルーティング設定とは、というところも細かく書きたいです。
RESTfulなルーティングを設定するというところも書きたい。。
でも今は、これが精一杯なのでご勘弁ください。

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

府中産農産物直売所検索ページをとおしてかんたんなrailsアプリつくってみよう

概要

  • 府中市が公開しているオープンデータを検索する事を事例にして、railsのアプリを作成する方法を丁寧に解説します。

作れるモノ

https://fuchu-nosanbutsu.herokuapp.com/

github

https://github.com/junara/fuchu-nosanbutsu

環境

  • ruby (rbenv) 2.6.1
  • rails 6.0.0 beta 2
  • mac

使っているGem

手順

以下の手順で説明します
1. rails new ! (空のアプリを作ろう)
2. migration ! (テーブル作ろう)
3. import ! (データをインポートしよう)
4. view ! (データを表示しよう)
4. search ! (データを検索できるようにしよう)
5. deploy ! (herokuにアップしてみんなで使えるようにしよう)

rails new ! (空のアプリを作ろう)

> bundle init
Writing new Gemfile to /Users/junara/IdeaProjects/opendata/Gemfile
> ls
Gemfile      Gemfile.lock 

railsをインストールするために gem "rails" のコメントをアウトを外します。

# frozen_string_literal: true

source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

gem "rails"

インストールします。フォルダの場所は ./vendor/bundle にします

bundle install --path vendor/bundle
# 省略

ここでいちど起動を確認しましょう

rails s

http://localhost:3000 にアクセスします。下記の画面が出たら成功です。
image.png

migration ! (テーブル作ろう)

今回対象となるデータを見ます。 府中産農産物直売所マップ(平成30年11月現在) (CSV:11KB)

 rails g model store                                                                                                     ?[HEAD]
Running via Spring preloader in process 84006
      invoke  active_record
      create    db/migrate/20190310103813_create_stores.rb
      create    app/models/store.rb
      invoke    test_unit
      create      test/models/store_test.rb
      create      test/fixtures/stores.yml

db/migrate/20190310103813_create_stores.rb
class CreateStores < ActiveRecord::Migration[6.0]
  def change
    create_table :stores do |t|
      t.string :name
      t.string :description
      t.timestamps
    end
  end
end
rails db:migrate                                                                                                        ?[HEAD]
== 20190310103813 CreateStores: migrating =====================================
-- create_table(:stores)
   -> 0.0113s
== 20190310103813 CreateStores: migrated (0.0113s) ============================

import ! (データをインポートしよう)

下記のgemを入れます。importするときの定番。

gem 'activerecord-import'
bundle install
# 省略

インポートするデータを府中市のHPからダウンロードして、下記に保存します。
府中産農産物直売所マップ(平成30年11月現在) (CSV:11KB)

db/30chokubaijo_map.csv
№,名 前,直売所住所,電話番号,営業時間,販売期間,休業日,販売品目,コメント
# 省略

取り込むためのメソッドをStoreモデルに書きます。

require 'csv'
class Store < ApplicationRecord
  def self.import_csv(file)
    list = []
    ActiveRecord::Base.transaction do
      CSV.foreach(file, encoding: 'cp932', headers: true) do |row|
        list << self.new(store_params(row))
      end
      import list
    end
  end

  def self.store_params(row)
    {
        name: row['名 前'],
        description: row['販売品目']
    }
  end
end

先ほど db/30chokubaijo_map.csv に保存したcsvをインポートします。

rails c
irb > Store.import_csv('db/30chokubaijo_map.csv')
   (0.2ms)  SELECT sqlite_version(*)
   (0.1ms)  begin transaction
   (0.1ms)  SAVEPOINT active_record_1
# 省略
   (0.1ms)  RELEASE SAVEPOINT active_record_1
   (0.8ms)  commit transaction
=> #<struct ActiveRecord::Import::Result failed_instances=[], num_inserts=1, ids=[], results=[]>

保存されているか確認します。

irb > Store.first.description
  Store Load (0.2ms)  SELECT "stores".* FROM "stores" ORDER BY "stores"."id" ASC LIMIT ?  [["LIMIT", 1]]
=> "トマト、きゅうり、おくら、いんげん、キャベツ、さつまいも、ブロッコリー、ねぎ、なす、モロヘイヤ、ピーマン、紫イモ、カリフラワー、じゃがいも、里いも、大根、ほうれん草、水菜 ほか"
irb(main):009:0>  Store.count
   (0.2ms)  SELECT COUNT(*) FROM "stores"
=> 46

view ! (データを表示しよう)

ルートを追加します。

config/routes.rb
Rails.application.routes.draw do
  root to: 'home#index'
end

上記で追加したhomeのアクションを行うコントローラーを新規で追加します。

app/controllers/home_controller.rb
class HomeController < ApplicationController
  def index
    @stores = Store.all
  end
end
app/views/home/index.html.erb
<h2>
  府中産農産物直売所一覧
</h2>
<% @stores.each do |store| %>
  <div>
    <h3>
      <%= store.name %>
    </h3>
    <div>
      <%= store.description %>
    </div>
  </div>
<% end %>

ここで確認します。
http://localhost:3000/

image.png

search ! (データを検索できるようにしよう)

Activerecordでやるのは面倒なので、定番の検索のgem ransackを入れます。

gem 'ransack'

で、インストール

bundle install

検索するために、indexアクションを修正します。
ransackの使い方は公式をどうぞ。

app/controllers/home_controller.rb
class HomeController < ApplicationController
  def index
    @stores = Store.ransack(description_cont: params[:keyword]).result
  end
end

検索フォームをviewについかします。

<h2>
  府中産農産物直売所一覧
</h2>

<div>
  <%= form_with url: root_path, method: :get, local: true do |f| %>
    <%= f.text_field :keyword, value: params[:keyword], autocomplete: 'off' %>
    <%= f.submit '検索' %>
  <% end %>
</div>
<% @stores.each do |store| %>
  <div>
    <h3>
      <%= store.name %>
    </h3>
    <div>
      <%= store.description %>
    </div>
  </div>
<% end %>

ためします。
入力ボックスに 乳酸菌飲料 と入力すると下記のようになれば成功です。

image.png

deploy ! (herokuにアップして世界のみんなに使ってもらおう)

developmentとtest環境ではsqlite3, productionではpgをインストールします。

group :development, :test do
  gem 'sqlite3'
end

group :production do
  gem 'pg'
end

herokuへpushと同時に migrationが走るようにしましょう

release: bundle exec rake db:migrate

herokuのアプリを作ります。

heroku create fuchu-nosanbutsu

現行のmasterをherokuへpushします。

git push heroku master

うまくdeployされたかみましょう

heroku open

こういう表示なら成功です。

image.png

次にデータをインポートします。herokuでrails cをします。

heroku run rails c

既にやったようにインポートをします。

Store.import_csv('db/30chokubaijo_map.csv')
Store.count # -> 46

終わったらexit

exit

herokuのページを再度リロードすると前述と同様に、一覧が表示され、検索も可能なことが確認できます。

image.png

完成です!!!これで、世界の人に府中市の農産物をアピールできました!

さらに発展させるには?

作ったのは、とてーもシンプルなアプリです。更に発展させるともっと使いやすいアプリになります。ご自身の興味にしたがって色々やってみましょう。
下記は、拡張例です!
是非挑戦しましょう!

かんたんめ

  • インポート対象を追加する:元のCSVには、住所などの列もあります。そちらもインポート対象にしましょう。
  • インポートした列を表示に追加しましょう。
  • 検索結果にページネーションを加えましょう
  • 検索キーワード結果の文章にマッチしたキーワードをハイライトさせましょう。
  • 複数のカラムを対象に検索できるようにしましょう
  • bootstrapを導入して、装飾しましょう
  • bulmaを導入して装飾しましょう
  • 住所を押した時、google mapに遷移させましょう
  • データを追加、編集できるフォームを追加しましょう
  • herokuにdeployしましょう

そこそこ

  • インポート時、重複列がある場合はupdateにしましょう
  • 空白スペースで区切った場合はand検索になるようにしましょう
  • 検索をページ遷移せずajaxで行いましょう
  • 地図(google map)を表示させましょう

むずかしめ

  • インクリメンタルサーチを入れましょう
  • vue or reactでフロントを書きましょう

enjoy !

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

Rails: 5分で住所を自動入力しよう

もっと住所入力を楽にしてみない?

CtoCサービスのWebアプリを作る時、大抵のアプリには住所入力の項目があるかと思います。
その時に、自分で一から実装するのもいいけどめんどくさい時ってありますよね?
そんなあなたに5分で実装出来るプラグイン「gem」を教えたい。

手順

まず最初に、下記で必要なjsファイルをダウンロードしてください。
ファイルは、assets/javascript/に置いてください。

jquery.jpostal.js
1. 練習なので$rails g scaffold Userを事前に作っておきます。
2. 次にgemを追加していきます。

必須gem
gem 'jp_prefecture'
gem 'jquery-rails' 

3. 次にbundle installをしましょ
4. ここでは、mifrationファイルを作っていきます。
  $rails g migration AddColumnsToUsers postcode:integer

class AddColumnsToUsers < ActiveRecord::Migration[5.1] 
  def change 
     add_column :users, :postcode, :integer 
     add_column :users, :prefecture_code, :integer 
     add_column :users, :address_city, :string 
     add_column :users, :address_street, :string 
     add_column :users, :address_building, :string 
  end 
end 

5. $ rails db:migrateをしましょ。
6. modelを編集していきます。
app/models/user.rb

class User < ApplicationRecord

  include JpPrefecture
  jp_prefecture :prefecture_code

  def prefecture_name
    JpPrefecture::Prefecture.find(code: prefecture_code).try(:name)
  end

  def prefecture_name=(prefecture_name)
    self.prefecture_code = JpPrefecture::Prefecture.find(name: prefecture_name).code
  end

end

7. Viewファイルを編集しています。
app/views/users/_form.html.erb

  <h2>Your address</h2>
  <p>zip code</p>
  <%= form.text_field :postcode %>
  <p>prefecture</p>
  <%= form.text_field :prefecture_code, collection: JpPrefecture::Prefecture.all, :value_method => :name, include_blank: '都道府県' %><br>
  <p>city</p>
  <%= form.text_field :address_city %>
  <p>street</p>
  <%= form.text_field :address_street %>
  <p>builbding name</p>
  <%= form.text_field :address_building %>

  <div class="actions">
    <%= form.submit %>

8. 次に、jQueryでjpostalメソッドの呼び出しをしていきます。
app/assets/javascripts/user.coffee

$ ->
  $("#user_postcode").jpostal({
    postcode : [ "#user_postcode" ],
    address  : {
                  "#user_prefecture_code" : "%3",
                  "#user_address_city"            : "%4",
                  "#user_address_street"          : "%5%6%7"
                }
  })

こうすると、郵便番号を入力すると反映されるかと思います。
9. 最後に、Controllerでストロングパラメーターを設定します。
app/controllers/users_controller.rb

def zipedit
  params.require(:user).permit(:postcode, :prefecture_name, :address_city, :address_street, :address_building)
end

すでに、関連する記事がいくつかありますが更新日が古かったので個人的メモのついでにアップデートしてみました。
こんな感じで、誰かの助けになればと思います。

なお、最短でやって5分なので思いのほか時間がかかっても責めないでないください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Rails: 5分で住所を自動入力かしよう

もっと住所入力を楽にしてみない?

CtoCサービスのWebアプリを作る時、大抵のアプリには住所入力の項目があるかと思います。
その時に、自分で一から実装するのもいいけどめんどくさい時ってありますよね?
そんなあなたに5分で実装出来るプラグイン「gem」を教えたい。

手順

まず最初に、下記で必要なjsファイルをダウンロードしてください。
ファイルは、assets/javascript/に置いてください。

jquery.jpostal.js
1. 練習なので$rails g scaffold Userを事前に作っておきます。
2. 次にgemを追加していきます。

必須gem
gem 'jp_prefecture'
gem 'jquery-rails' 

3. 次にbundle installをしましょ
4. ここでは、mifrationファイルを作っていきます。
  $rails g migration AddColumnsToUsers postcode:integer

class AddColumnsToUsers < ActiveRecord::Migration[5.1] 
  def change 
     add_column :users, :postcode, :integer 
     add_column :users, :prefecture_code, :integer 
     add_column :users, :address_city, :string 
     add_column :users, :address_street, :string 
     add_column :users, :address_building, :string 
  end 
end 

5. $ rails db:migrateをしましょ。
6. modelを編集していきます。
app/models/user.rb

class User < ApplicationRecord

  include JpPrefecture
  jp_prefecture :prefecture_code

  def prefecture_name
    JpPrefecture::Prefecture.find(code: prefecture_code).try(:name)
  end

  def prefecture_name=(prefecture_name)
    self.prefecture_code = JpPrefecture::Prefecture.find(name: prefecture_name).code
  end

end

7. Viewファイルを編集しています。
app/views/users/_form.html.erb

  <h2>Your address</h2>
  <p>zip code</p>
  <%= form.text_field :postcode %>
  <p>prefecture</p>
  <%= form.text_field :prefecture_code, collection: JpPrefecture::Prefecture.all, :value_method => :name, include_blank: '都道府県' %><br>
  <p>city</p>
  <%= form.text_field :address_city %>
  <p>street</p>
  <%= form.text_field :address_street %>
  <p>builbding name</p>
  <%= form.text_field :address_building %>

  <div class="actions">
    <%= form.submit %>

8. 次に、jQueryでjpostalメソッドの呼び出しをしていきます。
app/assets/javascripts/user.coffee

$ ->
  $("#user_postcode").jpostal({
    postcode : [ "#user_postcode" ],
    address  : {
                  "#user_prefecture_code" : "%3",
                  "#user_address_city"            : "%4",
                  "#user_address_street"          : "%5%6%7"
                }
  })

こうすると、郵便番号を入力すると反映されるかと思います。
9. 最後に、Controllerでストロングパラメーターを設定します。
app/controllers/users_controller.rb

def zipedit
  params.require(:user).permit(:postcode, :prefecture_name, :address_city, :address_street, :address_building)
end

すでに、関連する記事がいくつかありますが更新日が古かったので個人的メモのついでにアップデートしてみました。
こんな感じで、誰かの助けになればと思います。

なお、最短でやって5分なので思いのほか時間がかかっても責めないでないください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

プログラミング学習記録22〜ToDoアプリ完成(写経)〜

今日やったこと

  • Udemyの「Web開発入門完全攻略コース - プログラミングをはじめて学び創れる人へ!未経験から現場で使える開発スキルを習得!」のセクション15の215~248

なんとかコースを1周しました。

以下、パートごとの学習メモです。

セクション15Ruby on Rails 5入門

215.イントロダクション -Ruby on Rails 5入門-

このセクションの概要。

216.開発環境構築

AWS Cloud9
Ruby on Rails 5.1.4
Ruby 2.5.0
sqlite3

なぜか5.1.4をインストールしても,5.1.6.1になってしまうのですが、大きな違いはないと思うので、このまま進みます。

ターミナルでrailsをインストールしました。

217.railsプロジェクトの作成

helloプロジェクトを作成しました。

218.ディレクトリ構成について

MVC(モデル・ビュー・コントローラー)
Model→データ
View→画面
Controller→ModelとViewをつなぐ処理

どのファイルをいじっていくのかについての説明を受けました。

219.はじめてのRuby on Railsプログラミング

erbはテンプレートエンジンと呼ばれ、HTMLの中にrubyを組み込むことができます。

controllers、index.html.erb、routes.rbをいじり、無事Hello World!を表示させることができました。

220.TODOアプリの完成形の確認

この講座で作るTODOアプリの完成形を確認しました。

221.プロジェクトの作成

これから作るTODOアプリのプロジェクトを作りました。

動画の通りやっていたはずなのにうまくいかないハプニングが起こり、セクションの初めに戻るも解決せず…

※後日追記
todoのgemfileの方もgem 'sqlite3','~> 1.3.6’にして、ターミナルでbundle updateをしたらうまくいきました。

222.コントローラーの作成

tasks_controllerを作りました。

223.モデルの作成

224.マイグレーションファイルの編集

225.DBスキーマをDBに反映する

226.初期データ作成

227.ルーティングの設定

228.一覧画面のcontrollerを開発

229.一覧画面のviewを開発

230.一覧画面の動作確認

231.一覧画面へ新規追加画面へのリンクを追加

232.新規追加画面のviewを開発

233.新規追加画面のcontrollerを開発

234.新規追加画面の動作確認

235.バリデートの追加

テキストボックスに何も入力されていないときは、データベースに保存しないようにする設定をしました。

236.一覧画面から編集画面へのリンクを追加

237.編集機能のviewを開発

238.編集画面のcontrollerを開発

239.編集画面の動作確認

240.削除機能のviewを開発

241.削除機能のcontrollerを開発

242.削除機能 動作確認

243.チェックボックスのトグル動作について

244.jQueryのインストール

245.ルーティング設定

246.チェックボックスのトグル動作のcontrollerを開発

247.チェックボックスのトグル動作のクライアント側を開発

248.トグル動作の動作確認

セクション15Ruby on Rails 5入門

途中トラブルがありつつも、なんとか終えることができました。

よくわからずただ写経している部分がほとんどなのですが、それでも一通り体験できてよかったと思います。

今後はこの講座の復習を進めながら、中村先生のrailsのコースを受けてみます。



まだまだわからないことだらけですが、とりあえずコースを1周して達成感をしています。

raisはProgateすらやっていない状態で講座を受けたこともあり、理解が苦しかったです。

なので、これからProgateのrailsをやってみたいと思います。

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

おわり

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

Railsのrmagick(画像リサイズ用のgem)インストールエラー

rmagickインストールエラーの対処法

gemfileにgem 'rmagick'を足してbundle installを行うだけでは、ライブラリが足りずエラーが出ていたのですが、私の環境(Ubuntu)では、以下のコマンドを実行することで、正常にインストールできました。

$ sudo apt install imagemagick
$ sudo apt-get install imagemagick libmagickcore-dev libmagickwand-dev
$ bundle install
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

①連続した数を配列に入れる。②文字列からn個抜き出すと何通りあるか?

①1〜5の連続した数を配列に入れる

m = (1..5) => 1..5
m = (1..5).to_a => [1,2,3,4,5]

to_aを使うと配列に変換される。

②文字列から何個抜き出すと何通りあるか?

文字列.combination
[1,2,3,4]の中からn個抜き取る。重複しない組み合わせ。逆順含まない(例[1,2][2,1]は含まない)

n = 2
[1,2,3,4].combination(n).to_a => [[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]

文字列.permutation
[1,2,3,4]の中からn個抜き取る。重複しない組み合わせ。逆順含む(例[1,2][2,1]含む)

n = 2
[1,2,3,4].permutation(n).to_a => [[1, 2], [1, 3], [1, 4], [2, 1], [2, 3], [2, 4], [3, 1], [3, 2], [3, 4], [4, 1], [4, 2], [4, 3]]
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

fields_forにハマった

日記に画像を登録するのに、diaryモデルとimageモデルを使用して実装。

画像の登録はcarrierwaveを使いました。

別モデルのデータを表示するにはアソシエーションとfields_forでのフォーム生成が必要。

アソシエーション

diary:image = 1:多 の関係性なので

diary.rb
has_many :images, dependent: :destroy
#オプション(dependent: :destroy)で日記が消えたらそれに関連する画像も消える設定にした。
image.rb
belongs_to :diary

リファレンスキー追加

ターミナル
rails g migration add_references_to_images diary:references
create_images.rb
class CreateImages < ActiveRecord::Migration[5.2]
  def change
    create_table :images do |t|
      t.string :name
      t.references :diary, foreign_key: true #追記

      t.timestamps
    end
  end
end
add_references_to_images.rb
class AddReferencesToImages < ActiveRecord::Migration[5.2]
  def change
    add_reference :images, :diary, foreign_key: true
  end
end

これでimagesテーブルにdiary_idが入る。

gemインストール

Gemfile
gem 'carrierwave'
ターミナル
bundle install

uploader追加

ターミナル
rails g uploader image
image.rb
mount_uploader :name, ImageUploader
#nameカラムに画像のデータが入ります。

入力フォーム作成

_form.html.erb(diary)
<%= form_for(@diary) do |form| %>
  <% if @diary.errors.any? %>
    <div id="error_explanation">
      <%= pluralize(angel.errors.count, "error") %> prohibited this diary from being saved:

  <div class="field">
    <%= form.label :date %>
    <%= form.date_field :date, value: Time.now.strftime("%Y-%m-%d") %>
  </div>

   <div class="field">
    <%= form.label :content %>
    <%= form.text_area :content %>
  </div>

#異なるモデル(imageモデル)をいじるときはform.fields_forを使う
  <%= form.fields_for :images do |image| %> 
    <div class="field">
      <%= image.label :image %> #表示名
      <%= image.file_field :name %> #ファイル選択ボックスを生成し、データの送り場所を指定
      <%= image.hidden_field :id %>
    </div>
  <% end %>


  <div class="actions">
    <%= form.submit %>
  </div>

<% end %>

<%= link_to 'Back', diaries_path %>

accepts_nested_attributes_for

diaries_controller.rb
class DiariesController < ApplicationController
    def new
      @diary = current_user.diaries.new
      @diary.images.build
    end

    def create
      @diary = current_user.diaries.build(diary_params)
      if @diary.save
        redirect_to @diary, notice: 'diary was successfully created.'
      else
        render :new
      end
    end

  private

    def diary_params
      params.require(:diary).permit(:date ,:gift ,:content ,:user_id ,:angel_id,
        images_attributes: [:id, :name, :_destroy])#編集や削除の際にid,;_destroyが必要らしい
    end
end
diary.rb
accepts_nested_attributes_for :images

モデルでaccepts_nested_attributes_forを指定することでコントローラのstrongparameter内でimages_attributeを使ってカラムを指定することができる

画像の表示

show.html.erb
<%= image_tag @diary.images.first.name.to_s %>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Factory_Botで undefined method '×××' in '○○○' factoryが発生する場合

RailsでFactory Botを使う時にタイトルのエラーが発生したので、原因と対応のメモです。

バージョン

Ruby 2.5.1
Rails 5.2.2
Factory Bot 5.0.1

エラーメッセージ

具体的には以下のエラーメッセージが出力されました。

/vendor/bundle/ruby/2.5.0/gems/factory_bot-5.0.1/lib/factory_bot
/definition_proxy.rb:97:in `method_missing': 
undefined method 'name' in 'user' factory (NoMethodError)

解決方法

エラー発生時のファクトリ

spec/factories/user.rb
FactoryBot.define do
  factory :user do
    name "Beer Lover"
    email "beerlover@example.com"
    password "beerlover"
  end
end

↓修正版

spec/factories/user.rb
FactoryBot.define do
  factory :user do
    name {"Beer Lover"}
    email {"beerlover@example.com"}
    password {"beerlover"}
  end
end

属性名に設定する値は{}で囲う必要があります。
Factory Botのバージョンが5.0.0からは{}で囲わないとエラーがでるように変更されたみたいですね。

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

[Rails]パーシャルをパーシャル名のみで呼び出そうとしてハマったところ

Railsチュートリアルの演習で、パーシャル名によるパーシャルの呼び出しでハマったポイントをまとめます。

環境

・Rails 5.1.6
・Rails チュートリアル第4版(Rails5.1)

演習問題

演習13.3.2.1

Homeページをリファクタリングして、if-else文の分岐のそれぞれに対してパーシャルを作ってみましょう。

演習前時点でのHomeビューは以下の通り。

/sample_app/app/views/static_pages/home.html.erb
<% if logged_in? %>
  <div class="row">
    <aside class="col-md-4">
      <section class="user_info">
        <%= render 'shared/user_info' %>
      </section>
      <section class="micropost_form">
        <%= render 'shared/micropost_form' %>
      </section>
    </aside>
</div>
<% else %>
  <div class="center jumbotron">
  <h1>Welcome to the Sample App</h1>

  <h2>
    This is the home page for the
    <a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a>
    sample application.
  </h2>

  <%= link_to "Sign up now!", signup_path, class: "btn btn-lg btn-primary" %>
</div>

<%= link_to image_tag("rails.png", alt: "Rails logo"),
            'http://rubyonrails.org/' %>
<% end %>

上記のifelseの中身をそれぞれパーシャルに切り出し、renderで呼び出すことによって、ifelseの中身を一行でスッキリ書こうという問題ですね。

自分の解答

/sample_app/app/views/static_pages/内に二つのパーシャルlogged_innot_logged_inを切り出し、home.html.erbから呼び出す。

/sample_app/app/views/static_pages/home.html.erb
<% if logged_in? %>
  <%= render 'logged_in' %>
<% else %>
  <%= render 'not_logged_in' %>
<% end %>

パーシャルをhome.html.erbと同じフォルダに配置したため、パーシャル名のみで指定できると考え、上のように記述しました。このときのフォルダ構成は以下の通り。

views/
 └ static_pages/
    ├ _logged_in.html.erb
    ├ _not_logged_in.html.erb
    └ home.html.erb

一見これで問題なく動作していたのですが、homeから空白のマイクロポストを投稿した際に下記のようなエラーが発生しました。

ActionView::Template::Error (Missing partial microposts/_logged_in

views/microposts/内に_logged_inパーシャルが無いと怒られています。
views/static_pages/内の_logged_inパーシャルを探して欲しいのですが...

原因

コントローラからrenderでビューを描画したとき、パーシャル名のみで指定できるパーシャルは、コントローラと対応するビューフォルダ(views/コントローラ名)内のパーシャルである。

今回の場合、homeから投稿したmicropostが不正(空白または141文字以上)のとき、エラーメッセージを付け加えてhomeビューを再描画します。

/sample_app/app/controllers/microposts_controller.rb
class MicropostsController < ApplicationController
  before_action :logged_in_user, only: [:create, :destroy]

  def create
    @micropost = current_user.microposts.build(micropost_params)
    if @micropost.save
      flash[:success] = "Micropost created!"
      redirect_to root_url
    else
      render 'static_pages/home'     # micropostが不正な場合、homeを再描画
    end
  end

  def destroy
  end

  private
    def micropost_params
      params.require(:micropost).permit(:content)
    end
end

このように、マイクロポストの作成に失敗したときは、microposts_controller.rbから、render 'static_pages/home'によって、homeビューを再描画しています。このとき、パーシャル名のみで指定できるパーシャルはviews/microposts内のパーシャルです。そのため、パーシャル名のみでパーシャルを指定すると、views/microposts内を探してしまい、エラーとなります。

views/
 ├ microposts/      ⬅️ ここを探してしまう!
 └ static_pages/
    ├ _logged_in.html.erb
    ├ _not_logged_in.html.erb
    └ home.html.erb

逆に、マイクロポストの作成に成功した場合や、直接homeのページのURLを入力した場合などは、static_pages_controller.rbからhomeビューを描画するので、views/static_pages内のパーシャルを探します。そのため、この場合はパーシャル名のみでパーシャルを呼び出していても、エラーが起きていませんでした。

正しい解答

/sample_app/app/views/static_pages/home.html.erb
<% if logged_in? %>
  <%= render 'static_pages/logged_in' %>
<% else %>
  <%= render 'static_pages/not_logged_in' %>
<% end %>

views/からの相対パスを指定すると、期待通りのパーシャル(logged_in)を呼び出すことができ、エラーが出なくなりました。

まとめ

ビューから、パーシャル名のみでパーシャルを呼び出すときは、そのビューを描画するコントローラを考慮する必要がある。

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

binding.pryでデバッグする

binding.pryを使うためにGemをインストール。

Gemfile
group :development do
  gem 'pry-rails'
  gem 'pry'
end

bundle installを実行する。

$ bundle install

コンソールを立ち上げる。

$ rails c

デバックしたいブレークポイントにbinding.pryと書く。
viewの場合は、<% binding.pry %>

サーバーを起動し、ブレイクポイントを設定したアクションに遷移するとコンソールがとまる。

binding.pryから抜けるコマンド

[1] pry(Hoge)> exit

binding.pryから強制的に抜けるコマンド
プロセスを終了してしまうため、rails sが落ちる。

[2] pry(Hoge)> exit!
[3] pry(Hoge)> !!!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む