- 投稿日:2020-02-27T22:45:21+09:00
Tweet app コントローラの記載ミス
投稿はできるがtext, image_urlが保存されないトラブルについて
確認して言った手順
1.投稿は完了するがビューへ反映されない。
2.ターミナルなどにはエラー文が出てこない。
3.データベースのtweetsテーブルを確認したところ保存されていない事がわかった。
4.tweets_controller.rbのcreate アクション内でbinding.pryを設け、paramsの中身を確認。13: def create => 14: binding.pry 15: Tweet.create(tweet_params) 16: end [1] pry(#<TweetsController>)> params => <ActionController::Parameters {"utf8"=>"✓", "authenticity_token"=>"0OetjLpGY/lhw+49IYsP6z/lYBicOBakjt7zB/n3lXPLq1ShQdX3hu5sZApmOfmY+rCNTiNpym1PH0lREvaCnw==", "tweet"=>{"image"=>"〇〇.jpg", "text"=>"test"}, "commit"=>"SEND", "controller"=>"tweets", "action"=>"create"} permitted: false>5.image と text の情報は取得できていることがわかる。
6.次にtweet_paramsを確認すると、user_id しか取得できていないことがわかった。[2] pry(#<TweetsController>)> tweet_params User Load (0.4ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 ORDER BY `users`.`id` ASC LIMIT 1 ↳ app/controllers/tweets_controller.rb:42 => {:user_id=>1}7.したがって、ストロングパラメータで指定しているパラメータに不備があることがわかる。
8. ストロングパラメータにおいて、image と text も許可(permit)するように記載することで解決できる。"tweet"=>{"image"=>"〇〇.jpg", "text"=>"test"},※tweetの中にimageとtextが入ってるので出してあげる必要がある。
9.最後に下記の内容へ変更したら正常となった。tweets_controller.rbBefore def tweet_params {user_id: current_user.id} end After def tweet_params params.permit(:image, :text).merge(user_id: current_user.id) end
- 投稿日:2020-02-27T22:16:29+09:00
複数の配列にeachメソッドを使いたい
rubyのzipメソッドを使えば可能
Ruby 2.7.0 リファレンスマニュアルよりサンプルコードを引用
p [1,2,3].zip([4,5,6], [7,8,9]) # => [[1, 4, 7], [2, 5, 8], [3, 6, 9]] p [1,2].zip([:a,:b,:c], [:A,:B,:C,:D]) # => [[1, :a, :A], [2, :b, :B]] p [1,2,3,4,5].zip([:a,:b,:c], [:A,:B,:C,:D]) # => [[1, :a, :A], [2, :b, :B], # [3, :c, :C], [4, nil, :D], [5, nil, nil]] p [1,2,3].zip([4,5,6], [7,8,9]) {|ary| p ary } # => [1, 4, 7] # [2, 5, 8] # [3, 6, 9] # nil参考
https://docs.ruby-lang.org/ja/latest/method/Array/i/zip.html
- 投稿日:2020-02-27T20:23:46+09:00
bin/rails db:migrateしようとしたらMysql2::Error: Table '*****' doesn't existが出る
経緯
bin/rails g model imageと
bin/rials g model productによって作られたマイグレーションファイル
20200227092210_create_images.rbと
20200227092647_create_products.rbを,20200227092210_create_images.rb(中略) t.references :product, foreign_key: true (中略)と書いて, bin/rails db:migrate を実行
起きたエラ〜
(中略) rails aborted! StandardError: An error has occurred, all later migrations canceled: Mysql2::Error: Table 'プロジェクト名_development.products' doesn't exist: SHOW FULL FIELDS FROM `products` (中略)というエラーが発生した。
解決策
スペルのミスも、文法ミスも、探したけれど見つからないよ♪...
なので、googleで検索したところ、参考になる記事を発見。どうやら、
referencesされるマイグレーションファイル
の方が先にmigrateされるべきなようで、
20200227092647_create_products.rbを、
→2020022709 2209_create_products.rb
(20200227092210_create_images.rb)
にすると、images.rbよりも早くmigrateされた!!参照したwebページ
- 投稿日:2020-02-27T19:45:39+09:00
rails:DM送信機能を簡単に実装〜model〜
ダイレクトメッセージ機能
検索に苦労したのでDM機能について簡単に実装手順を紹介します。
前提として、DM機能の実装には
①トークルームを作成してそこで話す機能を実装する方法(中間テーブルが2つ)
②トークルームを作成しない方法
があります。今回は②についての説明です。
ER図
roomモデルを作らなくても作成できる理由は、routesで設定できます。
手順
usersモデルがある前提で書きていきます。
$ rails g model Messages content:string user:references receive_user:referencesMessages modelとmigrateファイルを作成します。
完成したものがこちら
_create_messages.rbclass CreateMessages < ActiveRecord::Migration[5.2] def change create_table :messages do |t| t.string :content t.references :user, foreign_key: true t.references :receive_user, foreign_key: { to_table: :users } t.timestamps end end end_create_messages.rb{ to_table: :users }を追記しています。
これが無いと、receive_usersテーブルを参照してしまうので『そんなテーブルは存在しないよ』と言われてしまいます。
そのため、外部キーとしてusersテーブルを参照するという指定を行っています。$ rails db:migrate↑します。
続いて、model
models/message.rbclass Message < ApplicationRecord belongs_to :user belongs_to :receive_user, class_name: 'User' endmodels/message.rbclass_name: ‘User’を追加します。
これによって、receive_userがReceive_userという存在しないクラスを参照することを防ぎます。models/user.rbhas_many :messages has_many :sent_messages, through: :messages, source: :receive_user has_many :reverses_of_message, class_name: 'Message', foreign_key: 'receive_user_id' has_many :received_messages, through: :reverses_of_message, source: :user def sent_messages(other_user, content) #メッセージを送るためのメソッド unless self == other_user self.messages.find_or_create_by(receive_user_id: other_user.id, content: content) end endこれで完成です!
しっかり作成できるか $ rails cで確認することは忘れないでください?♂️
補足
修正依頼などあれば気軽にお申し付けください。
- 投稿日:2020-02-27T17:44:42+09:00
マイグレーションファイルの修正方法
マイグレーションファイルの修正方法
マイグレーションファイルのカラムをスペルミスしたときにrails db:rollbackするとマイグレーションファイルを差し戻せる
ロールバック=>修正=>マイグレートで修復できるデータベースに反映済みのマイグレーションファイルは修正してはダメ
マイグレーションファイルが既にマイグレーション済みなのかどうかは、rails db:migrate:statusで確認できる
適用されているときはupと表示され、修正するためにはロールバックする必要がある。適用されていないときは、downと表示され、そのまま修正や削除が可能
修正し終わったらrails db:migrateで実行し、修正した内容を反映される
- 投稿日:2020-02-27T17:33:45+09:00
ルートパスとは
- 投稿日:2020-02-27T17:13:23+09:00
ストロングパラメーター、プライベートメソッドとは
ストロングパラメーター
ストロングパラメーターとは指定したキーを持つパラメーターのみを受け取るようにする
特定のキーしか受け取れないような仕組みを構築することができるプライベートメソッド
クラス外から呼び出すことのできないメソッド
ストロングパラメーターを記述したメソッドは、private以下に記載して、プライベートメソッドとして扱う
【例】プライベートメソッドclass PostsController < ApplicationController def index (処理) end def new (処理) end def create (処理) end private def private_method # プライベートメソッド params.require(`モデル名`).permit(`カラム名`) end enddef create Post.create(post_params) end private def post_params params.require(:post).permit(:title, :text, :image) endみたいな感じで記述する。privateのpost_paramsはcreateのpost_paramsに代入される
1.Classの外部から呼ばれたら困るメソッドを隔離
メソッドの中には、Classの外部から呼び出されてしまうとエラーを起こすメソッドも存在し、そのような事態を事前に防ぐことができる
2.可読性
classの外部から呼び出されるメソッドを探すときに、private以下の部分は目を通さなくて良くなり、繰り返し使用するメソッドもprivate以下に集約できますので、コードをシンプルにできる
- 投稿日:2020-02-27T17:09:39+09:00
【Rails】自分メモ マイグレーション実行時エラー ActiveRecord::StatementInvalid: Mysql2::Error: Table 'users' already exists: CREATE TABLE `users`
$ rails db:drop
$ rails db:create
$ rails db:migrate
こうしてDBをからにして入れ直したら直った!
- 投稿日:2020-02-27T17:03:46+09:00
deviseの関連ファイルが作られず、コマンドが適用されなくなった時の対処法
deviseをインストールしていると
config/initializers/devise.rb
と
config/locales/devise.en.yml
ファイルが生成されておらず、、さらにrails g devise user
やrails db:migrate:status
してもNoMethodError: undefined method `devise' for Install (call 'Install.connection' to establish a connection):Classというエラーが出ました。すでにuserモデル以外のデータべースは作ってあるので
rails db:migrate:status
が出来ないということはコマンドが適用されていないということだと思います。
同じ状態でbundle install
からやり直しても解決出来ませんでした。考えた仮説
このときGemfileにはちゃんと
gem 'devise'
と記述されていました。ターミナル履歴は以下の通りです。#ターミナル履歴 bundle install rails g devise:install rails g devise user rails db:migrateターミナル履歴におかしいところはない。
しかしconfig/initializers/devise.rb
と
config/locales/devise.en.yml
ファイルがインストールがされていないので、rails g devise install
に問題があるのではないか?
gemはローカルサーバーの再起動をしないと反映されないので、rails g devise install
の前に再起動をしていなかったのではないか?解決方法
調べると、
rails g devise install
が反映されていないとrails s
やrails g devise user
やrails db:migrate:status
など他のコマンドが競合してしまい、コマンドが反映されなくなってしまうようです。
参考記事 : https://qiita.com/ryouzi/items/9c5324ba567109ab2a22具体的な対処法
1. もう一度bundle install
2.routes.rb
にあるdevise_for :install
もしくはdevise_for :users
というコードを削除する
3. 2でrailsコマンドが適用されるようになったのでrails db:rollback
でマイグレーションファイルをロールバックする。
4.rails db:migrate:status
でステータス確認
5. userテーブルやモデルが作られている場合はrails d model user
で削除
6. rails g devise:install
7. rails g devise user
8. rails db:migrate最後に
プログラミングを始めて4週間の初心者なので、その目線でわかりやすく書くことを心がけました。
わかりにくい記述、間違っているところがあればご指摘ください。
最後まで見ていただきありがとうございました。
- 投稿日:2020-02-27T16:41:17+09:00
ヘルパーメソッドとは、また使用する利点は
ヘルパーメソッドとは
主にviewでHTMLタグを出現させたりテキストを加工するために予めメソッドが用意される。HTMLやRubyの記述がセットになった、ビューファイルで使用できるメソッド
|:-----|:-----|
| ヘルパーメソッド | 使用用途 |
| form_for | 投稿ページなどにおけるフォームの実装 |
| link_to | リンクの実装 |
| simple_format | 投稿した文章を自動で見やすく整形する |
などがある
フォームの実装例<%= form_for('モデルクラスのインスタンス') do |f| %> フォームの中身 <% end %><%= form_for(@post) do |f| %> <%= f.text_field :text %> <%= f.submit %> <% end %><%= link_to 'リンクに表示する文字', 'リンク先のURL' %><%= link_to '新規投稿', '/posts/new' %>みたいに使える
ヘルパーメソッドを使用する利点
- 複雑なアプリケーションにおいては、ヘルパーメソッドを使用するとコードがシンプルになる
- 特にフォームにおいては、ヘルパーメソッドを使用しないとセキュリティ上の問題が発生する
- 投稿日:2020-02-27T16:26:14+09:00
dependent: :destroyをつけていても削除できなかった原因
長時間調べたが解決方法が見つからないという状態が続きました。
私のミスだったので、同じような状態の人に私の経験を伝えれればと思い書きます。内容
紐付けしたオブジェクトを削除するために、
dependent: :destroy
をつけても、削除できない時に気をつけて欲しいことを書きます。問題点
ある特定のUserのみ削除できない
モデルの関係性
User
とCart
が親子関係で、
Cart
とProduct
がCart_products
と 1対多 です。
Users ー Carts → Cart_products ← Products
class User < ApplicationRecord has_one :cart, dependent: :destroy end class Cart < ApplicationRecord belongs_to :user has_many :cart_products, dependent: :destroy has_many :products, through: :cart_products end class Product < ApplicationRecord has_many :cart_products, dependent: :destroy end class CartProduct < ApplicationRecord belongs_to :cart belongs_to :product end行っていたこと
関連付けられたオブジェクトもdestroy削除できるように
has_many
,has_one
にdependent: :destroy
をつけていた。エラー文
Cannot delete or update a parent row: a foreign key constraint fails (`app_name_development`.`cart_products`, CONSTRAINT `fk_rails_a4f3e327f3` FOREIGN KEY (`cart_id`) REFERENCES `carts` (`id`))原因
User has_one Cart
でUser
にはCart
がは1つのみ紐づくようにしていたのですが、
削除できないUser
には2つのCart
が紐つかれていた。そのため
User has_one Cart
をUser has_many Carts
と変更すると削除できた。+----+---------------------+---------------------+---------+ | id | created_at | updated_at | user_id | +----+---------------------+---------------------+---------+ | 3 | 2020-02-21 07:07:57 | 2020-02-21 07:07:57 | 4 | | 12 | 2020-02-21 07:29:37 | 2020-02-21 07:29:37 | 7 | | 13 | 2020-02-21 07:34:26 | 2020-02-21 07:34:26 | 7 | | 16 | 2020-02-22 07:51:47 | 2020-02-22 07:51:47 | 11 | +----+---------------------+---------------------+---------+今後の対処法
モデルを作成する時に、オプションとして
unique: true
を付け、user
の重複をなしにする。XXXXXXX_create_cart.rbclass CreateCarts < ActiveRecord::Migration[5.2] def change create_table :carts do |t| t.references :user, foreign_key: true, unique: true #ここ t.timestamps end end end結論
User has_one Cart
関係の
User
に1つのみのCart
が紐づくようにしていたのですが、
削除できないUser
には2つのCart
が紐つかれていた。そのため、以下のように
User has_one Cart
をUser has_many Carts
と変更すると削除できた。class User < ApplicationRecord has_one :cart, dependent: :destroy end ⬇︎ class User < ApplicationRecord has_many :cart, dependent: :destroy end
- 投稿日:2020-02-27T16:25:54+09:00
RailsでのCookieのSameSite, Secureの対応
概要
2020年2月にChromeのバージョンが80にアップデートされました。
これはCSRFを防ぐためChromeのCookieのSameSite属性をデフォルトでSameSite=Lax
にしようというものです。アップデート前はSameSite=None
と同じ挙動をしていました。つまりアップデート前まで
SameSite=None
でないと正常に動作しないアプリケーションについては明示的にNone
を指定する必要があります。https://developers-jp.googleblog.com/2019/11/cookie-samesitenone-secure.html
から抜粋2月のChrome 80 以降、SameSite 値が宣言されていない Cookie は SameSite=Lax として扱われます。
外部アクセスは、SameSite=None; Secure 設定のある Cookie のみ可能になります。
ただし、これらが安全な接続からアクセスされることが条件です。SameSiteの挙動の説明
SameSite 説明 None クロスドメインでCookieの受け渡しが可能
(ただしSecure=Trueの設定は必須のためhttpの環境だと正常に動作しないはずです)Lax クロスドメインでGETメソッドであればCookieの受け渡しが可能だがPOSTメソッドは不可 Strict クロスドメインでGET、POSTメソッド両方ともCookieの受け渡しは不可 ただし、これはChromeでの挙動になります。
それ以外のブラウザでは違った挙動をするものがあるので注意が必要です。詳しくは下記のリンク先をご覧ください。
https://www.chromium.org/updates/same-site/incompatible-clientsこの中で結構問題があると思われるのは
Versions of Safari and embedded browsers on MacOS 10.14 and all browsers on iOS 12. These versions will erroneously treat cookies marked with SameSite=None as if they were marked SameSite=Strict. This bug has been fixed on newer versions of iOS and MacOS
です。
現時点(2020/2/27)でiOS 12、MacOS 10.14はそれほど古いバージョンではなく使用しているユーザーも多いと思われます。このユーザーに対してはSameSite=None
と設定しているとSameSite=Strict
と同じ挙動をするそうです。
対応するとしたらブラウザによってcookieを書き換える必要がありそうです。Ruby on RailsでSameSite=Noneを設定する対応例
こちらの記事ではgemでの対応が記載されているのでgemで対応したい方はこちらが良いと思います。
(rails_same_site_cookie gemで、RailsアプリにChrome 80向けのSameSite属性を指定する)以降はRuby on Railsでの実装例を記載します。
最初にrack gemのバージョンを確認します。
rackが2.0系だとSameSite=None
の対応が入っておらずエラーになるのでrackのバージョンアップをおこなうかRack::Utils
のモンキーパッチ以下のように作成します。
rackのバージョンアップ時に削除漏れがあるといけないので内容にTODOを記載しておきましょう。# -*- encoding: binary -*- # TODO: rack2.1.0以降だとsamesite=Noneの設定が入っているのでソースファイルごと削除する module Rack # Rack::Utils contains a grab-bag of useful methods for writing web # applications adopted from all kinds of Ruby libraries. module Utils def add_cookie_to_header(header, key, value) case value when Hash domain = "; domain=#{value[:domain]}" if value[:domain] path = "; path=#{value[:path]}" if value[:path] max_age = "; max-age=#{value[:max_age]}" if value[:max_age] # There is an RFC mess in the area of date formatting for Cookies. Not # only are there contradicting RFCs and examples within RFC text, but # there are also numerous conflicting names of fields and partially # cross-applicable specifications. # # These are best described in RFC 2616 3.3.1. This RFC text also # specifies that RFC 822 as updated by RFC 1123 is preferred. That is a # fixed length format with space-date delimited fields. # # See also RFC 1123 section 5.2.14. # # RFC 6265 also specifies "sane-cookie-date" as RFC 1123 date, defined # in RFC 2616 3.3.1. RFC 6265 also gives examples that clearly denote # the space delimited format. These formats are compliant with RFC 2822. # # For reference, all involved RFCs are: # RFC 822 # RFC 1123 # RFC 2109 # RFC 2616 # RFC 2822 # RFC 2965 # RFC 6265 expires = "; expires=" + rfc2822(value[:expires].clone.gmtime) if value[:expires] secure = "; secure" if value[:secure] httponly = "; HttpOnly" if (value.key?(:httponly) ? value[:httponly] : value[:http_only]) same_site = case value[:same_site] when false, nil nil when :none, 'None', :None '; SameSite=None'.freeze when :lax, 'Lax', :Lax '; SameSite=Lax'.freeze when true, :strict, 'Strict', :Strict '; SameSite=Strict'.freeze else raise ArgumentError, "Invalid SameSite value: #{value[:same_site].inspect}" end value = value[:value] end value = [value] unless Array === value cookie = "#{escape(key)}=#{value.map { |v| escape v }.join('&')}#{domain}" \ "#{path}#{max_age}#{expires}#{secure}#{httponly}#{same_site}" case header when nil, '' cookie when String [header, cookie].join("\n") when Array (header + [cookie]).join("\n") else raise ArgumentError, "Unrecognized cookie header value. Expected String, Array, or nil, got #{header.inspect}" end end module_function :add_cookie_to_header end end修正箇所は↓の部分を追記しただけです。
when :none, 'None', :None '; SameSite=None'.freezerackが2.1系以降であれば対応されているので上記の対応は不要です。
使い方はこんな感じでいけると思います。
cookies[:hogehoge] = { value: "sample value", expires: 1.hour.from_now, same_site: "None", secure: true }環境によって
Secure=True or False
を設定したい場合以下のようなClassを作成します。
# frozen_string_literal: true class SecureCookieWithSameSiteLax def self.secure? Rails.env.staging? || Rails.env.production? end end使い方はこんな感じです。
secure = SecureCookieWithSameSiteLax.secure? cookies[:hogehoge] = { value: "sample value", expires: 1.hour.from_now, same_site: "Lax", secure: secure }production環境、staging環境では
SameSite=Lax Secure=True
development環境ではSameSite=Lax Secure=False
としたい場合の実装方法となります。
SameSite=None
を設定しなくても問題なく動作するアプリケーションであればLax
、Strict
を明示的にセットしてsecureな設定にしておくのが良いと思います。
- 投稿日:2020-02-27T16:22:33+09:00
RSpecを導入する
RSpecをインストール
Gemfilegroup :development, :test do gem 'rspec-rails'$ bundle install $ bin/rails generate rspec:install You can silence deprecations warning by setting the environment variable THOR_SILENCE_DEPRECATION. create .rspec create spec create spec/spec_helper.rb create spec/rails_helper.rb
.rspec
(設定ファイル)、spec/spec_helper.rb
、spec/rails_helper.rb
が生成されます。.rspec--require spec_helper --format documentation #この行を追加して出力の形式を変更binstub をインストールしてテストスイートの起動時間を速くします。
Gemfilegroup :development do gem 'spring-commands-rspec'$ bundle install $ bundle exec spring binstub rspec動作確認
$ bin/rspecテストが走って
No examples found.
的な記述が確認できればOK。
次にrails generate
コマンドを叩いた時にテスト用ファイルが自動で生成されるように修正。config/application.rbconfig.generators do |g| g.stylesheets false g.javascripts false g.helper false g.test_framework :rspec, controller_specs: false, view_specs: false, helper_specs: false, routing_specs: false end最後に
test
ディレクトリを丸ごと削除してセットアップ完了。と思ったら、コマンドを叩くたびに
thor
とかいう、入れた覚えのないgemから以下のエラーが吐かれるようになってしまった。さっき追加したspring
と依存関係にある、シェルスクリプトを生成するためのgemらしい。Deprecation warning: Expected string default value for '--test-framework'; got false (boolean). This will be rejected in the future unless you explicitly pass the options `check_default_type: false` or call `allow_incompatible_default_type!` in your code You can silence deprecations warning by setting the environment variable THOR_SILENCE_DEPRECATION.指示通り環境変数をセットしてエラーを非表示に。dotenvのgemを使ってます。
.envTHOR_SILENCE_DEPRECATION = trueFactoryBotをインストール
テストデータ生成用のGem
FactoryBot
をインストールします。Gemfilegroup :development, :test do gem 'factory_bot_rails'$ bundle install
FactoryBot.create(:user)
→create(:user)
と書けるように設定を追加。spec/rails_helper.rbRSpec.configure do |config| . . config.include FactoryBot::Syntax::Methods endCapybaraをインストール
統合テスト用のGem
capybara
と、関連するGemをインストールします。Gemfilegroup :test do gem 'capybara' gem 'webdrivers' # gem 'selenium-webdriver' # gem 'chromedriver-helper' end
selenium-webdriver
、chromedriver-helper
は不要なので、もし書いてあったら削除します。$ bundle install
rails_helper.rb
を開き、以下の行をコメントアウトして有効化します。spec/rails_helper.rbDir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }これで
spec/support
にRSpec関連の設定ファイルを配置することができます。
最後にcapybara用の設定ファイルを作成します。spec/support/capybara.rbCapybara.javascript_driver = :selenium_chrome_headlessshoulda-matchersをインストール
マッチャーを拡張するgem
shoulda-matchers
をインストールします。Gemfilegroup :test do gem 'shoulda-matchers' end
rails_helper.rb
を開き、以下の記述を追加。spec/rails_helper.rbRSpec.configure do |config| . . Shoulda::Matchers.configure do |config| config.integrate do |with| with.test_framework :rspec with.library :rails end end end参考
- 投稿日:2020-02-27T16:15:46+09:00
チーム開発を始める際にチーム全員でgithubを共有する方法(rails)
チーム開発をする際にgithubを全員で共有する方法
某プログラミングスクールにて、チーム開発を始める際に全員でgithubを共有するのに苦戦したので分かりやすく丁寧にまとめたいと思います。
まず用語の説明をします。
ブラウザ上でのgithub = リモート
ブラウザ上でのgithubでのリポジトリ = リモートリポジトリ (リポジトリとは、chat-spaceなどのアプリケーションを指します。)
自分のPC = ローカル
github desktop = ローカルリポジトリまず簡単に流れを掴み、それから1つ1つの詳細を説明していきます。
流れ
1)チームの一人(これからオーナーと呼びます)が自分のローカルでアプリケーションを立ち上げる。
2)オーナーがそのアプリケーションを自分のgithubリモートと繋げる。
3)オーナーがチームメンバーを自分が作ったリモートリポジトリに招待する。
4)メンバーたちがそのリモートリポジトリに入り、その雛形のコードを自分のローカルにコピーする。
5)全員が何かしらの変更点を自分のエディターに書き、pushし、全員がちゃんと1つのリモートリポジトリにつながっているか確認する
6)全員がブランチを切って作業を開始する。それでは早速初めていきます。
1)チームの一人が自分のローカルでアプリケーションを立ち上げる。
チームの一人(基本的に誰でもOK)がローカルで普段何かアプリケーションを立ち上げる時にやっているように
rails newでアプリを立ち上げます。この際、できればバージョンを指定していた方が安全なので今回は5.2.3を指定して作っていく設定で行います。今回作るアプリの名前はsampleと言う名前で作る設定で行います。
$ rails _5.2.3_ new sample -d mysql2)オーナーがそのアプリケーションを自分のgithubリモートと繋げる。
次に、このアプリケーションをgithubに繋げます。
$ cd sample $ git init //現在のsampleをgit下に置きます $ git add . //全てのファイルを追加します $ git status //ちゃんと全てのファイルが入った確認できますすると、このように全てのファイルがgit下に入ったことが確認できます。
次に、このgit下に移動できたファイル達をgithub desktopに追加していきます。
$ git commit -m "initial commit"そして次にgithub desktopを開きます。
すると左上に
と言う表示があるので
Current Repositoryをクリックしてください。(この時点でsampleと表示されていますが気にしなくて大丈夫です)
その後
Add ボタンをクリックし、Add Existing Repository...
をクリックすると
このような表示が出てくるかと思います。
ここで
Choose...をクリックし、自分が作っているsampleファイルを選択し、
Add Repositoryを選択すると、
このような画面が出てくると思います。
ここで左の列の
の欄のSummary(required)のところに、initial commit と記載し、
下の青いボタンのCommit to masterが押せるようになりますので、クリックしてください。すると
このようにローカルに変更点はもうないよ。と言う表示が出ます。
そして、右側にある
で、Pubulish repositoryをクリックしてください。
すると
この表示が出ます。
Nameはそのままで大丈夫です。
Descriptionは空欄で大丈夫です。
その下のチェックボタンはこのコードをプライベートにする。と書いていますが、
今回はチーム開発をするため、このコードを共有しないといけません。よって、チェックボタンは外してください。
そしてPublish Repositoryをクリックしましょう。
そうすると、github ブラウザ(リモート)に、リモートリポジトリが作成されます。
おめでとうございます。
このように自分のアプリケーションが表示できましたでしょうか。
3)オーナーがチームメンバーを自分が作ったリモートリポジトリに招待する。
次に、このリモートリポジトリにメンバーを招待します。
まずこの画面でSetting ボタンをクリックしてください
するとこの画面に飛びますので、次に
Manage accessをクリックしてください。
するとパスワードを要求されますので入力してください。
すると
このような画面があるページに飛びます。
ここでInvite a collaboratorをクリックしましょう。
すると検索画面が出てきますので、メンバー達のgithubでのアカウント名を正しく記入し、追加していきます。追加されたメンバー達は、githubmに登録した時に使用したメールアドレスにメールが届きますので確認してください。
すると、メールには
View Invitationと書かれているのでクリックします。 (※メールはPCで閲覧しましょう)
すると、githubのページに飛びますので、そこで
Accept Invitationをクリックすると、無事、オーナーが作ったリポジトリに参加できます。4)メンバーたちがそのリモートリポジトリに入り、その雛形のコードを自分のローカルにコピーする。
お待たせしました。
ここからはやっとメンバー達も作業開始できます。
メンバー達はそのリポジトリに行ったあと、この
Clone or download
をクリックし、URLをコピーします。そしてgithub desktopに行きます。
そして左上にCurrent Repsitoryをクリックします。そして
Add
をクリックし
Clone Repositoryをクリックします。するとこのような画面が出てきます。
ここではURLを選択してください。
するとこのようなページに変わりますので
上の欄にはgithubブラウザでコピーしたURLをペーストします。
下のLocal Pathは、このコピーしたファイルをどこに入れるかを自分で決めることができます。
これで全員のローカル環境に、オーナーが作ったローカルと同じものがリモートを通じて繋げることができました。
ここからは実際に確認作業をします。
5)全員が1つのリモートリポジトリにつながっているか確認する.
これは簡単です。一人一人がマスターブランチで適当にREAD.Meなどに記載を加え、commit、pushしてください。
すると、一人一人が変えた場所がgithub desktopのhistryに反映されているはずです。6)全員がブランチを切って作業を開始する。
ここからは実際にコードをバリバリ書いていく作業です。
全員ブランチを切り、各々の作業をしてください。これで作業が開始できます。
以上になります。頑張ってください!
間違っている点やご指摘もお待ちしております。
- 投稿日:2020-02-27T15:03:37+09:00
railsのacts-as-taggable-onで人気のタグを表示する
初心者向けのacts-as-taggable-onで人気のタグを出す方法です。
自分がアプリ作成の際、使ったので健忘録的なものです。導入は先人の記事などがありますのでそちらをご参照ください
。rails 5.2.4.1での使用です。
最も使われているタグを配列で取得する
ActsAsTaggableOn::Tag.most_used ActsAsTaggableOn::Tag.most_used(3)デフォルトで20件取得。
引数で指定すると指定した件数まで取得(上記の場合使われている順番に3件)。コントローラの使いたいアクションに記載する
posts.controller.rb@popular_tags = ActsAsTaggableOn::Tag.most_used(3)インスタンス変数へ代入する。
渡されたインスタンス変数をView側で表示
<span>人気のタグ:</span> <% @popular_tags.each do |ptag| %> <%= ptag.name %> <% end %>上記の様にインスタンス変数をeachで取り出して表示することが出来ます。
タグにリンクをつける場合
config/routes.rbget 'tags/:tag', to: 'posts#index', as: :tagルーティングを設定して
<span>人気のタグ:</span> <% @popular_tags.each do |ptag| %> <%= link_to ptag, posts_path(tag_name: ptag.name) %>上記の様にすると選択したタグのついている記事などを
抽出して表示することが出来ます。参考
https://qiita.com/take1457a/items/90465189140ec77b14be
https://morizyun.github.io/blog/acts-as-taggable-on-gem-rails/index.html
- 投稿日:2020-02-27T14:54:44+09:00
アプリケーション作成で詰まった箇所
執筆中
環境
Ruby 2.6.5
Rails 5.2.4
Docker 19.03.5
bundler 2.1.4
bundler問題
フラッシュメッセージ
表示される
user_sessions_controller.rbredirect_back_or_to root_url, success: 'ログインしました'表示されない
user_sessions_controller.rbredirect_to root_path, success: 'ログアウトしました'解決法
application_controller.rb# 追加 add_flash_types :danger, :success, :warning原因
調査中
そもそもadd_flash_types
の指定がないとBootstrapに対応したsuccess
info
warning
danger
の4つのキーが使用できないはずなのにredirect_back_ro_to
だと表示されるのは4つのキーがデフォルトで備わっているからなのか?文字コードがlatin1による文字化け
データベース内で文字化けするだけであって、取り出して使用する場合は文字化けしないのでとりあえず放置。
jQueryのclickイベントでdocument使用時のみ発火しない
試したこと
turbolinks
が原因か?・
Gemfile.lock
からturbolinks
削除
・application.js
から読み込み削除
・application.html.slim
から読み込み削除
参考資料・
docker-compose bundle update
・docker-compose build
・コンテナの再起動
→変わらず原因
調査中
remote: true & application.jsの//= require rails-ujs
remote: trueで送信するとrails-ujsのjQueryがなんかしてるっぽくclickイベントが使用できない。
解決法
remote: trueをやめるかclickイベントをやめる。
今回はclickイベントを使用せず実装する。
- 投稿日:2020-02-27T14:40:06+09:00
Rails Active_hashを攻略する
今日の目標
acitive_hashでハッシュデータを扱う方法を学習する
active_hashとは?
gemの一種。
ハッシュのデータを、ActiveRecordと同じ感覚で使えるようにしてくれる。どういう時に使うのか
以下の条件2つにあてはまるとき。
これから扱うデータがDBにデータとして保存しておくほど重要ではない、かつ、基本的に変更されない。
ActiveRecordと同じ感覚でデータを操作したい。
具体的に
例えば都道府県名一覧やカテゴリなど「基本的に変更されないデータ」があったとする。
そういったデータをDBに保存しておけば取り扱いは楽だけど、データの価値としてはDBに保持しておくほど重要ではない。
じゃあ ↓ の例のように定数でやるか?というとそれも微妙。
コード全体の見通しが悪くなるし、Activerecordを通して使えないので扱いづらくなってしまう。modelTODOHUKEN = [ 1: {name: :北海道, location: [12.323245, 102.3231231]}, . . . ]そういう悩みを解決するのに便利なのがactive_hash。
ハッシュデータをモデルとして定義することで、
ハッシュをDBから引っ張ってきたデータと同じように扱うことができるようになる。導入方法
Gemfileにactive_hashを記載
Gemfilegem 'active_hash'$ bundle installこれでおしまい
モデル作成
次にモデルを作成する。
今回作成するモデルは2つ、AddressモデルとPrefectureモデル。
まずはrails g modelでAddressモデルを作成。$ rails g model Address prefecture_id:integer city:string続けてdb:createとdb:migrateを実行。
$ rails db:create$ rails db:migrate次にPrefectureモデルを作成。
こちらはrails g modelでの作成ではなく
ActiveHash::Baseを継承したPrefectureモデルを 自作 する。
※ActiveHash::Baseを継承することで初めて、ActiveRecordのメソッド(allなど)が使えるようになる。都道府県のデータはハッシュで配列に格納する。
app/models/prefecture.rbclass Prefecture < ActiveHash::Base self.data = [ {id: 1, name: '北海道'}, {id: 2, name: '青森県'}, {id: 3, name: '岩手県'}, {id: 4, name: '宮城県'}, {id: 5, name: '秋田県'}, {id: 6, name: '山形県'}, {id: 7, name: '福島県'}, {id: 8, name: '茨城県'}, {id: 9, name: '栃木県'}, {id: 10, name: '群馬県'}, {id: 11, name: '埼玉県'}, {id: 12, name: '千葉県'}, {id: 13, name: '東京都'}, {id: 14, name: '神奈川県'}, {id: 15, name: '新潟県'}, {id: 16, name: '富山県'}, {id: 17, name: '石川県'}, {id: 18, name: '福井県'}, {id: 19, name: '山梨県'}, {id: 20, name: '長野県'}, {id: 21, name: '岐阜県'}, {id: 22, name: '静岡県'}, {id: 23, name: '愛知県'}, {id: 24, name: '三重県'}, {id: 25, name: '滋賀県'}, {id: 26, name: '京都府'}, {id: 27, name: '大阪府'}, {id: 28, name: '兵庫県'}, {id: 29, name: '奈良県'}, {id: 30, name: '和歌山県'}, {id: 31, name: '鳥取県'}, {id: 32, name: '島根県'}, {id: 33, name: '岡山県'}, {id: 34, name: '広島県'}, {id: 35, name: '山口県'}, {id: 36, name: '徳島県'}, {id: 37, name: '香川県'}, {id: 38, name: '愛媛県'}, {id: 39, name: '高知県'}, {id: 40, name: '福岡県'}, {id: 41, name: '佐賀県'}, {id: 42, name: '長崎県'}, {id: 43, name: '熊本県'}, {id: 44, name: '大分県'}, {id: 45, name: '宮崎県'}, {id: 46, name: '鹿児島県'}, {id: 47, name: '沖縄県'} ] endactive_hashにはbelongs_to_active_hashメソッドが用意されているので、
address.rbに このメソッドを記述し、アソシエーションを定義する。extend ActiveHash::Associations::ActiveRecordExtensions
belongs_to_active_hash :prefecture
この2行を追加。なお、Prefectureモデルのファイルには、アソシエーションを明示する必要はない。
これで準備は完了。
app/models/address.rbclass Address < ApplicationRecord extend ActiveHash::Associations::ActiveRecordExtensions belongs_to_active_hash :prefecture endコンソールで試してみる
$ rails c [1] pry(main)> @address_1 = Address.create(prefecture_id: 1, city: '函館市') id: 1, prefecture_id: 1, city: "函館市", created_at: Tue, 08 Jan 2019 11:41:41 UTC +00:00, updated_at: Tue, 08 Jan 2019 11:41:41 UTC +00:00> [2] pry(main)> @address_2 = Address.create(prefecture_id: 13, city: '新宿区新宿') id: 2, prefecture_id: 13, city: "新宿区新宿", created_at: Tue, 08 Jan 2019 11:42:05 UTC +00:00, updated_at: Tue, 08 Jan 2019 11:42:05 UTC +00:00> ############################## [3] pry(main)> @address_1.prefecture.name => "北海道" [4] pry(main)> @address_2.prefecture.name => "東京都"って感じで、prefecuture_idにPrefectureモデルに定義したハッシュのidを渡して、
@address.prefecture.nameで名前を取れる。
もちろんPrefecture.find でハッシュを取ることも可能。利点
テーブルの数を無駄に増やさない
Activerecordを継承する
扱うデータが最初の2つの条件にあてはまる場合はactive_hashを活用していきましょう。使えるメソッド
Country.all # => returns all Country objects Country.count # => returns the length of the .data array Country.first # => returns the first country object Country.last # => returns the last country object Country.find 1 # => returns the first country object with that id Country.find [1,2] # => returns all Country objects with ids in the array Country.find :all # => same as .all Country.find :all, args # => the second argument is totally ignored, but allows it to play nicely with AR Country.find_by_id 1 # => find the first object that matches the id Country.find_by_name "foo" # => returns the first object matching that name Country.find_all_by_name "foo" # => returns an array of the objects with matching names Country.find_by_id_and_name 1, "Germany" # => returns the first object matching that id and name Country.find_all_by_id_and_name 1, "Germany" # => returns an array of objects matching that name and id使えるインスタンスメソッド
Country#id # => returns the id or nil Country#id= # => sets the id attribute Country#quoted_id # => returns the numeric id Country#to_param # => returns the id as a string Country#new_record? # => returns true if is not part of Country.all, false otherwise Country#readonly? # => true Country#hash # => the hash of the id (or the hash of nil) Country#eql? # => compares type and id, returns false if id is nil注意点
検索
ActiveRecordのincludesやjoinsを使ってテーブル間の検索をするのは(たぶん)無理なので、
おとなしくmigrationファイルでActiveRecordを使用したほうが良さそう。多階層化
gem ancestryを使った多階層カテゴリー化には向いていない
- 投稿日:2020-02-27T13:34:23+09:00
Before Rails Tutorial4章 ログイン機能
本投稿は講義資料であり、Rubyの基礎は理解しているが、rails tutorialで躓く読者を対象としています。
1章:環境構築
2章:Scaffold を用いた高速なアプリケーション構築 及び MVCの理解
3章:Scaffold を用いない開発方法 及び 応用
4章:ログイン機能3章で作成した、蔵書管理アプリ bukukore にログイン機能を付与していきます。
ログイン機能は、 Devise という GEM を用いて構築していきます。Devise
bukukore ディレクトリ内の、Gemfile を立ち上げて下記のコードを追記してください。
Gemfile(追記)gem 'devise'Gemfile に追記したら、 bundle install していきましょう。
terminal$ bundle install --path vendor/bundledevise のインストールが完了したら、deviseを適応させていきます。
terminal$ rails g devise:install (省略) =============================================================================== Some setup you must do manually if you haven't yet: 1. Ensure you have defined default url options in your environments files. Here is an example of default_url_options appropriate for a development environment in config/environments/development.rb: config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } In production, :host should be set to the actual host of your application. 2. Ensure you have defined root_url to *something* in your config/routes.rb. For example: root to: "home#index" 3. Ensure you have flash messages in app/views/layouts/application.html.erb. For example: <p class="notice"><%= notice %></p> <p class="alert"><%= alert %></p> 4. You can copy Devise views (for customization) to your app by running: rails g devise:views ===============================================================================deviseをインストールすると、上記のようなメッセージが表示されます。
1つ目のメッセージに従い、デフォルトのURL を設定します。今回は指示通りで良いので、
config/environments/development.rb の一番下に下記のコードを追加します。config/environments/development.rb(追加)(省略) config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }2つ目のメッセージは、3つ目のメッセージは、のちほど追加します。
4つ目のメッセージでViewを作成するのですが、そのまえにModelをつくっておきます。
devise で使いたいのは User登録機能なので 下記のコマンドを実行します。config/initializers/devise.rb(235行目あたりの該当箇所を書換)config.scoped_views = trueconfig.scoped_views を false から true に書き換えてください。
(devise をどのフォルダにインストールするかの設定です。)
使い方はこちらterminal$ rails g devise User create db/migrate/20200216064430_devise_create_users.rb create app/models/user.rb route devise_for :usersこれで user.rb の他に、devise に関するマイグレーションファイルと、ルーティングが追加されています。
ルーティングは、 rails routes を実行することで確認できます。
マイグレーションファイルは、 db/migrate の中にあります。
devise では機能毎に ON / OFF 設定可能です。
モジュール名 各機能の説明 database_authenticatable データベースに保存されたパスワードが正しいかどうかの検証とを行ってくれます。またパスワードの暗号化も同時に行ってくれます。 registerable ユーザー自身がアカウント登録、編集、削除することを許可します。 recoverable パスワードをリセットできるようにし、メールで通知します。 rememberable 30日間ログインしたままにするというような永続ログインを可能にします。ログイン画面の下のチェックボックスにチェックすることで永続ログインを有効化できます。 trackable ユーザーのサインイン回数や、サインイン時間、IPアドレスなどを記録できるようにします。 validatable Emailやパスワードのバリデーションを可能にします。独自に定義したバリデーションを追加することもできます。 confirmable メールに記載されているURLをクリックして本登録を完了する、といったよくある登録方式を可能にします。また、サインイン中にアカウントが認証済みかどうかを検証します。 lockable 一定回数ログインを失敗するとアカウントをロックします。ロック解除にはメールによる解除か、一定時間経つと解除するといった方法があります。 timeoutable 一定時間活動していないアカウントのログインを破棄します。 omniauthable TwitterやFacebookなどのSNS認証を追加したい場合に使用します。 db/migrate/2020(省略)_devise_create_users.rb# frozen_string_literal: true class DeviseCreateUsers < ActiveRecord::Migration[5.2] def change create_table :users do |t| ## Database authenticatable t.string :email, null: false, default: "" t.string :encrypted_password, null: false, default: "" ## Recoverable t.string :reset_password_token t.datetime :reset_password_sent_at ## Rememberable t.datetime :remember_created_at ## Trackable t.integer :sign_in_count, default: 0, null: false t.datetime :current_sign_in_at t.datetime :last_sign_in_at t.string :current_sign_in_ip t.string :last_sign_in_ip ## Confirmable t.string :confirmation_token t.datetime :confirmed_at t.datetime :confirmation_sent_at t.string :unconfirmed_email # Only if using reconfirmable ## Lockable t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts t.string :unlock_token # Only if unlock strategy is :email or :both t.datetime :locked_at t.timestamps null: false end add_index :users, :email, unique: true add_index :users, :reset_password_token, unique: true add_index :users, :confirmation_token, unique: true add_index :users, :unlock_token, unique: true end end上記のようにすべての機能をコメントアウトしておきます。(講義終了後に、興味ある学生が拡張して遊べるための配慮)
今回はメール認証を行いたいので Confirmable を使用します。
user.rb もすべての機能が使用できるように変更しておきます。app/models/user.rbclass User < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :confirmable, :lockable, :timeoutable endマイグレーションファイル を変更したので適応させましょう。
マイグレーションファイルの実行は下記のコマンドでしたね。terminal$ rails db:migrate == 20200220202020 DeviseCreateUsers: migrating ================================ -- create_table(:users) -> 0.0021s -- add_index(:users, :email, {:unique=>true}) -> 0.0008s -- add_index(:users, :reset_password_token, {:unique=>true}) -> 0.0010s == 20200220202020 DeviseCreateUsers: migrated (0.0041s) =======================rails db:migrate した後は、 rails sever を再起動しておいてください。
マイグレーションを実行することでデータベースの中に、usersテーブルが作成されます。
4つ目のメッセージに書いてあるように、Devise が使用するView(アカウント作成関連) も作っていきます。terminal$ rails g devise:views user app/views/devise/shared/_links.html.erb (リンク用パーシャル) app/views/devise/confirmations/new.html.erb (認証メールの再送信画面) app/views/devise/passwords/edit.html.erb (パスワード変更画面) app/views/devise/passwords/new.html.erb (パスワードを忘れた際、メールを送る画面) app/views/devise/registrations/edit.html.erb (ユーザー情報変更画面) app/views/devise/registrations/new.html.erb (ユーザー登録画面) app/views/devise/sessions/new.html.erb (ログイン画面) app/views/devise/unlocks/new.html.erb (ロック解除メール再送信画面) app/views/devise/mailer/confirmation_instructions.html.erb (メール用アカウント認証文) app/views/devise/mailer/password_change.html.erb (メール用パスワード変更完了文) app/views/devise/mailer/reset_password_instructions.html.erb (メール用パスワードリセット文) app/views/devise/mailer/unlock_instructions.html.erb (メール用ロック解除文)上記コマンドを実行することで、 Devise の機能により、ユーザー作成関連の View が自動生成されます。
この時点でアカウント作成画面などにアクセスは可能ですが、メール認証機能は実装していないのでアカウントは作れません。
http://localhost:3000/users/sign_upいまのうちに、新規登録、ログインへのリンクを用意しておきましょう。
app/views/layouts/application.html.erb<!DOCTYPE html> <html> <head> <title>Bukukore</title> <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> </head> <body> <% if user_signed_in? %> <%= link_to 'ユーザー編集', edit_user_registration_path %> | <%= link_to "ログアウト", destroy_user_session_path, method: :delete %> <% else %> <%= link_to "新規登録", new_user_registration_path %> | <%= link_to "ログイン", new_user_session_path %> <% end %> <%= yield %> </body> </html>メール認証
Google 二段階認証
config/initializers/devise.rb の21行目あたりにある
config.mailer_sender を自分の gmail アドレスに変更します。config/initializers/devise.rbconfig.mailer_sender = '[自分のアドレスに置き換えます]@gmail.com'最後に開発環境の設定ファイルの最後に以下を追加します。
config/environments/development.rb(追記)(省略) ActionMailer::Base.smtp_settings = { address: 'smtp.gmail.com', port: 587, user_name: '[自分のアドレスに置き換えます]@gmail.com', password: '先程取得した二段階認証のアプリパスワード', authentication: 'plain', enable_starttls_auto: true }以上でメール認証処理は完了です。
「こんなの自力でわかるわけない!自力開発なんてできない」
と思うかもしれませんが、GEMの使い方はリファレンスにすべて書いてあるのでご安心ください。
今後、リファレンスを読む癖、調べる癖をつけていきましょう。
https://github.com/heartcombo/devise#getting-started
https://qiita.com/gakkie/items/6ef70c0788c3cbff81ee実際にユーザー登録を行い、メールが届くことを確認できます。
http://localhost:3000/users/sign_up
届いたメールに記載されている URL をクリックすることで、認証完了です。
rails server のログにも URL が書いてあるので、そちらをコピペしても認証可能です。どういう仕組みで、メールの認証やログイン・ログアウトが行われているのか詳しくは
https://railstutorial.jp/
で学べます。ユーザーの一覧と詳細表示ページ
Userの一覧をみるページ、詳細情報をみるページを作成していきましょう。
Model はすでに作っているので、 Controller と View を作成します。terminal$ rails g controller Users index show2つ目のメッセージにあったルート設定もここでしておきましょう。
ユーザーの一覧ページ(users#index)をTOPページにしたいので、下記コードを追加します。config/routes.rb(追加)(省略) root to: 'users#index'これで、root(最初のページ)にアクセスがあった時に、usersControllerのindexアクションを呼び出します。
http://localhost:3000/課題 MVCの復習
1, User Model を使い、users テーブルから全データを取り出し
2, user index ページに表示してみましょう。
3, user show ページにユーザー情報を表示してください http://localhost:3000/users/show/1ヒント: Model は Controller に記述します。
一度何も見ずにやってみてみると理解度チェックになります。
曖昧な場合は、前章の内容を確認してください。
1の解答例はここをクリックすると表示されます
app/controllers/users_controller.rbclass UsersController < ApplicationController def index @users = User.all end def show end end
2の解答例はここをクリックすると表示されます
app/views/users/index.html.erb<h1>ユーザーの一覧</h1> <% @users.each do |user| %> <p><%= user[:id] %></p> <p><%= user[:email] %></p> <% end %>
3の解答例はここをクリックすると表示されます
app/controllers/users_controller.rbclass UsersController < ApplicationController def index @users = User.all end def show @user = User.find(params[:id]) end endconfig/routes.rb(書き換え)# get 'users/show'(コメントアウト) get 'users/show/:id', to: 'users#show'app/views/users/show.html.erb<h1>ユーザーの情報</h1> <p><%= @user.id %></p> <p><%= @user.email %></p>新しいカラムの追加方法
現在 id,email と2つのカラムがあります。これだけでは誰か分かりづらいので
名前を登録するために、 name カラムを追加してみましょう。terminal$ rails g migration AddNameToUsers name:string上記のコマンドで、usersテーブルに name カラムを追加するためのマイグレーションファイルが自動生成されます。
db/migrate/2020(省略)_add_name_to_users.rb(自動生成)class AddNameToUsers < ActiveRecord::Migration[5.2] def change add_column :users, :name, :string end endマイグレーションファイルを実行します。
terminal$ rails db:migrate == 20200222020202 AddNameToUsers: migrating =================================== -- add_column(:users, :name, :string) -> 0.0017s == 20200222020202 AddNameToUsers: migrated (0.0018s) ==========================users テーブルに、nameカラムを追加することができました。
ストロングパラメータに name を許可する
しかし、追加しただけでは保存できないようになっています。
これは rails が自動的行っているセキュリティ対策の為です
ストロングパラメータについて保存できるようにするためには、ストロングパラメータへの追加が必要です。
app/controllers/application_controller.rbclass ApplicationController < ActionController::Base before_action :permitted_parameters, if: :devise_controller? private def permitted_parameters devise_parameter_sanitizer.permit :sign_up, keys: [:name] devise_parameter_sanitizer.permit :account_update, keys: [:name] end endpermitted_parameters アクションの中を見てください。
devise_parameter_sanitizer.permit 【許可する場所】, keys: 【許可するカラム名】
というようにして、許可を与えます。before_action は、このファイルが呼び出されたときに最初に実行されるものです。
これで新たに、名前を保存できるようになりました。
課題
1, 登録画面に、名前を登録するためのフォームを追加してください。
http://localhost:3000/users/sign_up
2, 実際に名前を登録し、 show ページで名前を表示してください。
http://localhost:3000/users/show/1 (必要があればidは登録した番号に変更してください)BookテーブルとUserテーブルの関連付け
続いて、2章で学習したテーブルの関連付けの復習をやっていきます。
詳細ページに、そのユーザーが登録した、本の情報を表示していきましょう。http://localhost:3000/users/show/1 ←ユーザーの詳細ページ
http://localhost:3000/books/new ←本の情報登録ページ
http://localhost:3000/books/show/1 ←登録内容を確認課題
ユーザーの詳細ページに、登録した本の情報が表示されるようにしてください。
解答例はここをクリックすると表示されます
app/models/user.rb(1行追加)class User < ApplicationRecord has_many :books # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :confirmable, :lockable, :timeoutable endapp/models/book.rbclass Book < ApplicationRecord belongs_to :user endapp/controllers/users_controller.rbclass UsersController < ApplicationController def index @users = User.all end def show @user = User.find(params[:id]) @books = @user.books end endapp/views/users/show.html.erb<p><%= @user.id %></p> <p><%= @user.email %></p> <p><%= @user.name %></p> <% @books.each do |book| %> <p>本のタイトル: <%= book.title %></p> <p>著者: <%= book.author %></p> <% end %>
- 投稿日:2020-02-27T10:28:57+09:00
バリデーションエラーの表示とredirect_toとrenderの違い
flashメッセージは表示されるけど、バリデーションエラーが表示されなくて困っているのでteratailに質問を投げてみたところ、エラーメッセージを表示させるにはrenderを使うというご指摘をいただいたので、備忘録として記事に致します。
before
questions.controller.rbclass QuestionsController < ApplicationController def new @questions = Question.all @question = Question.new end def create @question = Question.new(question_params) begin @question.save! flash[:notice] = '投稿に成功しました' redirect_to new_question_path rescue flash.now[:alert] = '投稿に失敗しました' redirect_to new_question_path end end private def question_params params.require(:question).permit(:title, :detail) endafter
questions.controller.rbdef new @questions = Question.all @question = Question.new end def create @questions = Question.all @question = Question.new(question_params) begin @question.save! flash[:notice] = '投稿に成功しました' redirect_to new_question_path rescue flash.now[:alert] = '投稿に失敗しました' render :new end end private def question_params params.require(:question).permit(:title, :detail) endbeforeでは例外処理になった場合に
redirect_to new_question_pathによって、newアクションまで遡ってしまっています。遡ってしまった結果、モデルのインスタンスが失われてしまうので、save!で格納されたエラーメッセージも無かったことになるみたいです。 更新ボタンを押した処理に近いです。
afterではリダイレクトしない場合もnewと同じ情報が必要なので、beginの前はnewと同じコードを入れています。
rescue flash.now[:alert] = '投稿に失敗しました' render :newここをrender :newとすることで、リダイレクトせずにnewのviewファイルを表示しています。こうすることでモデルのインスタンスも失われないので、エラーメッセージも無くなりません。
- 投稿日:2020-02-27T09:09:46+09:00
【Rails】Slackへの通知をActionMailerのようなerbテンプレートを使う形で実装する
以下のGemを利用してSlackで通知を実装する際ActionMailerのようにerbを使ってviewを分けられないかと検討した。
https://github.com/stevenosloan/slack-notifier
app/views/admin_slack_notifier/receive_message_from_user.text.erb【<%= @subject %>】 ■□–––––––––––––––––––––□■ ▼送信者情報 <%= @message.user.name %> ▼送信内容 <%= @message.content %> ■□–––––––––––––––––––––□■app/libs/slack_notifier.rbmodule SlackNotifier CONFIG = YAML.load_file(Rails.root.join('config', 'slack.yml'))[Rails.env] class << self def post(to, text, options = {}) options = options.symbolize_keys dry_run = options.key?(:dry_run) ? options[:dry_run] : CONFIG['dry_run'] post_options = format_options(to, text, options) notifier = Slack::Notifier.new CONFIG['webhook_url'] notifier.post post_options unless dry_run end private # rubocop:disable Metrics/AbcSize def format_options(to, text, options) post_options = { 'channel' => (options[:channel].presence || CONFIG[to.to_s]['channel']), 'icon_emoji' => (options[:icon_emoji].presence || CONFIG[to.to_s]['icon_emoji']), 'username' => (options[:username].presence || CONFIG[to.to_s]['username']), 'text' => text } post_options[:title] = options[:title] if options.key?(:title) post_options end # rubocop:enable Metrics/AbcSize end endapp/libs/admin_slack_notifier.rbmodule AdminSlackNotifier class << self def receive_message_from_user(message) @message = message @subject = 'ユーザーより新しいメッセージが送信されました' post_with_template 'admin_channel', __method__, binding end private def post_with_template(to, view_name, binding) erb = Rails.root.join('app', 'views', name.underscore, "#{view_name}.text.erb").read text = ERB.new(erb).result(binding) SlackNotifier.post to, text end end endconfig/slack.ymldevelopment: &default dry_run: true username: &username Admin webhook_url: WEBHOOK_URL admin_channel: channel: admin_channel icon_emoji: ":crystal_ball:" username: *username staging: <<: *default dry_run: false production: <<: *default dry_run: false test: <<: *default以下のような形でAction名と同様のviewを習得してSlackの通知を送信することができる。
sample.rbAdminSlackNotifier.receive_message_from_user(message)
- 投稿日:2020-02-27T09:00:03+09:00
ネストしたものに削除機能導入
gorupの中のmessageに削除機能導入
ネストの中のmessageに削除機能導入するさい躓いたので備忘録として書きます。
routes.rbresources :groups, only: [:new, :create, :edit, :update, :show] do resources :messages, only: [:index, :create, :destroy] endmessages_controller.rbbefore_action :set_group ... def destroy message = Message.find(params[:id]) message.destroy redirect_to group_messages_path(@groups) end ... def set_group @groups = Group.find(params[:group_id]) end問題点
躓いた箇所は下記のlink_to後ろの記述
このままではどのグループのどのメッセージなのか指定できてないmessages/index.html.erb<%= link_to "/messages/#{message.id}", method: :delete do%>下記のようにメッセージの前にどのグループかを指定することで解決
messages/index.html.erb<%= link_to "/groups/#{@groups.id}/messages/#{message.id}", method: :delete do%>rails routesをした時にURI Patternを見ておく!!!
- 投稿日:2020-02-27T07:16:18+09:00
Ruby on Rails チュートリアル学習記録 第3章
第2章については特に書く内容がなかったため学習記録は付けませんでした
3.1
heroku create
を実行するとbash: heroku: command not found
というエラーメッセージ。
https://qiita.com/RyuGotoo/items/7d44f7aa51f7c90ad0b7
↑こちらの記事参考に
nvm install node
npm install -g heroku-cli
を実行後、あらためてheroku create
を実行すると上手くいった。3.2
特になし
3.3
特になし
3.4
特になし
3.5
特になし
3.6
特になし
- 投稿日:2020-02-27T06:57:24+09:00
rails g model/migrationの違い
- 投稿日:2020-02-27T01:35:20+09:00
chat-spaceを作ろう②
TOPページを作成する
コントローラーを作成し、ルートを設定する
ターミナルrails g controller messages messagesコントロラーと、views/messagesディレクトリが作成されるcontroller/messages_controller.rbdef index end topページ用のindexアクションを定義するroutes.rbroot "messages#index" とりあえず、TOPページを表示する為のルートを設定するビューファイルを作成する
views/messagesディレクトリ内に以下のファイルを作成する
- index.html.haml (indexアクションに対応したビューファイル)
- _side_bar.html.haml (TOPページの左サイド部分)
- _main_chat.html.haml (TOPページのメイン部分)
views/messages/index.html.haml.wrapper side_barとmain_chatの要素を囲むコンテナ(特に意味はない) = render "shared/side_bar.html.haml" = render "main_chat.html.haml" 部分テンプレートを呼び出す今日ここまで
次回はアイコンを使用できる様にします
見本サイト